Index: modules/upload.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/upload.module,v
retrieving revision 1.44
diff -u -r1.44 upload.module
--- modules/upload.module	22 Jul 2005 19:06:19 -0000	1.44
+++ modules/upload.module	28 Jul 2005 21:12:53 -0000
@@ -1,5 +1,5 @@
 <?php
-/* $Id: upload.module,v 1.44 2005/07/22 19:06:19 dries Exp $ */
+/* $Id: upload.module,v 1.41 2005/06/21 09:45:45 dries Exp $ */
 
 /**
  * @file
@@ -83,7 +83,8 @@
 function upload_admin() {
   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.'));
+  $group .= form_textfield(t('Maximum total file size'), 'upload_maxsize_total', variable_get('upload_maxsize_total', 0), 10, 10, t('The maximum size of a file a user can upload in megabytes. Enter 0 for unlimited.'));
+  $group .= form_textfield(t('Maximum resolution for uploaded images'), 'upload_max_resolution', variable_get('upload_max_resolution', 0), 10, 10, t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction.'));
 
   $output = form_group(t('General settings'), $group);
 
@@ -137,83 +138,7 @@
       break;
 
     case 'validate':
-      $node->files = upload_load($node);
-
-      // Double check existing files:
-      if (is_array($node->list)) {
-        foreach ($node->list as $key => $value) {
-          if ($file = file_check_upload($key)) {
-            $node->files[$file->source] = $file;
-            $node->files[$key]->list = $node->list[$key];
-            $node->files[$key]->remove = $node->remove[$key];
-            if ($file->source) {
-              $filesize += $file->filesize;
-            }
-          }
-        }
-      }
-      else {
-        foreach ($node->files as $key => $file) {
-          $node->list[$key] = $file->list;
-        }
-      }
-
-      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']++;
-            }
-          }
-        }
-
-        // 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) {
-          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;
-        }
-      }
+      $node = _upload_validate($node);
       break;
 
     case 'form post':
@@ -230,43 +155,8 @@
 
     case 'view':
       if ($node->files && user_access('view uploaded files')) {
-        $header = array(t('Attachment'), t('Size'));
-        $rows = array();
-        $previews = array();
-
-        // Build list of attached files
-        foreach ($node->files as $file) {
-          if ($file->list) {
-            $rows[] = array(
-              '<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>',
-              format_size($file->filesize)
-            );
-            // We save the list of files still in preview for later
-            if (!$file->fid) {
-              $previews[] = $file;
-            }
-          }
-        }
-
-        // URLs to files being previewed are actually Drupal paths. When Clean
-        // URLs are disabled, the two do not match. We perform an automatic
-        // replacement from temporary to permanent URLs. That way, the author
-        // can use the final URL in the body before having actually saved (to
-        // place inline images for example).
-        if (!variable_get('clean_url', 0)) {
-          foreach ($previews as $file) {
-            $old = file_create_filename($file->filename, file_create_path());
-            $new = url($old);
-            $node->body = str_replace($old, $new, $node->body);
-            $node->teaser = str_replace($old, $new, $node->teaser);
-          }
-        }
-
-        $teaser = $arg;
-        // Add the attachments list
-        if (count($rows) && !$teaser) {
-          $node->body .= theme('table', $header, $rows, array('id' => 'attachments'));
-        }
+        $node = _upload_table($node);
+        $node = _upload_inline($node);
       }
       break;
 
@@ -305,26 +195,15 @@
   return $output;
 }
 
-/**
- * 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.
- */
-function upload_space_used($uid) {
-  return db_result(db_query('SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE uid = %d', $uid));
-}
+function upload_count_size($uid = 0) {
+  if ($uid) {
+    $result = db_query("SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node} n ON f.nid = n.nid WHERE uid = %d", $uid);
+  }
+  else {
+    $result = db_query("SELECT SUM(f.filesize) FROM {files} f INNER JOIN {node} n ON f.nid = n.nid");
+  }
 
-/**
- * Determine how much disk space is occupied by uploaded files.
- *
- * @return
- *   The ammount 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} n ON f.nid = n.nid'));
+  return db_result($result);
 }
 
 function upload_save($node) {
@@ -336,8 +215,8 @@
       // Insert new files:
       if ($file = file_save_upload($file, $file->filename)) {
         $fid = db_next_id('{files}_fid');
-        db_query("INSERT INTO {files} (fid, nid, filename, filepath, filemime, filesize, list) VALUES (%d, %d, '%s', '%s', '%s', %d, %d)",
-                 $fid, $node->nid, $file->filename, $file->filepath, $file->filemime, $file->filesize, $node->list[$key]);
+        db_query("INSERT INTO {files} (fid, nid, filename, filepath, filemime, filesize, list, inline) VALUES (%d, %d, '%s', '%s', '%s', %d, %d, %d)",
+                 $fid, $node->nid, $file->filename, $file->filepath, $file->filemime, $file->filesize, $node->list[$key], $node->inline[$key]);
       }
     }
     else {
@@ -349,6 +228,9 @@
       if ($file->list != $node->list[$key]) {
         db_query("UPDATE {files} SET list = %d WHERE fid = %d", $node->list[$key], $key);
       }
+      if ($file->inline != $node->inline[$key]) {
+        db_query("UPDATE {files} SET inline = %d WHERE fid = %d", $node->inline[$key], $key);
+      }
     }
   }
   return;
@@ -363,14 +245,16 @@
 }
 
 function upload_form($node) {
-  $header = array(t('Delete'), t('List'), t('Url'), t('Size'));
+  $header = array(t('Delete'), t('List'), t('Inline'), t('Url'), t('Size'));
   $rows = array();
 
   if (is_array($node->files)) {
     foreach ($node->files as $key => $file) {
+      $is_image = ereg('^(image/)', $file->filemime);
       $rows[] = array(
         form_checkbox('', "remove][$key", 1, $file->remove),
         form_checkbox('', "list][$key", 1, $file->list),
+        form_checkbox('', "inline][$key", 1, $file->inline, '', $is_image ? '' : array('disabled'=>'disabled')),
         $file->filename ."<br /><small>". file_create_url(($file->fid ? $file->filepath : file_create_filename($file->filename, file_create_path()))) ."</small>",
         format_size($file->filesize)
       );
@@ -385,7 +269,7 @@
     $output .= form_button(t('Attach'), 'fileop');
   }
 
-  return '<div class="attachments">'. form_group_collapsible(t('File attachments'), $output, TRUE, t('Changes made to the attachments are not permanent until you save this post.  The first "listed" file will be included in RSS feeds.')) .'</div>';
+  return '<div class="attachments">'. form_group_collapsible(t('File Attachments'), $output, TRUE, t('Changes made to the attachments are not permanent until you save this post.  The first "listed" file will be included in RSS feeds.')) .'</div>';
 }
 
 function upload_load($node) {
@@ -422,4 +306,186 @@
   return $file;
 }
 
+/**
+ * Render the table under the node.
+ */
+function _upload_table($node) {
+  $header = array(t('Attachment'), t('Size'));
+  $rows = array();
+  $previews = array();
+
+  // Build list of attached files
+  foreach ($node->files as $file) {
+    if ($file->list) {
+      $rows[] = array(
+        '<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>',
+        format_size($file->filesize)
+      );
+      // We save the list of files still in preview for later
+      if (!$file->fid) {
+        $previews[] = $file;
+      }
+    }
+  }
+
+  // URLs to files being previewed are actually Drupal paths. When Clean
+  // URLs are disabled, the two do not match. We perform an automatic
+  // replacement from temporary to permanent URLs. That way, the author
+  // can use the final URL in the body before having actually saved (to
+  // place inline images for example).
+  if (!variable_get('clean_url', 0)) {
+    foreach ($previews as $file) {
+      $old = file_create_filename($file->filename, file_create_path());
+      $new = url($old);
+      $node->body = str_replace($old, $new, $node->body);
+      $node->teaser = str_replace($old, $new, $node->teaser);
+    }
+  }
+
+  $teaser = $arg;
+  // Add the attachments list
+  if (count($rows) && !$teaser) {
+    $node->body .= theme('table', $header, $rows, array('id' => 'attachments'));
+  }
+  return $node;
+}
+
+/**
+ * Render inline link, or image.
+ */
+function _upload_inline($node) {
+  $previews = array();
+  // Build list of attached files
+  foreach ($node->files as $file) {
+    if ($file->inline) {
+      $output .=  theme('upload_inline', $file);
+      // We save the list of files still in preview for later
+      if (!$file->fid) {
+        $previews[] = $file;
+      }
+    }
+  }
+  
+  $node->body = "$output \n $node->body";
+  $node->teaser = "$output \n $node->teaser";
+  
+  // URLs to files being previewed are actually Drupal paths. When Clean
+  // URLs are disabled, the two do not match. We perform an automatic
+  // replacement from temporary to permanent URLs. That way, the author
+  // can use the final URL in the body before having actually saved (to
+  // place inline images for example).
+  if (!variable_get('clean_url', 0)) {
+    foreach ($previews as $file) {
+      $old = file_create_filename($file->filename, file_create_path());
+      $new = url($old);
+      $node->body = str_replace($old, $new, $node->body);
+      $node->teaser = str_replace($old, $new, $node->teaser);
+    }
+  }
+
+  return $node;
+}
+
+/**
+ * Helper function for validating the uploads
+ */
+function _upload_validate($node) {
+  $node->files = upload_load($node);
+  // Double check existing files:
+  if (is_array($node->list)) {
+    foreach ($node->list as $key => $value) {
+      if ($file = file_check_upload($key)) {
+        $node->files[$file->source] = $file;
+        $node->files[$key]->list = $node->list[$key];
+        $node->files[$key]->inline = $node->inline[$key];
+        $node->files[$key]->remove = $node->remove[$key];
+        if ($file->source) {
+          $filesize += $file->filesize;
+        }
+      }
+    }
+  }
+  else {
+    foreach ($node->files as $key => $file) {
+      $node->list[$key] = $file->list;
+      $node->inline[$key] = $node->inline;
+    }
+  }
+  
+  if (($file = file_check_upload('upload')) && user_access('upload files')) {
+    global $user;
+  
+    $file = _upload_image($file);
+  
+    $maxsize = variable_get("upload_maxsize_total", 0) * 1024 * 1024;
+    $total_size = upload_count_size() + $filesize;
+    $total_usersize = upload_count_size($user->uid) + $filesize;
+  
+    if ($maxsize && $total_size > $maxsize) {
+      form_set_error('upload', t('The selected file %name can not be attached to this post, because it exceeded the maximum filesize of %max-size', array('%name' => theme('placeholder', $file->filename), '%max-size' => theme('placeholder', format_size($maxsize)))));
+      break;
+    }
+  
+    // 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.
+      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 ($file->filesize > $uploadsize) {
+          $error['uploadsize']++;
+        }
+  
+        if ($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';
+    }
+  
+    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;
+    }
+  }
+  return $node;
+}
+
+/**
+ * Theme function for rendering of inline images
+ * @param $file a file object.
+ * @param $image a Boolean, indicating whether an img tag (TRUE) or an anchor tag (FALSE) should be used. 
+ * @ingroup themable
+ */
+function theme_upload_inline($file) {
+  return '<img src="'. check_url(($file->fid ? file_create_url($file->filepath) : url(file_create_filename($file->filename, file_create_path())))) .'" alt="'.  check_plain($file->filename) .'" class="upload inline">';
+}
 ?>
