Index: modules/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload.module,v
retrieving revision 1.51
diff -u -r1.51 upload.module
--- modules/upload.module	2 Sep 2005 02:11:41 -0000	1.51
+++ modules/upload.module	16 Sep 2005 15:37:05 -0000
@@ -14,7 +14,17 @@
     case 'admin/modules#description':
       return t('Allows users to upload and attach files to content.');
     case 'admin/settings/upload':
-      return t('<p>Users with the <a href="%permissions">upload files permission</a> can upload attachments. You can choose which post types can take attachments on the <a href="%types">content types settings</a> page.</p>', array('%permissions' => url('admin/access'), '%types' => url('admin/settings/content-types')));
+      return t('
+<p>Users with the <a href="%permissions">upload files permission</a> can upload attachments. You can choose which post types can take attachments on the <a href="%types">content types settings</a> page.</p>', array('%permissions' => url('admin/access'), '%types' => url('admin/settings/content-types')));
+    case 'admin/upload':
+      return t('
+<p>Below is a list of all files uploaded to the site and statistics about those files.</p><p>Clicking a filename shows the file, clicking a title opens the post where the file was uploaded, and clicking an author will show information about the post\'s author.</p>');
+    case 'admin/upload/usage':
+      return t('
+<p>Below is a list of all the the users that have uploaded files to the site.</p><p>Clicking a username will show information about the user.</p>');
+    case 'upload':
+      return t('
+<p>Below is information about the files you can upload, a list of all the files you have uploaded, and statistics about those files.</p><p>Clicking a filename shows the file, while clicking a title opens the post where the file was uploaded.</p>');
   }
 }
 
@@ -22,7 +32,7 @@
  * Implementation of hook_perm().
  */
 function upload_perm() {
-  return array('upload files', 'view uploaded files');
+  return array('upload files', 'view uploaded files', 'administer uploaded files');
 }
 
 /**
@@ -48,6 +58,63 @@
 }
 
 /**
+ * Return statistics about uploads
+ *
+ * @return
+ *   Themed statistical information.
+**/
+function upload_statistics() {
+  global $user;
+  $extensions = array();
+
+  // get the total number and size of upload files
+  $total_size = upload_space_used($user->uid);
+  $total_num = upload_file_count($user->uid);
+
+  // determine what upload settings apply to the user
+  // User 1 can upload any file of any size without limit
+  if ($user->uid == 1) {
+     $max_one_size = t('unlimited');
+     $max_all_size = t('unlimited');
+     $extensions = t('unlimited');
+  }
+  else {
+    // loop through all roles user is part of to get actual set of allowable extensions and filesizes
+    foreach ($user->roles as $rid => $value) {
+      $temp = explode(' ', variable_get("upload_extensions_$rid", variable_get("upload_extensions_default", "jpg jpeg gif png txt html htm doc xls pdf ppt pps zip")));
+      $extensions = array_merge($extensions, $temp);
+  
+      $uploadsize = variable_get("upload_uploadsize_$rid", variable_get("upload_uploadsize_default", 1)) * 1024 * 1024;
+      $max_one_size = ($uploadsize > $max_one_size) ? $uploadsize : $max_one_size;
+      $usersize = variable_get("upload_usersize_$rid", variable_get("upload_usersize_default", 10)) * 1024 * 1024;
+      $max_all_size = ($usersize > $max_all_size) ? $usersize : $max_all_size;
+    }
+  
+    // prepare information
+    $percent = ($max_all_size) ? '('. sprintf("%.2f", ($total_size / $max_all_size) * 100) .'%)' : '';
+    $max_all_size = format_size($max_all_size);
+    $max_one_size = format_size($max_one_size);
+    $extensions = implode(' ', $extensions);
+  }
+
+  // output information
+  $items = array();
+  $items[] = t('<p>Allowed file extensions: %extensions</p>', array('%extensions' => $extensions));
+  $items[] .= t('<p>Maximum size of each file: %size</p>', array('%size' => $max_one_size));
+  $items[] .= t('<p>Maximum size of all files: %size</p>', array('%size' => $max_all_size));
+  $content = theme('item_list', $items);
+  $output = theme('box', t('Allowances'), $content);
+
+  $items = array();
+  $items[] = t('<p>Total files: %total</p>', array('%total' => $total_num));
+  $items[] .= t('<p>Disk usage: %used of %max %percent</p>', array('%used' => format_size($total_size), '%max' => $max_all_size, '%percent' => $percent));
+  $content = theme('item_list', $items);
+  $output .= theme('box', t('Statistics'), $content);
+
+  return $output;
+}
+
+/**
  * Implementation of hook_menu().
  */
 function upload_menu($may_cache) {
@@ -56,7 +123,7 @@
   if ($may_cache) {
     $items[] = array(
       'path' => 'admin/settings/upload', 'title' => t('uploads'),
-      'callback' => 'upload_admin',
+      'callback' => 'upload_settings',
       'access' => user_access('administer site configuration'),
       'type' => MENU_NORMAL_ITEM
     );
@@ -66,6 +133,30 @@
       'access' => user_access('upload files'),
       'type' => MENU_CALLBACK
     );
+    $items[] = array(
+      'path' => 'upload', 'title' => t('my uploads'),
+      'callback' => 'upload_page',
+      'access' => user_access('upload files'),
+      'type' => MENU_NORMAL_ITEM
+    );
+    $items[] = array(
+      'path' => 'admin/upload', 'title' => t('uploads'),
+      'callback' => 'upload_admin',
+      'access' => user_access('administer uploaded files'),
+      'type' => MENU_NORMAL_ITEM
+    );
+    $items[] = array(
+      'path' => 'admin/upload/list', 'title' => t('list'),
+      'access' => user_access('administer uploaded files'),
+      'type' => MENU_DEFAULT_LOCAL_TASK,
+      'weight' => -10
+    );
+    $items[] = array(
+      'path' => 'admin/upload/usage', 'title' => t('disk space usage'),
+      'callback' => 'upload_admin_usage',
+      'access' => user_access('administer uploaded files'),
+      'type' => MENU_LOCAL_TASK
+    );
   }
   else {
     // Add handlers for previewing new uploads.
@@ -86,19 +177,273 @@
   return $items;
 }
 
+/*
+ * Menu callback:
+ * Page where admins manage uploaded files
+ */
 function upload_admin() {
+
+  $operations = array(
+    'delete' => array(t('Delete the selected files'), '')
+  );
+
+  // Handle operations
+  $op = $_POST['op'];
+  $edit = $_POST['edit'];
+
+  if (($op == t('Update') || $op == t('Delete all')) && isset($edit['operation']) && isset($edit['files'])) {
+    $edit['files'] = array_diff($edit['files'], array(0));
+    if (count($edit['files']) == 0) {
+      form_set_error('', t('Please select some items to perform the update on.'));
+    }
+    else {
+      if ($edit['operation'] == 'delete') {
+        // Mass delete
+        if ($edit['confirm']) {
+          upload_delete('files', $edit['files']);
+          drupal_set_message(t('The items have been deleted.'));
+        }
+        else {
+          $extra = '<ul>';
+          foreach ($edit['files'] as $fid => $value) {
+            if ($value) {
+              $title = db_result(db_query('SELECT filename FROM {files} WHERE fid = %d', $fid));
+              $extra .= '<li>'. form_hidden('files]['. $fid, 1) . check_plain($title) .'</li>';
+            }
+          }
+          $extra .= '</ul>';
+          $extra .= form_hidden('operation', 'delete');
+
+          $output = theme('confirm',
+                          t('Are you sure you want to delete these items?'),
+                          'admin/upload',
+                          t('This action cannot be undone.'),
+                          t('Delete all'),
+                          t('Cancel'),
+                          $extra);
+          return $output;
+        }
+      }
+    }
+  }
+
+  // Get statistics about files
+  $total_size = upload_total_space_used();
+  $content = t('<p>Total disk space used: %size</p>', array('%size' => format_size($total_size)));
+  $output .= theme('box', t('Statistics'), $content);
+
+  $header = array(
+    NULL,
+    array('data' => t('Filename'), 'field' => 'filename'),
+    array('data' => t('Title'), 'field' => 'title'),
+    array('data' => t('Author'), 'field' => 'name'),
+    array('data' => t('Size'), 'field' => 'filesize', 'sort' => 'desc')
+  );
+
+  $sql = 'SELECT DISTINCT f.fid, n.nid, n.status, n.title, f.filename, f.filepath, f.filesize, n.uid, u.name FROM {files} f INNER JOIN {node} n ON f.nid = n.nid INNER JOIN {users} u ON u.uid = n.uid';
+  $sql .= tablesort_sql($header);
+  $result = pager_query($sql, 50);
+
+  // Make sure the update controls are disabled if we don't have any rows
+  // to select from.
+  $disabled = !db_num_rows($result);
+
+  $options = array();
+  foreach ($operations as $key => $value) {
+    $options[$key] = $value[0];
+  }
+
+  $form = form_select(NULL, 'operation', 0, $options, NULL, ($disabled ? 'disabled="disabled"' : ''));
+  $form .= form_submit(t('Update'), 'op', ($disabled ? array('disabled' => 'disabled') : array()));
+
+  $output .= form_group(t('Update options'), "<div class=\"container-inline\">$form</div>");
+
+  $destination = drupal_get_destination();
+  while ($file = db_fetch_object($result)) {
+    $format_user->name = $file->name;
+    $format_user->uid = $file->uid;
+
+    $rows[] = array(
+      form_checkbox(NULL, 'files]['. $file->fid, 1, 0),
+      '<a href="'. check_url(($file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path())))) .'">'. check_plain($file->filename) .'</a>',
+      ($file->status) ? l($file->title, "node/$file->nid") : $file->title,
+      theme('username', $format_user),
+      format_size($file->filesize)
+    );
+  }
+
+  if ($pager = theme('pager', NULL, 50, 0, tablesort_pager())) {
+    $rows[] = array(array('data' => $pager, 'colspan' => '5'));
+  }
+
+  if (!$rows) {
+    $rows[] = array(array('data' => t('No uploaded files available.'), 'colspan' => '5'));
+  }
+  $output .= theme('table', $header, $rows);
+  return form($output, 'post', url('admin/upload'));
+}
+
+/**
+ * Menu callback:
+ * Page listing disk space usage for each user
+**/
+function upload_admin_usage() {
+  // Unable to sort on file size becuase you can't use sub-selects and have only one query
+  // See upload_total_space_used for more info.
+  $header = array(
+    array('data' => t('Username'), 'field' => 'name'),
+    array('data' => t('Size'), array())
+  );
+
+  $sql = 'SELECT uid, name FROM {users} WHERE uid > 0';
+  $sql .= tablesort_sql($header);
+  $result = pager_query($sql, 50);
+
+  // Make sure the update controls are disabled if we don't have any rows
+  // to select from.
+  $disabled = !db_num_rows($result);
+
+  while ($users = db_fetch_object($result)) {
+    $format_user->name = $users->name;
+    $format_user->uid = $users->uid;
+
+    $rows[] = array(
+      theme('username', $format_user),
+      format_size(upload_space_used($users->uid))
+    );
+  }
+
+  if ($pager = theme('pager', NULL, 50, 0, tablesort_pager())) {
+    $rows[] = array(array('data' => $pager, 'colspan' => '2'));
+  }
+
+  if (!$rows) {
+    $rows[] = array(array('data' => t('No users have uploaded files.'), 'colspan' => '2'));
+  }
+
+  return theme('table', $header, $rows);
+}
+
+/*
+ * Menu callback:
+ * Page where users manage their uploaded files
+ */
+function upload_page() {
+  global $user;
+
+  $operations = array(
+    'delete' =>    array(t('Delete the selected files'), '')
+  );
+
+  // Handle operations
+  $op = $_POST['op'];
+  $edit = $_POST['edit'];
+
+  if (($op == t('Update') || $op == t('Delete all')) && isset($edit['operation']) && isset($edit['files'])) {
+    $edit['files'] = array_diff($edit['files'], array(0));
+    if (count($edit['files']) == 0) {
+      form_set_error('', t('Please select some items to perform the update on.'));
+    }
+    else {
+      if ($edit['operation'] == 'delete') {
+        // Mass delete
+        if ($edit['confirm']) {
+          upload_delete('files', $edit['files']);
+          drupal_set_message(t('The items have been deleted.'));
+        }
+		  // same as how node.module deletes lots of content
+        else {
+          $extra = '<ul>';
+          foreach ($edit['files'] as $fid => $value) {
+            if ($value) {
+              $title = db_result(db_query('SELECT filename FROM {files} WHERE fid = %d', $fid));
+              $extra .= '<li>'. form_hidden('files]['. $fid, 1) . check_plain($title) .'</li>';
+            }
+          }
+          $extra .= '</ul>';
+          $extra .= form_hidden('operation', 'delete');
+
+          $output = theme('confirm',
+                          t('Are you sure you want to delete these items?'),
+                          'upload',
+                          t('This action cannot be undone.'),
+                          t('Delete all'),
+                          t('Cancel'),
+                          $extra);
+          return $output;
+        }
+      }
+    }
+  }
+
+  $output .= upload_statistics();
+
+  $header = array(
+    NULL,
+    array('data' => t('Filename'), 'field' => 'filename'),
+    array('data' => t('Title'), 'field' => 'title'),
+    array('data' => t('Size'), 'field' => 'filesize', 'sort' => 'desc')
+  );
+
+  $sql = 'SELECT f.fid, n.nid, n.status, n.title, f.filename, f.filepath, f.filesize, n.uid FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE n.uid = %d';
+  $sql .= tablesort_sql($header);
+  $result = pager_query($sql, 50, 0, NULL, $user->uid);
+
+  // Make sure the update controls are disabled if we don't have any rows
+  // to select from.
+  $disabled = !db_num_rows($result);
+
+  $options = array();
+  foreach ($operations as $key => $value) {
+    $options[$key] = $value[0];
+  }
+
+  $form = form_select(NULL, 'operation', 0, $options, NULL, ($disabled ? 'disabled="disabled"' : ''));
+  $form .= form_submit(t('Update'), 'op', ($disabled ? array('disabled' => 'disabled') : array()));
+
+  $output .= form_group(t('Update options'), "<div class=\"container-inline\">$form</div>");
+
+  $destination = drupal_get_destination();
+  while ($file = db_fetch_object($result)) {
+    $rows[] = array(
+      form_checkbox(NULL, 'files]['. $file->fid, 1, 0),
+      '<a href="'. check_url(($file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path())))) .'">'. check_plain($file->filename) .'</a>',
+      ($file->status) ? l($file->title, "node/$file->nid") : $file->title,
+      format_size($file->filesize)
+    );
+  }
+
+  if ($pager = theme('pager', NULL, 50, 0, tablesort_pager())) {
+    $rows[] = array(array('data' => $pager, 'colspan' => '4'));
+  }
+
+  if (!$rows) {
+    $rows[] = array(array('data' => t('No uploaded files available.'), 'colspan' => '4'));
+  }
+  $output .= theme('table', $header, $rows);
+  return form($output, 'post', url('upload'));
+}
+
+function upload_settings() {
   system_settings_save();
 
-  $group .= form_textfield(t('Maximum resolution for uploaded images'), 'upload_max_resolution', variable_get('upload_max_resolution', 0), 15, 10, t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction.'));
+  $upload_extensions_default = variable_get("upload_extensions_default", "jpg jpeg gif png txt html htm doc xls pdf ppt pps zip");
+  $upload_uploadsize_default = variable_get("upload_uploadsize_default", 1);
+  $upload_usersize_default = variable_get("upload_usersize_default", 10);
+
+  $group = form_textfield(t('Maximum resolution for uploaded images'), 'upload_max_resolution', variable_get('upload_max_resolution', 0), 15, 10, t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction.'));
+  $group .= form_textfield(t('Default permitted file extensions'), "upload_extensions_default", $upload_extensions_default, 60, 255, t('Default extensions that users can upload. Separate extensions with a space and do not include the leading dot.'));
+  $group .= form_textfield(t('Default maximum file size per upload'), "upload_uploadsize_default", $upload_uploadsize_default, 5, 5, t('Default maximum size of a file a user can upload (in megabytes).'));
+  $group .= form_textfield(t('Default total file size per user'), "upload_usersize_default", $upload_usersize_default, 5, 5, t('Default maximum size of all files a user can have on the site (in megabytes).'));
 
   $output = form_group(t('General settings'), $group);
 
   $roles = user_roles(0, 'upload files');
 
   foreach ($roles as $rid => $role) {
-    $group = form_textfield(t('Permitted file extensions'), "upload_extensions_$rid", variable_get("upload_extensions_$rid", "jpg jpeg gif png txt html doc xls pdf ppt pps"), 60, 255, t('Extensions that users in this role can upload. Separate extensions with a space and do not include the leading dot.'));
-    $group .= form_textfield(t('Maximum file size per upload'), "upload_uploadsize_$rid", variable_get("upload_uploadsize_$rid", 1), 5, 5, t('The maximum size of a file a user can upload (in megabytes).'));
-    $group .= form_textfield(t('Total file size per user'), "upload_usersize_$rid", variable_get("upload_usersize_$rid", 10), 5, 5, t('The maximum size of all files a user can have on the site (in megabytes).'));
+    $group = form_textfield(t('Permitted file extensions'), "upload_extensions_$rid", variable_get("upload_extensions_$rid", $upload_extensions_default), 60, 255, t('Extensions that users in this role can upload. Separate extensions with a space and do not include the leading dot.'));
+    $group .= form_textfield(t('Maximum file size per upload'), "upload_uploadsize_$rid", variable_get("upload_uploadsize_$rid", $upload_uploadsize_default), 5, 5, t('Maximum size of a file a user can upload (in megabytes).'));
+    $group .= form_textfield(t('Total file size per user'), "upload_usersize_$rid", variable_get("upload_usersize_$rid", $upload_usersize_default), 5, 5, t('Maximum size of all files a user can have on the site (in megabytes).'));
     $output .= form_group(t('Settings for %role', array('%role' => theme('placeholder', $role))), $group);
   }
 
@@ -143,6 +488,7 @@
       break;
 
     case 'validate':
+
       $node->files = upload_load($node);
 
       // Double check existing files:
@@ -164,60 +510,62 @@
         }
       }
 
-      if (($file = file_check_upload('upload')) && user_access('upload files')) {
-        global $user;
-
-        $file = _upload_image($file);
-
-        // Don't do any checks for uid #1.
-        if ($user->uid != 1) {
-          // Validate file against all users roles. Only denies an upload when
-          // all roles prevent it.
-          $total_usersize = upload_space_used($user->uid) + $filesize;
-          foreach ($user->roles as $rid => $name) {
-            $extensions = variable_get("upload_extensions_$rid", 'jpg jpeg gif png txt html doc xls pdf ppt pps');
-            $uploadsize = variable_get("upload_uploadsize_$rid", 1) * 1024 * 1024;
-            $usersize = variable_get("upload_usersize_$rid", 1) * 1024 * 1024;
-
-            $regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i';
-
-            if (!preg_match($regex, $file->filename)) {
-              $error['extension']++;
-            }
-
-            if ($uploadsize && $file->filesize > $uploadsize) {
-              $error['uploadsize']++;
-            }
-
-            if ($usersize && $total_usersize + $file->filesize > $usersize) {
-              $error['usersize']++;
+      if ($file = file_check_upload('upload')) {
+        if (user_access('upload files')) {
+          global $user;
+
+          $file = _upload_image($file);
+
+          // Don't do any checks for uid #1.
+          if ($user->uid != 1) {
+            // Validate file against all users roles. Only denies an upload when
+            // all roles prevent it.
+            $total_usersize = upload_space_used($user->uid) + $filesize;
+            foreach ($user->roles as $rid => $name) {
+              $extensions = variable_get("upload_extensions_$rid", variable_get("upload_extensions_default", "jpg jpeg gif png txt html htm doc xls pdf ppt pps zip"));
+              $uploadsize = variable_get("upload_uploadsize_$rid", variable_get("upload_uploadsize_default", 1)) * 1024 * 1024;
+              $usersize = variable_get("upload_usersize_$rid", variable_get("upload_usersize_default", 10)) * 1024 * 1024;
+
+              $regex = '/\.('. ereg_replace(' +', '|', preg_quote($extensions)) .')$/i';
+
+              if (!preg_match($regex, $file->filename)) {
+                $error['extension']++;
+              }
+
+              if ($uploadsize && $file->filesize > $uploadsize) {
+                $error['uploadsize']++;
+              }
+
+              if ($usersize && $total_usersize + $file->filesize > $usersize) {
+                $error['usersize']++;
+              }
             }
           }
-        }
 
-        // Rename possibly executable scripts to prevent accidental execution.
-        // Uploaded files are attachments and should be shown in their original
-        // form, rather than run.
-        if (preg_match('/\.(php|pl|py|cgi|asp)$/i', $file->filename)) {
-          $file->filename .= '.txt';
-          $file->filemime = 'text/plain';
-        }
+          // Rename possibly executable scripts to prevent accidental execution.
+          // Uploaded files are attachments and should be shown in their original
+          // form, rather than run.
+          if (preg_match('/\.(php|pl|py|cgi|asp)$/i', $file->filename)) {
+            $file->filename .= '.txt';
+            $file->filemime = 'text/plain';
+          }
 
-        if ($error['extension'] == count($user->roles) && $user->uid != 1) {
-          form_set_error('upload', t('The selected file %name can not be attached to this post, because it is only possible to attach files with the following extensions: %files-allowed.', array('%name' => theme('placeholder', $file->filename), '%files-allowed' => theme('placeholder', $extensions))));
-        }
-        elseif ($error['uploadsize'] == count($user->roles) && $user->uid != 1) {
-          form_set_error('upload', t('The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %maxsize.', array('%name' => theme('placeholder', $file->filename), '%maxsize' => theme('placeholder', format_size($uploadsize)))));
-        }
-        elseif ($error['usersize'] == count($user->roles) && $user->uid != 1) {
+          if ($error['extension'] == count($user->roles) && $user->uid != 1) {
+            form_set_error('upload', t('The selected file %name can not be attached to this post, because it is only possible to attach files with the following extensions: %files-allowed.', array('%name' => theme('placeholder', $file->filename), '%files-allowed' => theme('placeholder', $extensions))));
+          }
+          elseif ($error['uploadsize'] == count($user->roles) && $user->uid != 1) {
+            form_set_error('upload', t('The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %maxsize.', array('%name' => theme('placeholder', $file->filename), '%maxsize' => theme('placeholder', format_size($uploadsize)))));
+          }
+          elseif ($error['usersize'] == count($user->roles) && $user->uid != 1) {
           form_set_error('upload', t('The selected file %name can not be attached to this post, because the disk quota of %quota has been reached.', array('%name' => theme('placeholder', $file->filename), '%quota' => theme('placeholder', format_size($usersize)))));
-        }
-        else {
-          $key = 'upload_'. count($_SESSION['file_uploads']);
-          $file->source = $key;
-          $file->list = 1;
-          $file = file_save_upload($file);
-          $node->files[$key] = $file;
+          }
+          else {
+            $key = 'upload_'. count($_SESSION['file_uploads']);
+            $file->source = $key;
+            $file->list = 1;
+            $file = file_save_upload($file);
+            $node->files[$key] = $file;
+          }
         }
       }
       break;
@@ -284,7 +632,7 @@
       break;
 
     case 'delete':
-      upload_delete($node);
+      upload_delete('node', $node);
       break;
     case 'search result':
       return $node->files ? format_plural(count($node->files), '1 attachment', '%count attachments') : null;
@@ -311,26 +659,56 @@
   return $output;
 }
 
+
+/**
+ * Determine how many files a user has.
+ *
+ * @param $uid
+ *   The integer user id of a user.
+ * @return
+ *   The number of files the user currently has.
+ */
+function upload_file_count($uid){
+  $result = db_query('SELECT fid filecount FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE n.uid = %d GROUP BY fid', $uid);
+  
+  return db_num_rows($result);
+}   
+ 
 /**
  * Determine how much disk space is occupied by a user's uploaded files.
  *
  * @param $uid
  *   The integer user id of a user.
  * @return
- *   The ammount of disk space used by the user in bytes.
+ *   The amount of disk space used by the user in bytes.
  */
 function upload_space_used($uid) {
-  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node_revisions} n ON f.vid = n.vid WHERE uid = %d', $uid));
+  $total = 0;
+  $result = db_query('SELECT fid,filesize FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE n.uid = %d GROUP BY fid', $uid);
+
+  while ($files = db_fetch_array($result)) {
+    $total += $files['filesize'];
+  }
+  return $total;
 }
 
 /**
  * Determine how much disk space is occupied by uploaded files.
  *
  * @return
- *   The ammount of disk space used by uploaded files in bytes.
+ *   The amount of disk space used by uploaded files in bytes.
  */
 function upload_total_space_used() {
-  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node_revisions} n ON f.vid = n.vid'));
+  // If we could use subselects we could get rid of this PHP code
+  // SELECT SUM(t.filesize) FROM (SELECT fid,filesize FROM files GROUP BY fid) as t
+  // This is because we are using the SUM aggregate function.
+  $total = 0;
+  $result = db_query('SELECT fid,filesize FROM {files} GROUP BY fid');
+
+  while ($files = db_fetch_array($result)) {
+    $total += $files['filesize'];
+  }
+  return $total;
 }
 
 function upload_save($node) {
@@ -375,12 +753,25 @@
   return;
 }
 
-function upload_delete($node) {
-  $node->files = upload_load($node);
-  foreach ($node->files as $file) {
-    file_delete($file->filepath);
+function upload_delete($op, $arg) {
+  switch($op) {
+    case 'node':
+      $node = $arg;
+      $node->files = upload_load($node);
+      foreach ($node->files as $file) {
+        file_delete($file->filepath);
+      }
+      db_query('DELETE FROM {files} WHERE nid = %d', $node->nid);
+      break;
+    case 'files':
+      foreach ($arg as $fid => $value) {
+        db_query('SELECT filepath FROM {files} WHERE fid = %d', $fid);
+        $file = db_fetch_object($result);
+        file_delete($file->filepath);
+        db_query('DELETE FROM {files} WHERE fid = %d', $fid);
+      }
+      break;
   }
-  db_query("DELETE FROM {files} WHERE nid = %d", $node->nid);
 }
 
 function upload_form($node) {
