diff --git a/include/class.file.php b/include/class.file.php
index 260c846af68059f1415bc0defe1c11e128717c4a..9c8eb9c53da2a4c450421c4e8261c1efcc511311 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -304,7 +304,7 @@ class AttachmentFile {
         return false;
     }
 
-    function save($file, $ft=false) {
+    function save(&$file, $ft=false) {
 
         if (isset($file['data'])) {
             // Allow a callback function to delay or avoid reading or
@@ -312,8 +312,10 @@ class AttachmentFile {
             if (is_callable($file['data']))
                 $file['data'] = $file['data']();
 
-            list($file['key'], $file['signature'])
-                = static::_getKeyAndHash($file['data']);
+            list($key, $file['signature'])
+                = self::_getKeyAndHash($file['data']);
+            if (!$file['key'])
+                $file['key'] = $key;
 
             if (!isset($file['size']))
                 $file['size'] = strlen($file['data']);
@@ -429,6 +431,9 @@ class AttachmentFile {
     static function getBackendForFile($file) {
         global $cfg;
 
+        if (!$cfg)
+            return new AttachmentChunkedData($file);
+
         $char = $cfg->getDefaultStorageBackendChar();
         return FileStorageBackend::lookup($char, $file);
     }
diff --git a/include/class.thread.php b/include/class.thread.php
index 7a1af0738caac9fd54afce0e3a07f99afcec37fc..b7a0d8eaf0df77ac3cf8ff9cff6a7fb4370c56cc 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -457,13 +457,13 @@ Class ThreadEntry {
         return $uploaded;
     }
 
-    function importAttachments($attachments) {
+    function importAttachments(&$attachments) {
 
         if(!$attachments || !is_array($attachments))
             return null;
 
         $files = array();
-        foreach($attachments as  $attachment)
+        foreach($attachments as &$attachment)
             if(($id=$this->importAttachment($attachment)))
                 $files[] = $id;
 
@@ -471,7 +471,7 @@ Class ThreadEntry {
     }
 
     /* Emailed & API attachments handler */
-    function importAttachment($attachment) {
+    function importAttachment(&$attachment) {
 
         if(!$attachment || !is_array($attachment))
             return null;
@@ -493,7 +493,7 @@ Class ThreadEntry {
     Save attachment to the DB.
     @file is a mixed var - can be ID or file hashtable.
     */
-    function saveAttachment($file) {
+    function saveAttachment(&$file) {
 
         if(!($fileId=is_numeric($file)?$file:AttachmentFile::save($file)))
             return 0;
@@ -850,21 +850,6 @@ Class ThreadEntry {
             if((list($msg) = explode($tag, $vars['body'], 2)) && trim($msg))
                 $vars['body'] = $msg;
 
-        if (isset($vars['attachments'])) {
-            foreach ($vars['attachments'] as &$a) {
-                // Change <img src="cid:"> inside the message to point to
-                // a unique hash-code for the attachment. Since the
-                // content-id will be discarded, only the unique hash-code
-                // will be available to retrieve the image later
-                if ($a['cid']) {
-                    $a['hash'] = Misc::randCode(32);
-                    $vars['body'] = str_replace('src="cid:'.$a['cid'].'"',
-                        'src="cid:'.$a['hash'].'"', $vars['body']);
-                }
-            }
-            unset($a);
-        }
-
         if (!$cfg->isHtmlThreadEnabled()) {
             // Data in the database is assumed to be HTML, change special
             // plain text XML characters
@@ -882,12 +867,16 @@ Class ThreadEntry {
             .' ,thread_type='.db_input($vars['type'])
             .' ,ticket_id='.db_input($vars['ticketId'])
             .' ,title='.db_input(Format::sanitize($vars['title'], true))
-            .' ,body='.db_input($vars['body'])
             .' ,staff_id='.db_input($vars['staffId'])
             .' ,user_id='.db_input($vars['userId'])
             .' ,poster='.db_input($poster)
             .' ,source='.db_input($vars['source']);
 
+        if (!isset($vars['attachments']))
+            // Otherwise, body will be configured in a block below (after
+            // inline attachments are saved and updated in the database)
+            $sql.=' ,body='.db_input($vars['body']);
+
         if(isset($vars['pid']))
             $sql.=' ,pid='.db_input($vars['pid']);
         // Check if 'reply_to' is in the $vars as the previous ThreadEntry
@@ -910,14 +899,30 @@ Class ThreadEntry {
         if($vars['files']) //expects well formatted and VALIDATED files array.
             $entry->uploadFiles($vars['files']);
 
-        //Emailed or API attachments
-        if($vars['attachments'])
-            $entry->importAttachments($vars['attachments']);
-
         //Canned attachments...
         if($vars['cannedattachments'] && is_array($vars['cannedattachments']))
             $entry->saveAttachments($vars['cannedattachments']);
 
+        //Emailed or API attachments
+        if (isset($vars['attachments']) && $vars['attachments']) {
+            $entry->importAttachments($vars['attachments']);
+            foreach ($vars['attachments'] as &$a) {
+                // Change <img src="cid:"> inside the message to point to
+                // a unique hash-code for the attachment. Since the
+                // content-id will be discarded, only the unique hash-code
+                // will be available to retrieve the image later
+                if ($a['cid'] && $a['key']) {
+                    $vars['body'] = str_replace('src="cid:'.$a['cid'].'"',
+                        'src="cid:'.$a['key'].'"', $vars['body']);
+                }
+            }
+            unset($a);
+            $sql = 'UPDATE '.TICKET_THREAD_TABLE.' SET body='.db_input($vars['body'])
+                .' WHERE `id`='.db_input($entry->getId());
+            if (!db_query($sql) || !db_affected_rows())
+                return false;
+        }
+
         // Email message id (required for all thread posts)
         if (!isset($vars['mid']))
             $vars['mid'] = sprintf('<%s@%s>', Misc::randCode(24),
diff --git a/include/i18n/en_US/file.yaml b/include/i18n/en_US/file.yaml
index 19f2e35a5a04618e8b08a015961581f82634937c..b6b9ac906fe09b8a61aa32c1c07f46138cc811ee 100644
--- a/include/i18n/en_US/file.yaml
+++ b/include/i18n/en_US/file.yaml
@@ -9,7 +9,7 @@
 # bill be cleaned up shortly after installation (by the autocron).
 #
 ---
-- hash: b56944cb4722cc5cda9d1e23a3ea7fbc
+- key: b56944cb4722cc5cda9d1e23a3ea7fbc
   name: powered-by-osticket.png
   type: image/png
   encoding: base64
@@ -105,7 +105,7 @@
       NQLJLj4m+f1lr/Kfzeo1TMm+prKzxxgz2AeQEd49EE0PDxwVGTx+lDbX4G94cZ021zwTueT9+79q
       vjLYs5AR3j0Seq638S2PileedN26W3OuWb8rz9FmsJfg/wBsHf7rZZG4/wAAAABJRU5ErkJggg==
 
-- hash: 6fe1efdea357534d238b86e7860a7c5a
+- key: 6fe1efdea357534d238b86e7860a7c5a
   name: kangaroo.png
   type: image/png
   encoding: base64
diff --git a/include/upgrader/streams/core.sig b/include/upgrader/streams/core.sig
index 9c7611253e6438aec902c1091dd72e2415f2e564..c285c35e59d5deb946eedf0157dd489ede195955 100644
--- a/include/upgrader/streams/core.sig
+++ b/include/upgrader/streams/core.sig
@@ -1 +1 @@
-227215f11d6a2625e13a528e40a156dd
+756b22698b4f69d1aa3b51e5cbd917da
diff --git a/include/upgrader/streams/core/ed60ba20-ee1f4b27.patch.sql b/include/upgrader/streams/core/ed60ba20-7e2017c8.patch.sql
similarity index 100%
rename from include/upgrader/streams/core/ed60ba20-ee1f4b27.patch.sql
rename to include/upgrader/streams/core/ed60ba20-7e2017c8.patch.sql
diff --git a/setup/inc/streams/core/install-mysql.sql b/setup/inc/streams/core/install-mysql.sql
index a8592ef317175889f8d7ee6cdd61bcb04a1cd51d..3cc30e3f1ab95285b761a62d8b96a609dff5fe10 100644
--- a/setup/inc/streams/core/install-mysql.sql
+++ b/setup/inc/streams/core/install-mysql.sql
@@ -320,13 +320,13 @@ CREATE TABLE `%TABLE_PREFIX%file` (
   `bk` CHAR( 1 ) NOT NULL DEFAULT  'D',
   `type` varchar(255) NOT NULL default '',
   `size` varchar(25) NOT NULL default '',
-  `key` varchar(125) collate ascii_bin NOT NULL,
+  `key` varchar(125) collate ascii_general_ci NOT NULL,
   `signature` varchar(125) collate ascii_bin NOT NULL,
   `name` varchar(255) NOT NULL default '',
   `created` datetime NOT NULL,
   PRIMARY KEY  (`id`),
   KEY `ft` (`ft`),
-  KEY `key` (`key`)
+  KEY `key` (`key`),
   KEY `signature` (`signature`)
 ) DEFAULT CHARSET=utf8;