diff --git a/include/class.attachment.php b/include/class.attachment.php
index 3247d06912d8baafaa895843556b6236f809a35d..cd2ef95ac8586ece6a790311be897c435fb87e9f 100644
--- a/include/class.attachment.php
+++ b/include/class.attachment.php
@@ -56,6 +56,10 @@ class Attachment extends VerySimpleModel {
         return $this->file;
     }
 
+    function getFilename() {
+        return $this->name ?: $this->file->name;
+    }
+
     function getHashtable() {
         return $this->ht;
     }
@@ -112,7 +116,8 @@ class GenericAttachments {
 
     function upload($files, $inline=false, $lang=false) {
         $i=array();
-        if (!is_array($files)) $files=array($files);
+        if (!is_array($files))
+            $files = array($files);
         foreach ($files as $file) {
             if (is_numeric($file))
                 $fileId = $file;
@@ -131,6 +136,17 @@ class GenericAttachments {
                 'file_id' => $fileId,
                 'inline' => $_inline ? 1 : 0,
             ));
+
+            // Record varying file names in the attachment record
+            if (is_array($file) && isset($file['name'])) {
+                $filename = $file['name'];
+            }
+            if ($filename) {
+                // This should be a noop since the ORM caches on PK
+                $file = AttachmentFile::lookup($fileId);
+                if ($file->name != $filename)
+                    $att->name = $filename;
+            }
             if ($lang)
                 $att->lang = $lang;
 
diff --git a/include/class.forms.php b/include/class.forms.php
index 9f4ece823e177d93a81a0df42d2a2f97923edc12..5a3302259f0d45c5f63aef02df47cd8881648951 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -3123,6 +3123,14 @@ class FileUploadWidget extends Widget {
     function getValue() {
         $data = $this->field->getSource();
         $ids = array();
+        $base = parent::getValue();
+        if (is_array($base)) {
+            foreach ($base as $info) {
+                list($id, $name) = explode(',', $info, 2);
+                // Keep the values as the IDs
+                $ids[$name] = $id;
+            }
+        }
         // Handle manual uploads (IE<10)
         if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_FILES[$this->name])) {
             foreach (AttachmentFile::format($_FILES[$this->name]) as $file) {
@@ -3132,13 +3140,13 @@ class FileUploadWidget extends Widget {
                 }
                 catch (FileUploadError $ex) {}
             }
-            return array_merge($ids, parent::getValue() ?: array());
+            return $ids;
         }
         // If no value was sent, assume an empty list
         elseif ($data && is_array($data) && !isset($data[$this->name]))
             return array();
 
-        return parent::getValue();
+        return $ids;
     }
 }
 
