public function testMailSendFailures()
 {
     $user = $this->generateNewTestUser();
     $phid = $user->getPHID();
     // Normally, the send should succeed.
     $mail = new PhabricatorMetaMTAMail();
     $mail->addTos(array($phid));
     $mailer = new PhabricatorMailImplementationTestAdapter();
     $mail->sendNow($force = true, $mailer);
     $this->assertEqual(PhabricatorMetaMTAMail::STATUS_SENT, $mail->getStatus());
     // When the mailer fails temporarily, the mail should remain queued.
     $mail = new PhabricatorMetaMTAMail();
     $mail->addTos(array($phid));
     $mailer = new PhabricatorMailImplementationTestAdapter();
     $mailer->setFailTemporarily(true);
     try {
         $mail->sendNow($force = true, $mailer);
     } catch (Exception $ex) {
         // Ignore.
     }
     $this->assertEqual(PhabricatorMetaMTAMail::STATUS_QUEUE, $mail->getStatus());
     // When the mailer fails permanently, the mail should be failed.
     $mail = new PhabricatorMetaMTAMail();
     $mail->addTos(array($phid));
     $mailer = new PhabricatorMailImplementationTestAdapter();
     $mailer->setFailPermanently(true);
     try {
         $mail->sendNow($force = true, $mailer);
     } catch (Exception $ex) {
         // Ignore.
     }
     $this->assertEqual(PhabricatorMetaMTAMail::STATUS_FAIL, $mail->getStatus());
 }
 public function processRequest()
 {
     // Get a page of mails together with pager.
     $request = $this->getRequest();
     $user = $request->getUser();
     $offset = $request->getInt('offset', 0);
     $related_phid = $request->getStr('phid');
     $status = $request->getStr('status');
     $pager = new AphrontPagerView();
     $pager->setOffset($offset);
     $pager->setURI($request->getRequestURI(), 'offset');
     $mail = new PhabricatorMetaMTAMail();
     $conn_r = $mail->establishConnection('r');
     $wheres = array();
     if ($status) {
         $wheres[] = qsprintf($conn_r, 'status = %s', $status);
     }
     if ($related_phid) {
         $wheres[] = qsprintf($conn_r, 'relatedPHID = %s', $related_phid);
     }
     if (count($wheres)) {
         $where_clause = 'WHERE ' . implode($wheres, ' AND ');
     } else {
         $where_clause = 'WHERE 1 = 1';
     }
     $data = queryfx_all($conn_r, 'SELECT * FROM %T
     %Q
     ORDER BY id DESC
     LIMIT %d, %d', $mail->getTableName(), $where_clause, $pager->getOffset(), $pager->getPageSize() + 1);
     $data = $pager->sliceResults($data);
     $mails = $mail->loadAllFromArray($data);
     // Render the details table.
     $rows = array();
     foreach ($mails as $mail) {
         $next_retry = $mail->getNextRetry() - time();
         if ($next_retry <= 0) {
             $next_retry = "None";
         } else {
             $next_retry = phabricator_format_relative_time_detailed($next_retry);
         }
         $rows[] = array(PhabricatorMetaMTAMail::getReadableStatus($mail->getStatus()), $mail->getRetryCount(), $next_retry, phabricator_datetime($mail->getDateCreated(), $user), phabricator_format_relative_time_detailed(time() - $mail->getDateModified()), phutil_escape_html($mail->getSubject()), phutil_render_tag('a', array('class' => 'button small grey', 'href' => $this->getApplicationURI('/view/' . $mail->getID() . '/')), 'View'));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Status', 'Retry', 'Next', 'Created', 'Updated', 'Subject', ''));
     $table->setColumnClasses(array(null, null, null, null, null, 'wide', 'action'));
     // Render the whole page.
     $panel = new AphrontPanelView();
     $panel->appendChild($table);
     $panel->setHeader('MetaMTA Messages');
     $panel->appendChild($pager);
     $nav = $this->buildSideNavView();
     $nav->selectFilter('sent');
     $nav->appendChild($panel);
     return $this->buildApplicationPage($nav, array('title' => 'Sent Mail'));
 }
 public function processRequest()
 {
     // Get a page of mails together with pager.
     $request = $this->getRequest();
     $user = $request->getUser();
     $offset = $request->getInt('offset', 0);
     $related_phid = $request->getStr('phid');
     $pager = new AphrontPagerView();
     $pager->setOffset($offset);
     $pager->setURI($request->getRequestURI(), 'offset');
     $mail = new PhabricatorMetaMTAMail();
     $conn_r = $mail->establishConnection('r');
     if ($related_phid) {
         $where_clause = qsprintf($conn_r, 'WHERE relatedPHID = %s', $related_phid);
     } else {
         $where_clause = 'WHERE 1 = 1';
     }
     $data = queryfx_all($conn_r, 'SELECT * FROM %T
     %Q
     ORDER BY id DESC
     LIMIT %d, %d', $mail->getTableName(), $where_clause, $pager->getOffset(), $pager->getPageSize() + 1);
     $data = $pager->sliceResults($data);
     $mails = $mail->loadAllFromArray($data);
     // Render the details table.
     $rows = array();
     foreach ($mails as $mail) {
         $rows[] = array(PhabricatorMetaMTAMail::getReadableStatus($mail->getStatus()), $mail->getRetryCount(), $mail->getNextRetry() - time() . ' s', phabricator_datetime($mail->getDateCreated(), $user), time() - $mail->getDateModified() . ' s', phutil_escape_html($mail->getSubject()), phutil_render_tag('a', array('class' => 'button small grey', 'href' => '/mail/view/' . $mail->getID() . '/'), 'View'));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Status', 'Retry', 'Next', 'Created', 'Updated', 'Subject', ''));
     $table->setColumnClasses(array(null, null, null, null, null, 'wide', 'action'));
     // Render the whole page.
     $panel = new AphrontPanelView();
     $panel->appendChild($table);
     $panel->setHeader('MetaMTA Messages');
     if ($user->getIsAdmin()) {
         $panel->setCreateButton('Send New Test Message', '/mail/send/');
     }
     $panel->appendChild($pager);
     return $this->buildStandardPageResponse($panel, array('title' => 'MetaMTA', 'tab' => 'queue'));
 }
 private function buildDeliveryProperties(PhabricatorMetaMTAMail $mail)
 {
     $viewer = $this->getViewer();
     $properties = id(new PHUIPropertyListView())->setUser($viewer);
     $actors = $mail->getDeliveredActors();
     $reasons = null;
     if (!$actors) {
         if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
             $delivery = $this->renderEmptyMessage(pht('This message has not been delivered yet, so delivery information ' . 'is not available.'));
         } else {
             $delivery = $this->renderEmptyMessage(pht('This is an older message that predates recording delivery ' . 'information, so none is available.'));
         }
     } else {
         $actor = idx($actors, $viewer->getPHID());
         if (!$actor) {
             $delivery = phutil_tag('em', array(), pht('This message was not delivered to you.'));
         } else {
             $deliverable = $actor['deliverable'];
             if ($deliverable) {
                 $delivery = pht('Delivered');
             } else {
                 $delivery = pht('Voided');
             }
             $reasons = id(new PHUIStatusListView());
             $reason_codes = $actor['reasons'];
             if (!$reason_codes) {
                 $reason_codes = array(PhabricatorMetaMTAActor::REASON_NONE);
             }
             $icon_yes = 'fa-check green';
             $icon_no = 'fa-times red';
             foreach ($reason_codes as $reason) {
                 $target = phutil_tag('strong', array(), PhabricatorMetaMTAActor::getReasonName($reason));
                 if (PhabricatorMetaMTAActor::isDeliveryReason($reason)) {
                     $icon = $icon_yes;
                 } else {
                     $icon = $icon_no;
                 }
                 $item = id(new PHUIStatusItemView())->setIcon($icon)->setTarget($target)->setNote(PhabricatorMetaMTAActor::getReasonDescription($reason));
                 $reasons->addItem($item);
             }
         }
     }
     $properties->addProperty(pht('Delivery'), $delivery);
     if ($reasons) {
         $properties->addProperty(pht('Reasons'), $reasons);
         $properties->addProperty(null, $this->renderEmptyMessage(pht('Delivery reasons are listed from weakest to strongest.')));
     }
     $properties->addSectionHeader(pht('Routing Rules'), 'fa-paper-plane-o');
     $map = $mail->getDeliveredRoutingMap();
     $routing_detail = null;
     if ($map === null) {
         if ($mail->getStatus() == PhabricatorMailOutboundStatus::STATUS_QUEUE) {
             $routing_result = $this->renderEmptyMessage(pht('This message has not been sent yet, so routing rules have ' . 'not been computed.'));
         } else {
             $routing_result = $this->renderEmptyMessage(pht('This is an older message which predates routing rules.'));
         }
     } else {
         $rule = idx($map, $viewer->getPHID());
         if ($rule === null) {
             $rule = idx($map, 'default');
         }
         if ($rule === null) {
             $routing_result = $this->renderEmptyMessage(pht('No routing rules applied when delivering this message to you.'));
         } else {
             $rule_const = $rule['rule'];
             $reason_phid = $rule['reason'];
             switch ($rule_const) {
                 case PhabricatorMailRoutingRule::ROUTE_AS_NOTIFICATION:
                     $routing_result = pht('This message was routed as a notification because it ' . 'matched %s.', $viewer->renderHandle($reason_phid)->render());
                     break;
                 case PhabricatorMailRoutingRule::ROUTE_AS_MAIL:
                     $routing_result = pht('This message was routed as an email because it matched %s.', $viewer->renderHandle($reason_phid)->render());
                     break;
                 default:
                     $routing_result = pht('Unknown routing rule "%s".', $rule_const);
                     break;
             }
         }
         $routing_rules = $mail->getDeliveredRoutingRules();
         if ($routing_rules) {
             $rules = array();
             foreach ($routing_rules as $rule) {
                 $phids = idx($rule, 'phids');
                 if ($phids === null) {
                     $rules[] = $rule;
                 } else {
                     if (in_array($viewer->getPHID(), $phids)) {
                         $rules[] = $rule;
                     }
                 }
             }
             // Reorder rules by strength.
             foreach ($rules as $key => $rule) {
                 $const = $rule['routingRule'];
                 $phids = $rule['phids'];
                 if ($phids === null) {
                     $type = 'A';
                 } else {
                     $type = 'B';
                 }
                 $rules[$key]['strength'] = sprintf('~%s%08d', $type, PhabricatorMailRoutingRule::getRuleStrength($const));
             }
             $rules = isort($rules, 'strength');
             $routing_detail = id(new PHUIStatusListView());
             foreach ($rules as $rule) {
                 $const = $rule['routingRule'];
                 $phids = $rule['phids'];
                 $name = PhabricatorMailRoutingRule::getRuleName($const);
                 $icon = PhabricatorMailRoutingRule::getRuleIcon($const);
                 $color = PhabricatorMailRoutingRule::getRuleColor($const);
                 if ($phids === null) {
                     $kind = pht('Global');
                 } else {
                     $kind = pht('Personal');
                 }
                 $target = array($kind, ': ', $name);
                 $target = phutil_tag('strong', array(), $target);
                 $item = id(new PHUIStatusItemView())->setTarget($target)->setNote($viewer->renderHandle($rule['reasonPHID']))->setIcon($icon, $color);
                 $routing_detail->addItem($item);
             }
         }
     }
     $properties->addProperty(pht('Effective Rule'), $routing_result);
     if ($routing_detail !== null) {
         $properties->addProperty(pht('All Matching Rules'), $routing_detail);
         $properties->addProperty(null, $this->renderEmptyMessage(pht('Matching rules are listed from weakest to strongest.')));
     }
     return $properties;
 }