diff --git a/bootstrap.php b/bootstrap.php
index 4e2259cc3c86660bca8b49c888af6f73c6264a01..b8971116fecb896cebe915240ce4c047fd5e983e 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -208,6 +208,9 @@ class Bootstrap {
     }
 
     function i18n_prep() {
+        ini_set('default_charset', 'utf-8');
+        ini_set('output_encoding', 'utf-8');
+
         // MPDF requires mbstring functions
         if (!extension_loaded('mbstring')) {
             if (function_exists('iconv')) {
diff --git a/include/ajax.orgs.php b/include/ajax.orgs.php
index c582b578060b8ba09151db6739cc49c6431809ad..b6a4002feac751e5a2bbf1a3a6ac34f38ee2db45 100644
--- a/include/ajax.orgs.php
+++ b/include/ajax.orgs.php
@@ -227,11 +227,11 @@ class OrgsAjaxAPI extends AjaxController {
         $info['title'] = __('Add New Organization');
         $info['search'] = false;
 
-        return self::_lookupform($form, $info);
+        return $this->_lookupform($form, $info);
     }
 
     function lookup() {
-        return self::_lookupform();
+        return $this->_lookupform();
     }
 
     function selectOrg($id) {
@@ -257,11 +257,15 @@ class OrgsAjaxAPI extends AjaxController {
         return $ajax->createNote('O'.$id);
     }
 
-    static function _lookupform($form=null, $info=array()) {
+    function _lookupform($form=null, $info=array()) {
 
         if (!$info or !$info['title'])
             $info += array('title' => __('Organization Lookup'));
 
+        if ($_POST && ($org = Organization::lookup($_POST['orgid']))) {
+            Http::response(201, $org->to_json());
+        }
+
         ob_start();
         include(STAFFINC_DIR . 'templates/org-lookup.tmpl.php');
         $resp = ob_get_contents();
diff --git a/include/class.api.php b/include/class.api.php
index c998cf244a6ddc314dfaa983a99cc03cfa7d81ce..ce8b28ad04501ade75b4096703e39d22401ace1e 100644
--- a/include/class.api.php
+++ b/include/class.api.php
@@ -297,7 +297,12 @@ class ApiController {
             $msg.="\n*[".$_SERVER['HTTP_X_API_KEY']."]*\n";
         $ost->logWarning(__('API Error')." ($code)", $msg, false);
 
-        $this->response($code, $error); //Responder should exit...
+        if (PHP_SAPI == 'cli') {
+            fwrite(STDERR, "({$code}) $error\n");
+        }
+        else {
+            $this->response($code, $error); //Responder should exit...
+        }
         return false;
     }
 
diff --git a/include/class.config.php b/include/class.config.php
index b7eae5da0e851d57f8766f1dc3ceaf44451b68a2..a2cad713eb487ab4542f4186fb19cc4c5f308fe1 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -741,19 +741,20 @@ class OsticketConfig extends Config {
         return ($this->get('message_alert_acct_manager'));
     }
 
-    function alertONNewNote() {
+    //TODO: change note_alert to activity_alert
+    function alertONNewActivity() {
         return ($this->get('note_alert_active'));
     }
 
-    function alertLastRespondentONNewNote() {
+    function alertLastRespondentONNewActivity() {
         return ($this->get('note_alert_laststaff'));
     }
 
-    function alertAssignedONNewNote() {
+    function alertAssignedONNewActivity() {
         return ($this->get('note_alert_assigned'));
     }
 
-    function alertDeptManagerONNewNote() {
+    function alertDeptManagerONNewActivity() {
         return ($this->get('note_alert_dept_manager'));
     }
 
diff --git a/include/class.dept.php b/include/class.dept.php
index e038c09f58da44bf682c699ff66474eff11d6fbc..588a71c127f553c10010a3f6dbf9eda3d506163c 100644
--- a/include/class.dept.php
+++ b/include/class.dept.php
@@ -239,6 +239,16 @@ class Dept extends VerySimpleModel {
         return ($this->getManagerId() && $this->getManagerId()==$staff);
     }
 
+    function isMember($staff) {
+
+        if (is_object($staff))
+            $staff = $staff->getId();
+
+        // Members are indexed by ID
+        $members = $this->getMembers();
+
+        return ($members && isset($members[$staff]));
+    }
 
     function isPublic() {
          return $this->ispublic;
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 2efcbec3c2fca60c77f19d49c60a30c7557ee415..23829e8a471b3b63b72cb9c071ed763888e7c187 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -838,6 +838,9 @@ class DynamicFormEntry extends VerySimpleModel {
                 'null' => true,
                 'constraint' => array('form_id' => 'DynamicForm.id'),
             ),
+            'answers' => array(
+                'reverse' => 'DynamicFormEntryAnswer.entry'
+            ),
         ),
     );
 
diff --git a/include/class.email.php b/include/class.email.php
index 2943192ef5c6734698829e874275c7574e590ed7..2d05f47800a1462b83dd111a9cb6cc4794bc9b79 100644
--- a/include/class.email.php
+++ b/include/class.email.php
@@ -358,8 +358,12 @@ class Email {
 
             if(!isset($vars['postfetch']))
                 $errors['postfetch']=__('Indicate what to do with fetched emails');
-            elseif(!strcasecmp($vars['postfetch'],'archive') && !$vars['mail_archivefolder'] )
-                $errors['postfetch']=__('Valid folder required');
+            elseif(!strcasecmp($vars['postfetch'],'archive')) {
+                if ($vars['mail_protocol'] == 'POP')
+                    $errors['postfetch'] =  __('POP mail servers do not support folders');
+                elseif (!$vars['mail_archivefolder'])
+                    $errors['postfetch'] = __('Valid folder required');
+            }
         }
 
         if($vars['smtp_active']) {
diff --git a/include/class.mailer.php b/include/class.mailer.php
index cc7341b7747c2c76704bbd5b983b795a035b30e5..ff1a463c3cfc9a444fdcb75020efbe4e2234b9ca 100644
--- a/include/class.mailer.php
+++ b/include/class.mailer.php
@@ -376,25 +376,13 @@ class Mailer {
                 $reply_tag = $cfg->getReplySeparator() . '<br/><br/>';
         }
 
-        // Use Mail_mime default initially
-        $eol = null;
+        // Use general failsafe default initially
+        $eol = "\n";
 
         // MAIL_EOL setting can be defined in `ost-config.php`
         if (defined('MAIL_EOL') && is_string(MAIL_EOL)) {
             $eol = MAIL_EOL;
         }
-        // The Suhosin patch will muck up the line endings in some
-        // cases
-        //
-        // References:
-        // https://github.com/osTicket/osTicket-1.8/issues/202
-        // http://pear.php.net/bugs/bug.php?id=12032
-        // http://us2.php.net/manual/en/function.mail.php#97680
-        elseif ((extension_loaded('suhosin') || defined("SUHOSIN_PATCH"))
-            && !$this->getSMTPInfo()
-        ) {
-            $eol = "\n";
-        }
         $mime = new Mail_mime($eol);
 
         // If the message is not explicitly declared to be a text message,
diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php
index db9026228caa6f024c57c43f906fce5cae683eab..3b0c7cecddcaa349ddd589415df13c50aa8908b0 100644
--- a/include/class.mailfetch.php
+++ b/include/class.mailfetch.php
@@ -347,10 +347,15 @@ class MailFetcher {
 
         // Ensure we have a message-id. If unable to read it out of the
         // email, use the hash of the entire email headers
-        if (!$header['mid'] && $header['header'])
-            if (!($header['mid'] = Mail_Parse::findHeaderEntry($header['header'],
-                    'message-id')))
+        if (!$header['mid'] && $header['header']) {
+            $header['mid'] = Mail_Parse::findHeaderEntry($header['header'],
+                    'message-id');
+
+            if (is_array($header['mid']))
+                $header['mid'] = array_pop(array_filter($header['mid']));
+            if (!$header['mid'])
                 $header['mid'] = '<' . md5($header['header']) . '@local>';
+        }
 
         return $header;
     }
@@ -544,11 +549,21 @@ class MailFetcher {
     }
 
     function getPriority($mid) {
-        if ($this->tnef && isset($this->tnef->Importance))
-            // PidTagImportance is 0, 1, or 2
+        if ($this->tnef && isset($this->tnef->Importance)) {
+            // PidTagImportance is 0, 1, or 2, 2 is high
             // http://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx
-            return $this->tnef->Importance + 1;
-        return Mail_Parse::parsePriority($this->getHeader($mid));
+            $urgency = 4 - $this->tnef->Importance;
+        }
+        elseif ($priority = Mail_Parse::parsePriority($this->getHeader($mid))) {
+            $urgency = $priority + 1;
+        }
+        if ($urgency) {
+            $sql = 'SELECT `priority_id` FROM '.PRIORITY_TABLE
+                .' WHERE `priority_urgency`='.db_input($urgency)
+                .' LIMIT 1';
+            $id = db_result(db_query($sql));
+            return $id;
+        }
     }
 
     function getBody($mid) {
@@ -643,7 +658,7 @@ class MailFetcher {
                 $vars['in-reply-to'] = @$headers['in-reply-to'] ?: null;
             }
             // Fetch deliver status report
-            $vars['message'] = $this->getDeliveryStatusMessage($mid);
+            $data['message'] = $this->getDeliveryStatusMessage($mid) ?: $this->getBody($mid);
             $vars['thread-type'] = 'N';
             $vars['flags']['bounce'] = true;
         }
diff --git a/include/class.mailparse.php b/include/class.mailparse.php
index 5c9cdf4d636fd04b4cdb4d894ca06b036eae8b37..855afe9a0ae16bad3c94b03c7c3b017097a1850b 100644
--- a/include/class.mailparse.php
+++ b/include/class.mailparse.php
@@ -242,8 +242,11 @@ class Mail_Parse {
     }
 
     function getMessageId(){
-        if (!($mid = $this->struct->headers['message-id']))
+        if (($mid = $this->struct->headers['message-id']) && is_array($mid))
+            $mid = array_pop(array_filter($mid));
+        if (!$mid)
             $mid = sprintf('<%s@local>', md5($this->getHeader()));
+
         return $mid;
     }
 
@@ -275,10 +278,9 @@ class Mail_Parse {
             && isset($this->struct->ctype_parameters['report-type'])
             && $this->struct->ctype_parameters['report-type'] == 'delivery-status'
         ) {
-            return sprintf('<pre>%s</pre>',
-                Format::htmlchars(
-                    $this->getPart($this->struct, 'text/plain', 1)
-                ));
+            return new TextThreadBody(
+                $this->getPart($this->struct, 'text/plain', 1)
+            );
         }
         return false;
     }
@@ -462,43 +464,59 @@ class Mail_Parse {
         return $files;
     }
 
-    function getPriority(){
-        if ($this->tnef && isset($this->tnef->Importance))
-            // PidTagImportance is 0, 1, or 2
+    function getPriority() {
+        if ($this->tnef && isset($this->tnef->Importance)) {
+            // PidTagImportance is 0, 1, or 2, 2 is high
             // http://msdn.microsoft.com/en-us/library/ee237166(v=exchg.80).aspx
-            return $this->tnef->Importance + 1;
-
-        return Mail_Parse::parsePriority($this->getHeader());
+            $urgency = 4 - $this->tnef->Importance;
+        }
+        elseif ($priority = Mail_Parse::parsePriority($this->getHeader())) {
+            $urgency = $priority + 1;
+        }
+        if ($urgency) {
+            $sql = 'SELECT `priority_id` FROM '.PRIORITY_TABLE
+                .' WHERE `priority_urgency`='.db_input($urgency)
+                .' LIMIT 1';
+            $id = db_result(db_query($sql));
+            return $id;
+        }
     }
 
+    /**
+     * Return a normalized priority urgency from the email headers received.
+     *
+     * Returns:
+     * (int) priority urgency, {1,2,3}, where 1 is high. Returns 0 if no
+     * priority could be inferred from the headers.
+     *
+     * References:
+     * https://github.com/osTicket/osTicket-1.8/issues/1674
+     * http://stackoverflow.com/questions/15568583/php-mail-priority-types
+     */
     static function parsePriority($header=null){
 
-    	if (! $header)
-    		return 0;
-    	// Test for normal "X-Priority: INT" style header & stringy version.
-    	// Allows for Importance possibility.
-    	$matching_char = '';
-    	if (preg_match ( '/priority: (\d|\w)/i', $header, $matching_char )
-    			|| preg_match ( '/importance: (\d|\w)/i', $header, $matching_char )) {
-    		switch ($matching_char[1]) {
-    			case 'h' :
-    			case 'H' :// high
-    			case 'u':
-    			case 'U': //Urgent
-    			case 6 :
-    			case 5 :
-    				return 1;
-    			case 'n' : // normal
-    			case 'N' :
-    			case 4 :
-    			case 3 :
-    				return 2;
-    			case 'l' : // low
-    			case 'L' :
-    			case 2 :
-    			case 1 :
-    				return 3;
-    		}
+        if (!$header)
+            return 0;
+
+        // Test for normal "X-Priority: INT" style header & stringy version.
+        // Allows for Importance possibility.
+        $matching_char = '';
+        if (preg_match('/(?:priority|importance): (\w)/i', $header, $matching_char)) {
+            switch (strtoupper($matching_char[1])) {
+            case 'H' :// high
+            case 'U': //Urgent
+            case '2' :
+            case '1' :
+                return 1;
+            case 'N' :
+            case '4' :
+            case '3' :
+                return 2;
+            case 'L' :
+            case '6' :
+            case '5' :
+                return 3;
+            }
     	}
     	return 0;
     }
@@ -657,7 +675,7 @@ class EmailDataParser {
                 $data['in-reply-to'] = @$headers['in-reply-to'] ?: null;
             }
             // Fetch deliver status report
-            $data['message'] = $parser->getDeliveryStatusMessage();
+            $data['message'] = $parser->getDeliveryStatusMessage() ?: $parser->getBody();
             $data['thread-type'] = 'N';
             $data['flags']['bounce'] = true;
         }
diff --git a/include/class.thread.php b/include/class.thread.php
index b537436d58a2c6bc6fc727f7321f1996e3cd5861..03fe49fb523b9ddb5405f07dd4dbd0db3bde3c74 100644
--- a/include/class.thread.php
+++ b/include/class.thread.php
@@ -380,7 +380,7 @@ class ThreadEntry extends VerySimpleModel {
     static $meta = array(
         'table' => THREAD_ENTRY_TABLE,
         'pk' => array('id'),
-        'select_related' => array('staff', 'user', 'email_info'),
+        'select_related' => array('staff', 'user'),
         'joins' => array(
             'thread' => array(
                 'constraint' => array('thread_id' => 'Thread.id'),
@@ -478,6 +478,10 @@ class ThreadEntry extends VerySimpleModel {
         return $this->save();
     }
 
+    function getMessage() {
+        return $this->getBody();
+    }
+
     function getCreateDate() {
         return $this->created;
     }
@@ -787,7 +791,8 @@ class ThreadEntry extends VerySimpleModel {
 
     function saveEmailInfo($vars) {
 
-        if(!$vars || !$vars['mid'])
+        // Don't save empty message ID
+        if (!$vars || !$vars['mid'])
             return 0;
 
         $this->ht['email_mid'] = $vars['mid'];
@@ -1019,7 +1024,7 @@ class ThreadEntry extends VerySimpleModel {
             return false;
 
         $check = sprintf('%s@%s',
-            substr(md5($to . $ticket->getNumber() . $ticket->getId()), -10),
+            substr(md5($from . $ticket->getNumber() . $ticket->getId()), -10),
             substr($domain, -10)
         );
 
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 12327054ca0f8c442c19a09baeb27c50a213f934..30b7ed09bc8eac8c1613fc42e230eb34c631aace 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -1454,9 +1454,15 @@ implements RestrictedAccess, Threadable {
         return true;
     }
 
-    function onResponse() {
+    function onResponse($response, $options=array()) {
         db_query('UPDATE '.TICKET_TABLE.' SET isanswered=1, lastresponse=NOW(), updated=NOW() WHERE ticket_id='.db_input($this->getId()));
         $this->reload();
+        $vars = array_merge($options,
+                array(
+                    'activity' => _S('New Response'),
+                    'threadentry' => $response));
+
+        $this->onActivity($vars);
     }
 
     /*
@@ -1594,6 +1600,86 @@ implements RestrictedAccess, Threadable {
         }
     }
 
+    function onActivity($vars, $alert=true) {
+        global $cfg, $thisstaff;
+
+        //TODO: do some shit
+
+        if (!$alert // Check if alert is enabled
+                || !$cfg->alertONNewActivity()
+                || !($dept=$this->getDept())
+                || !($email=$cfg->getAlertEmail())
+                || !($tpl = $dept->getTemplate())
+                || !($msg=$tpl->getNoteAlertMsgTemplate()))
+            return;
+
+        // Alert recipients
+        $recipients=array();
+
+        //Last respondent.
+        if ($cfg->alertLastRespondentONNewActivity())
+            $recipients[] = $this->getLastRespondent();
+
+        // Assigned staff / team
+        if ($cfg->alertAssignedONNewActivity()) {
+
+            if (isset($vars['assignee'])
+                    && $vars['assignee'] instanceof Staff)
+                 $recipients[] = $vars['assignee'];
+            elseif ($this->isOpen() && ($assignee = $this->getStaff()))
+                $recipients[] = $assignee;
+
+            if ($team = $this->getTeam())
+                $recipients = array_merge($recipients, $team->getMembers());
+        }
+
+        // Dept manager
+        if ($cfg->alertDeptManagerONNewActivity() && $dept && $dept->getManagerId())
+            $recipients[] = $dept->getManager();
+
+        $options = array();
+        $staffId = $thisstaff ? $thisstaff->getId() : 0;
+        if ($vars['threadentry'] && $vars['threadentry'] instanceof ThreadEntry) {
+            $options = array(
+                'inreplyto' => $vars['threadentry']->getEmailMessageId(),
+                'references' => $vars['threadentry']->getEmailReferences(),
+                'thread' => $vars['threadentry']);
+
+            // Activity details
+            if (!$vars['comments'])
+                $vars['comments'] = $vars['threadentry'];
+
+            // Staff doing the activity
+            $staffId = $vars['threadentry']->getStaffId() ?: $staffId;
+        }
+
+        $msg = $this->replaceVars($msg->asArray(),
+                array(
+                    'note' => $vars['threadentry'], // For compatibility
+                    'activity' => $vars['activity'],
+                    'comments' => $vars['comments']));
+
+        $isClosed = $this->isClosed();
+        $sentlist=array();
+        foreach ($recipients as $k=>$staff) {
+            if (!is_object($staff)
+                    // Don't bother vacationing staff.
+                    || !$staff->isAvailable()
+                    // No need to alert the poster!
+                    || $staffId == $staff->getId()
+                    // No duplicates.
+                    || isset($sentlist[$staff->getEmail()])
+                    // Make sure staff has access to ticket
+                    || ($isClosed && !$this->checkStaffPerm($staff))
+                    )
+                continue;
+            $alert = $this->replaceVars($msg, array('recipient' => $staff));
+            $email->sendAlert($staff, $alert['subj'], $alert['body'], null, $options);
+            $sentlist[$staff->getEmail()] = 1;
+        }
+
+    }
+
     function onAssign($assignee, $comments, $alert=true) {
         global $cfg, $thisstaff;
 
@@ -1843,11 +1929,21 @@ implements RestrictedAccess, Threadable {
         if($this->isClosed()) $this->reopen();
 
         $this->reload();
+        $dept = $this->getDept();
 
         // Set SLA of the new department
         if(!$this->getSLAId() || $this->getSLA()->isTransient())
             $this->selectSLAId();
 
+        // Make sure the new department allows assignment to the
+        // currently assigned agent (if any)
+        if ($this->isAssigned()
+                && ($staff=$this->getStaff())
+                && $dept->assignMembersOnly()
+                && !$dept->isMember($staff)) {
+            $this->setStaffId(0);
+        }
+
         /*** log the transfer comments as internal note - with alerts disabled - ***/
         $title=sprintf(_S('Ticket transferred from %1$s to %2$s'),
             $currentDept, $this->getDeptName());
@@ -1857,7 +1953,7 @@ implements RestrictedAccess, Threadable {
         $this->logEvent('transferred');
 
         //Send out alerts if enabled AND requested
-        if(!$alert || !$cfg->alertONTransfer() || !($dept=$this->getDept()))
+        if (!$alert || !$cfg->alertONTransfer())
             return true; //no alerts!!
 
          if (($email = $dept->getAlertEmail())
@@ -1900,6 +1996,21 @@ implements RestrictedAccess, Threadable {
          return true;
     }
 
+    function claim() {
+        global $thisstaff;
+
+        if (!$thisstaff || !$this->isOpen() || $this->isAssigned())
+            return false;
+
+        $dept = $this->getDept();
+        if ($dept->assignMembersOnly() && !$dept->isMember($thisstaff))
+            return false;
+
+        $comments = sprintf(_S('Ticket claimed by %s'), $thisstaff->getName());
+
+        return $this->assignToStaff($thisstaff->getId(), $comments, false);
+    }
+
     function assignToStaff($staff, $note, $alert=true) {
 
         if(!is_object($staff) && !($staff=Staff::lookup($staff)))
@@ -2214,20 +2325,23 @@ implements RestrictedAccess, Threadable {
         if(!($response = $this->getThread()->addResponse($vars, $errors)))
             return null;
 
+        $assignee = $this->getStaff();
         // Set status - if checked.
         if ($vars['reply_status_id']
                 && $vars['reply_status_id'] != $this->getStatusId())
             $this->setStatus($vars['reply_status_id']);
 
+        // Claim on response bypasses the department assignment restrictions
         if($thisstaff && $this->isOpen() && !$this->getStaffId()
                 && $cfg->autoClaimTickets())
             $this->setStaffId($thisstaff->getId()); //direct assignment;
 
         $this->lastrespondent = null;
-        $this->onResponse(); //do house cleaning..
+
+        $this->onResponse($response, array('assignee' => $assignee)); //do house cleaning..
 
         /* email the user??  - if disabled - then bail out */
-        if(!$alert) return $response;
+        if (!$alert) return $response;
 
         $dept = $this->getDept();
 
@@ -2356,62 +2470,12 @@ implements RestrictedAccess, Threadable {
                 $this->reload();
         }
 
-        // If alerts are not enabled then return a success.
-        if(!$alert || !$cfg->alertONNewNote() || !($dept=$this->getDept()))
-            return $note;
-
-        if (($email = $dept->getAlertEmail())
-                && ($tpl = $dept->getTemplate())
-                && ($msg=$tpl->getNoteAlertMsgTemplate())) {
-
-            $msg = $this->replaceVars($msg->asArray(),
-                array('note' => $note));
-
-            // Alert recipients
-            $recipients=array();
-
-            //Last respondent.
-            if ($cfg->alertLastRespondentONNewNote())
-                $recipients[] = $this->getLastRespondent();
-
-            // Assigned staff / team
-            if ($cfg->alertAssignedONNewNote()) {
-
-                if ($assignee && $assignee instanceof Staff)
-                    $recipients[] = $assignee;
-
-                if ($team = $this->getTeam())
-                    $recipients = array_merge($recipients, $team->getMembers());
-            }
-
-            // Dept manager
-            if ($cfg->alertDeptManagerONNewNote() && $dept && $dept->getManagerId())
-                $recipients[] = $dept->getManager();
-
-            $options = array(
-                'inreplyto'=>$note->getEmailMessageId(),
-                'references'=>$note->getEmailReferences(),
-                'thread'=>$note);
-
-            $isClosed = $this->isClosed();
-            $sentlist=array();
-            foreach( $recipients as $k=>$staff) {
-                if(!is_object($staff)
-                        // Don't bother vacationing staff.
-                        || !$staff->isAvailable()
-                        // No duplicates.
-                        || isset($sentlist[$staff->getEmail()])
-                        // No need to alert the poster!
-                        || $note->getStaffId() == $staff->getId()
-                        // Make sure staff has access to ticket
-                        || ($isClosed && !$this->checkStaffPerm($staff))
-                        )
-                    continue;
-                $alert = $this->replaceVars($msg, array('recipient' => $staff));
-                $email->sendAlert($staff, $alert['subj'], $alert['body'], null, $options);
-                $sentlist[$staff->getEmail()] = 1;
-            }
-        }
+        $activity = $vars['activity'] ?: _S('New Internal Note');
+        $this->onActivity(array(
+            'activity' => $activity,
+            'threadentry' => $note,
+            'assignee' => $assignee
+        ), $alert);
 
         return $note;
     }
diff --git a/include/class.user.php b/include/class.user.php
index 194b659a34777039b1484928c745f415310ce1bb..08e2ce3b4503a80f657d66ecaac54ae5b7d14e53 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -64,6 +64,13 @@ class UserModel extends VerySimpleModel {
                 'constraint' => array('id' => 'UserCdata.user_id'),
                 'null' => true,
             ),
+            'cdata_entry' => array(
+                'constraint' => array(
+                    'id' => 'DynamicFormEntry.object_id',
+                    "'U'" => 'DynamicFormEntry.object_type',
+                ),
+                'null' => true,
+            ),
         )
     );
 
@@ -884,7 +891,12 @@ class UserAccountModel extends VerySimpleModel {
 
     function lock() {
         $this->setStatus(UserAccountStatus::LOCKED);
-        $this->save();
+        return $this->save();
+    }
+
+    function unlock() {
+        $this->clearStatus(UserAccountStatus::LOCKED);
+        return $this->save();
     }
 
     function isLocked() {
diff --git a/include/client/header.inc.php b/include/client/header.inc.php
index 34cd76f4056355f180c5af257cf9192f56cc7009..19a00128011f9bac330a4bd05fe48f5b718063f7 100644
--- a/include/client/header.inc.php
+++ b/include/client/header.inc.php
@@ -5,7 +5,7 @@ $signin_url = ROOT_PATH . "login.php"
     . ($thisclient ? "?e=".urlencode($thisclient->getEmail()) : "");
 $signout_url = ROOT_PATH . "logout.php?auth=".$ost->getLinkToken();
 
-header("Content-Type: text/html; charset=UTF-8\r\n");
+header("Content-Type: text/html; charset=UTF-8");
 ?>
 <!DOCTYPE html>
 <html <?php
diff --git a/include/i18n/en_US/help/tips/settings.alerts.yaml b/include/i18n/en_US/help/tips/settings.alerts.yaml
index 323e1bba55882b32dc31c9cdcc725b2e6aa55052..21951c9e9595c1f911f4c95b50602ea03595ace6 100644
--- a/include/i18n/en_US/help/tips/settings.alerts.yaml
+++ b/include/i18n/en_US/help/tips/settings.alerts.yaml
@@ -42,10 +42,10 @@ message_alert:
         href: /scp/templates.php?default_for=message.alert
 
 internal_note_alert:
-    title: New Internal Note Alert
+    title: New Internal Activity Alert
     content: >
-        Alert sent out to Agents when a new <span
-        class="doc-desc-title">Internal Note</span> is appended to a ticket.
+        Alert sent out to Agents when internal activity such as an internal
+        note or an agent reply is appended to a ticket.
     links:
       - title: Default Ticket Activity Template
         href: /scp/templates.php?default_for=note.alert
diff --git a/include/i18n/en_US/help/tips/staff.department.yaml b/include/i18n/en_US/help/tips/staff.department.yaml
index ec16a46a1f13e2ad790f2ca9216fe447b5654ad8..0c6f555c240fb2b4609e8f325c2bf8059c0624fc 100644
--- a/include/i18n/en_US/help/tips/staff.department.yaml
+++ b/include/i18n/en_US/help/tips/staff.department.yaml
@@ -73,9 +73,9 @@ sandboxing:
     title: Ticket Assignment Restrictions
     content: >
         Enable this to restrict ticket assignement to only include members
-        of this Department. Department access can be extended to
-        Groups, if <span class="doc-desc-title">Group Membership</span> is
-        also enabled.
+        of this Department. Department membership can be extended to Groups,
+        if <span class="doc-desc-title">Alerts &amp; Notices
+        Recipients</span> includes groups members.
 
 auto_response_settings:
     title: Autoresponder Settings
diff --git a/include/i18n/en_US/templates/email/note.alert.yaml b/include/i18n/en_US/templates/email/note.alert.yaml
index a704830d6bb3300607be5b3c7f0c6a55741b4955..5a1bcd91e3d69d21fe5b61ba4e1ab7cc9d2405e1 100644
--- a/include/i18n/en_US/templates/email/note.alert.yaml
+++ b/include/i18n/en_US/templates/email/note.alert.yaml
@@ -6,14 +6,14 @@
 #
 ---
 notes: |
-    Sent to staff members when a new internal note is appended to a ticket.
-    Internal notes can only be added by staff members.
+    Alert sent out to Agents when internal activity such as an internal
+    note or an agent reply is appended to a ticket.
 
 subject: |
-    New Internal Note Alert
+    New Internal Activity Alert
 body: |
     <h3><strong>Hi %{recipient.name},</strong></h3>
-    An internal note has been appended to ticket <a
+    An agent has logged activity on ticket <a
     href="%{ticket.staff_link}">#%{ticket.number}</a>
     <br>
     <br>
diff --git a/include/ost-sampleconfig.php b/include/ost-sampleconfig.php
index 3fc0e71780edaca45f56fdefb698a59e5a5b2b1a..a4624d1e706ce75f36c2e23a6ac1c0ec3b916eb3 100644
--- a/include/ost-sampleconfig.php
+++ b/include/ost-sampleconfig.php
@@ -71,7 +71,7 @@ define('TABLE_PREFIX','%CONFIG-PREFIX');
 #
 # Mail Options
 # ---------------------------------------------------
-# Option: MAIL_EOL (default: \r\n)
+# Option: MAIL_EOL (default: \n)
 #
 # Some mail setups do not handle emails with \r\n (CRLF) line endings for
 # headers and base64 and quoted-response encoded bodies. This is an error
@@ -88,7 +88,7 @@ define('TABLE_PREFIX','%CONFIG-PREFIX');
 # https://github.com/osTicket/osTicket-1.8/issues/759
 # https://github.com/osTicket/osTicket-1.8/issues/1217
 
-# define(MAIL_EOL, "\n");
+# define(MAIL_EOL, "\r\n");
 
 #
 # HTTP Server Options
diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php
index 27e7dc449d0318da13a714748d5ced468cd4e737..8958d43a0fcb022d51445ebe93d2d4a665638a9d 100644
--- a/include/staff/email.inc.php
+++ b/include/staff/email.inc.php
@@ -217,7 +217,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info);
             <td>
 		<span>
 			<select name="mail_proto">
-                <option value=''>&mdash; <?php __('Select protocol'); ?> &mdash;</option>
+                <option value=''>&mdash; <?php echo __('Select protocol'); ?> &mdash;</option>
 <?php
     foreach (MailFetcher::getSupportedProtos() as $proto=>$desc) { ?>
                 <option value="<?php echo $proto; ?>" <?php
diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php
index dd9945a1eaf27fe2d48024df9ea5c722b2c83f29..4027d7b61d62366d32797ff4a8143ec3d16c221b 100644
--- a/include/staff/header.inc.php
+++ b/include/staff/header.inc.php
@@ -1,4 +1,6 @@
-<?php if (!isset($_SERVER['HTTP_X_PJAX'])) { ?>
+<?php
+header("Content-Type: text/html; charset=UTF-8");
+if (!isset($_SERVER['HTTP_X_PJAX'])) { ?>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
 <html <?php
 if (($lang = Internationalization::getCurrentLanguage())
diff --git a/include/staff/orgs.inc.php b/include/staff/orgs.inc.php
index 4973b0b6252933fc87a8106b3ad3f0fcbe79f6bf..fff47ba84ba16bb6f2d5cf6dbc35407b6c08f942 100644
--- a/include/staff/orgs.inc.php
+++ b/include/staff/orgs.inc.php
@@ -72,7 +72,7 @@ $qhash = md5($query);
 $_SESSION['orgs_qs_'.$qhash] = $query;
 ?>
 <h2><?php echo __('Organizations'); ?></h2>
-<div class="pull-left" style="width:700px;">
+<div class="pull-left">
     <form action="orgs.php" method="get">
         <?php csrf_token(); ?>
         <input type="hidden" name="a" value="search">
@@ -86,11 +86,31 @@ $_SESSION['orgs_qs_'.$qhash] = $query;
         </table>
     </form>
  </div>
+
+<div class="pull-right">
 <?php if ($thisstaff->getRole()->hasPerm(Organization::PERM_CREATE)) { ?>
- <div class="pull-right flush-right">
-    <b><a href="#orgs/add" class="Icon newDepartment add-org"><?php
-    echo __('Add New Organization'); ?></a></b></div>
+    <a class="action-button add-org"
+        href="#">
+        <i class="icon-plus-sign"></i>
+        <?php echo __('Add Organization'); ?>
+    </a>
+<?php }
+if ($thisstaff->getRole()->hasPerm(Organization::PERM_DELETE)) { ?>
+    <span class="action-button" data-dropdown="#action-dropdown-more"
+        style="/*DELME*/ vertical-align:top; margin-bottom:0">
+        <i class="icon-caret-down pull-right"></i>
+        <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
+    </span>
+    <div id="action-dropdown-more" class="action-dropdown anchor-right">
+        <ul>
+            <li><a class="orgs-action" href="#delete">
+                <i class="icon-trash icon-fixed-width"></i>
+                <?php echo __('Delete'); ?></a></li>
+        </ul>
+    </div>
 <?php } ?>
+</div>
+
 <div class="clear"></div>
 <?php
 $showing = $search ? __('Search Results').': ' : '';
@@ -100,14 +120,16 @@ if($res && ($num=db_num_rows($res)))
 else
     $showing .= __('No organizations found!');
 ?>
-<form action="orgs.php" method="POST" name="staff" >
+<form id="orgs-list" action="orgs.php" method="POST" name="staff" >
  <?php csrf_token(); ?>
- <input type="hidden" name="do" value="mass_process" >
- <input type="hidden" id="action" name="a" value="" >
+ <input type="hidden" name="a" value="mass_process" >
+ <input type="hidden" id="action" name="do" value="" >
+ <input type="hidden" id="selected-count" name="count" value="" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
     <thead>
         <tr>
+            <th nowrap width="12"> </th>
             <th width="400"><a <?php echo $name_sort; ?> href="orgs.php?<?php echo $qstr; ?>&sort=name"><?php echo __('Name'); ?></a></th>
             <th width="100"><a <?php echo $users_sort; ?> href="orgs.php?<?php echo $qstr; ?>&sort=users"><?php echo __('Users'); ?></a></th>
             <th width="150"><a <?php echo $create_sort; ?> href="orgs.php?<?php echo $qstr; ?>&sort=create"><?php echo __('Created'); ?></a></th>
@@ -125,6 +147,9 @@ else
                     $sel=true;
                 ?>
                <tr id="<?php echo $row['id']; ?>">
+                <td nowrap>
+                    <input type="checkbox" value="<?php echo $row['id']; ?>" class="ckb mass nowarn"/>
+                </td>
                 <td>&nbsp; <a href="orgs.php?id=<?php echo $row['id']; ?>"><?php echo $row['name']; ?></a> </td>
                 <td>&nbsp;<?php echo $row['users']; ?></td>
                 <td><?php echo Format::date($row['created']); ?></td>
@@ -134,6 +159,22 @@ else
             } //end of while.
         endif; ?>
     </tbody>
+    <tfoot>
+     <tr>
+        <td colspan="7">
+            <?php if ($res && $num) { ?>
+            <?php echo __('Select');?>:&nbsp;
+            <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
+            <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
+            <a id="selectToggle" href="#ckb"><?php echo __('Toggle');?></a>&nbsp;&nbsp;
+            <?php }else{
+                echo '<i>';
+                echo __('Query returned 0 results.');
+                echo '</i>';
+            } ?>
+        </td>
+     </tr>
+    </tfoot>
 </table>
 <?php
 if($res && $num): //Show options..
@@ -173,5 +214,31 @@ $(function() {
 
         return false;
      });
+
+    var goBaby = function(action) {
+        var ids = [],
+            $form = $('form#orgs-list');
+        $(':checkbox.mass:checked', $form).each(function() {
+            ids.push($(this).val());
+        });
+        if (ids.length) {
+          var submit = function() {
+            $form.find('#action').val(action);
+            $.each(ids, function() { $form.append($('<input type="hidden" name="ids[]">').val(this)); });
+            $form.find('#selected-count').val(ids.length);
+            $form.submit();
+          };
+          $.confirm(__('You sure?')).then(submit);
+        }
+        else if (!ids.length) {
+            $.sysAlert(__('Oops'),
+                __('You need to select at least one item'));
+        }
+    };
+    $(document).on('click', 'a.orgs-action', function(e) {
+        e.preventDefault();
+        goBaby($(this).attr('href').substr(1));
+        return false;
+    });
 });
 </script>
diff --git a/include/staff/settings-alerts.inc.php b/include/staff/settings-alerts.inc.php
index 14b3fee30ade06c2b8d190b83e276cb295dd2351..3a9326bc4127343b57831a14a81b8d50f1b5c5bb 100644
--- a/include/staff/settings-alerts.inc.php
+++ b/include/staff/settings-alerts.inc.php
@@ -88,7 +88,7 @@
                 <?php echo __('Organization Account Manager'); ?>
             </td>
         </tr>
-        <tr><th><em><b><?php echo __('New Internal Note Alert'); ?></b>:
+        <tr><th><em><b><?php echo __('New Internal Activity Alert'); ?></b>:
             <i class="help-tip icon-question-sign" href="#internal_note_alert"></i>
             </em></th></tr>
         <tr>
diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php
index a30454b50449800d35b9ddde351faa9ec0722dd1..55241ed1859dcef7290eff40b96d5f613142178e 100644
--- a/include/staff/ticket-view.inc.php
+++ b/include/staff/ticket-view.inc.php
@@ -80,8 +80,10 @@ if($ticket->isOverdue())
                     echo __('Edit'); ?></a>
             <?php
             }
-            if ($ticket->isOpen() && !$ticket->isAssigned() &&
-                    $role->hasPerm(TicketModel::PERM_ASSIGN)) {?>
+            if ($ticket->isOpen()
+                    && !$ticket->isAssigned()
+                    && $role->hasPerm(TicketModel::PERM_ASSIGN)
+                    && $ticket->getDept()->isMember($thisstaff)) {?>
                 <a id="ticket-claim" class="action-button pull-right confirm-action" href="#claim"><i class="icon-user"></i> <?php
                     echo __('Claim'); ?></a>
 
@@ -868,7 +870,9 @@ $tcount = $ticket->getThreadEntries($types)->count();
                     <select id="assignId" name="assignId">
                         <option value="0" selected="selected">&mdash; <?php echo __('Select an Agent OR a Team');?> &mdash;</option>
                         <?php
-                        if($ticket->isOpen() && !$ticket->isAssigned())
+                        if ($ticket->isOpen()
+                                && !$ticket->isAssigned()
+                                && $ticket->getDept()->isMember($thisstaff))
                             echo sprintf('<option value="%d">'.__('Claim Ticket (comments optional)').'</option>', $thisstaff->getId());
 
                         $sid=$tid=0;
diff --git a/include/staff/user-view.inc.php b/include/staff/user-view.inc.php
index eae6c28cb223625efcdb99d813589e1faa19889c..0497b74b8ce27d2795d700c235d4b4368c985b79 100644
--- a/include/staff/user-view.inc.php
+++ b/include/staff/user-view.inc.php
@@ -34,7 +34,7 @@ $org = $user->getOrganization();
             <?php
             } else { ?>
             <a id="user-register" class="action-button pull-right user-action"
-            href="#users/<?php echo $user->getId(); ?>/register"><i class="icon-edit"></i>
+            href="#users/<?php echo $user->getId(); ?>/register"><i class="icon-smile"></i>
             <?php echo __('Register'); ?></a>
             <?php
             } ?>
diff --git a/include/staff/users.inc.php b/include/staff/users.inc.php
index 7e9be8950c5cd1d9c5895018743c2ad79ecc51f7..e83671a684eb9bd63cfb79a83d57180bb615b587 100644
--- a/include/staff/users.inc.php
+++ b/include/staff/users.inc.php
@@ -57,7 +57,7 @@ $users->values('id', 'name', 'default_email__address', 'account__id',
 $users->order_by($order . $order_column);
 ?>
 <h2><?php echo __('User Directory'); ?></h2>
-<div class="pull-left" style="width:700px;">
+<div class="pull-left">
     <form action="users.php" method="get">
         <?php csrf_token(); ?>
         <input type="hidden" name="a" value="search">
@@ -71,14 +71,60 @@ $users->order_by($order . $order_column);
         </table>
     </form>
  </div>
+
+<div class="pull-right">
 <?php if ($thisstaff->getRole()->hasPerm(User::PERM_CREATE)) { ?>
- <div class="pull-right flush-right" style="padding-right:5px;">
-    <b><a href="#users/add" class="Icon newstaff popup-dialog"><?php echo __('Add User'); ?></a></b>
-    |
-    <b><a href="#users/import" class="popup-dialog"><i class="icon-cloud-upload icon-large"></i>
-    <?php echo __('Import'); ?></a></b>
-</div>
+    <a class="action-button popup-dialog"
+        href="#users/add">
+        <i class="icon-plus-sign"></i>
+        <?php echo __('Add User'); ?>
+    </a>
+    <a class="action-button popup-dialog"
+        href="#users/import">
+        <i class="icon-upload"></i>
+        <?php echo __('Import'); ?>
+    </a>
 <?php } ?>
+    <span class="action-button" data-dropdown="#action-dropdown-more"
+        style="/*DELME*/ vertical-align:top; margin-bottom:0">
+        <i class="icon-caret-down pull-right"></i>
+        <span ><i class="icon-cog"></i> <?php echo __('More');?></span>
+    </span>
+    <div id="action-dropdown-more" class="action-dropdown anchor-right">
+        <ul>
+<?php if ($thisstaff->getRole()->hasPerm(User::PERM_DELETE)) { ?>
+            <li><a class="users-action" href="#delete">
+                <i class="icon-trash icon-fixed-width"></i>
+                <?php echo __('Delete'); ?></a></li>
+<?php }
+if ($thisstaff->getRole()->hasPerm(User::PERM_EDIT)) { ?>
+            <li><a href="#orgs/lookup/form" onclick="javascript:
+$.dialog('ajax.php/orgs/lookup/form', 201);
+return false;">
+                <i class="icon-group icon-fixed-width"></i>
+                <?php echo __('Add to Organization'); ?></a></li>
+<?php
+}
+if ('disabled' != $cfg->getClientRegistrationMode()) { ?>
+            <li><a class="users-action" href="#reset">
+                <i class="icon-envelope icon-fixed-width"></i>
+                <?php echo __('Send Password Reset Email'); ?></a></li>
+<?php if ($thisstaff->getRole()->hasPerm(User::PERM_MANAGE)) { ?>
+            <li><a class="users-action" href="#register">
+                <i class="icon-smile icon-fixed-width"></i>
+                <?php echo __('Register'); ?></a></li>
+            <li><a class="users-action" href="#lock">
+                <i class="icon-lock icon-fixed-width"></i>
+                <?php echo __('Lock'); ?></a></li>
+            <li><a class="users-action" href="#unlock">
+                <i class="icon-unlock icon-fixed-width"></i>
+                <?php echo __('Unlock'); ?></a></li>
+<?php }
+} # end of registration-enabled? ?>
+        </ul>
+    </div>
+</div>
+
 <div class="clear"></div>
 <?php
 $showing = $search ? __('Search Results').': ' : '';
@@ -87,14 +133,17 @@ if($users->exists(true))
 else
     $showing .= __('No users found!');
 ?>
-<form action="users.php" method="POST" name="staff" >
+<form id="users-list" action="users.php" method="POST" name="staff" >
  <?php csrf_token(); ?>
  <input type="hidden" name="do" value="mass_process" >
  <input type="hidden" id="action" name="a" value="" >
+ <input type="hidden" id="selected-count" name="count" value="" >
+ <input type="hidden" id="org_id" name="org_id" value="" >
  <table class="list" border="0" cellspacing="1" cellpadding="0" width="940">
     <caption><?php echo $showing; ?></caption>
     <thead>
         <tr>
+            <th nowrap width="12"> </th>
             <th width="350"><a <?php echo $name_sort; ?> href="users.php?<?php
                 echo $qstr; ?>&sort=name"><?php echo __('Name'); ?></a></th>
             <th width="250"><a  <?php echo $status_sort; ?> href="users.php?<?php
@@ -126,6 +175,9 @@ else
                     $sel=true;
                 ?>
                <tr id="<?php echo $U['id']; ?>">
+                <td nowrap>
+                    <input type="checkbox" value="<?php echo $U['id']; ?>" class="ckb mass nowarn"/>
+                </td>
                 <td>&nbsp;
                     <a class="preview"
                         href="users.php?id=<?php echo $U['id']; ?>"
@@ -144,6 +196,22 @@ else
                </tr>
 <?php   } //end of foreach. ?>
     </tbody>
+    <tfoot>
+     <tr>
+        <td colspan="7">
+            <?php if ($res && $num) { ?>
+            <?php echo __('Select');?>:&nbsp;
+            <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
+            <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
+            <a id="selectToggle" href="#ckb"><?php echo __('Toggle');?></a>&nbsp;&nbsp;
+            <?php }else{
+                echo '<i>';
+                echo __('Query returned 0 results.');
+                echo '</i>';
+            } ?>
+        </td>
+     </tr>
+    </tfoot>
 </table>
 <?php
 if ($total) {
@@ -183,7 +251,44 @@ $(function() {
          });
 
         return false;
-     });
+    });
+    var goBaby = function(action, confirmed) {
+        var ids = [],
+            $form = $('form#users-list');
+        $(':checkbox.mass:checked', $form).each(function() {
+            ids.push($(this).val());
+        });
+        if (ids.length) {
+          var submit = function() {
+            $form.find('#action').val(action);
+            $.each(ids, function() { $form.append($('<input type="hidden" name="ids[]">').val(this)); });
+            $form.find('#selected-count').val(ids.length);
+            $form.submit();
+          };
+          if (!confirmed)
+              $.confirm(__('You sure?')).then(submit);
+          else
+              submit();
+        }
+        else {
+            $.sysAlert(__('Oops'),
+                __('You need to select at least one item'));
+        }
+    };
+    $(document).on('click', 'a.users-action', function(e) {
+        e.preventDefault();
+        goBaby($(this).attr('href').substr(1));
+        return false;
+    });
+    $(document).on('dialog:close', function(e, json) {
+        $form = $('form#users-list');
+        try {
+            var json = $.parseJSON(json);
+            $form.find('#org_id').val(json.id);
+            goBaby('setorg', true);
+        }
+        catch (e) { console.log(e); }
+    });
 });
 </script>
 
diff --git a/scp/ajax.php b/scp/ajax.php
index ed9e37345c16c29766b223c3d5a5da37ec02a1f0..7a6b95fcb3662333969698cfc58ff0527f82b5e7 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -118,7 +118,7 @@ $dispatcher = patterns('',
         url_post('^/(?P<id>\d+)/profile$', 'updateOrg', array(true)),
         url_get('^/(?P<id>\d+)/edit$', 'editOrg'),
         url_get('^/lookup/form$', 'lookup'),
-        url_post('^/lookup/form$', 'addOrg'),
+        url_post('^/lookup$', 'lookup'),
         url_get('^/add$', 'addOrg'),
         url_post('^/add$', 'addOrg'),
         url_get('^/select$', 'selectOrg'),
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 30b384e1436c824a598c231203d9335700c6aaba..744fbf9d1e62d4a0041478a312a8735d9dc06061 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1095,7 +1095,7 @@ ul.tabs.vertical li a {
     display:block;
     height:30px;
     position:absolute;
-    z-index:101;
+    z-index:5;
 }
 
 .tip_arrow {
diff --git a/scp/js/scp.js b/scp/js/scp.js
index 9e1b5d714419856c0b3ebd434701a5265bc7b8ff..3efd18bdbd74008f70e6360c0a3511cb8929c1f4 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -587,12 +587,14 @@ $.dialog = function (url, codes, cb, options) {
                 data: $form.serialize(),
                 cache: false,
                 success: function(resp, status, xhr) {
+                    var done = $.Event('dialog:close');
                     if (xhr && xhr.status && codes
                         && $.inArray(xhr.status, codes) != -1) {
                         $.toggleOverlay(false);
                         $popup.hide();
                         $('div.body', $popup).empty();
                         if(cb) cb(xhr, resp);
+                        $popup.trigger(done, [resp, status, xhr]);
                     } else {
                         try {
                             var json = $.parseJSON(resp);
@@ -629,6 +631,39 @@ $.sysAlert = function (title, msg, cb) {
     }
 };
 
+$.confirm = function(message, title) {
+    title = title || __('Please Confirm');
+    var D = $.Deferred(),
+      $popup = $('.dialog#popup'),
+      hide = function() {
+          $('#overlay').hide();
+          $popup.hide();
+      };
+      $('div#popup-loading', $popup).hide();
+      $('div.body', $popup).empty()
+        .append($('<h3></h3>').text(title))
+        .append($('<a class="close" href="#"><i class="icon-remove-circle"></i></a>'))
+        .append($('<hr/>'))
+        .append($('<p class="confirm-action"></p>')
+            .text(message)
+        ).append($('<div></div>')
+            .append($('<b>').text(__('Please confirm to continue.')))
+        ).append($('<hr style="margin-top:1em"/>'))
+        .append($('<p class="full-width"></p>')
+            .append($('<span class="buttons pull-left"></span>')
+                .append($('<input type="button" class="close"/>')
+                    .attr('value', __('Cancel'))
+                    .click(function() { hide(); })
+            )).append($('<span class="buttons pull-right"></span>')
+                .append($('<input type="button"/>')
+                    .attr('value', __('OK'))
+                    .click(function() {  hide(); D.resolve(); })
+        ))).append($('<div class="clear"></div>'));
+    $('#overlay').fadeIn();
+    $popup.show();
+    return D.promise();
+};
+
 $.userLookup = function (url, cb) {
     $.dialog(url, 201, function (xhr) {
         var user = $.parseJSON(xhr.responseText);
diff --git a/scp/js/ticket.js b/scp/js/ticket.js
index 7082679962d08b54af60a24b6b85645812613e55..a105918683214496cb4050d7d238089924dc120b 100644
--- a/scp/js/ticket.js
+++ b/scp/js/ticket.js
@@ -56,7 +56,7 @@ var autoLock = {
     //Incoming event...
     handleEvent: function(e) {
 
-        if(!autoLock.lasteventTime) { //I hate nav away warnings..but
+        if(autoLock.lockId && !autoLock.lasteventTime) { //I hate nav away warnings..but
             $(document).on('pjax:beforeSend.changed', function(e) {
                 return confirm(__("Any changes or info you've entered will be discarded!"));
             });
diff --git a/scp/orgs.php b/scp/orgs.php
index bb16dcce7e2f8da7ea949d7c1a2b9f9c1fc9bf6f..fb224a5047c58d21ee85d931b4092836f086d03e 100644
--- a/scp/orgs.php
+++ b/scp/orgs.php
@@ -59,6 +59,39 @@ if ($_POST) {
                     _N('selected end user', 'selected end users', $count));
         }
         break;
+
+    case 'mass_process':
+        if (!$_POST['ids'] || !is_array($_POST['ids']) || !count($_POST['ids'])) {
+            $errors['err'] = sprintf(__('You must select at least %s.'),
+                __('one organization'));
+        }
+        else {
+            $orgs = Organization::objects()->filter(
+                array('id__in' => $_POST['ids'])
+            );
+            $count = 0;
+            switch (strtolower($_POST['do'])) {
+            case 'delete':
+                foreach ($orgs as $O)
+                    if ($O->delete())
+                        $count++;
+                break;
+
+            default:
+                $errors['err']=__('Unknown action - get technical help.');
+            }
+            if (!$errors['err'] && !$count) {
+                $errors['err'] = __('Unable to manage any of the selected organizations');
+            }
+            elseif ($_POST['count'] && $count != $_POST['count']) {
+                $warn = __('Not all selected items were updated');
+            }
+            elseif ($count) {
+                $msg = __('Successfully managed selected organizations');
+            }
+        }
+        break;
+
     default:
         $errors['err'] = __('Unknown action');
     }
diff --git a/scp/tickets.php b/scp/tickets.php
index 9821e037c737e55299556a71ddd4169fe2febbe7..86247b2b03e0089e8f0dff7d42b5483cb232abdd 100644
--- a/scp/tickets.php
+++ b/scp/tickets.php
@@ -162,12 +162,21 @@ if($_POST && !$errors):
 
                  $id = preg_replace("/[^0-9]/", "",$_POST['assignId']);
                  $claim = (is_numeric($_POST['assignId']) && $_POST['assignId']==$thisstaff->getId());
+                 $dept = $ticket->getDept();
 
-                 if(!$_POST['assignId'] || !$id)
+                 if (!$_POST['assignId'] || !$id)
                      $errors['assignId'] = __('Select assignee');
-                 elseif($_POST['assignId'][0]!='s' && $_POST['assignId'][0]!='t' && !$claim)
-                     $errors['assignId']=__('Invalid assignee ID - get technical support');
-                 elseif($ticket->isAssigned()) {
+                 elseif ($_POST['assignId'][0]!='s' && $_POST['assignId'][0]!='t' && !$claim)
+                     $errors['assignId']= sprintf('%s - %s',
+                             __('Invalid assignee '),
+                             __('get technical support'));
+                 elseif ($_POST['assignId'][0]!='s'
+                         && $dept->assignMembersOnly()
+                         && !$dept->isMember($id)) {
+                     $errors['assignId'] = sprintf('%s. %s',
+                             __('Invalid assignee'),
+                             __('Must be department member'));
+                 } elseif($ticket->isAssigned()) {
                      if($_POST['assignId'][0]=='s' && $id==$ticket->getStaffId())
                          $errors['assignId']=__('Ticket already assigned to the agent.');
                      elseif($_POST['assignId'][0]=='t' && $id==$ticket->getTeamId())
@@ -274,7 +283,7 @@ if($_POST && !$errors):
                         $errors['err'] = __('Only open tickets can be assigned');
                     } elseif($ticket->isAssigned()) {
                         $errors['err'] = sprintf(__('Ticket is already assigned to %s'),$ticket->getAssigned());
-                    } elseif($ticket->assignToStaff($thisstaff->getId(), (sprintf(__('Ticket claimed by %s'),$thisstaff->getName())), false)) {
+                    } elseif ($ticket->claim()) {
                         $msg = __('Ticket is now assigned to you!');
                     } else {
                         $errors['err'] = __('Problems assigning the ticket. Try again');
diff --git a/scp/users.php b/scp/users.php
index a606ddca6adadd5aa34b520348d3ad9f760cd045..20956ae8b21381b093f8d9aeb51849fa5ece351b 100644
--- a/scp/users.php
+++ b/scp/users.php
@@ -75,7 +75,70 @@ if ($_POST) {
                 $errors['err'] = sprintf(__('You must select at least %s.'),
                     __('one end user'));
             } else {
-                $errors['err'] = "Coming soon!";
+                $users = User::objects()->filter(
+                    array('id__in' => $_POST['ids'])
+                );
+                $count = 0;
+                switch (strtolower($_POST['a'])) {
+                case 'lock':
+                    foreach ($users as $U)
+                        if (($acct = $U->getAccount()) && $acct->lock())
+                            $count++;
+                    break;
+
+                case 'unlock':
+                    foreach ($users as $U)
+                        if (($acct = $U->getAccount()) && $acct->unlock())
+                            $count++;
+                    break;
+
+                case 'delete':
+                    foreach ($users as $U)
+                        if ($U->delete())
+                            $count++;
+                    break;
+
+                case 'reset':
+                    foreach ($users as $U)
+                        if (($acct = $U->getAccount()) && $acct->sendResetEmail())
+                            $count++;
+                    break;
+
+                case 'register':
+                    foreach ($users as $U) {
+                        if (($acct = $U->getAccount()) && $acct->sendConfirmEmail())
+                            $count++;
+                        elseif ($acct = UserAccount::register($U,
+                            array('sendemail' => true), $errors
+                        )) {
+                            $count++;
+                        }
+                    }
+                    break;
+
+                case 'setorg':
+                    if (!($org = Organization::lookup($_POST['org_id'])))
+                        $errors['err'] = __('Unknown action - get technical help.');
+                    foreach ($users as $U) {
+                        if ($U->setOrganization($org))
+                            $count++;
+                    }
+                    break;
+
+                default:
+                    $errors['err']=__('Unknown action - get technical help.');
+                }
+                if (!$errors['err'] && !$count) {
+                    $errors['err'] = __('Unable to manage any of the selected end users');
+                }
+                elseif ($_POST['count'] && $count != $_POST['count']) {
+                    $warn = __('Not all selected items were updated');
+                }
+                elseif ($count) {
+                    $msg = __('Successfully managed selected end users');
+                }
+
+
             }
             break;
         case 'import-users':
diff --git a/setup/cli/modules/class.module.php b/setup/cli/modules/class.module.php
index c6af32572dfde210a1014d884d91cff4acf18d9a..f5f866b0e48196b81b36040edfa0a3601130463b 100644
--- a/setup/cli/modules/class.module.php
+++ b/setup/cli/modules/class.module.php
@@ -212,8 +212,11 @@ class Module {
             $this->parseArgs(array_slice($argv, 1));
 
         foreach (array_keys($this->arguments) as $idx=>$name)
-            if (!isset($this->_args[$idx]))
-                $this->optionError($name . " is a required argument");
+            if (!isset($this->_args[$idx])) {
+                $info = $this->arguments[$name];
+                if (!is_array($info) || !isset($info['required']) || $info['required'])
+                    $this->optionError($name . " is a required argument");
+            }
             elseif (is_array($this->arguments[$name])
                     && isset($this->arguments[$name]['options'])
                     && !isset($this->arguments[$name]['options'][$this->_args[$idx]]))
diff --git a/setup/cli/modules/file.php b/setup/cli/modules/file.php
index f5057230ac293cae0b23b0944e0b419aca033369..b1a2f9be697e36f6c837b4584d6a6f5c7eed6735 100644
--- a/setup/cli/modules/file.php
+++ b/setup/cli/modules/file.php
@@ -374,6 +374,14 @@ class FileManager extends Module {
                             ));
                         }
                     }
+
+                    // Update file to record current backend
+                    $sql = 'UPDATE '.FILE_TABLE.' SET bk='
+                        .db_input($bk->getBkChar())
+                        .' WHERE id='.db_input($f->getId());
+                    if (!db_query($sql) || db_affected_rows()!=1)
+                        return false;
+
                 } // end try
                 catch (Exception $ex) {
                     if ($bk) $bk->unlink();
diff --git a/setup/test/tests/stubs.php b/setup/test/tests/stubs.php
index fa0706313a77a2edde33868231556c017d88b306..392873e1957f9b29bb5daa9d2db2f7070fba3050 100644
--- a/setup/test/tests/stubs.php
+++ b/setup/test/tests/stubs.php
@@ -156,4 +156,7 @@ class ResourceBundle {
     function getLocales() {}
 }
 
+class Aws_Route53_Client {
+    function changeResourceRecordSets() {}
+}
 ?>
diff --git a/setup/test/tests/test.header_functions.php b/setup/test/tests/test.header_functions.php
index b64a1c400946e590e01a8742d47d9a09ffefbd46..0b2328ce4f30cd42ea6ee09a3e51fd138ffffb91 100644
--- a/setup/test/tests/test.header_functions.php
+++ b/setup/test/tests/test.header_functions.php
@@ -5,65 +5,67 @@ define('PEAR_DIR', INCLUDE_DIR.'/pear/');
 require_once INCLUDE_DIR."class.mailparse.php";
 
 abstract class Priorities {
-	const HIGH_PRIORITY = 1;
-	const NORMAL_PRIORITY = 2;
-	const LOW_PRIORITY = 3;
-	const NO_PRIORITY = 0;
+    const HIGH_PRIORITY = 1;
+    const NORMAL_PRIORITY = 2;
+    const LOW_PRIORITY = 3;
+    const NO_PRIORITY = 0;
 }
 
 class TestHeaderFunctions extends Test {
     var $name = "Email Header Function Algorithm Regression Tests.";
-    
+
     function testMailParsePriority() {
-    	$func_class_method = array('Mail_Parse','parsePriority');
-    	$strlen_base = strlen($this->h());
+        $func_class_method = array('Mail_Parse','parsePriority');
+        $strlen_base = strlen($this->h());
+
+        foreach ( array (
+                // input => output
+                'X-Priority: isNAN' => Priorities::NO_PRIORITY,
+                'X-Priority: 1' => Priorities::HIGH_PRIORITY,
+                'X-Priority: 2' => Priorities::HIGH_PRIORITY,
+                'X-Priority: 3' => Priorities::NORMAL_PRIORITY,
+                'X-Priority: 4' => Priorities::NORMAL_PRIORITY,
+                'X-Priority: 5' => Priorities::LOW_PRIORITY,
+                'X-Priority: 6' => Priorities::LOW_PRIORITY,
+                'No priority set' => Priorities::NO_PRIORITY,
+                'Priority: normal' => Priorities::NORMAL_PRIORITY,
+                'xyz-priority: high' => Priorities::HIGH_PRIORITY,
+                'Priority: high' => Priorities::HIGH_PRIORITY,
+                'priority: low' => Priorities::LOW_PRIORITY,
+                'x-priority: 1000' => Priorities::HIGH_PRIORITY, // only matches first 1, not the full 1000
+                'priority: 3' => Priorities::NORMAL_PRIORITY,
+                'IPM-Importance: low' => Priorities::LOW_PRIORITY,
+                'My-Importance: URGENT' => Priorities::HIGH_PRIORITY,
+                'Urgency: High' => Priorities::NO_PRIORITY, //urgency doesn't match.. maybe it should?
+                'Importance: Low' => Priorities::LOW_PRIORITY,
+                'X-MSMail-Priority: High' => Priorities::HIGH_PRIORITY,
+                '' => Priorities::NO_PRIORITY
+        ) as $priority => $response ) {
+            $this->assert(is_int($response), "Setup fail, function should only return Integer values");
+            //get header
+            $header = $this->h($priority);
+
+            if(strlen($priority)){
+                $this->assert((strlen($header) > $strlen_base), "Setup fail, function h not returning correct string length");
+            }
+            if (! (call_user_func_array ($func_class_method , array($header) ) == $response)){
+                //TODO: make line number dynamic
+                $this->fail ( "class.mailparse.php", 351, "Algorithm mistake: $priority should return $response!" );
+            }else{
+                $this->pass();
+            }
+        }
 
-    	foreach ( array (
-    			'X-Priority: isNAN' => Priorities::NO_PRIORITY, // input => output
-    			'X-Priority: 1' => Priorities::LOW_PRIORITY,
-    			'X-Priority: 2' => Priorities::LOW_PRIORITY,
-    			'X-Priority: 3' => Priorities::NORMAL_PRIORITY,
-    			'X-Priority: 4' => Priorities::NORMAL_PRIORITY,
-    			'X-Priority: 5' => Priorities::HIGH_PRIORITY,
-    			'X-Priority: 6' => Priorities::HIGH_PRIORITY,
-    			'No priority set' => Priorities::NO_PRIORITY,
-    			'Priority: normal' => Priorities::NORMAL_PRIORITY,
-    			'xyz-priority: high' => Priorities::HIGH_PRIORITY,
-    			'Priority: high' => Priorities::HIGH_PRIORITY,
-    			'priority: low' => Priorities::LOW_PRIORITY,
-    			'x-priority: 1000' => Priorities::LOW_PRIORITY, // only matches first 1, not the full 1000
-    			'priority: 3' => Priorities::NORMAL_PRIORITY,
-    			'IPM-Importance: low' => Priorities::LOW_PRIORITY,
-    			'My-Importance: URGENT' => Priorities::HIGH_PRIORITY,
-    			'Urgency: High' => Priorities::NO_PRIORITY, //urgency doesn't match.. maybe it should?
-    			'X-Importance: 5' => Priorities::HIGH_PRIORITY,
-    			'' => Priorities::NO_PRIORITY
-    	) as $priority => $response ) {
-    		$this->assert(is_int($response), "Setup fail, function should only return Integer values");
-    		//get header
-    		$header = $this->h($priority);
-    		
-    		if(strlen($priority)){
-    			$this->assert((strlen($header) > $strlen_base), "Setup fail, function h not returning correct string length");
-    		}
-    		if (! (call_user_func_array ($func_class_method , array($header) ) == $response)){
-    			//TODO: make line number dynamic
-    			$this->fail ( "class.mailparse.php", 351, "Algorithm mistake: $priority should return $response!" );
-    		}else{
-    			$this->pass();
-    		}
-    	}
-  
     }
-    
+
     /**
      * Generate some header text to test with. Allows insertion of a known header variable
-     * 
+     *
      * @param string $setPriority
      * @return string
      */
     function h($setPriority = "") {
-    	return <<<HEADER
+        return <<<HEADER
 Delivered-To: clonemeagain@gmail.com
 Received: by 10.69.18.42 with SMTP id gj10csp88238pbd;
 Fri, 20 Dec 2013 10:08:25 -0800 (PST)