diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f4eb97a090..9528a958a1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1069,6 +1069,7 @@ phutil_register_library_map(array( 'ManiphestUpdateConduitAPIMethod' => 'applications/maniphest/conduit/ManiphestUpdateConduitAPIMethod.php', 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 'MetaMTAConstants' => 'applications/metamta/constants/MetaMTAConstants.php', + 'MetaMTAEmailTransactionCommand' => 'applications/metamta/command/MetaMTAEmailTransactionCommand.php', 'MetaMTAMailReceivedGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailReceivedGarbageCollector.php', 'MetaMTAMailSentGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailSentGarbageCollector.php', 'MetaMTANotificationType' => 'applications/metamta/constants/MetaMTANotificationType.php', @@ -2544,6 +2545,7 @@ phutil_register_library_map(array( 'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php', 'PhabricatorSubscriptionsTransactionController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsTransactionController.php', 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', + 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php', 'PhabricatorSupportApplication' => 'applications/support/application/PhabricatorSupportApplication.php', 'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php', 'PhabricatorSyntaxHighlightingConfigOptions' => 'applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php', @@ -4320,6 +4322,7 @@ phutil_register_library_map(array( 'ManiphestTransactionSaveController' => 'ManiphestController', 'ManiphestUpdateConduitAPIMethod' => 'ManiphestConduitAPIMethod', 'ManiphestView' => 'AphrontView', + 'MetaMTAEmailTransactionCommand' => 'Phobject', 'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAMailSentGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTANotificationType' => 'MetaMTAConstants', @@ -5921,6 +5924,7 @@ phutil_register_library_map(array( 'PhabricatorSubscriptionsListController' => 'PhabricatorController', 'PhabricatorSubscriptionsTransactionController' => 'PhabricatorController', 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', + 'PhabricatorSubscriptionsUnsubscribeEmailCommand' => 'MetaMTAEmailTransactionCommand', 'PhabricatorSupportApplication' => 'PhabricatorApplication', 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSystemActionEngine' => 'Phobject', diff --git a/src/applications/files/mail/FileReplyHandler.php b/src/applications/files/mail/FileReplyHandler.php index 881bf06519..b21c487e14 100644 --- a/src/applications/files/mail/FileReplyHandler.php +++ b/src/applications/files/mail/FileReplyHandler.php @@ -13,22 +13,4 @@ final class FileReplyHandler return 'F'; } - protected function processMailCommands(array $commands) { - $actor = $this->getActor(); - - $xactions = array(); - foreach ($commands as $command) { - switch (head($command)) { - case 'unsubscribe': - $xaction = id(new PhabricatorFileTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) - ->setNewValue(array('-' => array($actor->getPHID()))); - $xactions[] = $xaction; - break; - } - } - - return $xactions; - } - } diff --git a/src/applications/metamta/command/MetaMTAEmailTransactionCommand.php b/src/applications/metamta/command/MetaMTAEmailTransactionCommand.php new file mode 100644 index 0000000000..9e20ef43e1 --- /dev/null +++ b/src/applications/metamta/command/MetaMTAEmailTransactionCommand.php @@ -0,0 +1,81 @@ +setAncestorClass(__CLASS__) + ->loadObjects(); + $commands = array(); + foreach ($kinds as $kind) { + foreach ($kind->getCommandObjects() as $command) { + $commands[] = $command; + } + } + } + + return $commands; + } + + public static function getAllCommandsForObject( + PhabricatorApplicationTransactionInterface $object) { + + $commands = self::getAllCommands(); + foreach ($commands as $key => $command) { + if (!$command->isCommandSupportedForObject($object)) { + unset($commands[$key]); + } + } + + return $commands; + } + + public static function getCommandMap(array $commands) { + assert_instances_of($commands, 'MetaMTAEmailTransactionCommand'); + + $map = array(); + foreach ($commands as $command) { + $keywords = $command->getCommandAliases(); + $keywords[] = $command->getCommand(); + + foreach ($keywords as $keyword) { + $keyword = phutil_utf8_strtolower($keyword); + if (empty($map[$keyword])) { + $map[$keyword] = $command; + } else { + throw new Exception( + pht( + 'Mail commands "%s" and "%s" both respond to keyword "%s". '. + 'Keywords must be uniquely associated with commands.', + get_class($command), + get_class($map[$keyword]), + $keyword)); + } + } + } + + return $map; + } + +} diff --git a/src/applications/paste/mail/PasteReplyHandler.php b/src/applications/paste/mail/PasteReplyHandler.php index 64945c5101..b8c498b76e 100644 --- a/src/applications/paste/mail/PasteReplyHandler.php +++ b/src/applications/paste/mail/PasteReplyHandler.php @@ -13,22 +13,4 @@ final class PasteReplyHandler return 'P'; } - protected function processMailCommands(array $commands) { - $actor = $this->getActor(); - - $xactions = array(); - foreach ($commands as $command) { - switch (head($command)) { - case 'unsubscribe': - $xaction = id(new PhabricatorPasteTransaction()) - ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) - ->setNewValue(array('-' => array($actor->getPHID()))); - $xactions[] = $xaction; - break; - } - } - - return $xactions; - } - } diff --git a/src/applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php b/src/applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php new file mode 100644 index 0000000000..124ba9605a --- /dev/null +++ b/src/applications/subscriptions/command/PhabricatorSubscriptionsUnsubscribeEmailCommand.php @@ -0,0 +1,33 @@ +getApplicationTransactionTemplate() + ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) + ->setNewValue( + array( + '-' => array($viewer->getPHID()), + )); + + return $xactions; + } + +} diff --git a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php index fbfeb6303f..2eb8955f91 100644 --- a/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php +++ b/src/applications/transactions/replyhandler/PhabricatorApplicationTransactionReplyHandler.php @@ -49,7 +49,9 @@ abstract class PhabricatorApplicationTransactionReplyHandler $body_data = $mail->parseBody(); - $xactions = $this->processMailCommands($body_data['commands']); + $xactions = $this->processMailCommands( + $mail, + $body_data['commands']); // If this object is subscribable, subscribe all the users who were // CC'd on the message. @@ -84,9 +86,60 @@ abstract class PhabricatorApplicationTransactionReplyHandler ->applyTransactions($target, $xactions); } - protected function processMailCommands(array $commands) { - // TODO: Modularize this. - return array(); + private function processMailCommands( + PhabricatorMetaMTAReceivedMail $mail, + array $command_list) { + + $viewer = $this->getActor(); + $object = $this->getMailReceiver(); + + $list = MetaMTAEmailTransactionCommand::getAllCommandsForObject($object); + $map = MetaMTAEmailTransactionCommand::getCommandMap($list); + + $xactions = array(); + foreach ($command_list as $command_argv) { + $command = head($command_argv); + $argv = array_slice($command_argv, 1); + + $handler = idx($map, phutil_utf8_strtolower($command)); + if ($handler) { + $results = $handler->buildTransactions( + $viewer, + $object, + $mail, + $command, + $argv); + foreach ($results as $result) { + $xactions[] = $result; + } + } else { + $valid_commands = array(); + foreach ($list as $valid_command) { + $aliases = $valid_command->getCommandAliases(); + if ($aliases) { + foreach ($aliases as $key => $alias) { + $aliases[$key] = '!'.$alias; + } + $aliases = implode(', ', $aliases); + $valid_commands[] = pht( + '!%s (or %s)', + $valid_command->getCommand(), + $aliases); + } else { + $valid_commands[] = '!'.$valid_command->getCommand(); + } + } + + throw new Exception( + pht( + 'The command "!%s" is not a supported mail command. Valid '. + 'commands for this object are: %s.', + $command, + implode(', ', $valid_commands))); + } + } + + return $xactions; } }