diff --git a/api/pipe.php b/api/pipe.php
index d7d4b33be96644c484c846d47bf36179829ccdc2..29dfcff1d1aa10a20386589927830ffed8211911 100644
--- a/api/pipe.php
+++ b/api/pipe.php
@@ -21,7 +21,7 @@ require_once(INCLUDE_DIR.'class.mailparse.php');
 require_once(INCLUDE_DIR.'class.email.php');
 
 //Make sure piping is enabled!
-if(!$cfg->enableEmailPiping())
+if(!$cfg->isEmailPipingEnabled())
     api_exit(EX_UNAVAILABLE,'Email piping not enabled - check MTA settings.');
 //Get the input
 $data=isset($_SERVER['HTTP_HOST'])?file_get_contents('php://input'):file_get_contents('php://stdin');
@@ -99,20 +99,18 @@ if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
 }        
 $errors=array();
 $msgid=0;
-if(!$ticket){ //New tickets...
+if(!$ticket) { //New tickets...
     $ticket=Ticket::create($var,$errors,'email');
-    if(!is_object($ticket) || $errors){
+    if(!is_object($ticket) || $errors) {
         api_exit(EX_DATAERR,'Ticket create Failed '.implode("\n",$errors)."\n\n");
     }
+
     $msgid=$ticket->getLastMsgId();
-}else{
-    $message=$var['message'];
-    //Strip quoted reply...TODO: figure out how mail clients do it without special tag..
-    if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
-        list($message)=split($tag,$var['message']);
+
+} else {
     //post message....postMessage does the cleanup.
-    if(!($msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']))) {
-        api_exit(EX_DATAERR,"Unable to post message \n\n $message\n");
+    if(!($msgid=$ticket->postMessage($var['message'], 'Email',$var['mid'],$var['header']))) {
+        api_exit(EX_DATAERR, 'Unable to post message');
     }
 }
 //Ticket created...save attachments if enabled.
diff --git a/include/class.config.php b/include/class.config.php
index 2c9afb2448b276dc9364a36b3f16e5c62bb22f45..cc9b497682097d0e622dbbd410b0a4f5b0fae601 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -320,23 +320,23 @@ class Config {
         return ($this->config['clickable_urls']);
     }
         
-    function canFetchMail() {
-        return ($this->config['enable_mail_polling']);
-    }
-
     function enableStaffIPBinding() {
         return ($this->config['staff_ip_binding']);
     }
 
-    function enableCaptcha() {
+    function isCaptchaEnabled() {
         return (extension_loaded('gd') && function_exists('gd_info') && $this->config['enable_captcha']);
     }
 
-    function enableAutoCron() {
+    function isAutoCronEnabled() {
         return ($this->config['enable_auto_cron']);
     }
+
+    function isEmailPollingEnabled() {
+        return ($this->config['enable_mail_polling']);
+    }
         
-    function enableEmailPiping() {
+    function isEmailPipingEnabled() {
         return ($this->config['enable_email_piping']);
     }
 
diff --git a/include/class.cron.php b/include/class.cron.php
index c8e3a81def985b99eb0f21eaea8751362e1ced05..15ca7078b27785b6721b0a9f04b2d4b84eb28c9c 100644
--- a/include/class.cron.php
+++ b/include/class.cron.php
@@ -20,7 +20,7 @@ class Cron {
 
     function MailFetcher() {
         require_once(INCLUDE_DIR.'class.mailfetch.php');
-        MailFetcher::fetchMail(); //Fetch mail..frequency is limited by email account setting.
+        MailFetcher::run(); //Fetch mail..frequency is limited by email account setting.
     }
 
     function TicketMonitor() {
diff --git a/include/class.email.php b/include/class.email.php
index dba9a45d5d4c569c9a5e7b2c17c4254f12abdcee..0cc04010bf54d85212f3d49f8c05143be9c1c107 100644
--- a/include/class.email.php
+++ b/include/class.email.php
@@ -98,6 +98,27 @@ class Email {
         return $this->getHashtable();
     }
 
+    function getMailAccountInfo() {
+
+        /*NOTE: Do not change any of the tags - otherwise mail fetching will fail */
+        $info = array(
+                //Mail server info
+                'host'  => $this->ht['mail_host'],
+                'port'  => $this->ht['mail_port'],
+                'protocol'  => $this->ht['mail_protocol'],
+                'encryption' => $this->ht['mail_encryption'],
+                'username'  => $this->ht['userid'],
+                'password' => Mcrypt::decrypt($this->ht['userpass'], SECRET_SALT),
+                //osTicket specific                
+                'email_id'  => $this->getId(), //Required for email routing to work.
+                'max_fetch' => $this->ht['mail_fetchmax'],
+                'delete_mail' => $this->ht['mail_delete'],
+                'archive_folder' => $this->ht['mail_archivefolder']
+                );
+
+        return $info;
+    }
+
     function isSMTPEnabled() {
         return $this->ht['smtp_active'];
     }
@@ -106,17 +127,15 @@ class Email {
         return ($this->ht['smtp_spoofing']);
     }
 
-    function getSMTPInfo($active=true) {
-        $info=array();
-        if(!$active || ($active && $this->isSMTPEnabled())) {
-
-            $info = array ('host' => $this->ht['smtp_host'],
-                           'port' => $this->ht['smtp_port'],
-                           'auth' => $this->ht['smtp_auth'],
-                           'username' => $this->ht['userid'],
-                           'password' =>Mcrypt::decrypt($this->ht['userpass'],SECRET_SALT)
-                           );
-        }
+    function getSMTPInfo() {
+            
+        $info = array (
+                'host' => $this->ht['smtp_host'],
+                'port' => $this->ht['smtp_port'],
+                'auth' => $this->ht['smtp_auth'],
+                'username' => $this->ht['userid'],
+                'password' => Mcrypt::decrypt($this->ht['userpass'], SECRET_SALT)
+                );
 
         return $info;
     }
@@ -207,12 +226,12 @@ class Email {
         $vars=$vars;
         $vars['cpasswd']=$this->getPasswd(); //Current decrypted password.
 
-        if($this->save($this->getId(),$vars,$errors)) {
-            $this->reload();
-            return true;
-        }
+        if(!$this->save($this->getId(), $vars, $errors))
+            return false;
 
-        return false;
+        $this->reload();
+        
+        return true;
     }
 
 
@@ -341,11 +360,8 @@ class Email {
 
             if(!isset($vars['postfetch']))
                 $errors['postfetch']='Indicate what to do with fetched emails';
-            elseif(!strcasecmp($vars['postfetch'],'archive')) {
-                if(!$vars['mail_archivefolder'])
-                    $errors['postfetch']='Valid folder required';
-            }
-            
+            elseif(!strcasecmp($vars['postfetch'],'archive') && !$vars['mail_archivefolder'] )
+                $errors['postfetch']='Valid folder required';
         }
         
         if($vars['smtp_active']) {
@@ -370,10 +386,16 @@ class Email {
         
         $passwd=$vars['passwd']?$vars['passwd']:$vars['cpasswd'];
         if(!$errors && $vars['mail_active']) {
-           
             //note: password is unencrypted at this point...MailFetcher expect plain text.
-            $fetcher = new MailFetcher($vars['userid'],$passwd,$vars['mail_host'],$vars['mail_port'],
-                                            $vars['mail_protocol'],$vars['mail_encryption']);
+            $fetcher = new MailFetcher(
+                    array(
+                        'host'  => $vars['mail_host'],
+                        'port'  => $vars['mail_port'],
+                        'username'  => $vars['userid'],
+                        'password'  => $passwd,
+                        'protocol'  => $vars['mail_protocol'],
+                        'encryption' => $vars['mail_encryption'])
+                    );
             if(!$fetcher->connect()) {
                 $errors['err']='Invalid login. Check '.Format::htmlchars($vars['mail_protocol']).' settings';
                 $errors['mail']='<br>'.$fetcher->getLastError();
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index fb17d8a26ac719854a683ba778c287321ddefea9..fb8402169e83b39c258118329215d2459d7547a2 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -17,112 +17,161 @@
 require_once(INCLUDE_DIR.'class.mailparse.php');
 require_once(INCLUDE_DIR.'class.ticket.php');
 require_once(INCLUDE_DIR.'class.dept.php');
+require_once(INCLUDE_DIR.'class.email.php');
 require_once(INCLUDE_DIR.'class.filter.php');
 
 class MailFetcher {
-    var $hostname;
-    var $username;
-    var $password;
 
-    var $port;
-    var $protocol;
-    var $encryption;
+    var $ht;
 
     var $mbox;
+    var $srvstr;
 
-    var $charset= 'UTF-8';
+    var $charset = 'UTF-8';
+    var $encodings =array('UTF-8','WINDOWS-1251', 'ISO-8859-5', 'ISO-8859-1','KOI8-R');
     
-    function MailFetcher($username,$password,$hostname,$port,$protocol,$encryption='') {
+    function MailFetcher($email, $charset='UTF-8') {
 
-        if(!strcasecmp($protocol,'pop')) //force pop3
-            $protocol='pop3';
-
-        $this->hostname=$hostname;
-        $this->username=$username;
-        $this->password=$password;
-        $this->protocol=strtolower($protocol);
-        $this->port = $port;
-        $this->encryption = $encryption;
+        
+        if($email && is_numeric($email)) //email_id
+            $email=Email::lookup($email);
+
+        if(is_object($email))
+            $this->ht = $email->getMailAccountInfo();
+        elseif(is_array($email) && $email['host']) //hashtable of mail account info
+            $this->ht = $email; 
+        else
+            $this->ht = null;
+           
+        $this->charset = $charset;
+
+        if($this->ht) {
+            if(!strcasecmp($this->ht['protocol'],'pop')) //force pop3
+                $this->ht['protocol'] = 'pop3';
+            else
+                $this->ht['protocol'] = strtolower($this->ht['protocol']);
+
+            //Max fetch per poll
+            if(!$this->ht['max_fetch'] || !is_numeric($this->ht['max_fetch']))
+                $this->ht['max_fetch'] = 20;
+
+            //Mail server string
+            $this->srvstr=sprintf('{%s:%d/%s', $this->getHost(), $this->getPort(), $this->getProtocol());
+            if(!strcasecmp($this->getEncryption(), 'SSL'))
+                $this->srvstr.='/ssl';
+        
+            $this->srvstr.='/novalidate-cert}';
 
-        $this->serverstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL')){
-            $this->serverstr.='/ssl';
         }
-        $this->serverstr.='/novalidate-cert}INBOX'; //add other flags here as needed.
 
-        //echo $this->serverstr;
-        //Charset to convert the mail to.
-        $this->charset='UTF-8';
         //Set timeouts 
-        if(function_exists('imap_timeout'))
-            imap_timeout(1,20); //Open timeout.
+        if(function_exists('imap_timeout')) imap_timeout(1,20);
+
+    }
+
+    function getEmailId() {
+        return $this->ht['email_id'];
+    }
+
+    function getHost() {
+        return $this->ht['host'];
+    }
+
+    function getPort() {
+        return $this->ht['port'];
+    }
+
+    function getProtocol() {
+        return $this->ht['protocol'];
+    }
+
+    function getEncryption() {
+        return $this->ht['encryption'];
+    }
+
+    function getUsername() {
+        return $this->ht['username'];
     }
     
+    function getPassword() {
+        return $this->ht['password'];
+    }
+
+    /* osTicket Settings */
+
+    function canDeleteEmails() {
+        return ($this->ht['delete_mail']);
+    }
+
+    function getMaxFetch() {
+        return $this->ht['max_fetch'];
+    }
+
+    function getArchiveFolder() {
+        return $this->ht['archive_folder'];
+    }
+
+    /* Core */
+    
     function connect() {
-        return $this->open()?true:false;
+        return ($this->mbox && $this->ping())?$this->mbox:$this->open();
     }
 
-    function open() {
-       
-        //echo $this->serverstr;
-        if($this->mbox && imap_ping($this->mbox))
-            return $this->mbox;
-            
-        $this->mbox =@imap_open($this->serverstr,$this->username,$this->password);
-        
+    function ping() {
+        return ($this->mbox && imap_ping($this->mbox));
+    }
+
+    /* Default folder is inbox - TODO: provide user an option to fetch from diff folder/label */
+    function open($box='INBOX') {
+      
+        if($this->mbox)
+           $this->close();
+
+        $this->mbox = imap_open($this->srvstr.$box, $this->getUsername(), $this->getPassword());
+
         return $this->mbox;
     }
 
-    function close() {
-        imap_close($this->mbox,CL_EXPUNGE);
+    function close($flag=CL_EXPUNGE) {
+        imap_close($this->mbox, $flag);
     }
 
-    function mailcount(){
+    function mailcount() {
         return count(imap_headers($this->mbox));
     }
 
     //Get mail boxes.
-    function getMailboxes(){
+    function getMailboxes() {
 
+        if(!($folders=imap_list($this->mbox, $this->srvstr, "*")) || !is_array($folders))
+            return null;
 
-        $mstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL'))
-            $mstr.='/ssl';
-        $mstr.='/novalidate-cert}';
-        $list=array();
-        if(($folders=imap_listmailbox($this->mbox,$mstr,'*')) && is_array($folders)){
-            foreach($folders as $k=>$folder){
-                $list[]= str_replace($mstr, "", imap_utf7_decode(trim($folder)));
-            }
-        }
+        $list = array();
+        foreach($folders as $folder)
+            $list[]= str_replace($this->srvstr, '', imap_utf7_decode(trim($folder)));
 
         return $list;
     }
 
     //Create a folder.
-    function createMailbox($folder){
+    function createMailbox($folder) {
 
         if(!$folder) return false;
-
-        $mstr=sprintf('{%s:%d/%s',$this->hostname,$this->port,strtolower($this->protocol));
-        if(!strcasecmp($this->encryption,'SSL'))
-            $mstr.='/ssl';
-        $mstr.='/novalidate-cert}'.$folder;
             
-        return imap_createmailbox($this->mbox,imap_utf7_encode($mstr));
+        return imap_createmailbox($this->mbox, imap_utf7_encode($this->srvstr.trim($folder)));
     }
 
-    /* check if a folder exits - create on if requested */
-    function checkMailbox($folder,$create=false){
+    /* check if a folder exists - create one if requested */
+    function checkMailbox($folder, $create=false) {
 
-        if(($mailboxes=$this->getMailboxes()) && in_array($folder,$mailboxes))
+        if(($mailboxes=$this->getMailboxes()) && in_array(trim($folder), $mailboxes))
             return true;
 
         return ($create && $this->createMailbox($folder));
     }
 
 
-    function decode($encoding,$text) {
+    function decode($encoding, $text) {
 
         switch($encoding) {
             case 1:
@@ -145,14 +194,13 @@ class MailFetcher {
     }
 
     //Convert text to desired encoding..defaults to utf8
-    function mime_encode($text,$charset=null,$enc='utf-8') { //Thank in part to afterburner  
-                
-        $encodings=array('UTF-8','WINDOWS-1251', 'ISO-8859-5', 'ISO-8859-1','KOI8-R');
-        if(function_exists("iconv") and $text) {
+    function mime_encode($text, $charset=null, $enc='utf-8') { //Thank in part to afterburner  
+        
+        if(function_exists('iconv') and $text) {
             if($charset)
-                return iconv($charset,$enc.'//IGNORE',$text);
-            elseif(function_exists("mb_detect_encoding"))
-                return iconv(mb_detect_encoding($text,$encodings),$enc,$text);
+                return iconv($charset, $enc.'//IGNORE', $text);
+            elseif(function_exists('mb_detect_encoding'))
+                return iconv(mb_detect_encoding($text, $this->encodings), $enc, $text);
         }
 
         return utf8_encode($text);
@@ -161,15 +209,15 @@ class MailFetcher {
     //Generic decoder - mirrors imap_utf8
     function mime_decode($text) {
         
-        $a = imap_mime_header_decode($text);
         $str = '';
-        foreach ($a as $k => $part)
+        $parts = imap_mime_header_decode($text);
+        foreach ($parts as $part)
             $str.= $part->text;
         
         return $str?$str:imap_utf8($text);
     }
 
-    function getLastError(){
+    function getLastError() {
         return imap_last_error();
     }
 
@@ -183,67 +231,128 @@ class MailFetcher {
 
     function getHeaderInfo($mid) {
         
-        $headerinfo=imap_headerinfo($this->mbox,$mid);
-        $sender=$headerinfo->from[0];
+        if(!($headerinfo=imap_headerinfo($this->mbox, $mid)) || !$headerinfo->from)
+            return null;
 
-        //Parse what we need...
-        $header=array(
-                      'from'   =>array('name'  =>@$sender->personal,'email' =>strtolower($sender->mailbox).'@'.$sender->host),
+        $sender=$headerinfo->from[0];
+        //Just what we need...
+        $header=array('name'  =>@$sender->personal,
+                      'email' =>(strtolower($sender->mailbox).'@'.$sender->host),
                       'subject'=>@$headerinfo->subject,
-                      'mid'    =>$headerinfo->message_id);
+                      'mid'    =>$headerinfo->message_id
+                      );
+
         return $header;
     }
 
+    function getAttachment($part) {
+
+        if(!$part) return null;
+
+        if($part->ifdisposition && in_array(strtolower($part->disposition), array('attachment', 'inline')))
+            return $part->dparameters[0]->value;
+
+        if($part->ifparameters && $part->type == 5)
+            return $part->parameters[0]->value;
+
+
+        return null;
+    }
+
     //search for specific mime type parts....encoding is the desired encoding.
-    function getPart($mid,$mimeType,$encoding=false,$struct=null,$partNumber=false){
+    function getPart($mid, $mimeType, $encoding=false, $struct=null, $partNumber=false) {
           
         if(!$struct && $mid)
             $struct=@imap_fetchstructure($this->mbox, $mid);
+
         //Match the mime type.
-        if($struct && !$struct->ifdparameters && strcasecmp($mimeType,$this->getMimeType($struct))==0){
+        if($struct && !$struct->ifdparameters && strcasecmp($mimeType, $this->getMimeType($struct))==0) {
             $partNumber=$partNumber?$partNumber:1;
-            if(($text=imap_fetchbody($this->mbox, $mid, $partNumber))){
+            if(($text=imap_fetchbody($this->mbox, $mid, $partNumber))) {
                 if($struct->encoding==3 or $struct->encoding==4) //base64 and qp decode.
-                    $text=$this->decode($struct->encoding,$text);
+                    $text=$this->decode($struct->encoding, $text);
 
                 $charset=null;
                 if($encoding) { //Convert text to desired mime encoding...
-                    if($struct->ifparameters){
+                    if($struct->ifparameters) {
                         if(!strcasecmp($struct->parameters[0]->attribute,'CHARSET') && strcasecmp($struct->parameters[0]->value,'US-ASCII'))
                             $charset=trim($struct->parameters[0]->value);
                     }
-                    $text=$this->mime_encode($text,$charset,$encoding);
+                    $text=$this->mime_encode($text, $charset, $encoding);
                 }
                 return $text;
             }
         }
+
         //Do recursive search
         $text='';
-        if($struct && $struct->parts){
+        if($struct && $struct->parts) {
             while(list($i, $substruct) = each($struct->parts)) {
                 if($partNumber) 
                     $prefix = $partNumber . '.';
-                if(($result=$this->getPart($mid,$mimeType,$encoding,$substruct,$prefix.($i+1))))
+                if(($result=$this->getPart($mid, $mimeType, $encoding, $substruct, $prefix.($i+1))))
                     $text.=$result;
             }
         }
+
         return $text;
     }
 
-    function getHeader($mid){
+    /*
+     getAttachments
+
+     search and return a hashtable of attachments....
+     NOTE: We're not actually fetching the body of the attachment  - we'll do it on demand to save some memory.
+
+     */
+    function getAttachments($part, $index=0) {
+
+        if($part && !$part->parts) {
+            //Check if the part is an attachment.
+            $filename = '';
+            if($part->ifdisposition && in_array(strtolower($part->disposition), array('attachment', 'inline')))
+                $filename = $part->dparameters[0]->value;
+            elseif($part->ifparameters && $part->type == 5) //inline image without disposition.
+                $filename = $part->parameters[0]->value;
+
+            if($filename) {
+                return array(
+                        array(
+                            'name'  => $filename,
+                            'mime'  => $this->getMimeType($part),
+                            'encoding' => $part->encoding,
+                            'index' => ($index?$index:1)
+                            )
+                        );
+            }
+        }
+
+        //Recursive attachment search!
+        $attachments = array();
+        if($part && $part->parts) {
+            foreach($part->parts as $k=>$struct) {
+                if($index) $prefix = $index.'.';
+                $attachments = array_merge($attachments, $this->getAttachments($struct, $prefix.($k+1)));
+            }
+        }
+
+        return $attachments;
+    }
+
+    function getHeader($mid) {
         return imap_fetchheader($this->mbox, $mid,FT_PREFETCHTEXT);
     }
 
     
-    function getPriority($mid){
+    function getPriority($mid) {
         return Mail_Parse::parsePriority($this->getHeader($mid));
     }
 
     function getBody($mid) {
         
         $body ='';
-        if(!($body = $this->getPart($mid,'TEXT/PLAIN',$this->charset))) {
-            if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) {
+        if(!($body = $this->getPart($mid,'TEXT/PLAIN', $this->charset))) {
+            if(($body = $this->getPart($mid,'TEXT/HTML', $this->charset))) {
                 //Convert tags of interest before we striptags
                 $body=str_replace("</DIV><DIV>", "\n", $body);
                 $body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
@@ -251,171 +360,201 @@ class MailFetcher {
                 $body=Format::striptags($body); //Strip tags??
             }
         }
+
         return $body;
     }
 
-    function createTicket($mid,$emailid=0){
-        global $cfg, $ost;
+    //email to ticket 
+    function createTicket($mid) { 
+        global $ost;
 
-        $mailinfo=$this->getHeaderInfo($mid);
+        if(!($mailinfo = $this->getHeaderInfo($mid)))
+            return false;
 
-        //Make sure the email is NOT one of the undeleted emails.
-        if($mailinfo['mid'] && ($id=Ticket::getIdByMessageId(trim($mailinfo['mid']),$mailinfo['from']['email']))){
-            //TODO: Move emails to a fetched folder when delete is false?? 
-            return true;
-        }
+        //Make sure the email is NOT already fetched... (undeleted emails)
+        if($mailinfo['mid'] && ($id=Ticket::getIdByMessageId(trim($mailinfo['mid']), $mailinfo['email'])))
+            return true; //Reporting success so the email can be moved or deleted.
 
 	    //Is the email address banned?
-        if($mailinfo['from']['email'] && EmailFilter::isBanned($mailinfo['from']['email'])) {
+        if($mailinfo['email'] && EmailFilter::isBanned($mailinfo['email'])) {
 	        //We need to let admin know...
-            $ost->logWarning('Ticket denied', 'Banned email - '.$mailinfo['from']['email']);
-	        return true;
+            $ost->logWarning('Ticket denied', 'Banned email - '.$mailinfo['email']);
+	        return true; //Report success (moved or delete)
         }
-	
 
-        $var['name']=$this->mime_decode($mailinfo['from']['name']);
-        $var['email']=$mailinfo['from']['email'];
+        $emailId = $this->getEmailId();
+
+        $var['name']=$this->mime_decode($mailinfo['name']);
+        $var['email']=$mailinfo['email'];
         $var['subject']=$mailinfo['subject']?$this->mime_decode($mailinfo['subject']):'[No Subject]';
         $var['message']=Format::stripEmptyLines($this->getBody($mid));
         $var['header']=$this->getHeader($mid);
-        $var['emailId']=$emailid?$emailid:$cfg->getDefaultEmailId(); //ok to default?
+        $var['emailId']=$emailId?$emailId:$ost->getConfig()->getDefaultEmailId(); //ok to default?
         $var['name']=$var['name']?$var['name']:$var['email']; //No name? use email
         $var['mid']=$mailinfo['mid'];
 
-        if($cfg->useEmailPriority())
+        if(!$var['message']) //An email with just attachments can have empty body.
+            $var['message'] = '(EMPTY)';
+
+        if($ost->getConfig()->useEmailPriority())
             $var['priorityId']=$this->getPriority($mid);
        
         $ticket=null;
         $newticket=true;
         //Check the subject line for possible ID.
-        if(preg_match ("[[#][0-9]{1,10}]",$var['subject'],$regs)) {
-            $extid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
-            $ticket= new Ticket(Ticket::getIdByExtId($extid));
+        if($var['subject'] && preg_match ("[[#][0-9]{1,10}]", $var['subject'], $regs)) {
+            $tid=trim(preg_replace("/[^0-9]/", "", $regs[0]));
             //Allow mismatched emails?? For now NO.
-            if(!$ticket || strcasecmp($ticket->getEmail(),$var['email']))
+            if(!($ticket=Ticket::lookupByExtId($tid)) || strcasecmp($ticket->getEmail(), $var['email']))
                 $ticket=null;
         }
         
         $errors=array();
-        if(!$ticket) {
-            # Apply email filters for the new ticket
-            $ef = new EmailFilter($var); $ef->apply($var);
-            if(!($ticket=Ticket::create($var,$errors,'Email')) || $errors)
-                return null;
-            $msgid=$ticket->getLastMsgId();
-        }else{
-            $message=$var['message'];
-            //Strip quoted reply...TODO: figure out how mail clients do it without special tag..
-            if($cfg->stripQuotedReply() && ($tag=$cfg->getReplySeparator()) && strpos($var['message'],$tag))
-                list($message)=split($tag,$var['message']);
-            $msgid=$ticket->postMessage($message,'Email',$var['mid'],$var['header']);
+        if($ticket) {
+            if(!($msgid=$ticket->postMessage($var['message'], 'Email', $var['mid'], $var['header'])))
+                return false;
+
+        } elseif (($ticket=Ticket::create($var, $errors, 'Email'))) {
+            $msgid = $ticket->getLastMsgId();
+        } else {
+            //TODO: Log error..
+            return null;
         }
-        //Save attachments if any.
-        if($msgid && $cfg->allowEmailAttachments()){
-            if(($struct = imap_fetchstructure($this->mbox,$mid)) && $struct->parts) {
-                if($ticket->getLastMsgId()!=$msgid)
-                    $ticket->setLastMsgId($msgid);
-                $this->saveAttachments($ticket,$mid,$struct);
 
+        //Save attachments if any.
+        if($msgid 
+                && $ost->getConfig()->allowEmailAttachments()
+                && ($struct = imap_fetchstructure($this->mbox, $mid)) 
+                && $struct->parts 
+                && ($attachments=$this->getAttachments($struct))) {
+                
+            //We're just checking the type of file - not size or number of attachments...
+            // Restrictions are mainly due to PHP file uploads limitations
+            foreach($attachments as $a ) {
+                if($ost->isFileTypeAllowed($a['name'], $a['mime'])) {
+                    $file = array(
+                            'name'  => $a['name'],
+                            'type'  => $a['mime'],
+                            'data'  => $this->decode($a['encoding'], imap_fetchbody($this->mbox, $mid, $a['index']))
+                            );
+                    $ticket->saveAttachment($file, $msgid, 'M');
+                } else {
+                    //This should be really a comment on message - NoT an internal note.
+                    //TODO: support comments on Messages and Responses.
+                    $error = sprintf('Attachment %s [%s] rejected because of file type', $a['name'], $a['mime']);
+                    $ticket->postNote('Email Attachment Rejected', $error, false);
+                    $ost->logDebug('Email Attachment Rejected (Ticket #'.$ticket->getExtId().')', $error);
+                }
             }
-        } 
+        }
+
         return $ticket;
     }
 
-    function saveAttachments($ticket,$mid,$part,$index=0) {
-        global $ost;
 
-        if($part && $part->ifdparameters && ($filename=$part->dparameters[0]->value)){ //attachment
-            $index=$index?$index:1;
-            if($ticket 
-                    && $ost->isFileTypeAllowed($filename) 
-                    && $ost->getConfig()->getMaxFileSize()>=$part->bytes) {
-                //extract the attachments...and do the magic.
-                $data=$this->decode($part->encoding, imap_fetchbody($this->mbox,$mid,$index));
-                $ticket->saveAttachment(array('name'=>$filename, 'data'=>$data),$ticket->getLastMsgId(),'M');
-                return;
-            }
-            //TODO: Log failure??
-        }
+    function fetchEmails() {
 
-        //Recursive attachment search!
-        if($part && $part->parts) {
-            foreach($part->parts as $k=>$struct) {
-                if($index) $prefix = $index.'.';
-                $this->saveAttachments($ticket,$mid,$struct,$prefix.($k+1));
-            }
-        }
 
-    }
+        if(!$this->connect())
+            return false;
 
-    function fetchTickets($emailid,$max=20,$deletemsgs=false,$archivefolder){
+        $archiveFolder = $this->getArchiveFolder();
+        $delete = $this->canDeleteEmails();
+        $max = $this->getMaxFetch();
 
         $nummsgs=imap_num_msg($this->mbox);
         //echo "New Emails:  $nummsgs\n";
         $msgs=$errors=0;
-        for($i=$nummsgs; $i>0; $i--){ //process messages in reverse. Latest first. FILO.
-            if($this->createTicket($i,$emailid)){
-                imap_setflag_full($this->mbox, imap_uid($this->mbox,$i), "\\Seen", ST_UID); //IMAP only??
-                if((!$archivefolder || !imap_mail_move($this->mbox,$i,$archivefolder)) && $deletemsgs)
-                    imap_delete($this->mbox,$i);
+        for($i=$nummsgs; $i>0; $i--) { //process messages in reverse.
+            if($this->createTicket($i)) {
+
+                imap_setflag_full($this->mbox, imap_uid($this->mbox, $i), "\\Seen", ST_UID); //IMAP only??
+                if((!$archiveFolder || !imap_mail_move($this->mbox, $i, $archiveFolder)) && $delete)
+                    imap_delete($this->mbox, $i);
+
                 $msgs++;
                 $errors=0; //We are only interested in consecutive errors.
-            }else{
+            } else {
                 $errors++;
             }
-            if(($max && $msgs>=$max) || $errors>20)
+
+            if($max && ($msgs>=$max || $errors>($max*0.8)))
                 break;
         }
+
+        //Warn on excessive errors
+        if($errors>$msgs) {
+            $warn=sprintf('Excessive errors processing emails for %s/%s. Please manually check the inbox.',
+                    $this->getHost(), $this->getUsername());
+            $this->log($warn);
+        }
+
         @imap_expunge($this->mbox);
 
         return $msgs;
     }
 
-    function fetchMail(){
-        global $ost, $cfg;
+    function log($error) {
+        global $ost;
+        $ost->logWarning('Mail Fetcher', $error);
+    }
+
+    /*
+       MailFetcher::run()
+
+       Static function called to initiate email polling 
+     */
+    function run() {
+        global $ost;
       
-        if(!$cfg->canFetchMail())
+        if(!$ost->getConfig()->isEmailPollingEnabled())
             return;
 
         //We require imap ext to fetch emails via IMAP/POP3
+        //We check here just in case the extension gets disabled post email config...
         if(!function_exists('imap_open')) {
-            $msg='osTicket requires PHP IMAP extension enabled for IMAP/POP3 fetch to work!';
+            $msg='osTicket requires PHP IMAP extension enabled for IMAP/POP3 email fetch to work!';
             $ost->logWarning('Mail Fetch Error', $msg);
             return;
         }
 
-        $MAX_ERRORS=5; //Max errors before we start delayed fetch attempts - hardcoded for now.
+        //Hardcoded error control... 
+        $MAXERRORS = 5; //Max errors before we start delayed fetch attempts
+        $TIMEOUT = 10; //Timeout in minutes after max errors is reached.
 
-        $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_archivefolder,mail_errors,userid,userpass FROM '.EMAIL_TABLE.
-             ' WHERE mail_active=1 AND (mail_errors<='.$MAX_ERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(),mail_lasterror))>5*60) )'.
-             ' AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(),mail_lastfetch))>mail_fetchfreq*60) ';
-        //echo $sql;
-        if(!($accounts=db_query($sql)) || !db_num_rows($accounts))
-            return;
+        $sql=' SELECT email_id, mail_errors FROM '.EMAIL_TABLE
+            .' WHERE mail_active=1 '
+            .'  AND (mail_errors<='.$MAXERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(), mail_lasterror))>'.($TIMEOUT*60).') )'
+            .'  AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(), mail_lastfetch))>mail_fetchfreq*60)'
+            .' ORDER BY mail_lastfetch DESC'
+            .' LIMIT 10'; //Processing up to 10 emails at a time.
+
+       // echo $sql;
+        if(!($res=db_query($sql)) || !db_num_rows($res))
+            return;  /* Failed query (get's logged) or nothing to do... */
 
         //TODO: Lock the table here??
-        while($row=db_fetch_array($accounts)) {
-            $fetcher = new MailFetcher($row['userid'], Mcrypt::decrypt($row['userpass'],SECRET_SALT),
-                                       $row['mail_host'],$row['mail_port'],$row['mail_protocol'],$row['mail_encryption']);
-            if($fetcher->connect()){   
-                $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false,$row['mail_archivefolder']);
+
+        while(list($emailId, $errors)=db_fetch_row($res)) {
+            $fetcher = new MailFetcher($emailId);
+            if($fetcher->connect()) {
+                $fetcher->fetchEmails();
                 $fetcher->close();
-                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($row['email_id']));
-            }else{
-                $errors=$row['mail_errors']+1;
-                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($row['email_id']));
-                if($errors>=$MAX_ERRORS){
+                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($emailId));
+            } else {
+                db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=mail_errors+1, mail_lasterror=NOW() WHERE email_id='.db_input($emailId));
+                if(++$errors>=$MAXERRORS) {
                     //We've reached the MAX consecutive errors...will attempt logins at delayed intervals
-                    $msg="\nThe system is having trouble fetching emails from the following mail account: \n".
-                        "\nUser: ".$row['userid'].
-                        "\nHost: ".$row['mail_host'].
+                    $msg="\nosTicket is having trouble fetching emails from the following mail account: \n".
+                        "\nUser: ".$fetcher->getUsername().
+                        "\nHost: ".$fetcher->getHost().
                         "\nError: ".$fetcher->getLastError().
-                        "\n\n ".$errors.' consecutive errors. Maximum of '.$MAX_ERRORS. ' allowed'.
-                        "\n\n This could be connection issues related to the host. Next delayed login attempt in aprox. 10 minutes";
+                        "\n\n ".$errors.' consecutive errors. Maximum of '.$MAXERRORS. ' allowed'.
+                        "\n\n This could be connection issues related to the mail server. Next delayed login attempt in aprox. $TIMEOUT minutes";
                     $ost->alertAdmin('Mail Fetch Failure Alert', $msg, true);
                 }
             }
-        }
+        } //end while.
     }
 }
 ?>
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index f56006fa9c1e35c88d67165302a7797f43f562d7..8d162e52a6d9182b6cca5284ff061538b4124ff9 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -140,7 +140,7 @@ class Mail_Parse {
                 //Cleanup the html.
                 $body=str_replace("</DIV><DIV>", "\n", $body);                        
                 $body=str_replace(array("<br>", "<br />", "<BR>", "<BR />"), "\n", $body);
-                $body=Format::striptags($body);
+                $body=Format::striptags(Format::html($body));
             }
         }
         return $body;
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 104ff20b4517ef22d785b3f4f40ede84195134e9..da45d51935322d606f6e6b60b102c6c63ea363b8 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1296,7 +1296,16 @@ class Ticket{
         global $cfg;
        
         if(!$this->getId()) return 0;
-        
+
+
+            
+        //Strip quoted reply...on emailed replies
+        if(!strcasecmp($source, 'Email') 
+                && $cfg->stripQuotedReply() 
+                && ($tag=$cfg->getReplySeparator()) && strpos($msg, $tag))
+            list($msg)=split($tag, $msg);
+
+
         # XXX: Refuse auto-response messages? (via email) XXX: No - but kill our auto-responder.
 
         $sql='INSERT INTO '.TICKET_THREAD_TABLE.' SET created=NOW()'
@@ -1316,8 +1325,7 @@ class Ticket{
                 .' SET message_id='.db_input($msgid)
                 .', email_mid='.db_input($emsgid)
                 .', headers='.db_input($headers);
-
-            if (!db_query($sql)) return 0;
+            db_query($sql);
         }
 
         if($newticket) return $msgid; //Our work is done...
diff --git a/include/client/open.inc.php b/include/client/open.inc.php
index 42cf10c92d6eb3a45fdbf3775fc3cde7103d247b..2fd076100388888765970d1a561dc3c5235a8b90 100644
--- a/include/client/open.inc.php
+++ b/include/client/open.inc.php
@@ -122,7 +122,7 @@ $info=($_POST && $errors)?Format::htmlchars($_POST):$info;
     }
     ?>
     <?php
-    if($cfg && $cfg->enableCaptcha() && (!$thisclient || !$thisclient->isValid())) {
+    if($cfg && $cfg->isCaptchaEnabled() && (!$thisclient || !$thisclient->isValid())) {
         if($_POST && $errors && !$errors['captcha'])
             $errors['captcha']='Please re-enter the text again';
         ?>
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index e16b350bdbd3a58f64862da9de74b4c835e9dc23..5e2935e06a02157c4cc7f62e45a38eb4af87326d 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -77,7 +77,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
                 Login Password
             </td>
             <td>
-                <input type="text" size="35" name="passwd" value="<?php echo $info['passwd']; ?>">
+                <input type="password" size="35" name="passwd" value="<?php echo $info['passwd']; ?>">
                 &nbsp;<span class="error">&nbsp;<?php echo $errors['passwd']; ?>&nbsp;</span>
                 <br><em><?php echo $passwdtxt; ?></em>
             </td>
@@ -118,10 +118,10 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
 
         <tr><td>Encryption</td>
             <td>
-                 <label><input type="radio" name="mail_encryption"  value="NONE"
-                    <?php echo ($info['mail_encryption']!='SSL')?'checked="checked"':''; ?> />None</label>
-                 <label><input type="radio" name="mail_encryption"  value="SSL"
-                    <?php echo ($info['mail_encryption']=='SSL')?'checked="checked"':''; ?> />SSL</label>
+                <select name="mail_encryption">
+                    <option value='NONE'>None</option>
+                    <option value='SSL' <?php echo ($info['mail_encryption']=='SSL')?'selected="selected"':''; ?> >SSL</option>
+                </select>
                 <font class="error">&nbsp;<?php echo $errors['mail_encryption']; ?></font>
             </td>
         </tr>
diff --git a/open.php b/open.php
index 7bdc8fc8ffccfee37516c5ec60c0e1d16119df75..a7f064fb9ca58d26f4827b0abb8537df8ef4c3b2 100644
--- a/open.php
+++ b/open.php
@@ -22,7 +22,7 @@ if($_POST):
     if($thisclient) {
         $_POST['name']=$thisclient->getName();
         $_POST['email']=$thisclient->getEmail();
-    } elseif($cfg->enableCaptcha()) {
+    } elseif($cfg->isCaptchaEnabled()) {
         if(!$_POST['captcha'])
             $errors['captcha']='Enter text shown on the image';
         elseif(strcmp($_SESSION['captcha'],md5($_POST['captcha'])))
diff --git a/scp/autocron.php b/scp/autocron.php
index 366351c9defedffd2bccd478b1d3c8bd2e349ba4..08b65ba3481e65f99e6bb06567c3be46efb60631 100644
--- a/scp/autocron.php
+++ b/scp/autocron.php
@@ -19,10 +19,10 @@ ignore_user_abort(1);//Leave me a lone bro!
 @set_time_limit(0); //useless when safe_mode is on
 $data=sprintf ("%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%",
         71,73,70,56,57,97,1,0,1,0,128,255,0,192,192,192,0,0,0,33,249,4,1,0,0,0,0,44,0,0,0,0,1,0,1,0,0,2,2,68,1,0,59);
-$datasize=strlen($data);
+
 header('Content-type:  image/gif');
 header('Cache-Control: no-cache, must-revalidate');
-header("Content-Length: $datasize");
+header('Content-Length: '.strlen($data));
 header('Connection: Close');
 print $data;
 
@@ -32,10 +32,10 @@ ob_start(); //Keep the image output clean. Hide our dirt.
 $sec=time()-$_SESSION['lastcroncall'];
 if($sec>180): //user can call cron once every 3 minutes.
 require_once(INCLUDE_DIR.'class.cron.php');    
-Cron::TicketMonitor(); //Age tickets: We're going to age tickets ever regardless of cron settings. 
-if($cfg && $cfg->enableAutoCron()){ //ONLY fetch tickets if autocron is enabled!
+Cron::TicketMonitor(); //Age tickets: We're going to age tickets regardless of cron settings. 
+if($cfg && $cfg->isAutoCronEnabled()) { //ONLY fetch tickets if autocron is enabled!
     Cron::MailFetcher();  //Fetch mail.
-    $ost->logDebug('Autocron', 'Cron job executed ['.$thisstaff->getUserName().']');
+    $ost->logDebug('Auto Cron', 'Mail fetcher cron call ['.$thisstaff->getUserName().']');
 } 
 
 $_SESSION['lastcroncall']=time();