diff --git a/css/jquery.multiselect.css b/css/jquery.multiselect.css
new file mode 100644
index 0000000000000000000000000000000000000000..8a08e22b75ba758290971dbadb1a903bddca534e
--- /dev/null
+++ b/css/jquery.multiselect.css
@@ -0,0 +1,23 @@
+.ui-multiselect { padding:2px 0 2px 4px; text-align:left }
+.ui-multiselect span.ui-icon { float:right }
+.ui-multiselect-single .ui-multiselect-checkboxes input { position:absolute !important; top: auto !important; left:-9999px; }
+.ui-multiselect-single .ui-multiselect-checkboxes label { padding:5px !important }
+
+.ui-multiselect-header { margin-bottom:3px; padding:3px 0 3px 4px }
+.ui-multiselect-header ul { font-size:0.9em }
+.ui-multiselect-header ul li { float:left; padding:0 10px 0 0 }
+.ui-multiselect-header a { text-decoration:none }
+.ui-multiselect-header a:hover { text-decoration:underline }
+.ui-multiselect-header span.ui-icon { float:left }
+.ui-multiselect-header li.ui-multiselect-close { float:right; text-align:right; padding-right:0 }
+
+.ui-multiselect-menu { display:none; padding:3px; position:absolute; z-index:10000; text-align: left }
+.ui-multiselect-checkboxes { position:relative /* fixes bug in IE6/7 */; overflow-y:auto }
+.ui-multiselect-checkboxes label { cursor:default; display:block; border:1px solid transparent; padding:3px 1px }
+.ui-multiselect-checkboxes label input { position:relative; top:1px }
+.ui-multiselect-checkboxes li { clear:both; font-size:0.9em; padding-right:3px }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label { text-align:center; font-weight:bold; border-bottom:1px solid }
+.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a { display:block; padding:3px; margin:1px 0; text-decoration:none }
+
+/* remove label borders in IE6 because IE6 does not support transparency */
+* html .ui-multiselect-checkboxes label { border:none }
diff --git a/include/ajax.orgs.php b/include/ajax.orgs.php
index eeaa23c7eb4a9a1405c624d731dac599ad49a946..9a72c20449470d3c8ce8fa916132e063374fd862 100644
--- a/include/ajax.orgs.php
+++ b/include/ajax.orgs.php
@@ -61,11 +61,12 @@ class OrgsAjaxAPI extends AjaxController {
         );
 
         $forms = $org->getForms();
+        $action = "#orgs/{$org->id}/profile";
 
-        include(STAFFINC_DIR . 'templates/org.tmpl.php');
+        include(STAFFINC_DIR . 'templates/org-profile.tmpl.php');
     }
 