Index: database/database.mysql
===================================================================
RCS file: /cvs/drupal/drupal/database/database.mysql,v
retrieving revision 1.189
diff -u -r1.189 database.mysql
--- database/database.mysql	6 Jun 2005 18:59:36 -0000	1.189
+++ database/database.mysql	28 Jul 2005 21:12:53 -0000
@@ -246,6 +246,7 @@
   filemime varchar(255) NOT NULL default '',
   filesize int(10) unsigned NOT NULL default '0',
   list tinyint(1) unsigned NOT NULL default '0',
+  inline tinyint(1) unsigned NOT NULL default '0',
   PRIMARY KEY (fid)
 ) TYPE=MyISAM;
 
Index: database/database.pgsql
===================================================================
RCS file: /cvs/drupal/drupal/database/database.pgsql,v
retrieving revision 1.128
diff -u -r1.128 database.pgsql
--- database/database.pgsql	27 Jun 2005 04:45:36 -0000	1.128
+++ database/database.pgsql	28 Jul 2005 21:12:53 -0000
@@ -242,6 +242,7 @@
   filemime varchar(255) NOT NULL default '',
   filesize integer NOT NULL default '0',
   list smallint NOT NULL default '0',
+  inline tinyint(1) unsigned NOT NULL default '0',
   PRIMARY KEY  (fid)
 );
 
