--- ./webfm.module.orig	2008-07-14 10:51:44.000000000 +0200
+++ ./webfm.module	2008-07-14 11:26:17.000000000 +0200
@@ -545,6 +545,7 @@
  * Implementation of hook_nodeapi().
  */
 function webfm_nodeapi(&$node, $op, $teaser) {
+  global $user;
   switch ($op) {
     case 'load':
       if ((variable_get("wfm_attach_$node->type", 1) == 1) &&
@@ -555,19 +556,61 @@
       break;
 
     case 'view':
-      // Add the attachments list to node body if configured to appear in body
-      if (is_array($node->webfm_files) && variable_get('webfm_attach_body', '')) {
-        if (count($node->webfm_files) && !$teaser) {
+      // Add the attachments list to node body if configured to appear in body.
+      if (variable_get('webfm_attach_body', '')) {
+        // We could be viewing or previewing this node.
+        // Loading a node defines $node->webfm_files, possibly as empty list,
+        // but loading an edit form unsets $node->webfm_files again. Thus, if
+        // $node->webfm is not set, we are previewing this node.
+        // Two cases then:
+        // 1) The user has no webfm access rights, so he can't change anything
+        // and $_POST['attachlist'] is empty. Simulate the 'load' operation
+        // to get the files from the database to show them in the preview.
+        // 2) If user has webfm access, all attachments (saved/unsaved)
+        // are in $_POST['attachlist']. But $_POST['attachlist'] is also set if
+        // we preview e.g. a comment where this node is shown, too, but then
+        // the attachlist is not ours. So we check for webfm_files *before*
+        // checking for $_POST to get around this.
+        if (!user_access('access webfm') && (variable_get("wfm_attach_$node->type", 1) == 1)
+            && user_access('view webfm attachments')) {
+          $node->webfm_files =  webfm_get_attachments($node->nid);
+        }
+        if (is_array($node->webfm_files)) {
+          if (count($node->webfm_files) && !$teaser) {
+            $show_files = $node->webfm_files;
+          }
+        }
+	// We must check for view permissions in a preview, but wfm_attach_$node->type
+	// is true if we already have attachments here.
+        elseif ($_POST['attachlist'] && user_access('view webfm attachments')) {
+          $show_files = webfm_get_temp_attachments($_POST['attachlist']);
+        }
+        if ($show_files) {
           $node->content['webfm_attachments'] = array(
-            '#value' => theme('webfm_attachments', $node->webfm_files),
+            '#value' => theme('webfm_attachments', $show_files),
             '#weight' => 10,
-          );
+            );
           drupal_add_css(drupal_get_path('module', 'webfm').'/css/webfm.css');
         }
       }
       break;
 
+    case 'validate':
+      // When form_validate fails for preview or save, we must reinitialize
+      // javascript, otherwise webfm doesn't work anymore.
+      $modulepath = drupal_get_path('module', 'webfm');
+      drupal_add_js($modulepath .'/js/webfm.js');
+      drupal_add_css($modulepath .'/css/webfm.css');
+      if (is_null($inline_js)) {
+        $clean_url = variable_get('clean_url', 0);
+        $clean = (($clean_url == 0) || ($clean_url == '0')) ? FALSE : TRUE;
+        $inline_js = webfm_inline_js($base_url, $clean, $user->uid);
+      }
+      break;
+
     case 'insert':
+      // We saved the attachment list for preview. Remove before saving.
+      unset($node->attachlist);
       if($_POST['attachlist']) {
         $files = explode(',', $_POST['attachlist']);
         $i = 0;
@@ -580,6 +611,8 @@
       break;
 
     case 'update':
+      // We saved the attachment list for preview. Remove before saving.
+      unset($node->attachlist);
       $files = explode(',', $_POST['attachlist']);
       webfm_dbupdate_attach($node->nid, $files);
       break;
@@ -703,11 +736,24 @@
 function webfm_attach_attached_form($node) {
   $form['#theme'] = 'webfm_attach_attached_form';
 
-  // This form input (id = edit-attachlist) will hold the comma-separated ordered list of attached fids
+  // This form input (id = edit-attachlist) will hold the comma-separated
+  // ordered list of attached fids. We need to store the attachments (which
+  // might not yet been saved to the database) in two cases:
+  // 1) A form_validate fails when trying to save/preview. The form is not
+  //    rebuild by form_alter, but form values are refilled. #value => '' would
+  //    delete the attachlist collected so far, so use #default_value => '' instead.
   $form['new']['attachlist']  = array(
     '#type' => 'hidden',
-    '#value' => '');
+    '#default_value' => '',
+    );
 
+  // 2) If form_validate didn't fail, the form is rebuild with form_alter
+  //    and the value is reset. But we have the list in the POST parameters.
+  //    Use default_value here, too, so that it can still be changed if we get
+  //    a form_validate error *after* a successful preview.
+  if ($_POST['attachlist']) {
+    $form['new']['attachlist']['#default_value'] = $_POST['attachlist'];
+  }
   return $form;
 }
 
@@ -1350,6 +1396,17 @@
       case "attach":
         global $node;
         if(isset($_POST["param0"])) {
+          // If $_POST["param1"] is set, we are in a preview or validation failure
+          // and have fids stored in the edit-attachments form, those that we fetched
+          // from the database before and those which are not yet attached (during
+          // a preview). Those fids are transfered through param1.
+          if (isset($_POST["param1"])) {
+            $fids = trim(strtolower(rawurldecode($_POST["param1"])));
+            webfm_json(array('status' => TRUE, 'data' => webfm_get_temp_attachments($fids), 'admin' => 'attach'));
+            exit();
+            break;
+          }
+          // Here we are in the edit form for the first time. Work as before.
           $node_str = trim(strtolower(rawurldecode($_POST["param0"])));
           // the 'node' var passed via AJAX is the action attribute of id=node-form
           if (($node_num = strstr($node_str, 'node/')) !== FALSE) {
@@ -2086,6 +2143,26 @@
 }
 
 /**
+ * Return file descriptors for an attachment that have not yet been saved.
+ * This happens on previewing posts.
+ *
+ * @param array $fids - a comma separated list of fids.
+ * @return array of file descriptors.
+ */
+function webfm_get_temp_attachments($fids) {
+  $files = array();
+  $fids_arr = split(',', $fids);
+  $file_result = db_query('SELECT * FROM {webfm_file} WHERE fid in ('. db_placeholders($fids_arr) .')', $fids_arr);
+  while ($file_record = db_fetch_object($file_result)) {
+    $_file = new webfm_fdesc($file_record);
+    if ($_file->result == TRUE) {
+      $files[] = $_file;
+    }
+  }
+  return $files;
+}
+
+/**
  * File description class
  */
 class webfm_fdesc {
--- ./js/webfm.js.orig  2008-07-14 09:53:23.000000000 +0200
+++ ./js/webfm.js       2008-07-14 11:27:56.000000000 +0200
@@ -2464,6 +2464,12 @@
   var node_url = Webfm.$('node-form').action;
   Webfm.progressObj.show(Webfm.js_msg["work"],  "blue");
   var postObj = { action:encodeURIComponent("attach"), param0:encodeURIComponent(node_url) };
+  // If we are in a preview/validate, the fids are still stored in the form.
+  // Pass them to webfm_ajax to reload them.
+  var fids = Webfm.$(Webfm.attachFormInput).value;
+  if (fids.length != 0) {
+    postObj.param1 = encodeURIComponent(fids);
+  }
   Webfm.HTTPPost(url, this.callback, this, postObj);
 }

@@ -2476,9 +2482,19 @@
       if(result.data.length) {
         Webfm.admin = result.admin;
         var elInput = Webfm.$(Webfm.attachFormInput);
+        var attach_arr = [];
+        attach_arr = Webfm.$(Webfm.attachFormInput).value.split(',');
         for(var i = 0; i < result.data.length; i++) {
           var filerow = new Webfm.filerow(obj.body, result.data[i], 'attach', '', true, Webfm.menuHT.get('det'), obj.eventListeners);
-          elInput.setAttribute('value', (elInput.getAttribute('value')?elInput.getAttribute('value')+',':'') + result.data[i].id);
+          // Don't add if it already exists.
+          // Note that values are kept in the form for preview/failed validate.
+          for (var j = 0; j < attach_arr.length; j++) {
+            if (result.data[i].id == attach_arr[j])
+              break;
+          }
+          if (j == attach_arr.length) {
+            elInput.setAttribute('value', (elInput.getAttribute('value')?elInput.getAttribute('value')+',':'') + result.data[i].id);
+          }
         }
       }
     } else