-    function updateOrg($id) {
+    function updateOrg($id, $profile=false) {
         global $thisstaff;
 
         if(!$thisstaff)
@@ -78,7 +79,15 @@ class OrgsAjaxAPI extends AjaxController {
              Http::response(201, $org->to_json());
 
         $forms = $org->getForms();
-        include(STAFFINC_DIR . 'templates/org.tmpl.php');
+
+        if ($profile) {
+            $action = "#orgs/{$org->id}/profile";
+            include(STAFFINC_DIR . 'templates/org-profile.tmpl.php');
+        }
+        else {
+            $action = "#orgs/{$org->id}";
+            include(STAFFINC_DIR . 'templates/org.tmpl.php');
+        }
     }
 
 
diff --git a/include/class.config.php b/include/class.config.php
index 03fe8891c0acfbabe2ea41c750f926a606225277..aae5a2a7e8eb8d98bc0a234fbe5b1e4d84d94995 100644
--- a/include/class.config.php
+++ b/include/class.config.php
@@ -610,6 +610,10 @@ class OsticketConfig extends Config {
         return ($this->get('message_alert_dept_manager'));
     }
 
+    function alertAcctManagerONNewMessage() {
+        return ($this->get('message_alert_acct_manager'));
+    }
+
     function alertONNewNote() {
         return ($this->get('note_alert_active'));
     }
@@ -642,6 +646,10 @@ class OsticketConfig extends Config {
         return ($this->get('ticket_alert_dept_members'));
     }
 
+    function alertAcctManagerONNewTicket() {
+        return ($this->get('ticket_alert_acct_manager'));
+    }
+
     function alertONTransfer() {
         return ($this->get('transfer_alert_active'));
     }
@@ -1061,13 +1069,15 @@ class OsticketConfig extends Config {
        if($vars['ticket_alert_active']
                 && (!isset($vars['ticket_alert_admin'])
                     && !isset($vars['ticket_alert_dept_manager'])
-                    && !isset($vars['ticket_alert_dept_members']))) {
+                    && !isset($vars['ticket_alert_dept_members'])
+                    && !isset($vars['ticket_alert_acct_manager']))) {
             $errors['ticket_alert_active']='Select recipient(s)';
         }
         if($vars['message_alert_active']
                 && (!isset($vars['message_alert_laststaff'])
                     && !isset($vars['message_alert_assigned'])
-                    && !isset($vars['message_alert_dept_manager']))) {
+                    && !isset($vars['message_alert_dept_manager'])
+                    && !isset($vars['message_alert_acct_manager']))) {
             $errors['message_alert_active']='Select recipient(s)';
         }
 
@@ -1106,10 +1116,12 @@ class OsticketConfig extends Config {
             'ticket_alert_admin'=>isset($vars['ticket_alert_admin'])?1:0,
             'ticket_alert_dept_manager'=>isset($vars['ticket_alert_dept_manager'])?1:0,
             'ticket_alert_dept_members'=>isset($vars['ticket_alert_dept_members'])?1:0,
+            'ticket_alert_acct_manager'=>isset($vars['ticket_alert_acct_manager'])?1:0,
             'message_alert_active'=>$vars['message_alert_active'],
             'message_alert_laststaff'=>isset($vars['message_alert_laststaff'])?1:0,
             'message_alert_assigned'=>isset($vars['message_alert_assigned'])?1:0,
             'message_alert_dept_manager'=>isset($vars['message_alert_dept_manager'])?1:0,
+            'message_alert_acct_manager'=>isset($vars['message_alert_acct_manager'])?1:0,
             'note_alert_active'=>$vars['note_alert_active'],
             'note_alert_laststaff'=>isset($vars['note_alert_laststaff'])?1:0,
             'note_alert_assigned'=>isset($vars['note_alert_assigned'])?1:0,
diff --git a/include/class.organization.php b/include/class.organization.php
index a837505fa4b61c1f40311e2d562f8a9081caa827..4f55f290b3d08d038c07c2d97552095d80932633 100644
--- a/include/class.organization.php
+++ b/include/class.organization.php
@@ -28,6 +28,12 @@ class OrganizationModel extends VerySimpleModel {
         )
     );
 
+    const COLLAB_ALL_MEMBERS =      0x0001;
+    const COLLAB_PRIMARY_CONTACT =  0x0002;
+    const ASSIGN_AGENT_MANAGER =    0x0004;
+
+    var $_manager;
+
     function getId() {
         return $this->id;
     }
@@ -36,6 +42,32 @@ class OrganizationModel extends VerySimpleModel {
         return $this->name;
     }
 
+    function getAccountManager() {
+        if (!isset($this->_manager)) {
+            if ($this->manager[0] == 't')
+                $this->_manager = Team::lookup(substr($this->manager, 1));
+            if ($this->manager[0] == 's')
+                $this->_manager = Staff::lookup(substr($this->manager, 1));
+        }
+        return $this->_manager;
+    }
+
+    function getAccountManagerId() {
+        return $this->manager;
+    }
+
+    function autoAddCollabs() {
+        return $this->check(self::COLLAB_ALL_MEMBERS | self::COLLAB_PRIMARY_CONTACT);
+    }
+
+    function autoAddPrimaryContactsAsCollabs() {
+        return $this->check(self::COLLAB_PRIMARY_CONTACT);
+    }
+
+    function autoAddMembersAsCollabs() {
+        return $this->check(self::COLLAB_ALL_MEMBERS);
+    }
+
     function getUpdateDate() {
         return $this->updated;
     }
@@ -43,6 +75,22 @@ class OrganizationModel extends VerySimpleModel {
     function getCreateDate() {
         return $this->created;
     }
+
+    function check($flag) {
+        return 0 !== ($this->status & $flag);
+    }
+
+    protected function clearStatus($flag) {
+        return $this->set('status', $this->get('status') & ~$flag);
+    }
+
+    protected function setStatus($flag) {
+        return $this->set('status', $this->get('status') | $flag);
+    }
+
+    function allMembers() {
+        return $this->users;
+    }
 }
 
 class Organization extends OrganizationModel {
@@ -96,6 +144,28 @@ class Organization extends OrganizationModel {
         return $this->_forms;
     }
 
+    function getInfo() {
+        $base = $this->ht;
+        foreach (array(
+                'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS,
+                'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT,
+                'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER,
+        ) as $ck=>$flag) {
+            if ($this->check($flag))
+                $base[$ck] = true;
+        }
+        return $base;
+    }
+
+    function isMappedToDomain($domain) {
+        foreach (explode(',', $this->domain) as $d) {
+            if (strcasecmp($domain, trim($d)) === 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     function to_json() {
 
         $info = array(
@@ -129,7 +199,29 @@ class Organization extends OrganizationModel {
             }
         }
 
-        if (!$valid)
+        if ($vars['domain']) {
+            foreach (explode(',', $vars['domain']) as $d) {
+                if (!Validator::is_email('t@' . trim($d))) {
+                    $errors['domain'] = 'Enter a valid email domain, like domain.com';
+                }
+            }
+        }
+
+        if ($vars['manager']) {
+            switch ($vars['manager'][0]) {
+            case 's':
+                if ($staff = Staff::lookup(substr($vars['manager'], 1)))
+                    break;
+            case 't':
+                if ($vars['manager'][0] == 't'
+                        && $team = Team::lookup(substr($vars['manager'], 1)))
+                    break;
+            default:
+                $errors['manager'] = 'Select a staff member or team from the list';
+            }
+        }
+
+        if (!$valid || $errors)
             return false;
 
         foreach ($this->getDynamicData() as $cd) {
@@ -142,7 +234,29 @@ class Organization extends OrganizationModel {
             $cd->save();
         }
 
-        return true;
+        // Set flags
+        foreach (array(
+                'collab-all-flag' => Organization::COLLAB_ALL_MEMBERS,
+                'collab-pc-flag' => Organization::COLLAB_PRIMARY_CONTACT,
+                'assign-am-flag' => Organization::ASSIGN_AGENT_MANAGER,
+        ) as $ck=>$flag) {
+            if ($vars[$ck])
+                $this->setStatus($flag);
+            else
+                $this->clearStatus($flag);
+        }
+
+        // Set staff and primary contacts
+        $this->set('domain', $vars['domain']);
+        $this->set('manager', $vars['manager'] ?: '');
+        if ($vars['contacts'] && is_array($vars['contacts'])) {
+            foreach ($this->allMembers() as $u) {
+                $u->setPrimaryContact(array_search($u->id, $vars['contacts']) !== false);
+                $u->save();
+            }
+        }
+
+        return $this->save();
     }
 
     static function fromVars($vars) {
diff --git a/include/class.ticket.php b/include/class.ticket.php
index a61717b811dcbd94460edd0167e135262dbbef67..0bf1e57d7c80e088db109e2e989914d464dd55eb 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -937,6 +937,16 @@ class Ticket {
             if($cfg->alertDeptManagerONNewTicket() && $dept && ($manager=$dept->getManager()))
                 $recipients[]= $manager;
 
+            // Account manager
+            if ($cfg->alertAcctManagerONNewMessage()
+                    && ($org = $this->getOwner()->getOrganization())
+                    && ($acct_manager = $org->getAcctManager())) {
+                if ($acct_manager instanceof Team)
+                    $recipients = array_merge($recipients, $acct_manager->getMembers());
+                else
+                    $recipients[] = $acct_manager;
+            }
+
             foreach( $recipients as $k=>$staff) {
                 if(!is_object($staff) || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
                 $alert = $this->replaceVars($msg, array('recipient' => $staff));
@@ -1132,7 +1142,7 @@ class Ticket {
                 $recipients[] = $assignee;
         } elseif(!strcasecmp(get_class($assignee), 'Team')) {
             if($cfg->alertTeamMembersONAssignment() && ($members=$assignee->getMembers()))
-                $recipients+=$members;
+                $recipients = array_merge($recipients, $members);
             elseif($cfg->alertTeamLeadONAssignment() && ($lead=$assignee->getTeamLead()))
                 $recipients[] = $lead;
         }
@@ -1388,11 +1398,11 @@ class Ticket {
                 if($this->getStaffId())
                     $recipients[]=$this->getStaff();
                 elseif($this->getTeamId() && ($team=$this->getTeam()) && ($members=$team->getMembers()))
-                    $recipients+=$members;
+                    $recipients = array_merge($recipients, $members);
             } elseif($cfg->alertDeptMembersONTransfer() && !$this->isAssigned()) {
                 //Only alerts dept members if the ticket is NOT assigned.
                 if(($members=$dept->getMembers()))
-                    $recipients+=$members;
+                    $recipients = array_merge($recipients, $members);
             }
 
             //Always alert dept manager??
@@ -1620,6 +1630,16 @@ class Ticket {
             if($cfg->alertDeptManagerONNewMessage() && $dept && ($manager=$dept->getManager()))
                 $recipients[]=$manager;
 
+            // Account manager
+            if ($cfg->alertAcctManagerONNewMessage()
+                    && ($org = $this->getOwner()->getOrganization())
+                    && ($acct_manager = $org->getAcctManager())) {
+                if ($acct_manager instanceof Team)
+                    $recipients = array_merge($recipients, $acct_manager->getMembers());
+                else
+                    $recipients[] = $acct_manager;
+            }
+
             $sentlist=array(); //I know it sucks...but..it works.
             foreach( $recipients as $k=>$staff) {
                 if(!$staff || !$staff->getEmail() || !$staff->isAvailable() || in_array($staff->getEmail(), $sentlist)) continue;
@@ -2333,6 +2353,15 @@ class Ticket {
             $source = 'Email';
         }
 
+        // Auto assignment to organization account manager
+        if (($org = $user->getOrganization())
+                && ($code = $org->getAccountManagerId())) {
+            if (!isset($vars['staffId']) && $code[0] == 's')
+                $vars['staffId'] = substr($code, 1);
+            elseif (!isset($vars['teamId']) && $code[0] == 't')
+                $vars['teamId'] = substr($code, 1);
+        }
+
         // Intenal mapping magic...see if we need to override anything
         if (isset($topic)) {
             $deptId = $deptId ?: $topic->getDeptId();
@@ -2409,6 +2438,28 @@ class Ticket {
 
         $dept = $ticket->getDept();
 
+        // Add organizational collaborators
+        if ($org && $org->autoAddCollabs()) {
+            $pris = $org->autoAddPrimaryContactsAsCollabs();
+            $members = $org->autoAddMembersAsCollabs();
+            $settings = array('isactive' => true);
+            $collabs = array();
+            foreach ($org->allMembers() as $u) {
+                if ($members || ($pris && $u->isPrimaryContact())) {
+                    if ($c = $this->addCollaborator($u, $settings, $errors)) {
+                        $collabs[] = (string) $c;
+                    }
+                }
+            }
+            //TODO: Can collaborators add others?
+            if ($collabs) {
+                //TODO: Change EndUser to name of  user.
+                $this->logNote(sprintf('Collaborators for %s organization added',
+                        $org->getName()),
+                    implode("<br>", $collabs), $org->getName(), false);
+            }
+        }
+
         //post the message.
         unset($vars['cannedattachments']); //Ticket::open() might have it set as part of  open & respond.
         $vars['title'] = $vars['subject']; //Use the initial subject as title of the post.
@@ -2418,11 +2469,18 @@ class Ticket {
         // Configure service-level-agreement for this ticket
         $ticket->selectSLAId($vars['slaId']);
 
-        //Auto assign staff or team - auto assignment based on filter rules.
-        if($vars['staffId'] && !$vars['assignId'])
-             $ticket->assignToStaff($vars['staffId'], 'Auto Assignment');
-        if($vars['teamId'] && !$vars['assignId'])
-            $ticket->assignToTeam($vars['teamId'], 'Auto Assignment');
+        // Assign ticket to staff or team (new ticket by staff)
+        if($vars['assignId']) {
+            $ticket->assign($vars['assignId'], $vars['note']);
+        }
+        else {
+            // Auto assign staff or team - auto assignment based on filter
+            // rules. Both team and staff can be assigned
+            if ($vars['staffId'])
+                 $ticket->assignToStaff($vars['staffId'], 'Auto Assignment');
+            if ($vars['teamId'])
+                $ticket->assignToTeam($vars['teamId'], 'Auto Assignment');
+        }
 
         /**********   double check auto-response  ************/
         //Override auto responder if the FROM email is one of the internal emails...loop control.
@@ -2489,7 +2547,10 @@ class Ticket {
                 $errors['name'] = 'Name required';
         }
 
-        if(!($ticket=Ticket::create($vars, $errors, 'staff', false, (!$vars['assignId']))))
+        if (!$thisstaff->canAssignTickets())
+            unset($vars['assignId']);
+
+        if(!($ticket=Ticket::create($vars, $errors, 'staff', false)))
             return false;
 
         $vars['msgId']=$ticket->getLastMsgId();
@@ -2510,13 +2571,14 @@ class Ticket {
             }
         }
 
-        //Post Internal note
-        if($vars['assignId'] && $thisstaff->canAssignTickets()) { //Assign ticket to staff or team.
-            $ticket->assign($vars['assignId'], $vars['note']);
-        } elseif($vars['note']) { //Not assigned...save optional note if any
+        // Not assigned...save optional note if any
+        if (!$vars['assignId'] && $vars['note']) {
             $ticket->logNote('New Ticket', $vars['note'], $thisstaff, false);
-        } else { //Not assignment and no internal note - log activity
-            $ticket->logActivity('New Ticket by Staff','Ticket created by staff -'.$thisstaff->getName());
+        }
+        else {
+            // Not assignment and no internal note - log activity
+            $ticket->logActivity('New Ticket by Staff',
+                'Ticket created by staff -'.$thisstaff->getName());
         }
 
         $ticket->reload();
diff --git a/include/class.user.php b/include/class.user.php
index 65f40b103f2b213350bbb6f97ce29419eb0b571d..8adb24ea07d5294cdcd2ad4d99331dd937c9789b 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -77,6 +77,8 @@ class UserModel extends VerySimpleModel {
         )
     );
 
+    const PRIMARY_ORG_CONTACT   = 0x0001;
+
     function getId() {
         return $this->id;
     }
@@ -110,6 +112,29 @@ class UserModel extends VerySimpleModel {
 
         return true;
     }
+
+    protected function hasStatus($flag) {
+        return $this->get('status') & $flag !== 0;
+    }
+
+    protected function clearStatus($flag) {
+        return $this->set('status', $this->get('status') & ~$flag);
+    }
+
+    protected function setStatus($flag) {
+        return $this->set('status', $this->get('status') | $flag);
+    }
+
+    function isPrimaryContact() {
+        return $this->hasStatus(User::PRIMARY_ORG_CONTACT);
+    }
+
+    function setPrimaryContact($flag) {
+        if ($flag)
+            $this->setStatus(User::PRIMARY_ORG_CONTACT);
+        else
+            $this->clearStatus(User::PRIMARY_ORG_CONTACT);
+    }
 }
 
 class User extends UserModel {
@@ -129,6 +154,16 @@ class User extends UserModel {
                 // of the detached emails is fixed.
                 'default_email' => UserEmail::ensure($vars['email'])
             ));
+            // Is there an organization registered for this domain
+            list($mailbox, $domain) = explode('@', $vars['email'], 2);
+            foreach (Organization::objects()
+                    ->filter(array('domain__contains'=>$domain)) as $org) {
+                if ($org->isMappedToDomain($domain)) {
+                    $user->setOrganization($org);
+                    break;
+                }
+            }
+
             $user->save(true);
             $user->emails->add($user->default_email);
             // Attach initial custom fields
diff --git a/include/class.validator.php b/include/class.validator.php
index c5cd2283eb362a58325e6291a3d2c5f245816116..28bf61c2b90f917c97b31a2b6bf049b2b7668299 100644
--- a/include/class.validator.php
+++ b/include/class.validator.php
@@ -140,13 +140,23 @@ class Validator {
 
     /*** Functions below can be called directly without class instance.
          Validator::func(var..);  (nolint) ***/
-    function is_email($email) {
-        if (strpos($email, '@') === false)
-            return false;
-
+    function is_email($email, $list=false) {
         require_once 'Mail/RFC822.php';
         require_once 'PEAR.php';
-        return !PEAR::isError(Mail_RFC822::parseAddressList($email));
+        if (!($mails = Mail_RFC822::parseAddressList($email)) || PEAR::isError($mails))
+            return false;
+
+        if (!$list && count($mails) > 1)
+            return false;
+
+        foreach ($mails as $m) {
+            if (!$m->mailbox)
+                return false;
+            if ($m->host == 'localhost')
+                return false;
+        }
+
+        return true;
     }
     function is_phone($phone) {
         /* We're not really validating the phone number but just making sure it doesn't contain illegal chars and of acceptable len */
diff --git a/include/i18n/en_US/help/tips/settings.alerts.yaml b/include/i18n/en_US/help/tips/settings.alerts.yaml
index 19fb979c9b472557ec09a9a3b51920afe422be4b..c0532f1ac482f33efabdc2d0acb02b0284c68c56 100644
--- a/include/i18n/en_US/help/tips/settings.alerts.yaml
+++ b/include/i18n/en_US/help/tips/settings.alerts.yaml
@@ -16,8 +16,14 @@
 new_ticket:
     title: New Ticket Alert
     content: >
+        <p>
         Alert sent out to staff members when new tickets are created in the
         system.
+        </p><p class="info-banner">
+        <i class="icon-info-sign"></i>
+        Staff members (department members) are not
+        notified with this alert if the ticket is automatically assigned.
+        </p>
     links:
       - title: Default New Ticket Alert Template
         href: /scp/templates.php?default_for=ticket.alert
diff --git a/include/staff/settings-alerts.inc.php b/include/staff/settings-alerts.inc.php
index 0ab5cb689367ca713400a67af17613d261eec4b8..c0dbc628e38bae07c38eac2da5a83258229e56c3 100644
--- a/include/staff/settings-alerts.inc.php
+++ b/include/staff/settings-alerts.inc.php
@@ -36,6 +36,11 @@
                 <input type="checkbox" name="ticket_alert_dept_members" <?php echo $config['ticket_alert_dept_members']?'checked':''; ?>> Department Members <em>(spammy)</em>
             </td>
         </tr>
+        <tr>
+            <td>
+                <input type="checkbox" name="ticket_alert_acct_manager" <?php echo $config['ticket_alert_acct_manager']?'checked':''; ?>> Organization Account Manager
+            </td>
+        </tr>
         <tr><th><em><b>New Message Alert</b>:
             <i class="help-tip icon-question-sign" href="#new_message"></i>
             </em></th></tr>
@@ -61,6 +66,11 @@
               <input type="checkbox" name="message_alert_dept_manager" <?php echo $config['message_alert_dept_manager']?'checked':''; ?>> Department Manager <em>(spammy)</em>
             </td>
         </tr>
+        <tr>
+            <td>
+                <input type="checkbox" name="message_alert_acct_manager" <?php echo $config['message_alert_acct_manager']?'checked':''; ?>> Organization Account Manager
+            </td>
+        </tr>
         <tr><th><em><b>New Internal Note Alert</b>:
             <i class="help-tip icon-question-sign" href="#new_activity"></i>
             </em></th></tr>
@@ -72,11 +82,6 @@
               &nbsp;&nbsp;&nbsp;<font class="error">&nbsp;<?php echo $errors['note_alert_active']; ?></font>
             </td>
         </tr>
-        <tr>
-            <td>
-              <input type="checkbox" name="note_alert_laststaff" <?php echo $config['note_alert_laststaff']?'checked':''; ?>> Last Respondent
-            </td>
-        </tr>
         <tr>
             <td>
               <input type="checkbox" name="note_alert_assigned" <?php echo $config['note_alert_assigned']?'checked':''; ?>> Assigned Staff
diff --git a/include/staff/templates/org-profile.tmpl.php b/include/staff/templates/org-profile.tmpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..3dda76484b0a7e0432957b2045eff10b83580f9f
--- /dev/null
+++ b/include/staff/templates/org-profile.tmpl.php
@@ -0,0 +1,171 @@
+<?php
+$info=($_POST && $errors)?Format::input($_POST):@Format::htmlchars($org->getInfo());
+
+if (!$info['title'])
+    $info['title'] = Format::htmlchars($org->getName());
+?>
+<script type="text/javascript" src="<?php echo ROOT_PATH; ?>js/jquery.multiselect.min.js"></script>
+<link rel="stylesheet" href="<?php echo ROOT_PATH; ?>css/jquery.multiselect.css"/>
+<h3><?php echo $info['title']; ?></h3>
+<b><a class="close" href="#"><i class="icon-remove-circle"></i></a></b>
+<hr/>
+<?php
+if ($info['error']) {
+    echo sprintf('<p id="msg_error">%s</p>', $info['error']);
+} elseif ($info['msg']) {
+    echo sprintf('<p id="msg_notice">%s</p>', $info['msg']);
+} ?>
+<ul class="tabs">
+    <li><a href="#tab-profile" class="active"
+        ><i class="icon-edit"></i>&nbsp;Fields</a></li>
+    <li><a href="#contact-settings"
+        ><i class="icon-fixed-width icon-cogs faded"></i>&nbsp;Settings</a></li>
+</ul>
+<form method="post" class="org" action="<?php echo $action; ?>">
+
+<div class="tab_content" id="tab-profile" style="margin:5px;">
+<?php
+$action = $info['action'] ? $info['action'] : ('#orgs/'.$org->getId());
+if ($ticket && $ticket->getOwnerId() == $user->getId())
+    $action = '#tickets/'.$ticket->getId().'/user';
+?>
+    <input type="hidden" name="id" value="<?php echo $org->getId(); ?>" />
+    <table width="100%">
+    <?php
+        if (!$forms) $forms = $org->getForms();
+        foreach ($forms as $form)
+            $form->render();
+    ?>
+    </table>
+</div>
+
+<div class="tab_content" id="contact-settings" style="display:none;margin:5px;">
+    <table style="width:100%">
+        <tbody>
+            <tr>
+                <td width="180">
+                    Account Manager:
+                </td>
+                <td>
+                    <select name="manager">
+                        <option value="0" selected="selected">&mdash; None &mdash;</option><?php
+                        if ($users=Staff::getAvailableStaffMembers()) { ?>
+                            <optgroup label="Staff Members (<?php echo count($users); ?>)">
+<?php                       foreach($users as $id => $name) {
+                                $k = "s$id";
+                                echo sprintf('<option value="%s" %s>%s</option>',
+                                    $k,(($info['manager']==$k)?'selected="selected"':''),$name);
+                            }
+                            echo '</optgroup>';
+                        }
+
+                        if ($teams=Team::getActiveTeams()) { ?>
+                            <optgroup label="Teams (<?php echo count($teams); ?>)">
+<?php                       foreach($teams as $id => $name) {
+                                $k="t$id";
+                                echo sprintf('<option value="%s" %s>%s</option>',
+                                    $k,(($info['manager']==$k)?'selected="selected"':''),$name);
+                            }
+                            echo '</optgroup>';
+                        } ?>
+                    </select>
+                    <br/><span class="error"><?php echo $errors['manager']; ?></span>
+                </td>
+            </tr>
+            <tr>
+                <td width="180">
+                    Auto-Assignment:
+                </td>
+                <td>
+                    <input type="checkbox" name="assign-am-flag" value="1" <?php echo $info['assign-am-flag']?'checked="checked"':''; ?>>
+                    Assign tickets from this organization to the <em>Account Manager</em>
+            </tr>
+            <tr>
+                <td width="180">
+                    Primary Contacts:
+                </td>
+                <td>
+                    <select name="contacts[]" id="primary_contacts" multiple="multiple">
+<?php               foreach ($org->allMembers() as $u) { ?>
+                        <option value="<?php echo $u->id; ?>" <?php
+                            if ($u->isPrimaryContact())
+                            echo 'selected="selected"'; ?>><?php echo $u->getName(); ?></option>
+<?php               } ?>
+                    </select>
+                    <br/><span class="error"><?php echo $errors['contacts']; ?></span>
+                </td>
+            <tr>
+                <th colspan="2">
+                    Automated Collaboration:
+                </th>
+            </tr>
+            <tr>
+                <td width="180">
+                    Primary Contacts:
+                </td>
+                <td>
+                    <input type="checkbox" name="collab-pc-flag" value="1" <?php echo $info['collab-pc-flag']?'checked="checked"':''; ?>>
+                    Add to all tickets from this organization
+                </td>
+            </tr>
+            <tr>
+                <td width="180">
+                    Organization Members:
+                </td>
+                <td>
+                    <input type="checkbox" name="collab-all-flag" value="1" <?php echo $info['collab-all-flag']?'checked="checked"':''; ?>>
+                    Add to all tickets from this organization
+                </td>
+            </tr>
+            <tr>
+                <th colspan="2">
+                    Main Domain
+                </th>
+            </tr>
+            <tr>
+                <td style="width:180px">
+                    Auto Add Members From:
+                </td>
+                <td>
+                    <input type="text" size="40" maxlength="60" name="domain"
+                        value="<?php echo $info['domain']; ?>" />
+                    <br/><span class="error"><?php echo $errors['domain']; ?></span>
+                </td>
+            </tr>
+        </tbody>
+    </table>
+</div>
+
+<div class="clear"></div>
+
+<hr>
+<p class="full-width">
+    <span class="buttons" style="float:left">
+        <input type="reset" value="Reset">
+        <input type="button" name="cancel" class="<?php
+echo $account ? 'cancel' : 'close'; ?>"  value="Cancel">
+    </span>
+    <span class="buttons" style="float:right">
+        <input type="submit" value="Update Organization">
+    </span>
+</p>
+</form>
+
+<script type="text/javascript">
+$(function() {
+    $('a#editorg').click( function(e) {
+        e.preventDefault();
+        $('div#org-profile').hide();
+        $('div#org-form').fadeIn();
+        return false;
+     });
+
+    $(document).on('click', 'form.org input.cancel', function (e) {
+        e.preventDefault();
+        $('div#org-form').hide();
+        $('div#org-profile').fadeIn();
+        return false;
+    });
+    $("#primary_contacts").multiselect({'noneSelectedText':'Select Contacts'});
+});
+</script>
diff --git a/js/jquery.multiselect.min.js b/js/jquery.multiselect.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9243506c0555f0d53b58b40d5d185ace8035b7c
--- /dev/null
+++ b/js/jquery.multiselect.min.js
@@ -0,0 +1,20 @@
+/*
+ * jQuery MultiSelect UI Widget 1.13
+ * Copyright (c) 2012 Eric Hynds
+ *
+ * http://www.erichynds.com/jquery/jquery-ui-multiselect-widget/
+ *
+ * Depends:
+ *   - jQuery 1.4.2+
+ *   - jQuery UI 1.8 widget factory
+ *
+ * Optional:
+ *   - jQuery UI effects
+ *   - jQuery UI position utility
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ */
+(function(d){var k=0;d.widget("ech.multiselect",{options:{header:!0,height:175,minWidth:225,classes:"",checkAllText:"Check all",uncheckAllText:"Uncheck all",noneSelectedText:"Select options",selectedText:"# selected",selectedList:0,show:null,hide:null,autoOpen:!1,multiple:!0,position:{}},_create:function(){var a=this.element.hide(),b=this.options;this.speed=d.fx.speeds._default;this._isOpen=!1;a=(this.button=d('<button type="button"><span class="ui-icon ui-icon-triangle-2-n-s"></span></button>')).addClass("ui-multiselect ui-widget ui-state-default ui-corner-all").addClass(b.classes).attr({title:a.attr("title"),"aria-haspopup":!0,tabIndex:a.attr("tabIndex")}).insertAfter(a);(this.buttonlabel=d("<span />")).html(b.noneSelectedText).appendTo(a);var a=(this.menu=d("<div />")).addClass("ui-multiselect-menu ui-widget ui-widget-content ui-corner-all").addClass(b.classes).appendTo(document.body),c=(this.header=d("<div />")).addClass("ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix").appendTo(a);(this.headerLinkContainer=d("<ul />")).addClass("ui-helper-reset").html(function(){return!0===b.header?'<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>'+b.checkAllText+'</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>'+b.uncheckAllText+"</span></a></li>":"string"===typeof b.header?"<li>"+b.header+"</li>":""}).append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>').appendTo(c);(this.checkboxContainer=d("<ul />")).addClass("ui-multiselect-checkboxes ui-helper-reset").appendTo(a);this._bindEvents();this.refresh(!0);b.multiple||a.addClass("ui-multiselect-single")},_init:function(){!1===this.options.header&&this.header.hide();this.options.multiple||this.headerLinkContainer.find(".ui-multiselect-all, .ui-multiselect-none").hide();this.options.autoOpen&&this.open();this.element.is(":disabled")&&this.disable()},refresh:function(a){var b=this.element,c=this.options,f=this.menu,h=this.checkboxContainer,g=[],e="",i=b.attr("id")||k++;b.find("option").each(function(b){d(this);var a=this.parentNode,f=this.innerHTML,h=this.title,k=this.value,b="ui-multiselect-"+(this.id||i+"-option-"+b),l=this.disabled,n=this.selected,m=["ui-corner-all"],o=(l?"ui-multiselect-disabled ":" ")+this.className,j;"OPTGROUP"===a.tagName&&(j=a.getAttribute("label"),-1===d.inArray(j,g)&&(e+='<li class="ui-multiselect-optgroup-label '+a.className+'"><a href="#">'+j+"</a></li>",g.push(j)));l&&m.push("ui-state-disabled");n&&!c.multiple&&m.push("ui-state-active");e+='<li class="'+o+'">';e+='<label for="'+b+'" title="'+h+'" class="'+m.join(" ")+'">';e+='<input id="'+b+'" name="multiselect_'+i+'" type="'+(c.multiple?"checkbox":"radio")+'" value="'+k+'" title="'+f+'"';n&&(e+=' checked="checked"',e+=' aria-selected="true"');l&&(e+=' disabled="disabled"',e+=' aria-disabled="true"');e+=" /><span>"+f+"</span></label></li>"});h.html(e);this.labels=f.find("label");this.inputs=this.labels.children("input");this._setButtonWidth();this._setMenuWidth();this.button[0].defaultValue=this.update();a||this._trigger("refresh")},update:function(){var a=this.options,b=this.inputs,c=b.filter(":checked"),f=c.length,a=0===f?a.noneSelectedText:d.isFunction(a.selectedText)?a.selectedText.call(this,f,b.length,c.get()):/\d/.test(a.selectedList)&&0<a.selectedList&&f<=a.selectedList?c.map(function(){return d(this).next().html()}).get().join(", "):a.selectedText.replace("#",f).replace("#",b.length);this.buttonlabel.html(a);return a},_bindEvents:function(){function a(){b[b._isOpen? "close":"open"]();return!1}var b=this,c=this.button;c.find("span").bind("click.multiselect",a);c.bind({click:a,keypress:function(a){switch(a.which){case 27:case 38:case 37:b.close();break;case 39:case 40:b.open()}},mouseenter:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-hover")},mouseleave:function(){d(this).removeClass("ui-state-hover")},focus:function(){c.hasClass("ui-state-disabled")||d(this).addClass("ui-state-focus")},blur:function(){d(this).removeClass("ui-state-focus")}});this.header.delegate("a","click.multiselect",function(a){if(d(this).hasClass("ui-multiselect-close"))b.close();else b[d(this).hasClass("ui-multiselect-all")?"checkAll":"uncheckAll"]();a.preventDefault()});this.menu.delegate("li.ui-multiselect-optgroup-label a","click.multiselect",function(a){a.preventDefault();var c=d(this),g=c.parent().nextUntil("li.ui-multiselect-optgroup-label").find("input:visible:not(:disabled)"),e=g.get(),c=c.parent().text();!1!==b._trigger("beforeoptgrouptoggle",a,{inputs:e,label:c})&&(b._toggleChecked(g.filter(":checked").length!==g.length,g),b._trigger("optgrouptoggle",a,{inputs:e,label:c,checked:e[0].checked}))}).delegate("label","mouseenter.multiselect",function(){d(this).hasClass("ui-state-disabled")||(b.labels.removeClass("ui-state-hover"),d(this).addClass("ui-state-hover").find("input").focus())}).delegate("label","keydown.multiselect",function(a){a.preventDefault();switch(a.which){case 9:case 27:b.close();break;case 38:case 40:case 37:case 39:b._traverse(a.which,this);break;case 13:d(this).find("input")[0].click()}}).delegate('input[type="checkbox"], input[type="radio"]',"click.multiselect",function(a){var c=d(this),g=this.value,e=this.checked,i=b.element.find("option");this.disabled||!1===b._trigger("click",a,{value:g,text:this.title,checked:e})?a.preventDefault():(c.focus(),c.attr("aria-selected",e),i.each(function(){this.value===g?this.selected=e:b.options.multiple||(this.selected=!1)}),b.options.multiple||(b.labels.removeClass("ui-state-active"),c.closest("label").toggleClass("ui-state-active",e),b.close()),b.element.trigger("change"),setTimeout(d.proxy(b.update,b),10))});d(document).bind("mousedown.multiselect",function(a){b._isOpen&&(!d.contains(b.menu[0],a.target)&&!d.contains(b.button[0],a.target)&&a.target!==b.button[0])&&b.close()});d(this.element[0].form).bind("reset.multiselect",function(){setTimeout(d.proxy(b.refresh,b),10)})},_setButtonWidth:function(){var a=this.element.outerWidth(),b=this.options;/\d/.test(b.minWidth)&&a<b.minWidth&&(a=b.minWidth);this.button.width(a)},_setMenuWidth:function(){var a=this.menu,b=this.button.outerWidth()-parseInt(a.css("padding-left"),10)-parseInt(a.css("padding-right"),10)-parseInt(a.css("border-right-width"),10)-parseInt(a.css("border-left-width"),10);a.width(b||this.button.outerWidth())},_traverse:function(a,b){var c=d(b),f=38===a||37===a,c=c.parent()[f?"prevAll":"nextAll"]("li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)")[f?"last":"first"]();c.length?c.find("label").trigger("mouseover"):(c=this.menu.find("ul").last(),this.menu.find("label")[f? "last":"first"]().trigger("mouseover"),c.scrollTop(f?c.height():0))},_toggleState:function(a,b){return function(){this.disabled||(this[a]=b);b?this.setAttribute("aria-selected",!0):this.removeAttribute("aria-selected")}},_toggleChecked:function(a,b){var c=b&&b.length?b:this.inputs,f=this;c.each(this._toggleState("checked",a));c.eq(0).focus();this.update();var h=c.map(function(){return this.value}).get();this.element.find("option").each(function(){!this.disabled&&-1<d.inArray(this.value,h)&&f._toggleState("selected",a).call(this)});c.length&&this.element.trigger("change")},_toggleDisabled:function(a){this.button.attr({disabled:a,"aria-disabled":a})[a?"addClass":"removeClass"]("ui-state-disabled");var b=this.menu.find("input"),b=a?b.filter(":enabled").data("ech-multiselect-disabled",!0):b.filter(function(){return!0===d.data(this,"ech-multiselect-disabled")}).removeData("ech-multiselect-disabled");b.attr({disabled:a,"arial-disabled":a}).parent()[a?"addClass":"removeClass"]("ui-state-disabled");this.element.attr({disabled:a,"aria-disabled":a})},open:function(){var a=this.button,b=this.menu,c=this.speed,f=this.options,h=[];if(!(!1===this._trigger("beforeopen")||a.hasClass("ui-state-disabled")||this._isOpen)){var g=b.find("ul").last(),e=f.show,i=a.offset();d.isArray(f.show)&&(e=f.show[0],c=f.show[1]||this.speed);e&&(h=[e,c]);g.scrollTop(0).height(f.height);d.ui.position&&!d.isEmptyObject(f.position)?(f.position.of=f.position.of||a,b.show().position(f.position).hide()):b.css({top:i.top+a.outerHeight(),left:i.left});d.fn.show.apply(b,h);this.labels.eq(0).trigger("mouseover").trigger("mouseenter").find("input").trigger("focus");a.addClass("ui-state-active");this._isOpen=!0;this._trigger("open")}},close:function(){if(!1!==this._trigger("beforeclose")){var a=this.options,b=a.hide,c=this.speed,f=[];d.isArray(a.hide)&&(b=a.hide[0],c=a.hide[1]||this.speed);b&&(f=[b,c]);d.fn.hide.apply(this.menu,f);this.button.removeClass("ui-state-active").trigger("blur").trigger("mouseleave");this._isOpen=!1;this._trigger("close")}},enable:function(){this._toggleDisabled(!1)},disable:function(){this._toggleDisabled(!0)},checkAll:function(){this._toggleChecked(!0);this._trigger("checkAll")},uncheckAll:function(){this._toggleChecked(!1);this._trigger("uncheckAll")},getChecked:function(){return this.menu.find("input").filter(":checked")},destroy:function(){d.Widget.prototype.destroy.call(this);this.button.remove();this.menu.remove();this.element.show();return this},isOpen:function(){return this._isOpen},widget:function(){return this.menu},getButton:function(){return this.button},_setOption:function(a,b){var c=this.menu;switch(a){case "header":c.find("div.ui-multiselect-header")[b?"show":"hide"]();break;case "checkAllText":c.find("a.ui-multiselect-all span").eq(-1).text(b);break;case "uncheckAllText":c.find("a.ui-multiselect-none span").eq(-1).text(b);break;case "height":c.find("ul").last().height(parseInt(b,10));break;case "minWidth":this.options[a]=parseInt(b,10);this._setButtonWidth();this._setMenuWidth();break;case "selectedText":case "selectedList":case "noneSelectedText":this.options[a]=b;this.update();break;case "classes":c.add(this.button).removeClass(this.options.classes).addClass(b);break;case "multiple":c.toggleClass("ui-multiselect-single",!b),this.options.multiple=b,this.element[0].multiple=b,this.refresh()}d.Widget.prototype._setOption.apply(this,arguments)}})})(jQuery);
diff --git a/scp/ajax.php b/scp/ajax.php
index 27fb8022a9d143a2856bc3ad95b686dfef8ffb06..d0830bdf84cf81116154d9caf9f29fd0b1272d28 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -96,6 +96,7 @@ $dispatcher = patterns('',
         url_get('^/search$', 'search'),
         url_get('^/(?P<id>\d+)$', 'getOrg'),
         url_post('^/(?P<id>\d+)$', 'updateOrg'),
+        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'),
diff --git a/scp/css/scp.css b/scp/css/scp.css
index c73e107cf7fa7b7d8c54417541f7490909acc36a..ce9023b6cbe3e735d8e36bb326eda625154770ed 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -51,13 +51,17 @@ a {
     color: #555;
 }
 
-#msg_info { margin: 0; padding: 5px; margin-bottom: 10px; color: #3a87ad; border: 1px solid #bce8f1;  background-color: #d9edf7; }
+#msg_info,
+.info-banner { margin: 0; padding: 5px; margin-bottom: 10px; color: #3a87ad; border: 1px solid #bce8f1;  background-color: #d9edf7; }
 
-#msg_notice { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png') 10px 50% no-repeat #e0ffe0; }
+#msg_notice,
+.notice-banner { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png') 10px 50% no-repeat #e0ffe0; }
 
-#msg_warning { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png') 10px 50% no-repeat #ffffdd; }
+#msg_warning,
+.warning-banner { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png') 10px 50% no-repeat #ffffdd; }
 
-#msg_error { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; }
+#msg_error,
+.error-banner { margin: 0; padding: 5px 10px 5px 36px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; }
 
 #notice_bar { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; border: 1px solid #0a0; background: url('../images/icons/ok.png') 10px 50% no-repeat #e0ffe0; }
 
diff --git a/scp/js/scp.js b/scp/js/scp.js
index 79f5804f2c5727ecf13694b4f4f5112020aa2987..e2bb171c5a8a7a0e1beef6ce8a7bc1b068304d3f 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -589,9 +589,10 @@ $(document).ready(function(){
    $(document).on('click.tab', 'ul.tabs li a', function(e) {
         e.preventDefault();
         if ($('.tab_content'+$(this).attr('href')).length) {
-            $('ul.tabs li a', $(this).closest('ul').parent()).removeClass('active');
+            var ul = $(this).closest('ul');
+            $('ul.tabs li a', ul.parent()).removeClass('active');
             $(this).addClass('active');
-            $('.tab_content').hide();
+            $('.tab_content', ul.parent()).hide();
             $('.tab_content'+$(this).attr('href')).show();
         }
     });
diff --git a/setup/test/tests/test.validation.php b/setup/test/tests/test.validation.php
index 27e61af8438a4fc8a75bcb3003013af6ab56801d..bce9fe85505d08e41251fc127e230bba9f775394 100644
--- a/setup/test/tests/test.validation.php
+++ b/setup/test/tests/test.validation.php
@@ -37,6 +37,9 @@ class TestValidation extends Test {
         // Illegal or unsupported
         $this->assert(!Validator::is_email('jared r@domain.tld'));
         $this->assert(!Validator::is_email('jared'));
+        $this->assert(!Validator::is_email('jared@'));
+        $this->assert(!Validator::is_email('@domain.tld'));
+        $this->assert(!Validator::is_email('@domain.tld, @domain2.tld'));
 
         // Odd cases, but legal
         $this->assert(Validator::is_email('jared@host'));