diff --git a/include/class.forms.php b/include/class.forms.php
index e2c8ff18fb4d4988c5acc22947060e82cd52c9e4..aa9405d80d056e0e8764c0b330d7469e14426798 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -1919,7 +1919,7 @@ class FileUploadWidget extends Widget {
           paramname: 'upload[]',
           fallback_id: 'file-<?php echo $id; ?>',
           allowedfileextensions: <?php echo JsonDataEncoder::encode(
-            $config['__extensions']); ?>,
+            $config['__extensions'] ?: array()); ?>,
           allowedfiletypes: <?php echo JsonDataEncoder::encode(
             $mimetypes); ?>,
           maxfiles: <?php echo $config['max'] ?: 20; ?>,
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index addb9aa3bbe019388755a78388fb548708687338..190658f6f44d1882ee55b2fa4239f0172395dc34 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -148,12 +148,14 @@ if($ticket->isOverdue())
                      if(!$emailBanned) {?>
                         <li><a class="confirm-action" id="ticket-banemail"
                             href="#banemail"><i class="icon-ban-circle"></i> <?php echo sprintf(
-                                __('Ban Email <%s>'), $ticket->getEmail()); ?></a></li>
+                                Format::htmlchars(__('Ban Email <%s>')),
+                                $ticket->getEmail()); ?></a></li>
                 <?php
                      } elseif($unbannable) { ?>
                         <li><a  class="confirm-action" id="ticket-banemail"
                             href="#unbanemail"><i class="icon-undo"></i> <?php echo sprintf(
-                                __('Unban Email <%s>'), $ticket->getEmail()); ?></a></li>
+                                Format::htmlchars(__('Unban Email <%s>')),
+                                $ticket->getEmail()); ?></a></li>
                     <?php
                      }
                 }?>
diff --git a/js/filedrop.field.js b/js/filedrop.field.js
index 6427d0d4aaf6434190b84252fa8b9cc3137938ed..d4724aa8679cd81400dfceeb08bc8aed42c1d6f8 100644
--- a/js/filedrop.field.js
+++ b/js/filedrop.field.js
@@ -15,7 +15,7 @@
       beforeSend: $.proxy(this.beforeSend, this),
       beforeEach: $.proxy(this.beforeEach, this),
       error: $.proxy(this.handleError, this),
-      globalProgressUpdated: $.proxy(this.lockSubmit, this)
+      afterAll: $.proxy(this.afterAll, this)
     };
 
     this.options = $.extend({}, $.fn.filedropbox.defaults, events, options);
