diff --git a/file.php b/file.php
index 33ffec5ff1cf038dbfb999b64ce8af5d1c1db3b7..994b77a0c2256a0218a27ffebb01b1c7d77a344b 100644
--- a/file.php
+++ b/file.php
@@ -26,21 +26,34 @@ if (!$_GET['key']
     Http::response(404, __('Unknown or invalid file'));
 }
 
-// Enforce security settings
-if ($cfg->isAuthRequiredForFiles() && !$thisclient) {
-    if (!($U = StaffAuthenticationBackend::getUser())) {
-        // Try and determine if a staff is viewing this page
-        if (strpos($_SERVER['HTTP_REFERRER'], ROOT_PATH .  'scp/') !== false) {
-            $_SESSION['_staff']['auth']['dest'] =
-                '/' . ltrim($_SERVER['REQUEST_URI'], '/');
-            Http::redirect(ROOT_PATH.'scp/login.php');
-        }
-        else {
-            require 'secure.inc.php';
-        }
+// Get the object type the file is attached to
+$type = '';
+if ($_GET['id']
+        && ($a=$file->attachments->findFirst(array(
+                    'id' => $_GET['id']))))
+    $type = $a->type;
+
+// Enforce security settings if enabled.
+if ($cfg->isAuthRequiredForFiles()
+        // FAQ & Page files allowed without login.
+        && !in_array($type, ['P', 'F'])
+        // Check user login
+        && !$thisuser
+        // Check staff login
+        && !StaffAuthenticationBackend::getUser()
+        ) {
+
+    // Try and determine if an agent is viewing the page / file
+    if (strpos($_SERVER['HTTP_REFERRER'], ROOT_PATH .  'scp/') !== false) {
+        $_SESSION['_staff']['auth']['dest'] =
+            '/' . ltrim($_SERVER['REQUEST_URI'], '/');
+        Http::redirect(ROOT_PATH.'scp/login.php');
+    } else {
+        require 'secure.inc.php';
     }
 }
 
+
 // Validate session access hash - we want to make sure the link is FRESH!
 // and the user has access to the parent ticket!!
 if ($file->verifySignature($_GET['signature'], $_GET['expires'])) {
diff --git a/include/ajax.draft.php b/include/ajax.draft.php
index e1bb78a0435b619f9bba99973b806543e6fd4a23..43e7f98b8651001ac5416b35c6f0563f84821f49 100644
--- a/include/ajax.draft.php
+++ b/include/ajax.draft.php
@@ -133,7 +133,8 @@ class DraftAjaxAPI extends AjaxController {
             'content_id' => 'cid:'.$f->getKey(),
             // Return draft_id to connect the auto draft creation
             'draft_id' => $draft->getId(),
-            'filelink' => $f->getDownloadUrl(false, 'inline'),
+            'filelink' => $f->getDownloadUrl(
+                ['type' => 'D', 'deposition' => 'inline']),
         ));
     }
 
@@ -339,14 +340,14 @@ class DraftAjaxAPI extends AjaxController {
             && ($object = $thread->getObject())
             && ($thisstaff->canAccess($object))
         ) {
-            $union = ' UNION SELECT f.id, a.`type`, a.`name` FROM '.THREAD_TABLE.' t
+            $union = ' UNION SELECT f.id, a.id as aid, a.`type`, a.`name` FROM '.THREAD_TABLE.' t
                 JOIN '.THREAD_ENTRY_TABLE.' th ON (th.thread_id = t.id)
                 JOIN '.ATTACHMENT_TABLE.' a ON (a.object_id = th.id AND a.`type` = \'H\')
                 JOIN '.FILE_TABLE.' f ON (a.file_id = f.id)
                 WHERE a.`inline` = 1 AND t.id='.db_input($_GET['threadId']);
         }
 
-        $sql = 'SELECT distinct f.id, COALESCE(a.type, f.ft), a.`name` FROM '.FILE_TABLE
+        $sql = 'SELECT distinct f.id, a.id as aid, COALESCE(a.type, f.ft), a.`name` FROM '.FILE_TABLE
             .' f LEFT JOIN '.ATTACHMENT_TABLE.' a ON (a.file_id = f.id)
             WHERE ((a.`type` IN (\'C\', \'F\', \'T\', \'P\') AND a.`inline` = 1) OR f.ft = \'L\')'
                 .' AND f.`type` LIKE \'image/%\'';
@@ -354,9 +355,11 @@ class DraftAjaxAPI extends AjaxController {
             Http::response(500, 'Unable to lookup files');
 
         $files = array();
-        while (list($id, $type, $name) = db_fetch_row($res)) {
-            $f = AttachmentFile::lookup((int) $id);
-            $url = $f->getDownloadUrl();
+        while (list($id, $aid, $type, $name) = db_fetch_row($res)) {
+            if (!($f = AttachmentFile::lookup((int) $id)))
+                continue;
+
+            $url = $f->getDownloadUrl(['id' => $aid]);
             $files[] = array(
                 // Don't send special sizing for thread items 'cause they
                 // should be cached already by the client
diff --git a/include/class.category.php b/include/class.category.php
index 3eeedfd144b09721f4004a31a3aa26c9be2e5108..c4b1ff0d1ab8f2d2c40db18c8ff5fc5980facccc 100644
--- a/include/class.category.php
+++ b/include/class.category.php
@@ -55,7 +55,9 @@ class Category extends VerySimpleModel {
         return $count;
     }
     function getDescription() { return $this->description; }
-    function getDescriptionWithImages() { return Format::viewableImages($this->description); }
+    function getDescriptionWithImages() {
+        return Format::viewableImages($this->description);
+    }
     function getNotes() { return $this->notes; }
     function getCreateDate() { return $this->created; }
     function getUpdateDate() { return $this->updated; }
diff --git a/include/class.faq.php b/include/class.faq.php
index 4eb1c2d83df46c4953ed0712c1cb03c5a8d913ba..555fd3aee7f6f01fb485259e338c13c394dc826b 100644
--- a/include/class.faq.php
+++ b/include/class.faq.php
@@ -74,7 +74,7 @@ class FAQ extends VerySimpleModel {
     function getQuestion() { return $this->question; }
     function getAnswer() { return $this->answer; }
     function getAnswerWithImages() {
-        return Format::viewableImages($this->answer);
+        return Format::viewableImages($this->answer, ['type' => 'F']);
     }
     function getTeaser() {
         return Format::truncate(Format::striptags($this->answer), 150);
@@ -194,7 +194,8 @@ class FAQ extends VerySimpleModel {
         return $this->_getLocal('answer', $lang);
     }
     function getLocalAnswerWithImages($lang=false) {
-        return Format::viewableImages($this->getLocalAnswer($lang));
+        return Format::viewableImages($this->getLocalAnswer($lang),
+                ['type' => 'F']);
     }
     function _getLocal($what, $lang=false) {
         if (!$lang) {
diff --git a/include/class.file.php b/include/class.file.php
index bcdb9e0ed68f0ce7a944a9ae866ea5626dd4b90b..ed7adb93633fab2a1bd980ea3bde942be6ff9035 100644
--- a/include/class.file.php
+++ b/include/class.file.php
@@ -184,25 +184,31 @@ class AttachmentFile extends VerySimpleModel {
         exit();
     }
 
-    function getDownloadUrl($minage=false, $disposition=false, $handler=false) {
-        // XXX: Drop this when AttachmentFile goes to ORM
+    function getDownloadUrl($options=array()) {
+        // Add attachment ref id if object type is set
+        if (isset($options['type'])
+                && !isset($options['id'])
+                && ($a=$this->attachments->findFirst(array(
+                            'type' => $options['type']))))
+            $options['id'] = $a->getId();
+
         return static::generateDownloadUrl($this->getId(),
-            strtolower($this->getKey()), $this->getSignature(), $minage,
-            $disposition, $handler);
+                strtolower($this->getKey()), $this->getSignature(),
+                $options);
     }
 
-    static function generateDownloadUrl($id, $key, $hash, $minage=false,
-        $disposition=false, $handler=false
-    ) {
-        // Expire at the nearest midnight, allowing at least 12 hours access
-        $minage = $minage ?: 43200;
-        $gmnow = Misc::gmtime() + $minage;
+    static function generateDownloadUrl($id, $key, $hash, $options = array()) {
+
+        // Expire at the nearest midnight, allow at least12 hrs access
+        $minage = @$options['minage'] ?: 43200;
+        $gmnow = Misc::gmtime() +  $options['minage'];
         $expires = $gmnow + 86400 - ($gmnow % 86400);
 
         // Generate a signature based on secret content
         $signature = static::_genUrlSignature($id, $key, $hash, $expires);
 
-        $handler = $handler ?: ROOT_PATH . 'file.php';
+        // Handler / base url
+        $handler = @$options['handler'] ?: ROOT_PATH . 'file.php';
 
         // Return sanitized query string
         $args = array(
@@ -211,10 +217,13 @@ class AttachmentFile extends VerySimpleModel {
             'signature' => $signature,
         );
 
-        if ($disposition)
-            $args['disposition'] = $disposition;
+        if (isset($options['disposition']))
+            $args['disposition'] =  $options['disposition'];
+
+        if (isset($options['id']))
+            $args['id'] =  $options['id'];
 
-        return $handler . '?' . http_build_query($args);
+        return sprintf('%s?%s', $handler, http_build_query($args));
     }
 
     function verifySignature($signature, $expires) {
diff --git a/include/class.format.php b/include/class.format.php
index 50c8a7fdf144c12d23f9f59ff4c1b3dc87cd4609..7d7d7d9225a76aba2f3d7f72bee7084c75ac9c1f 100644
--- a/include/class.format.php
+++ b/include/class.format.php
@@ -455,14 +455,17 @@ class Format {
     }
 
 
-    function viewableImages($html, $script=false) {
+    function viewableImages($html, $options=array()) {
         $cids = $images = array();
+        $options +=array(
+                'deposition' => 'inline');
         return preg_replace_callback('/"cid:([\w._-]{32})"/',
-        function($match) use ($script, $images) {
+        function($match) use ($options, $images) {
             if (!($file = AttachmentFile::lookup($match[1])))
                 return $match[0];
+
             return sprintf('"%s" data-cid="%s"',
-                $file->getDownloadUrl(false, 'inline', $script), $match[1]);
+                $file->getDownloadUrl($options), $match[1]);
         }, $html);
     }
 
diff --git a/include/class.forms.php b/include/class.forms.php
index 2f8582855c64596e1f364476b4a449f0b0185d04..161e06fdb24ec34f700b025b55adff01f80f4c78 100644
--- a/include/class.forms.php
+++ b/include/class.forms.php
@@ -4513,13 +4513,15 @@ class FreeTextWidget extends Widget {
         if (($attachments = $this->field->getFiles()) && count($attachments)) { ?>
             <section class="freetext-files">
             <div class="title"><?php echo __('Related Resources'); ?></div>
-            <?php foreach ($attachments as $attach) { ?>
+            <?php foreach ($attachments as $attach) {
+                $filename = Format::htmlchars($attach->getFilename());
+                ?>
                 <div class="file">
                 <a href="<?php echo $attach->file->getDownloadUrl(); ?>"
-                    target="_blank" download="<?php echo $attach->file->getDownloadUrl();
-                    ?>" class="truncate no-pjax">
+                    target="_blank" download="<?php echo $filename; ?>"
+                    class="truncate no-pjax">
                     <i class="icon-file"></i>
-                    <?php echo Format::htmlchars($attach->getFilename()); ?>
+                    <?php echo $filename; ?>
                 </a>
                 </div>
             <?php } ?>
diff --git a/include/class.page.php b/include/class.page.php
index 3ea5ca0f98839dc5fcdc4638c5de515b492bc245..a430fc2e66cd20da6b5a1711b1739094bbc8fdbc 100644
--- a/include/class.page.php
+++ b/include/class.page.php
@@ -70,7 +70,7 @@ class Page extends VerySimpleModel {
         return $this->_getLocal('body', $lang);
     }
     function getBodyWithImages() {
-        return Format::viewableImages($this->getLocalBody());
+        return Format::viewableImages($this->getLocalBody(), ['type' => 'P']);
     }
 
     function _getLocal($what, $lang=false) {
diff --git a/include/client/faq.inc.php b/include/client/faq.inc.php
index 9bc723a6e61c4dfbdf9571ce215c8f132e22b0e7..176ae429a5065d545fb4361faee019b015232971 100644
--- a/include/client/faq.inc.php
+++ b/include/client/faq.inc.php
@@ -43,7 +43,8 @@ $category=$faq->getCategory();
     <strong><?php echo __('Attachments');?>:</strong>
 <?php foreach ($attachments as $att) { ?>
     <div>
-    <a href="<?php echo $att->file->getDownloadUrl(); ?>" class="no-pjax">
+    <a href="<?php echo $att->file->getDownloadUrl(['id' => $att->getId()]);
+    ?>" class="no-pjax">
         <i class="icon-file"></i>
         <?php echo Format::htmlchars($att->getFilename()); ?>
     </a>
diff --git a/include/client/templates/thread-entry.tmpl.php b/include/client/templates/thread-entry.tmpl.php
index fed92a5c657b6bba249f6f365cae8462b62c895d..ad9f3dc9fa33282b4a9bec980cc7daf2ee9fc7fc 100644
--- a/include/client/templates/thread-entry.tmpl.php
+++ b/include/client/templates/thread-entry.tmpl.php
@@ -60,7 +60,8 @@ if ($cfg->isAvatarsEnabled() && $user)
 ?>
         <span class="attachment-info">
         <i class="icon-paperclip icon-flip-horizontal"></i>
-        <a class="no-pjax truncate filename" href="<?php echo $A->file->getDownloadUrl();
+        <a  class="no-pjax truncate filename"
+            href="<?php echo $A->file->getDownloadUrl(['id' => $A->getId()]);
             ?>" download="<?php echo Format::htmlchars($A->getFilename()); ?>"
             target="_blank"><?php echo Format::htmlchars($A->getFilename());
         ?></a><?php echo $size;?>
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index bc39255ab0e02367b43f151e1e1b9a05c5c41bd7..fa48bdc3eaf2bb3aaf44ca37690fa64ff509eed3 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -208,7 +208,7 @@ foreach (AttachmentFile::objects()->filter(array(
     'attachments__inline' => true,
 )) as $file) {
     $urls[strtolower($file->getKey())] = array(
-        'download_url' => $file->getDownloadUrl(),
+        'download_url' => $file->getDownloadUrl(['type' => 'H']),
         'filename' => $file->name,
     );
 } ?>
diff --git a/include/staff/faq-view.inc.php b/include/staff/faq-view.inc.php
index a5dc4e56010c41ca059d7701d1bd19345c533661..531fbc2cd44bb603b860f5de9e4e833bcbaf2a88 100644
--- a/include/staff/faq-view.inc.php
+++ b/include/staff/faq-view.inc.php
@@ -41,7 +41,8 @@ if ($thisstaff->hasPerm(FAQ::PERM_MANAGE)) { ?>
 <?php foreach ($attachments as $att) { ?>
 <div>
     <i class="icon-paperclip pull-left"></i>
-    <a target="_blank" href="<?php echo $att->file->getDownloadUrl(); ?>"
+    <a target="_blank" href="<?php echo $att->file->getDownloadUrl(['id' =>
+    $att->getId()]); ?>"
         class="attachment no-pjax">
         <?php echo Format::htmlchars($att->getFilename()); ?>
     </a>
diff --git a/include/staff/templates/thread-entries.tmpl.php b/include/staff/templates/thread-entries.tmpl.php
index 0d15aa0c9f15dfd410a9c60914a5c17ef67d3ab5..9b267bbae835c20484b484db1e963a1d4e5db2a0 100644
--- a/include/staff/templates/thread-entries.tmpl.php
+++ b/include/staff/templates/thread-entries.tmpl.php
@@ -80,7 +80,8 @@ foreach (Attachment::objects()->filter(array(
                 if (!$A->inline)
                     continue;
                 $urls[strtolower($A->file->getKey())] = array(
-                    'download_url' => $A->file->getDownloadUrl(),
+                    'download_url' => $A->file->getDownloadUrl(['id' =>
+                        $A->getId()]),
                     'filename' => $A->getFilename(),
                 );
             }
diff --git a/include/staff/templates/thread-entry.tmpl.php b/include/staff/templates/thread-entry.tmpl.php
index d36d2b7c9ab08e1e50e14829fa7726cbe5ee2050..5781db359fb9fe1383bd8f2235f536bb2f910774 100644
--- a/include/staff/templates/thread-entry.tmpl.php
+++ b/include/staff/templates/thread-entry.tmpl.php
@@ -101,7 +101,8 @@ if ($entry->flags & ThreadEntry::FLAG_COLLABORATOR && $entry->type == 'N') {
 ?>
         <span class="attachment-info">
         <i class="icon-paperclip icon-flip-horizontal"></i>
-        <a class="no-pjax truncate filename" href="<?php echo $A->file->getDownloadUrl();
+        <a class="no-pjax truncate filename" href="<?php echo
+        $A->file->getDownloadUrl(['id' => $A->getId()]);
             ?>" download="<?php echo Format::htmlchars($A->getFilename()); ?>"
             target="_blank"><?php echo Format::htmlchars($A->getFilename());
         ?></a><?php echo $size;?>
diff --git a/open.php b/open.php
index 450b9d1f60609daaa31e77673e4898d672230403..a507bc979515181f5d46eb035a8ccaf9ade92e59 100644
--- a/open.php
+++ b/open.php
@@ -82,7 +82,8 @@ if ($ticket
     echo Format::viewableImages(
         $ticket->replaceVars(
             $page->getLocalBody()
-        )
+        ),
+        ['type' => 'P']
     );
 }
 else {