protected function processReceivedObjectMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorLiskDAO $object, PhabricatorUser $sender)
 {
     $handler = DifferentialMail::newReplyHandlerForRevision($object);
     $handler->setActor($sender);
     $handler->setExcludeMailRecipientPHIDs($mail->loadExcludeMailRecipientPHIDs());
     $handler->processEmail($mail);
 }
 public function processReceivedMail()
 {
     $to = idx($this->headers, 'to');
     $to = $this->getRawEmailAddress($to);
     $from = idx($this->headers, 'from');
     $create_task = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email');
     if ($create_task && $to == $create_task) {
         $receiver = new ManiphestTask();
         $user = $this->lookupPublicUser();
         if ($user) {
             $this->setAuthorPHID($user->getPHID());
         } else {
             $default_author = PhabricatorEnv::getEnvConfig('metamta.maniphest.default-public-author');
             if ($default_author) {
                 $user = id(new PhabricatorUser())->loadOneWhere('username = %s', $default_author);
                 if ($user) {
                     $receiver->setOriginalEmailSource($from);
                 } else {
                     throw new Exception("Phabricator is misconfigured, the configuration key " . "'metamta.maniphest.default-public-author' is set to user " . "'{$default_author}' but that user does not exist.");
                 }
             } else {
                 // TODO: We should probably bounce these since from the user's
                 // perspective their email vanishes into a black hole.
                 return $this->setMessage("Invalid public user '{$from}'.")->save();
             }
         }
         $receiver->setAuthorPHID($user->getPHID());
         $receiver->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
         $handler->setActor($user);
         $handler->receiveEmail($this);
         $this->setRelatedPHID($receiver->getPHID());
         $this->setMessage('OK');
         return $this->save();
     }
     // We've already stripped this, so look for an object address which has
     // a format like: D291+291+b0a41ca848d66dcc@example.com
     $matches = null;
     $single_handle_prefix = PhabricatorEnv::getEnvConfig('metamta.single-reply-handler-prefix');
     $prefixPattern = $single_handle_prefix ? preg_quote($single_handle_prefix, '/') . '\\+' : '';
     $pattern = "/^{$prefixPattern}((?:D|T)\\d+)\\+([\\w]+)\\+([a-f0-9]{16})@/U";
     $ok = preg_match($pattern, $to, $matches);
     if (!$ok) {
         return $this->setMessage("Unrecognized 'to' format: {$to}")->save();
     }
     $receiver_name = $matches[1];
     $user_id = $matches[2];
     $hash = $matches[3];
     if ($user_id == 'public') {
         if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
             return $this->setMessage("Public replies not enabled.")->save();
         }
         $user = $this->lookupPublicUser();
         if (!$user) {
             return $this->setMessage("Invalid public user '{$from}'.")->save();
         }
         $use_user_hash = false;
     } else {
         $user = id(new PhabricatorUser())->load($user_id);
         if (!$user) {
             return $this->setMessage("Invalid private user '{$user_id}'.")->save();
         }
         $use_user_hash = true;
     }
     if ($user->getIsDisabled()) {
         return $this->setMessage("User '{$user_id}' is disabled")->save();
     }
     $this->setAuthorPHID($user->getPHID());
     $receiver = self::loadReceiverObject($receiver_name);
     if (!$receiver) {
         return $this->setMessage("Invalid object '{$receiver_name}'")->save();
     }
     $this->setRelatedPHID($receiver->getPHID());
     if ($use_user_hash) {
         // This is a private reply-to address, check that the user hash is
         // correct.
         $check_phid = $user->getPHID();
     } else {
         // This is a public reply-to address, check that the object hash is
         // correct.
         $check_phid = $receiver->getPHID();
     }
     $expect_hash = self::computeMailHash($receiver->getMailKey(), $check_phid);
     // See note at computeOldMailHash().
     $old_hash = self::computeOldMailHash($receiver->getMailKey(), $check_phid);
     if ($expect_hash != $hash && $old_hash != $hash) {
         return $this->setMessage("Invalid mail hash!")->save();
     }
     if ($receiver instanceof ManiphestTask) {
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
     } else {
         if ($receiver instanceof DifferentialRevision) {
             $handler = DifferentialMail::newReplyHandlerForRevision($receiver);
         }
     }
     $handler->setActor($user);
     $handler->receiveEmail($this);
     $this->setMessage('OK');
     return $this->save();
 }
 public function processReceivedMail()
 {
     // If Phabricator sent the mail, always drop it immediately. This prevents
     // loops where, e.g., the public bug address is also a user email address
     // and creating a bug sends them an email, which loops.
     $is_phabricator_mail = idx($this->headers, 'x-phabricator-sent-this-message');
     if ($is_phabricator_mail) {
         $message = "Ignoring email with 'X-Phabricator-Sent-This-Message' " . "header to avoid loops.";
         return $this->setMessage($message)->save();
     }
     list($to, $receiver_name, $user_id, $hash) = $this->getPhabricatorToInformation();
     if (!$to) {
         $raw_to = idx($this->headers, 'to');
         return $this->setMessage("Unrecognized 'to' format: {$raw_to}")->save();
     }
     $from = idx($this->headers, 'from');
     // TODO -- make this a switch statement / better if / when we add more
     // public create email addresses!
     $create_task = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email');
     if ($create_task && $to == $create_task) {
         $receiver = new ManiphestTask();
         $user = $this->lookupPublicUser();
         if ($user) {
             $this->setAuthorPHID($user->getPHID());
         } else {
             $default_author = PhabricatorEnv::getEnvConfig('metamta.maniphest.default-public-author');
             if ($default_author) {
                 $user = id(new PhabricatorUser())->loadOneWhere('username = %s', $default_author);
                 if ($user) {
                     $receiver->setOriginalEmailSource($from);
                 } else {
                     throw new Exception("Phabricator is misconfigured, the configuration key " . "'metamta.maniphest.default-public-author' is set to user " . "'{$default_author}' but that user does not exist.");
                 }
             } else {
                 // TODO: We should probably bounce these since from the user's
                 // perspective their email vanishes into a black hole.
                 return $this->setMessage("Invalid public user '{$from}'.")->save();
             }
         }
         $receiver->setAuthorPHID($user->getPHID());
         $receiver->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
         $handler->setActor($user);
         $handler->processEmail($this);
         $this->setRelatedPHID($receiver->getPHID());
         $this->setMessage('OK');
         return $this->save();
     }
     if ($user_id == 'public') {
         if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
             return $this->setMessage("Public replies not enabled.")->save();
         }
         $user = $this->lookupPublicUser();
         if (!$user) {
             return $this->setMessage("Invalid public user '{$from}'.")->save();
         }
         $use_user_hash = false;
     } else {
         $user = id(new PhabricatorUser())->load($user_id);
         if (!$user) {
             return $this->setMessage("Invalid private user '{$user_id}'.")->save();
         }
         $use_user_hash = true;
     }
     if ($user->getIsDisabled()) {
         return $this->setMessage("User '{$user_id}' is disabled")->save();
     }
     $this->setAuthorPHID($user->getPHID());
     $receiver = self::loadReceiverObject($receiver_name);
     if (!$receiver) {
         return $this->setMessage("Invalid object '{$receiver_name}'")->save();
     }
     $this->setRelatedPHID($receiver->getPHID());
     if ($use_user_hash) {
         // This is a private reply-to address, check that the user hash is
         // correct.
         $check_phid = $user->getPHID();
     } else {
         // This is a public reply-to address, check that the object hash is
         // correct.
         $check_phid = $receiver->getPHID();
     }
     $expect_hash = self::computeMailHash($receiver->getMailKey(), $check_phid);
     // See note at computeOldMailHash().
     $old_hash = self::computeOldMailHash($receiver->getMailKey(), $check_phid);
     if ($expect_hash != $hash && $old_hash != $hash) {
         return $this->setMessage("Invalid mail hash!")->save();
     }
     if ($receiver instanceof ManiphestTask) {
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
     } else {
         if ($receiver instanceof DifferentialRevision) {
             $handler = DifferentialMail::newReplyHandlerForRevision($receiver);
         } else {
             if ($receiver instanceof PhabricatorRepositoryCommit) {
                 $handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit($receiver);
             }
         }
     }
     $handler->setActor($user);
     $handler->processEmail($this);
     $this->setMessage('OK');
     return $this->save();
 }
 public function processReceivedMail()
 {
     $to = idx($this->headers, 'to');
     $to = $this->getRawEmailAddress($to);
     $from = idx($this->headers, 'from');
     $create_task = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email');
     if ($create_task && $to == $create_task) {
         $user = $this->lookupPublicUser();
         if (!$user) {
             // TODO: We should probably bounce these since from the user's
             // perspective their email vanishes into a black hole.
             return $this->setMessage("Invalid public user '{$from}'.")->save();
         }
         $this->setAuthorPHID($user->getPHID());
         $receiver = new ManiphestTask();
         $receiver->setAuthorPHID($user->getPHID());
         $receiver->setPriority(ManiphestTaskPriority::PRIORITY_TRIAGE);
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
         $handler->setActor($user);
         $handler->receiveEmail($this);
         $this->setRelatedPHID($receiver->getPHID());
         $this->setMessage('OK');
         return $this->save();
     }
     // We've already stripped this, so look for an object address which has
     // a format like: D291+291+b0a41ca848d66dcc@example.com
     $matches = null;
     $ok = preg_match('/^((?:D|T)\\d+)\\+([\\w]+)\\+([a-f0-9]{16})@/U', $to, $matches);
     if (!$ok) {
         return $this->setMessage("Unrecognized 'to' format: {$to}")->save();
     }
     $receiver_name = $matches[1];
     $user_id = $matches[2];
     $hash = $matches[3];
     if ($user_id == 'public') {
         if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) {
             return $this->setMessage("Public replies not enabled.")->save();
         }
         $user = $this->lookupPublicUser();
         if (!$user) {
             return $this->setMessage("Invalid public user '{$from}'.")->save();
         }
         $use_user_hash = false;
     } else {
         $user = id(new PhabricatorUser())->load($user_id);
         if (!$user) {
             return $this->setMessage("Invalid private user '{$user_id}'.")->save();
         }
         $use_user_hash = true;
     }
     if ($user->getIsDisabled()) {
         return $this->setMessage("User '{$user_id}' is disabled")->save();
     }
     $this->setAuthorPHID($user->getPHID());
     $receiver = self::loadReceiverObject($receiver_name);
     if (!$receiver) {
         return $this->setMessage("Invalid object '{$receiver_name}'")->save();
     }
     $this->setRelatedPHID($receiver->getPHID());
     if ($use_user_hash) {
         // This is a private reply-to address, check that the user hash is
         // correct.
         $check_phid = $user->getPHID();
     } else {
         // This is a public reply-to address, check that the object hash is
         // correct.
         $check_phid = $receiver->getPHID();
     }
     $expect_hash = self::computeMailHash($receiver->getMailKey(), $check_phid);
     if ($expect_hash != $hash) {
         return $this->setMessage("Invalid mail hash!")->save();
     }
     if ($receiver instanceof ManiphestTask) {
         $editor = new ManiphestTransactionEditor();
         $handler = $editor->buildReplyHandler($receiver);
     } else {
         if ($receiver instanceof DifferentialRevision) {
             $handler = DifferentialMail::newReplyHandlerForRevision($receiver);
         }
     }
     $handler->setActor($user);
     $handler->receiveEmail($this);
     $this->setMessage('OK');
     return $this->save();
 }