diff --git a/ajax.php b/ajax.php
index 60fca4337ec3df74e71df4037b49bdbfc917ac89..bfa481a20aed7cf8c1d6134ff835a46584dcbb0e 100644
--- a/ajax.php
+++ b/ajax.php
@@ -36,7 +36,9 @@ $dispatcher = patterns('',
         url_post('^(?P<namespace>[\w.]+)$', 'createDraftClient')
     )),
     url('^/form/', patterns('ajax.forms.php:DynamicFormsAjaxAPI',
-        url_get('^help-topic/(?P<id>\d+)$', 'getClientFormsForHelpTopic')
+        url_get('^help-topic/(?P<id>\d+)$', 'getClientFormsForHelpTopic'),
+        url_post('^upload/(\d+)?$', 'upload'),
+        url_post('^upload/(\w+)?$', 'attach')
     )),
     url('^/i18n/(?P<lang>[\w_]+)/', patterns('ajax.i18n.php:i18nAjaxAPI',
         url_get('(?P<tag>\w+)$', 'getLanguageFile')
diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css
index c88bba906cdef9b040661312900e7f63b0015f10..e50724e19283d088aceb3acfd64cf4feb51acc8a 100644
--- a/assets/default/css/theme.css
+++ b/assets/default/css/theme.css
@@ -703,25 +703,6 @@ label.required {
   border: 1px solid #aaa;
   background: #fff;
 }
-#reply .attachments .uploads div {
-  display: inline-block;
-  padding-right: 20px;
-}
-#reply .file {
-  display: inline-block;
-  padding-left: 20px;
-  margin-right: 20px;
-  background: url('../images/icons/file.gif') 0 50% no-repeat;
-}
-.uploads {
-  display: inline-block;
-  padding-right: 20px;
-}
-.uploads label {
-  padding: 3px;
-  padding-right: 10px;
-  width: auto !important;
-}
 /* Ticket icons */
 .Icon {
   width: auto;
diff --git a/css/filedrop.css b/css/filedrop.css
index 3f617b2d7454096be158d3ba5e237304695a1f6b..b045b343688400a9f3fe884007a766fd4547b150 100644
--- a/css/filedrop.css
+++ b/css/filedrop.css
@@ -1,3 +1,6 @@
+.filedrop {
+    padding-bottom: 10px;
+}
 .filedrop .dropzone {
     border: 2px dashed rgba(0, 0, 0, 0.2);
     padding: 8px;
diff --git a/include/class.forms.php b/include/class.forms.php
index 2390912d00e70e9ed1e122650d33a6ff7e93537a..00588ddb68793df89cb4beda2b941663b7144047 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -113,23 +113,14 @@ class Form {
         static $dedup = array();
 
         foreach ($this->getFields() as $f) {
-            if (($M = $f->getImpl()->getMedia()) && is_array($M)) {
+            if (($M = $f->getMedia()) && is_array($M)) {
                 foreach ($M as $type=>$files) {
                     foreach ($files as $url) {
                         $key = strtolower($type.$url);
                         if (isset($dedup[$key]))
                             continue;
-                        if ($url[0] == '/')
-                            $url = ROOT_PATH . $url;
-
-                        switch (strtolower($type)) {
-                        case 'css': ?>
-            <link rel="stylesheet" type="text/css" href="<?php echo $url; ?>"/><?php
-                            break;
-                        case 'js': ?>
-            <script type="text/javascript" src="<?php echo $url; ?>"></script><?php
-                            break;
-                        }
+
+                        self::emitMedia($url, $type);
 
                         $dedup[$key] = true;
                     }
@@ -137,6 +128,20 @@ class Form {
             }
         }
     }
+
+    static function emitMedia($url, $type) {
+        if ($url[0] == '/')
+            $url = ROOT_PATH . substr($url, 1);
+
+        switch (strtolower($type)) {
+        case 'css': ?>
+        <link rel="stylesheet" type="text/css" href="<?php echo $url; ?>"/><?php
+            break;
+        case 'js': ?>
+        <script type="text/javascript" src="<?php echo $url; ?>"></script><?php
+            break;
+        }
+    }
 }
 
 require_once(INCLUDE_DIR . "class.json.php");
@@ -1681,22 +1686,11 @@ class ThreadEntryWidget extends Widget {
     function showAttachments($errors=array()) {
         global $cfg, $thisclient;
 
-        if(($cfg->allowOnlineAttachments()
-            && !$cfg->allowAttachmentsOnlogin())
-            || ($cfg->allowAttachmentsOnlogin()
-                && ($thisclient && $thisclient->isValid()))) { ?>
-        <div class="clear"></div>
-        <hr/>
-        <div><strong style="padding-right:1em;vertical-align:top"><?php
-        echo __('Attachments'); ?>: </strong>
-        <div style="display:inline-block">
-        <div class="uploads" style="display:block"></div>
-        <input type="file" class="multifile" name="attachments[]" id="attachments" size="30" value="" />
-        </div>
-        <font class="error">&nbsp;<?php echo $errors['attachments']; ?></font>
-        </div>
-        <hr/>
-        <?php
+        $attachments = new FileUploadField(array('id'=>'attach'));
+        print $attachments->render($client);
+        foreach ($attachments->getMedia() as $type=>$urls) {
+            foreach ($urls as $url)
+                Form::emitMedia($url, $type);
         }
     }
 }
diff --git a/include/class.ticket.php b/include/class.ticket.php
index acded0c81c769d753360626775c0d797e9653982..d44303ca9acdf2bba0cbc0584a46ec347ed2bbb1 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -2681,7 +2681,6 @@ class Ticket {
         }
 
         //post the message.
-        unset($vars['cannedattachments']); //Ticket::open() might have it set as part of  open & respond.
         $vars['title'] = $vars['subject']; //Use the initial subject as title of the post.
         $vars['userId'] = $ticket->getUserId();
         $message = $ticket->postMessage($vars , $origin, false);
@@ -2773,7 +2772,9 @@ class Ticket {
         if (!$thisstaff->canAssignTickets())
             unset($vars['assignId']);
 
-        if(!($ticket=Ticket::create($vars, $errors, 'staff', false)))
+        $create_vars = $vars;
+        unset($create_vars['cannedattachments']);
+        if(!($ticket=Ticket::create($create_vars, $errors, 'staff', false)))
             return false;
 
         $vars['msgId']=$ticket->getLastMsgId();
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index 8e547913a10b73e7efac108fd81d141365f17858..cc7a2f84e83055434ebd95b5992b8f40990b2bcf 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -186,15 +186,10 @@ if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) {
         <?php
         if($cfg->allowOnlineAttachments()) { ?>
         <tr>
-            <td width="160">
-                <label for="attachment"><?php echo __('Attachments');?>:</label>
-            </td>
-            <td width="640" id="reply_form_attachments" class="attachments">
-                <div class="uploads">
-                </div>
-                <div class="file_input">
-                    <input class="multifile" type="file" name="attachments[]" size="30" value="" />
-                </div>
+            <td colspan="2">
+<?php
+            print $response_form->getField('attachments')->render(true);
+?>
             </td>
         </tr>
         <?php
diff --git a/open.php b/open.php
index d7aa3cb986c58b2242b19ca09241635823824c08..dc6325529be414986231c746acdcd10f4122f626 100644
--- a/open.php
+++ b/open.php
@@ -29,8 +29,9 @@ if ($_POST) {
             $errors['captcha']=__('Invalid - try again!');
     }
 
-    if (!$errors && $cfg->allowOnlineAttachments() && $_FILES['attachments'])
-        $vars['files'] = AttachmentFile::format($_FILES['attachments'], true);
+    $attachments = new FileUploadField(array('id'=>'attach'));
+    if (!$errors && $cfg->allowOnlineAttachments())
+        $vars['cannedattachments'] = $attachments->getClean();
 
     // Drop the draft.. If there are validation errors, the content
     // submitted will be displayed back to the user
diff --git a/tickets.php b/tickets.php
index 4e38384b2b05a877701f72c05d6479873c742bd2..8fc98e92c4bd3a24bc20edeb1fd7e79533a7efcf 100644
--- a/tickets.php
+++ b/tickets.php
@@ -35,6 +35,10 @@ if($_REQUEST['id']) {
 if (!$ticket && $thisclient->isGuest())
     Http::redirect('view.php');
 
+$response_form = new Form(array(
+    'attachments' => new FileUploadField(array('id'=>'attach'))
+));
+
 //Process post...depends on $ticket object above.
 if($_POST && is_object($ticket) && $ticket->getId()):
     $errors=array();
@@ -75,8 +79,8 @@ if($_POST && is_object($ticket) && $ticket->getId()):
                     'userId' => $thisclient->getId(),
                     'poster' => (string) $thisclient->getName(),
                     'message' => $_POST['message']);
-            if($cfg->allowOnlineAttachments() && $_FILES['attachments'])
-                $vars['files'] = AttachmentFile::format($_FILES['attachments'], true);
+            if ($cfg->allowOnlineAttachments())
+                $vars['cannedattachments'] = $response_form->getField('attachments')->getClean();
             if (isset($_POST['draft_id']))
                 $vars['draft_id'] = $_POST['draft_id'];
 
@@ -85,6 +89,9 @@ if($_POST && is_object($ticket) && $ticket->getId()):
                 // Cleanup drafts for the ticket. If not closed, only clean
                 // for this staff. Else clean all drafts for the ticket.
                 Draft::deleteForNamespace('ticket.client.' . $ticket->getId());
+                // Drop attachments
+                $response_form->getField('attachments')->reset();
+                $response_form->setSource(array());
             } else {
                 $errors['err']=__('Unable to post the message. Try again');
             }
@@ -117,5 +124,6 @@ if($ticket && $ticket->checkUserAccess($thisclient)) {
 }
 include(CLIENTINC_DIR.'header.inc.php');
 include(CLIENTINC_DIR.$inc);
+print $response_form->getMedia();
 include(CLIENTINC_DIR.'footer.inc.php');
 ?>