diff --git a/include/class.mailer.php b/include/class.mailer.php
index 83f097050624924326e9da6b22e90eeb041f5deb..2665944089e6bbc72c4b1a71a48e780d1879bb37 100644
--- a/include/class.mailer.php
+++ b/include/class.mailer.php
@@ -82,7 +82,7 @@ class Mailer {
     function addAttachment(Attachment $attachment) {
         // XXX: This looks too assuming; however, the attachment processor
         // in the ::send() method seems hard coded to expect this format
-        $this->attachments[$attachment->file_id] = $attachment->file;
+        $this->attachments[$attachment->file_id] = $attachment;
     }
 
     function addFile(AttachmentFile $file) {
@@ -433,7 +433,10 @@ class Mailer {
                     $file = false;
                     foreach ($self->attachments as $id=>$F) {
                         if (strcasecmp($F->getKey(), $match[1]) === 0) {
-                            $file = $F;
+                            if ($F instanceof Attachment)
+                                $file = $F->getFile();
+                            else
+                                $file = $F;
                             break;
                         }
                     }
@@ -452,8 +455,16 @@ class Mailer {
         //XXX: Attachments
         if(($attachments=$this->getAttachments())) {
             foreach($attachments as $id=>$file) {
+                // Read the filename from the Attachment if possible
+                if ($file instanceof Attachment) {
+                    $filename = $file->getFilename();
+                    $file = $file->getFile();
+                }
+                else {
+                    $filename = $file->getName();
+                }
                 $mime->addAttachment($file->getData(),
-                    $file->getType(), $file->getName(),false);
+                    $file->getType(), $filename, false);
             }
         }
 
diff --git a/include/class.thread.php b/include/class.thread.php
index b228fd63e3d3de9f083b45314d5bebbcd4947dae..d1439b243c8e4257b58c994c009c139b29fd01ba 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -877,7 +877,7 @@ implements TemplateVariable {
     Save attachment to the DB.
     @file is a mixed var - can be ID or file hashtable.
     */
-    function saveAttachment(&$file) {
+    function saveAttachment(&$file, $name=false) {
 
         $inline = is_array($file) && @$file['inline'];
 
@@ -898,6 +898,21 @@ implements TemplateVariable {
             'file_id' => $fileId,
             'inline' => $inline ? 1 : 0,
         ));
+
+        // Record varying file names in the attachment record
+        if (is_array($file) && isset($file['name'])) {
+            $filename = $file['name'];
+        }
+        elseif (is_string($name)) {
+            $filename = $name;
+        }
+        if ($filename) {
+            // This should be a noop since the ORM caches on PK
+            $file = AttachmentFile::lookup($fileId);
+            if ($file->name != $filename)
+                $att->name = $filename;
+        }
+
         if (!$att->save())
             return false;
         return $att;
@@ -905,9 +920,10 @@ implements TemplateVariable {
 
     function saveAttachments($files) {
         $attachments = array();
-        foreach ($files as $file)
-           if (($A = $this->saveAttachment($file)))
+        foreach ($files as $name=>$file) {
+           if (($A = $this->saveAttachment($file, $name)))
                $attachments[] = $A;
+        }
 
         return $attachments;
     }
@@ -921,7 +937,7 @@ implements TemplateVariable {
         foreach ($this->attachments as $att) {
             $json[$att->file->getKey()] = array(
                 'download_url' => $att->file->getDownloadUrl(),
-                'filename' => $att->file->name,
+                'filename' => $att->getFilename(),
             );
         }
 
diff --git a/include/client/templates/thread-entry.tmpl.php b/include/client/templates/thread-entry.tmpl.php
index fe9f686e8201d0e1ee66551dd0d29e55c6ec7039..70e4bbb5c6fae24ba42a48a2c67520b044d03e58 100644
--- a/include/client/templates/thread-entry.tmpl.php
+++ b/include/client/templates/thread-entry.tmpl.php
@@ -70,8 +70,8 @@ if ($user && ($url = $user->get_gravatar(48)))
         <span class="attachment-info">
         <i class="icon-paperclip icon-flip-horizontal"></i>
         <a class="no-pjax truncate filename" href="<?php echo $A->file->getDownloadUrl();
-            ?>" download="<?php echo Format::htmlchars($A->file->name); ?>"
-            target="_blank"><?php echo Format::htmlchars($A->file->name);
+            ?>" download="<?php echo Format::htmlchars($A->getFilename()); ?>"
+            target="_blank"><?php echo Format::htmlchars($A->getFilename());
         ?></a><?php echo $size;?>
         </span>
 <?php   }  ?>
diff --git a/include/staff/templates/thread-entry.tmpl.php b/include/staff/templates/thread-entry.tmpl.php
index f06b376ef463876cfcbcc5df7737acde11d34cd9..01839aac5e37639df635dfc366cb289a159242a8 100644
--- a/include/staff/templates/thread-entry.tmpl.php
+++ b/include/staff/templates/thread-entry.tmpl.php
@@ -70,8 +70,8 @@ if ($user && ($url = $user->get_gravatar(48)))
         <span class="attachment-info">
         <i class="icon-paperclip icon-flip-horizontal"></i>
         <a class="no-pjax truncate filename" href="<?php echo $A->file->getDownloadUrl();
-            ?>" download="<?php echo Format::htmlchars($A->file->name); ?>"
-            target="_blank"><?php echo Format::htmlchars($A->file->name);
+            ?>" download="<?php echo Format::htmlchars($A->getFilename()); ?>"
+            target="_blank"><?php echo Format::htmlchars($A->getFilename());
         ?></a><?php echo $size;?>
         </span>
 <?php   }  ?>
diff --git a/include/upgrader/streams/core/9143a511-00000000.patch.sql b/include/upgrader/streams/core/9143a511-00000000.patch.sql
index 83bfa49cc58d80a53dc9b873e55eee5b5ebf7767..dd28bbed98dfcff312264e17889231ab9f4547e7 100644
--- a/include/upgrader/streams/core/9143a511-00000000.patch.sql
+++ b/include/upgrader/streams/core/9143a511-00000000.patch.sql
@@ -1,6 +1,6 @@
 /**
  * @signature 959aca6ed189cd918d227a3ea8a135a3
- * @version v1.9.6
+ * @version v1.10.0
  * @title Retire `private`, `required`, and `edit_mask` for fields
  *
  */
@@ -109,6 +109,10 @@ DROP TABLE IF EXISTS `%TABLE_PREFIX%_search`;
 UPDATE `%TABLE_PREFIX%config` SET `value` = '1'
   WHERE `key` = 'reindex' and `namespace` = 'mysqlsearch';
 
+-- Support varying names for duplicated content
+ALTER TABLE `%TABLE_PREFIX%attachment`
+  ADD `name` varchar(255) NULL default NULL AFTER `file_id`;
+
 -- Finished with patch
 UPDATE `%TABLE_PREFIX%config`
     SET `value` = '00000000000000000000000000000000'
diff --git a/js/filedrop.field.js b/js/filedrop.field.js
index 4e82280aeeb894a8249c8723fefd22570635d1c8..8b863fc9f6f897b3c85b72f61d0422dc31394c7b 100644
--- a/js/filedrop.field.js
+++ b/js/filedrop.field.js
@@ -109,7 +109,7 @@
             // Upload failed. TODO: Add a button to the UI to retry on
             // HTTP 500
             return e.remove();
-          e.find('[name="'+that.options.name+'"]').val(json.id);
+          e.find('[name="'+that.options.name+'"]').val(''+json.id+','+file.name);
           e.data('fileId', json.id);
           e.find('.progress-bar')
             .width('100%')
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index 873da492077dee0aa9ac826c7f9e6be4fa122558..963adce7f9fa57eed7c8bd5c81f1ba33cba1a68f 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -21,6 +21,7 @@ CREATE TABLE `%TABLE_PREFIX%attachment` (
   `object_id` int(11) unsigned NOT NULL,
   `type` char(1) NOT NULL,
   `file_id` int(11) unsigned NOT NULL,
+  `name` varchar(255) NULL default NULL,
   `inline` tinyint(1) unsigned NOT NULL DEFAULT '0',
   `lang` varchar(16),
   PRIMARY KEY  (`id`),