Index: database/updates.inc
===================================================================
RCS file: /cvs/drupal/drupal/database/updates.inc,v
retrieving revision 1.120
diff -u -r1.120 updates.inc
--- database/updates.inc	22 Jul 2005 19:06:19 -0000	1.120
+++ database/updates.inc	28 Jul 2005 21:12:53 -0000
@@ -117,7 +117,8 @@
   "2005-05-10" => "update_138",
   "2005-05-11" => "update_139",
   "2005-05-12" => "update_140",
-  "2005-05-22" => "update_141"
+  "2005-05-22" => "update_141",
+  "2005-07-28" => "update_142"
 );
 
 function update_32() {
@@ -2511,6 +2512,13 @@
   return $ret;
 }
 
+function update_142() {
+  $ret = array();
+  $ret[] = update_sql("ALTER TABLE {files} ADD inline tinyint(1) unsigned default 0 not NULL");
+  return $ret;
+}
+
+
 function update_sql($sql) {
   $edit = $_POST["edit"];
   $result = db_query($sql);
Index: misc/drupal.css
===================================================================
RCS file: /cvs/drupal/drupal/misc/drupal.css,v
retrieving revision 1.110
diff -u -r1.110 drupal.css
--- misc/drupal.css	23 Jul 2005 05:55:11 -0000	1.110
+++ misc/drupal.css	28 Jul 2005 21:12:53 -0000
@@ -460,6 +460,9 @@
 .user-login-block {
   text-align: center;
 }
+img.upload {
+  float:left;
+}
 .more-help-link {
   font-size: 0.85em;
   text-align: right;
