? comment_upload_d6_port.patch
Index: comment_upload.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/comment_upload/comment_upload.info,v
retrieving revision 1.2
diff -u -p -r1.2 comment_upload.info
--- comment_upload.info	18 Jun 2007 22:53:34 -0000	1.2
+++ comment_upload.info	31 Dec 2007 01:29:28 -0000
@@ -1,4 +1,6 @@
 ; $ID$
 name = Comment upload
 description = Allows users to attach files to comments.
-dependencies = upload comment
+dependencies[] = upload
+dependencies[] = comment
+core = 6.x
\ No newline at end of file
Index: comment_upload.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/comment_upload/comment_upload.install,v
retrieving revision 1.3
diff -u -p -r1.3 comment_upload.install
--- comment_upload.install	17 Jan 2007 09:08:52 -0000	1.3
+++ comment_upload.install	31 Dec 2007 01:29:28 -0000
@@ -1,66 +1,100 @@
 <?php
+// $ID$
+
+/**
+* Implementation of hook_schema().
+*/
+function comment_upload_schema() {
+  $schema['comment_upload_files'] = array(
+    'fields' => array(
+       'fid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'nid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'cid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filepath' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filemime' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filesize' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'description' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'list' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'weight' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'),
+    ),
+    'indexes' => array(
+       'nid'    => array('nid'),
+    ),
+    'primary key' => array('fid')
+  );
+
+  return $schema;
+}
 
 function comment_upload_install() {
-  switch ($GLOBALS['db_type']) {
-    case 'mysql':
-    case 'mysqli':
-      db_query("CREATE TABLE {comment_upload_files} (
-          `fid` int(10) unsigned NOT NULL default '0',
-          `nid` int(10) unsigned NOT NULL default '0',
-          `cid` int NOT NULL default '0',
-          `filename` varchar(255) NOT NULL default '',
-          `filepath` varchar(255) NOT NULL default '',
-          `filemime` varchar(255) NOT NULL default '',
-          `filesize` int(10) unsigned NOT NULL default '0',
-           description varchar(255) NOT NULL default '',
-           list tinyint(1) unsigned NOT NULL default 0,
-           PRIMARY KEY (`fid`)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
-      break;
-  }
+  drupal_install_schema('comment_upload');
 }
 
-function comment_upload_update_1() {
+function comment_upload_update_5000() {
   $ret = array();
-  $ret = update_sql("ALTER TABLE {comment_files} ADD nid int NOT NULL default '0'");
+  db_add_field($ret, 'comment_files', 'nid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
 
   // loop through all the comment upload records and populate the nid column
   $results = db_query("SELECT c.cid, c.nid FROM {comments} c WHERE c.cid IN (SELECT DISTINCT cf.cid FROM {comment_files} cf)");
   while ($c = db_fetch_object($results)) {
-    $ret = update_sql("UPDATE {comment_files} SET nid = $c->nid WHERE cid = $c->cid");
+    $ret[] = update_sql("UPDATE {comment_files} SET nid = $c->nid WHERE cid = $c->cid");
   }
   return $ret;
 }
 
 /**
  * Move previously saved data from {files}, {file_revisions} and {comment_files}
- * into {comment_upload_files} and {comment_upload_file_revisions}.
+ * into {comment_upload_files}.
  */
-function comment_upload_update_2() {
+function comment_upload_update_5001() {
+  $schema['comment_upload_files'] = array(
+    'fields' => array(
+       'fid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'nid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'cid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filepath' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filemime' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'filesize' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'description' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+       'list' => array('type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+       'weight' => array('type' => 'int', 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0),
+    ),
+    'primary key' => array('vid')
+  );
+
   $ret = array();
-  $ret[] = update_sql("CREATE TABLE {comment_upload_files} (
-          `fid` int(10) unsigned NOT NULL default '0',
-          `nid` int(10) unsigned NOT NULL default '0',
-          `cid` int NOT NULL default '0',
-          `filename` varchar(255) NOT NULL default '',
-          `filepath` varchar(255) NOT NULL default '',
-          `filemime` varchar(255) NOT NULL default '',
-          `filesize` int(10) unsigned NOT NULL default '0',
-           description varchar(255) NOT NULL default '',
-           list tinyint(1) unsigned NOT NULL default 0,
-           PRIMARY KEY (`fid`)
-        ) /*!40100 DEFAULT CHARACTER SET utf8 */;");
+  db_create_table($ret, 'comment_upload_files', $schema['comment_upload_files']);
 
   $max_fid = db_result(db_query("SELECT MAX(fid) FROM {comment_files}"));
   $results = db_query("SELECT f.fid, cf.nid, cf.cid, cf.cid, f.filename, f.filepath, f.filemime, f.filesize, r.list, r.description FROM {files} f INNER JOIN {file_revisions} r ON f.fid = r.fid INNER JOIN {comment_files} cf ON f.fid = cf.fid WHERE f.nid = 0");
 
   while ($c = db_fetch_object($results)) {
-    db_query("INSERT INTO {comment_upload_files} (fid, nid, cid, filename, filepath, filemime, filesize, description, list) VALUES(%d, %d, %d, '%s', '%s', '%s', %d, '%s', %d)", $c->fid, $c->nid, $c->cid, $c->filename, $c->filepath, $c->filemime, $c->filesize, $c->description, $c->list);
+    db_query("INSERT INTO {comment_upload_files} (fid, nid, cid, filename, filepath, filemime, filesize, description, list, weigth) VALUES(%d, %d, %d, '%s', '%s', '%s', %d, '%s', %d)", $c->fid, $c->nid, $c->cid, $c->filename, $c->filepath, $c->filemime, $c->filesize, $c->description, $c->list);
     db_query("DELETE FROM {files} WHERE fid = %d", $c->fid);
     db_query("DELETE FROM {file_revisions} WHERE fid = %d", $c->fid);
   }
+  if ($max_fid) {
+    $ret[] = update_sql("INSERT INTO {sequences} (name, id) VALUES('" . db_prefix_tables('{comment_upload_files}'). "_fid', $max_fid)");
+  }
+  db_drop_table($ret, "comment_files");
+  return $ret;
+}
 
-  $ret[] = update_sql("INSERT INTO {sequences} (name, id) VALUES('" . db_prefix_tables('{comment_upload_files}'). "_fid', $max_fid)");
-  $ret[] = update_sql("DROP TABLE {comment_files}");
+/**
+ * Update column cid to be an unsigned int.
+ * Add index on nid.
+ */
+function comment_upload_update_5002() {
+  $ret = array();
+    db_change_field($ret, 'comment_upload_files', 'cid', 'cid', array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0));
+    db_add_index($ret, 'comment_upload_files', 'nid', array('nid'));
+    return $ret;
+}
+
+function comment_upload_update_5003() {
+  $ret = array();
+  db_add_field($ret, 'comment_upload_files', 'weight', array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny'));
   return $ret;
 }
\ No newline at end of file
Index: comment_upload.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/comment_upload/comment_upload.module,v
retrieving revision 1.6
diff -u -p -r1.6 comment_upload.module
--- comment_upload.module	17 Jan 2007 10:00:18 -0000	1.6
+++ comment_upload.module	31 Dec 2007 01:29:29 -0000
@@ -1,58 +1,14 @@
 <?php
-// $Id: comment_upload.module,v 1.6 2007/01/17 10:00:18 heine Exp $
 
+// $ID$
+
+/**
+ * Implementation of hook_comment.
+ */
 function comment_upload_comment(&$comment, $op) {
   $cid = is_object($comment) ? $comment->cid : $comment['cid'];
   $cid = is_array($cid) ? $cid['#value'] : $cid;
   switch ($op) {
-    case 'form':
-      $node = node_load($comment['nid']['#value']);
-      if (!user_access('upload files') || !variable_get('comment_upload_'. $node->type, 1)) {
-        break;
-      }
-      $cobj->cid = $cid;
-      $cobj->files = _comment_upload_load_files($cid);
-      _upload_prepare($cobj);
-      $form = array('#attributes' => array('enctype' => 'multipart/form-data'));
-      if (variable_get('comment_upload_single', 0)) {
-        $form['upload'] = array(
-        '#type' => 'file',
-          '#title' => t('Attachment'),
-          '#size' => 50,
-          '#description' => !empty($cobj->files) ? t('You already have a file uploaded, if you upload another it will overwrite the current one.') :''
-          );
-      }
-      else {
-        drupal_add_js('misc/progress.js');
-        drupal_add_js('misc/upload.js');
-
-        // Attachments fieldset
-        $form['attachments'] = array(
-          '#type' => 'fieldset',
-          '#title' => t('File attachments'),
-          '#collapsible' => TRUE,
-          '#collapsed' => empty($cobj->files),
-          '#description' => t('Changes made to the attachments are not permanent until you save this post.'),
-          '#prefix' => '<div class="attachments">',
-          '#suffix' => '</div>',
-          '#weight' => 10,
-        );
-
-        // Wrapper for fieldset contents (used by upload JS).
-        $form['attachments']['wrapper'] = array(
-          '#prefix' => '<div id="attach-wrapper">',
-          '#suffix' => '</div>',
-        );
-        $form['attachments']['wrapper'] += _upload_form($cobj);
-
-        $form['attachments']['wrapper']['attach-url']['#value'] = url('comment_upload/js', NULL, NULL, TRUE);
-        $form['current']['cid'] = array('#type' => 'hidden', '#value' => $cid);
-        unset($form['attachments']['wrapper']['current']['vid']);
-      }
-      return $form;
-    case 'validate':
-      _upload_validate($comment);
-      break;
     case 'insert':
     case 'update':
       $node = node_load($comment['nid']);
@@ -60,9 +16,11 @@ function comment_upload_comment(&$commen
         _comment_upload_save_files($comment);
       }
       break;
+    
     case 'delete':
       _comment_upload_delete($cid);
       break;
+    
     case 'view':
       if (!user_access('view uploaded files')) {
         break;
@@ -80,19 +38,99 @@ function comment_upload_comment(&$commen
         }
       }
       if ($comment->files) {
-        if (count($comment->files) == 1 && variable_get('comment_upload_single', 0)) {
-          $files = $comment->files;
-          $comment->comment .= theme('comment_attachment', (object)array_pop($files), $comment);
+        $comment->comment .= theme('comment_attachments', $comment->files);
+      }
+      break;
+    }
+}
+
+function comment_upload_form_submit_build_comment($form, &$form_state) {
+  // Unset any button-level handlers, execute all the form-level submit
+  // functions to process the form values into an updated comment.
+  unset($form_state['submit_handlers']);
+  upload_node_form_submit($form, &$form_state);
+  comment_form_submit($form, &$form_state);
+}
+
+/**
+ * Hook into node type and upload settings forms.
+ */
+function comment_upload_form_alter(&$form, $form_state, $form_id) {
+  if ($form_id == 'comment_form') {
+    $cid = $form['cid']['#value'];
+    $node = node_load($form['nid']['#value']);
+    $cobj->cid = $cid;
+    
+    if(!$_POST) {
+      $_SESSION['upload_files'] = array();
+      $cobj->files = _comment_upload_load_files($cid);
+    }
+    else {
+      $cobj->files = isset($_SESSION['upload_files']) ? $_SESSION['upload_files'] : array();
+    }
+
+    if (variable_get('comment_upload_single', 0)) {
+      $form['upload'] = array(
+        '#type' => 'file',
+        '#title' => t('Attachment'),
+        '#size' => 50,
+        '#description' => !empty($cobj->files) ? t('You already have a file uploaded, if you upload another it will overwrite the current one.') :''
+      );
+    }
+    else {
+      // Attachments fieldset
+      $form['attachments'] = array(
+        '#type' => 'fieldset',
+        '#access' => user_access('upload files'),
+        '#title' => t('File attachments'),
+        '#collapsible' => TRUE,
+        '#collapsed' => empty($cobj->files),
+        '#description' => t('Changes made to the attachments are not permanent until you save this post.'),
+        '#prefix' => '<div class="attachments">',
+        '#suffix' => '</div>',
+        '#weight' => 10,
+      );
+	
+      // Wrapper for fieldset contents (used by ahah JS).
+      $form['attachments']['wrapper'] = array(
+        '#prefix' => '<div id="attach-wrapper">',
+        '#suffix' => '</div>',
+      );
+      
+      // Make sure necessary directories for upload.module exist and are
+      // writable before displaying the attachment form.
+      $path = file_directory_path();
+      $temp = file_directory_temp();
+      // Note: pass by reference
+      if (!file_check_directory($path, FILE_CREATE_DIRECTORY) || !file_check_directory($temp, FILE_CREATE_DIRECTORY)) {
+        $form['attachments']['#description'] =  t('File attachments are disabled. The file directories have not been properly configured.');
+        if (user_access('administer site configuration')) {
+          $form['attachments']['#description'] .= ' '. t('Please visit the <a href="@admin-file-system">file system configuration page</a>.', array('@admin-file-system' => url('admin/settings/file-system')));
         }
         else {
-          $comment->comment .= theme('upload_attachments', $comment->files);
+          $form['attachments']['#description'] .= ' '. t('Please contact the site administrator.');
         }
       }
-      break;
+      else {
+        $form['attachments']['wrapper'] += _upload_form($cobj);
+        $form['#attributes']['enctype'] = 'multipart/form-data';
+      }
+
+	
+      // Enable the upload_preview module (when enabled) to modify the attachment display.
+      if (module_exists('upload_preview')) {
+        _upload_preview_node_form($form['attachments']['wrapper']['files'], 0);
+      }
+	 
+	 
+      $form['attachments']['wrapper']['new']['attach']['#ahah']['path'] = 'comment_upload/js';
+      $form['attachments']['wrapper']['new']['attach']['#submit'][0] = 'comment_upload_form_submit_build_comment';
+      $form['current']['cid'] = array('#type' => 'hidden', '#value' => $cid);
+      unset($form['attachments']['wrapper']['current']['vid']);
+    }
+    $form['submit']['#submit'] = array('comment_upload_form_submit_build_comment'); 
   }
-}
 
-function comment_upload_form_alter($form_id, &$form) {
   if ($form_id == 'node_type_form') {
     $form['workflow']['comment_upload'] = array(
       '#type' => 'radios',
@@ -119,16 +157,12 @@ function comment_upload_form_alter($form
   }
 }
 
-function comment_upload_menu($may_cache) {
-  $items = array();
-  if ($may_cache) {
-    $items[] = array(
-      'path' => 'comment_upload/js',
-      'callback' => 'comment_upload_js',
-      'access' => user_access('upload files'),
-      'type' => MENU_CALLBACK
-    );
-  }
+function comment_upload_menu() {
+  $items['comment_upload/js'] = array(
+    'page callback' => 'comment_upload_js',
+    'access arguments' => array('upload files'),
+    'type' => MENU_CALLBACK
+  );
   return $items;
 }
 
@@ -137,104 +171,163 @@ function comment_upload_menu($may_cache)
  */
 function comment_upload_js() {
   // We only do the upload.module part of the node validation process.
-  $comment = (object)$_POST['edit'];
+  $comment = (object)$_POST;
+  
+  $form_state = array();
 
   // Load existing files.
-  $comment->files = _comment_upload_load_files($comment->cid);
 
   // Handle new uploads, and merge tmp files into node-files.
-  _upload_prepare($comment);
-  _upload_validate($comment);
+  upload_node_form_submit(array(), $form_state);
+
+
+  if (isset($comment->cid)) {
+    $comment->files = _comment_upload_load_files($comment->cid);
+  }
+  
+
+  if (!empty($form_state['values']['files'])) {
+    foreach ($form_state['values']['files'] as $fid => $file) {
+      $comment->files[$fid] = $file;
+    }
+  }
 
   $form = _upload_form($comment);
-  foreach (module_implements('form_alter') as $module) {
-    $function = $module .'_form_alter';
-    $function('upload_js', $form);
+  $form += array(
+    '#post' => $_POST,
+    '#programmed' => FALSE,
+    '#tree' => FALSE,
+    '#parents' => array(),
+  );
+    
+
+  // Swap upload/js for the comment_upload callback.
+  
+  $form['new']['attach']['#ahah']['path'] = 'comment_upload/js';
+  $form['new']['attach']['#submit'][0] = 'comment_upload_form_submit_build_comment';
+
+  drupal_alter('form', $form, array(), 'comment_upload_js');
+  $form_state = array('submitted' => FALSE);
+  $form = form_builder('comment_upload_js', $form, $form_state);
+
+  // Maintain the list and delete checkboxes values.
+  $files = isset($_POST['files']) ? $_POST['files'] : array();
+  foreach ($files as $fid => $file) {
+    if (is_numeric($fid)) {
+      $form['files'][$fid]['list']['#value'] = isset($file['list']) ? 1 : 0;
+      $form['files'][$fid]['remove']['#value'] = isset($file['remove']) ? 1 : 0;
+    }
   }
-  $form = form_builder('upload_js', $form);
-  $output = theme('status_messages') . drupal_render($form);
 
+  $output = theme('status_messages') . drupal_render($form);
+    
   // We send the updated file attachments form.
   print drupal_to_js(array('status' => TRUE, 'data' => $output));
   exit;
 }
 
+/**
+ * Load files belonging to the comment $cid.
+ *
+ * When the optional argument $nid is provided all files belonging to
+ * comments on that nid are loaded at once and later served from memory.
+ * This reduces the amount of queries on node/nid pages.
+ *
+ * @return Array of file objects.
+ */
 function _comment_upload_load_files($cid, $nid = NULL) {
+  if(!$cid) return array();
   static $cache = array();
   if ($nid) {
     // Cache all for this node to avoid one query per comment
     if (!isset($cache[$nid])) {
       $cache[$nid] = array();
-      $result = db_query('SELECT * FROM {comment_upload_files} f WHERE f.nid = %d ORDER BY f.fid DESC', $nid);
+      $result = db_query('SELECT * FROM {comment_upload_files} f WHERE f.nid = %d ORDER BY f.weight, f.fid DESC', $nid);
       while ($file = db_fetch_object($result)) {
         $cache[$nid][$file->cid][] = $file;
       }
     }
-    return $cache[$nid][$cid];
+    return isset($cache[$nid][$cid]) ? $cache[$nid][$cid] : array();
   }
   else if ($cid) {
-    $result = db_query('SELECT * FROM {comment_upload_files} f WHERE f.cid = %d ORDER BY f.fid DESC', $cid);
+    $result = db_query('SELECT * FROM {comment_upload_files} f WHERE f.cid = %d ORDER BY f.weight, f.fid DESC', $cid);
     while ($file = db_fetch_object($result)) {
       $files[] = $file;
     }
-    return $files;
+    return isset($files) ? $files : array();
   }
 }
 
 function _comment_upload_save_files($comment) {
-  if (!is_array($comment['files'])) {
+  if (empty($comment['files']) ||  !is_array($comment['files'])) {
     return;
   }
 
   foreach ($comment['files'] as $file) {
     $file = (object)$file;
 
+    $fid = $file->fid;
+
     // Remove file. Process removals first since no further processing will be required.
-    if ($file->remove) {
+    if (!empty($file->remove)) {
       // Remove file previews...
-      if (strpos($file->fid, 'upload') !== false) {
-        file_delete($file->filepath);
-      }
-
-      // Remove managed files.
-      else {
-        db_query('DELETE FROM {comment_upload_files} WHERE fid = %d', $file->fid);
-      }
+     
+      file_delete($file->filepath);
+      db_query('DELETE FROM {comment_upload_files} WHERE fid = %d', $fid);
+      
+      
+      // Remove it from the session in the case of new uploads,
+      // that you want to disassociate before comment submission.
+      unset($_SESSION['upload_files'][$fid]);
+      // Move on, so the removed file won't be added
+      continue;
     }
 
-    // New file upload
-    elseif (strpos($file->fid, 'upload') !== false) {
-      if ($file = file_save_upload($file, $file->filename)) {
+    // Associate a new file needed
+    if (isset($_SESSION['upload_files'][$fid])) {
         // Overwrite existing in single-attachment mode
         if (variable_get('comment_upload_single', 0) && isset($comment['files'][0])) {
-          db_query("UPDATE {comment_upload_files} SET filename = '%s', filepath = '%s', filemime = '%s', filesize = %d WHERE fid = %d", $file->filename, $file->filepath, $file->filemime, $file->filesize, $comment['files'][0]['fid']);
+          db_query("UPDATE {comment_upload_files} SET filename = '%s', filepath = '%s', filemime = '%s', filesize = %d, weight = %d WHERE fid = %d", $file->filename, $file->filepath, $file->filemime, $file->filesize, $file->weight, $comment['files'][0]['fid']);
+	  file_set_status($file, FILE_STATUS_PERMANENT);
         }
         else {
-          $file->fid = db_next_id('{comment_upload_files}_fid');
-          db_query("INSERT INTO {comment_upload_files} (fid, nid, cid, filename, filepath, filemime, filesize, description, list) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, '%s', %d)", $file->fid, $comment['nid'], $comment['cid'], $file->filename, $file->filepath, $file->filemime, $file->filesize, $file->description, $file->list);
+	  db_query("INSERT INTO {comment_upload_files} (fid, nid, cid, filename, filepath, filemime, filesize, description, list, weight) VALUES (%d, %d, %d, '%s', '%s', '%s', %d, '%s', %d, %d)", $file->fid, $comment['nid'], $comment['cid'], $file->filename, $file->filepath, $file->filemime, $file->filesize, $file->description, $file->list, $file->weight);
+	  file_set_status($file, FILE_STATUS_PERMANENT);
         }
-      }
-      unset($_SESSION['file_previews'][$fid]);
+	unset($_SESSION['file_previews'][$fid]);
     }
-
+    
+    
     // Update existing description.
     else {
       db_query("UPDATE {comment_upload_files} SET list = %d, description = '%s' WHERE fid = %d", $file->list, $file->description, $file->fid);
     }
   }
+  // Empty the session storage after save. We use this variable to track files
+  // that haven't been related to the node yet.
+  unset($_SESSION['upload_files']);
 }
 
+/**
+ * Delete files associated with the comment $cid.
+ *
+ * @param $cid The comment id of the comment that is deleted.
+ */
 function _comment_upload_delete($cid) {
   $files = _comment_upload_load_files($cid);
-  if (empty($files)) {
-    return;
-  }
-  foreach ($files as $file) {
-    file_delete($file->filepath);
-    db_query('DELETE FROM {comment_upload_files} WHERE fid = %d', $file->fid);
+  if (!empty($files)) {
+    foreach ($files as $file) {
+      file_delete($file->filepath);
+      db_query('DELETE FROM {comment_upload_files} WHERE fid = %d', $file->fid);
+    }
   }
 }
 
+/**
+ * Delete files and records associated with comments on the deleted node.
+ *
+ * Implementation of hook_nodeapi.
+ */
 function comment_upload_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
   if ($op == 'delete') {
     $result = db_query("SELECT * FROM {comment_upload_files} WHERE nid = %d", $node->nid);
@@ -246,19 +339,56 @@ function comment_upload_nodeapi(&$node, 
   }
 }
 
+/**
+ * Implementation of hook_theme().
+ */
+function comment_upload_theme() {
+  return array(
+    'comment_attachments' => array(
+      'arguments' => array('files' => NULL)
+    )
+  );
+}
 
-function theme_comment_attachment($file, $comment) {
-  $href = check_url(strpos($file->fid, 'upload') === false ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path())));
-  $regex = '/\.('. ereg_replace(' +', '|', preg_quote('jpg jpeg gif png')) .')$/i';
-  if (variable_get('comment_upload_inline_image', 0) && preg_match($regex, $file->filename)) {
-    $html = '<img src="'. $href .'"/>';
+/**
+ * Style the attachment display.
+ *
+ * Images are displayed inline when Inline display has been set.
+ * Any remaining files are styled by theme('upload_attachments').
+ *
+ * @param $files An array containing files objects ($comment->files structure).
+ *
+ * @return HTML representation of attachments.
+ */
+function theme_comment_attachments($files) {
+  // Display images.
+  $html = '';
+  if (variable_get('comment_upload_inline_image', 0)) {
+    $regex = '/\.('. ereg_replace(' +', '|', preg_quote('jpg jpeg gif png')) .')$/i';
+    foreach ($files as $key => $file) {
+      if ($file->list) {
+        if (preg_match($regex, $file->filename)) {
+          unset($files[$key]);
+          $href = check_url(strpos($file->fid, 'upload') === false ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path())));
+          $html .= '<img src="'. $href .'" title="'. check_plain($file->description) . '"/>';
+        }
+      }
+    }
   }
-  else {
-    $html = '<a href="'. $href .'">'. check_plain($file->filename) .' ('. format_size($file->filesize) .')</a>';
+  // Style the remaining files as an attachment table.
+  $html .= theme('upload_attachments', $files);
+  if ($html) {
+    return $html;
   }
-  return $html;
 }
 
+/**
+ * Enable downloads via private downloads setting.
+ *
+ * Users must be able to view the parent node and have the 'view uploaded files'
+ * permission. Implementation of hook_file_download.
+ *
+ */
 function comment_upload_file_download($file) {
   $file = file_create_path($file);
   $result = db_query("SELECT f.* FROM {comment_upload_files} f WHERE filepath = '%s'", $file);
@@ -271,7 +401,7 @@ function comment_upload_file_download($f
         return array(
           'Content-Type: '. $type .'; name='. $name,
           'Content-Length: '. $file->filesize,
-          'Expires: 0', 'Pragma: cache', 'Cache-Control: private'
+          'Expires: 0', 'Pragma: cache', 'Cache-Control: private',
         );
       }
       else {
