diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php
new file mode 100644
index 0000000000000000000000000000000000000000..6475ac03cf1ca6247e9e0402e447635d886f188b
--- /dev/null
+++ b/setup/inc/class.migrater.php
@@ -0,0 +1,55 @@
+<?php
+/*********************************************************************
+    class.migrater.php
+
+    SQL database migrater. This provides the engine capable of rolling the
+    database for an osTicket installation forward (and perhaps even
+    backward) in time using a set of included migration scripts. Each script
+    will roll the database between two database checkpoints. Where possible,
+    the migrater will roll several checkpoint scripts into one to be applied
+    together.
+
+    Jared Hancock <jared@osticket.com>
+    Copyright (c)  2006-2012 osTicket
+    http://www.osticket.com
+
+    Released under the GNU General Public License WITHOUT ANY WARRANTY.
+    See LICENSE.TXT for details.
+
+    vim: expandtab sw=4 ts=4 sts=4:
+**********************************************************************/
+
+class DatabaseMigrater {
+
+    function DatabaseMigrater($sqldir) {
+        $this->sqldir = $sqldir;
+    }
+
+    function getRollup($stops) {
+        $cfg->reload();
+        $start = $cfg->getSchemaSignature();
+
+        $patches = array();
+        while (true) {
+            $next = glob($this->sqldir . $substr($start,0,8)
+                         . '-*.patch.sql');
+            if (count($next) == 1) {
+                $patches[] = $next[0];
+                $start = substr($next[0], 0, 8);
+            } elseif ($count($next) == 0) {
+                # There are no patches leaving the current signature. We
+                # have to assume that we've applied all the available
+                # patches.
+                break;
+            } else {
+                # Problem -- more than one patch exists from this snapshot.
+                # We probably need a graph approach to solve this.
+                break;
+            }
+
+            if (array_key_exists($next[0], $stops))
+                break;
+        }
+        return $patches;
+    }
+}
diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php
index b0fd42ca4205ad922e4ac23890ef775c15bd2b3f..af34a86beaad76f400aec12833a1b45566e08f3a 100644
--- a/setup/inc/class.setup.php
+++ b/setup/inc/class.setup.php
@@ -144,6 +144,12 @@ class Upgrader extends SetupWizard {
 
         //Tasks to perform - saved on the session.
         $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks'];
+
+        $this->migrater = DatabaseMigrater($this->sqldir);
+    }
+
+    function getStops() {
+        return array('7be60a84' => 'migrateAttachments2DB');
     }
 
     function onError($error) {
@@ -183,32 +189,32 @@ class Upgrader extends SetupWizard {
         $this->state = $state;
     }
 
-    function getNextPatch() {
-
-        if(!($patch=glob($this->getSQLDir().$this->getShash().'-*.patch.sql')))
-            return null;
-
-        return $patch[0];
+    function getPatches() {
+        return $this->migrater->getRollup($this->getStops());
     }
 
-    function getThisPatch() {
-                
-        if(!($patch=glob($this->getSQLDir().'*-'.$this->getShash().'.patch.sql')))
-            return null;
-
-        return $patch[0];
-
+    function getNextPatch() {
+        $p = $this->getPatches();
+        return (count($p)) ? $p[0] : false;
     }
 
     function getNextVersion() {
         if(!$patch=$this->getNextPatch())
             return '(Latest)';
 
-        if(preg_match('/\*(.*)\*/', file_get_contents($patch), $matches))
-            $info=$matches[0];
-        else
-            $info=substr(basename($patch), 9, 8);
+        $info = $this->readPatchInfo($patch);
+        return $info['version'];
+    }
 
+    function readPatchInfo($patch) {
+        $info = array();
+        if (preg_match('/\*(.*)\*/', file_get_contents($patch), $matches)) {
+            if (preg_match('/@([\w\d_-]+)\s+(.*)$/', $matches[0], $matches2))
+                foreach ($matches2 as $match)
+                    $info[$match[0]] = $match[1];
+        }
+        if (!isset($info['version']))
+            $info['version'] = substr(basename($patch), 9, 8);
         return $info;
     }
 
@@ -237,19 +243,6 @@ class Upgrader extends SetupWizard {
         return null;
     }
 
-    function getPatches($ToSignature) {
-     
-        $signature = $this->getSignature();
-        $patches = array();
-        while(($patch=glob($this->getSQLDir().substr($signature,0,8).'-*.patch.sql')) && $i++) {
-            $patches = array_merge($patches, $patch);
-            if(!($signature=substr(basename($patch[0]), 10, 8)) || !strncasecmp($signature, $ToSignature, 8))
-                break;
-        }
-
-        return $patches;
-    }
-
     function getNumPendingTasks() {
 
         return count($this->getPendingTasks());
@@ -311,11 +304,12 @@ class Upgrader extends SetupWizard {
     
     function upgrade() {
 
-        if($this->getPendingTasks() || !($patch=$this->getNextPatch()))
+        if($this->getPendingTasks() || !($patches=$this->getPatches()))
             return false;
 
-        if(!$this->load_sql_file($patch, $this->getTablePrefix()))
-            return false;
+        foreach ($patches as $patch)
+            if (!$this->load_sql_file($patch, $this->getTablePrefix()))
+                return false;
 
         //TODO: Log the upgrade
 
@@ -380,6 +374,10 @@ class Upgrader extends SetupWizard {
 
     function migrateAttachments2DB($tId=0) {
         echo "Process attachments here - $tId";
+        $att_migrater = new AttachmentMigrater();
+        $att_migrater->start_migration();
+        # XXX: Loop here (with help of task manager)
+        $att_migrater->do_batch();
         return 0;
     }
 }
diff --git a/setup/inc/sql/522e5b78-02decaa2.patch.sql b/setup/inc/sql/522e5b78-02decaa2.patch.sql
index a6d9a6e09cc1c16aac70dc6a9b4a0f03987a6c9b..78c951d69cc10f255ffb3e4ba85fcf93dae6db58 100644
--- a/setup/inc/sql/522e5b78-02decaa2.patch.sql
+++ b/setup/inc/sql/522e5b78-02decaa2.patch.sql
@@ -1,4 +1,6 @@
-/* v1.7-DPR2-P2 */
+/**
+ * @version v1.7-DPR2-P2 
+ */
 UPDATE `%TABLE_PREFIX%sla`
     SET `created` = NOW(),
         `updated` = NOW()
diff --git a/setup/inc/sql/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql
index 35e744566d50f8a5e8d37d56c3fe3b795db2e1e5..acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9 100644
--- a/setup/inc/sql/7be60a84-522e5b78.patch.sql
+++ b/setup/inc/sql/7be60a84-522e5b78.patch.sql
@@ -1,4 +1,6 @@
-/* v1.7-DPR1 (P1) */ 
+/**
+ * @version v1.7-DPR1 (P1)
+ */ 
 UPDATE `%TABLE_PREFIX%email_template`
     SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached'
     WHERE `tpl_id` = 1 AND `cfg_id` = 1;