@@ -102,6 +102,8 @@
       this.uploads.some(function(e) {
         if (e.data('file') == file) {
           if (!json || !json.id)
+            // 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.data('fileId', json.id);
@@ -125,6 +127,12 @@
       }
       return (suffix ? size.toPrecision(3) + suffix : size) + 'B';
     },
+    findNode: function(file) {
+      var nodes = $.grep(this.uploads, function(e) {
+        return e.data('file') == file;
+      });
+      return nodes ? nodes[0] : null;
+    },
     addNode: function(file) {
       // Check if the file is already in the list of files for this dropbox
       var already_added = false;
@@ -190,28 +198,32 @@
     cancelUpload: function(node) {
       if (node.data('xhr')) {
         node.data('xhr').abort();
-        return this.deleteNode(node, false);
       }
+      return this.deleteNode(node, false);
     },
-    handleError: function(err, i, file, status) {
-      var message = $.fn.filedropbox.messages[err];
+    handleError: function(err, file, i, status) {
+      var message = $.fn.filedropbox.messages[err],
+          filenode = this.findNode(file);
       if (file instanceof File) {
         message = '<b>' + file.name + '</b><br/>' + message;
       }
       $.sysAlert(__('File Upload Error'), message);
+      if (filenode) this.cancelUpload(filenode);
     },
-    lockSubmit: function(total_progress) {
+    afterAll: function() {
       var submit = this.$element.closest('form').find('input[type=submit]'),
           $submit = $(submit);
-      if (0 < total_progress  && total_progress < 100) {
-        if (!$submit.data('original')) {
-          $submit.data('original', $submit.val());
-        }
-        $submit.val(__('Uploading ...')).prop('disabled', true);
-      }
-      else if ($submit.data('original')) {
+      if ($submit.data('original')) {
         $submit.val($submit.data('original')).prop('disabled', false);
       }
+    },
+    lockSubmit: function() {
+      var submit = this.$element.closest('form').find('input[type=submit]'),
+          $submit = $(submit);
+      if (!$submit.data('original')) {
+        $submit.data('original', $submit.val());
+      }
+      $submit.val(__('Uploading ...')).prop('disabled', true);
     }
   };
 
@@ -435,11 +447,6 @@
       }
     }
 
-    function abort(e) {
-      global_progress[this.global_progress_index] = 100;
-      globalProgress();
-    }
-
     function globalProgress() {
       if (global_progress.length === 0) {
         return;
@@ -642,7 +649,6 @@
         upload.global_progress_index = global_progress_index;
         upload.startData = 0;
         upload.addEventListener("progress", progress, false);
-        upload.addEventListener("abort", abort, false);
 
         // Allow url to be a method
         if (jQuery.isFunction(opts.url)) {
@@ -666,6 +672,32 @@
 
         opts.uploadStarted(index, file, files_count, xhr);
 
+        var afterComplete = function() {
+          filesDone++;
+
+          // Remove from processing queue
+          processingQueue.forEach(function(value, key) {
+            if (value === fileIndex) {
+              processingQueue.splice(key, 1);
+            }
+          });
+
+          // Add to donequeue
+          doneQueue.push(fileIndex);
+
+          // Make sure the global progress is updated
+          global_progress[global_progress_index] = 100;
+          globalProgress();
+
+          if (filesDone === (files_count - filesRejected)) {
+            afterAll();
+          }
+          if (result === false) {
+            stop_loop = true;
+          }
+        };
+
+        xhr.onabort = afterComplete;
         xhr.onload = function() {
             var serverResponse = null;
 
@@ -681,29 +713,8 @@
             var now = new Date().getTime(),
                 timeDiff = now - start_time,
                 result = opts.uploadFinished(index, file, serverResponse, timeDiff, xhr);
-            filesDone++;
-
-            // Remove from processing queue
-            processingQueue.forEach(function(value, key) {
-              if (value === fileIndex) {
-                processingQueue.splice(key, 1);
-              }
-            });
-
-            // Add to donequeue
-            doneQueue.push(fileIndex);
-
-            // Make sure the global progress is updated
-            global_progress[global_progress_index] = 100;
-            globalProgress();
-
-            if (filesDone === (files_count - filesRejected)) {
-              afterAll();
-            }
-            if (result === false) {
-              stop_loop = true;
-            }
 
+            afterComplete();
 
           // Pass any errors to the error option
           if (xhr.status < 200 || xhr.status > 299) {
diff --git a/js/osticket.js b/js/osticket.js
index 099169067145379c95429d28a08c3ed26df982a3..684c71cdf9d3c8e4db9e851aacb86f7643027172 100644
--- a/js/osticket.js
+++ b/js/osticket.js
@@ -201,6 +201,18 @@ showImagesInline = function(urls, thread_id) {
     });
 }
 
+$.sysAlert = function (title, msg, cb) {
+    var $dialog =  $('.dialog#alert');
+    if ($dialog.length) {
+        $('#title', $dialog).html(title);
+        $('#body', $dialog).html(msg);
+        $dialog.show();
+    } else {
+        msg = msg.replace(/<br\s*\/?>/, "\n").replace(/<\/?\w+[^>]*>/g, '');
+        alert(title+':\n'+msg);
+    }
+};
+
 function __(s) {
   if ($.oststrings && $.oststrings[s])
     return $.oststrings[s];
diff --git a/js/redactor-osticket.js b/js/redactor-osticket.js
index 8deaeb6ad0944e1aa135e574c6bcd55c7fa103ee..6dcf19a38710060304915e13608353fbac802d9e 100644
--- a/js/redactor-osticket.js
+++ b/js/redactor-osticket.js
@@ -177,6 +177,7 @@ RedactorPlugins.signature = {
                 }, 'fast');
                 $(this).css('box-shadow', originalShadow);
             });
+            this.$box.find('.redactor_editor').css('border-bottom-style', 'none', true);
         }
     },
     updateSignature: function(e) {
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 40f3bd8eec014765440ee1760b4a7f591d46a006..2bf39a34dcc947712413b7e5eafbe8a7b284f563 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1660,28 +1660,13 @@ div.selected-signature {
     border: 1px solid #ddd;
     border: 1px solid rgba(0,0,0,0.1);
     border-top-style: dotted;
+    border-bottom-style: none;
     padding: 0.3em 10px 5px;
-    background: repeating-linear-gradient(
-      -45deg,
-      transparent,
-      transparent 10px,
-      rgba(255, 255, 255, 0.6) 10px,
-      rgba(255, 255, 255, 0.6) 20px),
-      #f9f9f9;
     height: 2.5em;
     overflow-y: hidden;
     font-size: 15px;
     line-height: 1.25rem;
 }
-div.selected-signature::after {
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    content: '';
-    box-shadow: rgba(0, 0, 0, 0.2) 0px -15px 15px -19px inset;
-}
 div.selected-signature .inner {
     opacity: 0.5;
 }