From 341079c3cf25ce90691fb8e3af57b53d9fd5ee29 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 14 May 2013 10:57:41 -0700 Subject: [PATCH] Move some received mail responsibility to applications Summary: Ref T1205. Continuation of D5915. Currently, `PhabricatorMetaMTAReceivedMail` has //all// the logic for routing mail. In particular: - New mail receivers in applications must edit it. - Mail receivers don't drop out when applications are uninstalled. Applications have some logic in subclasses of `PhabricatorMailReplyHandler`, but this class is a bit of a mess. It is also heavily based on the assumption that mail receivers are objects (like revisions), but this is not true in at least two cases today (creating new tasks with `bugs@`, creating a new Conpherence thread) and likely other cases in the future (e.g., revision-by-mail). Move this logic into a new `PhabricatorMailReceiver` classtree. This is similar to `PhabricatorMailReplyHandler` but a bit cleaner and more general. I plan to heavily reduce the responsibilities of `PhabricatorMailReplyHandler` or possibly eliminate it entirely. For now, the new classtree doesn't do much of interest. The only behavioral change this diff causes is that Phabricator will now reject mail to an application when that application is uninstalled. I also moved all the `ReplyHandler` classes into `mail/` directories in their respective applications. Test Plan: Unit tests, used receive test to route mail to various objects. Reviewers: btrahan Reviewed By: btrahan CC: Afaque_Hussain, edward, aran Maniphest Tasks: T1205 Differential Revision: https://secure.phabricator.com/D5922 --- src/__phutil_library_map__.php | 33 +++++++-- .../mail/PhabricatorAuditMailReceiver.php | 14 ++++ .../PhabricatorAuditReplyHandler.php | 0 .../base/PhabricatorApplication.php | 5 ++ .../ConpherenceCreateThreadMailReceiver.php | 37 ++++++++++ .../mail/ConpherenceThreadMailReceiver.php | 15 ++++ .../{ => mail}/DifferentialReplyHandler.php | 0 .../mail/DifferentialRevisionMailReceiver.php | 15 ++++ .../mail/PhabricatorMacroMailReceiver.php | 14 ++++ .../mail/ManiphestCreateMailReceiver.php | 23 ++++++ .../{ => mail}/ManiphestReplyHandler.php | 0 .../mail/ManiphestTaskMailReceiver.php | 14 ++++ .../constants/MetaMTAReceivedMailStatus.php | 6 +- .../PhabricatorMetaMTAReceiveController.php | 2 +- .../receiver/PhabricatorMailReceiver.php | 72 +++++++++++++++++++ .../PhabricatorObjectMailReceiver.php | 37 ++++++++++ .../PhabricatorMetaMTAReceivedMail.php | 40 +++++++++++ ...PhabricatorMetaMTAReceivedMailTestCase.php | 15 ++++ .../{ => mail}/OwnersPackageReplyHandler.php | 0 .../pholio/mail/PholioMockMailReceiver.php | 14 ++++ .../mail/PonderQuestionMailReceiver.php | 14 ++++ .../ponder/{ => mail}/PonderReplyHandler.php | 0 .../mail/ReleephRequestMailReceiver.php | 14 ++++ 23 files changed, 376 insertions(+), 8 deletions(-) create mode 100644 src/applications/audit/mail/PhabricatorAuditMailReceiver.php rename src/applications/audit/{ => mail}/PhabricatorAuditReplyHandler.php (100%) create mode 100644 src/applications/conpherence/mail/ConpherenceCreateThreadMailReceiver.php create mode 100644 src/applications/conpherence/mail/ConpherenceThreadMailReceiver.php rename src/applications/differential/{ => mail}/DifferentialReplyHandler.php (100%) create mode 100644 src/applications/differential/mail/DifferentialRevisionMailReceiver.php create mode 100644 src/applications/macro/mail/PhabricatorMacroMailReceiver.php create mode 100644 src/applications/maniphest/mail/ManiphestCreateMailReceiver.php rename src/applications/maniphest/{ => mail}/ManiphestReplyHandler.php (100%) create mode 100644 src/applications/maniphest/mail/ManiphestTaskMailReceiver.php create mode 100644 src/applications/metamta/receiver/PhabricatorMailReceiver.php create mode 100644 src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php rename src/applications/owners/{ => mail}/OwnersPackageReplyHandler.php (100%) create mode 100644 src/applications/pholio/mail/PholioMockMailReceiver.php create mode 100644 src/applications/ponder/mail/PonderQuestionMailReceiver.php rename src/applications/ponder/{ => mail}/PonderReplyHandler.php (100%) create mode 100644 src/applications/releeph/mail/ReleephRequestMailReceiver.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 0255274696..39cdd72ccc 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -234,6 +234,7 @@ phutil_register_library_map(array( 'ConpherenceConfigOptions' => 'applications/conpherence/config/ConpherenceConfigOptions.php', 'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php', 'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php', + 'ConpherenceCreateThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceCreateThreadMailReceiver.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFileWidgetView' => 'applications/conpherence/view/ConpherenceFileWidgetView.php', @@ -254,6 +255,7 @@ phutil_register_library_map(array( 'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php', 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', + 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', @@ -365,7 +367,7 @@ phutil_register_library_map(array( 'DifferentialPrimaryPaneView' => 'applications/differential/view/DifferentialPrimaryPaneView.php', 'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php', 'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php', - 'DifferentialReplyHandler' => 'applications/differential/DifferentialReplyHandler.php', + 'DifferentialReplyHandler' => 'applications/differential/mail/DifferentialReplyHandler.php', 'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php', 'DifferentialRevertPlanFieldSpecification' => 'applications/differential/field/specification/DifferentialRevertPlanFieldSpecification.php', 'DifferentialReviewRequestMail' => 'applications/differential/mail/DifferentialReviewRequestMail.php', @@ -386,6 +388,7 @@ phutil_register_library_map(array( 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListData' => 'applications/differential/data/DifferentialRevisionListData.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', + 'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php', 'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php', 'DifferentialRevisionStatsController' => 'applications/differential/controller/DifferentialRevisionStatsController.php', 'DifferentialRevisionStatsView' => 'applications/differential/view/DifferentialRevisionStatsView.php', @@ -610,6 +613,7 @@ phutil_register_library_map(array( 'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php', 'ManiphestConstants' => 'applications/maniphest/constants/ManiphestConstants.php', 'ManiphestController' => 'applications/maniphest/controller/ManiphestController.php', + 'ManiphestCreateMailReceiver' => 'applications/maniphest/mail/ManiphestCreateMailReceiver.php', 'ManiphestDAO' => 'applications/maniphest/storage/ManiphestDAO.php', 'ManiphestDefaultTaskExtensions' => 'applications/maniphest/extensions/ManiphestDefaultTaskExtensions.php', 'ManiphestEdgeEventListener' => 'applications/maniphest/event/ManiphestEdgeEventListener.php', @@ -619,7 +623,7 @@ phutil_register_library_map(array( 'ManiphestHovercardEventListener' => 'applications/maniphest/event/ManiphestHovercardEventListener.php', 'ManiphestPeopleMenuEventListener' => 'applications/maniphest/event/ManiphestPeopleMenuEventListener.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', - 'ManiphestReplyHandler' => 'applications/maniphest/ManiphestReplyHandler.php', + 'ManiphestReplyHandler' => 'applications/maniphest/mail/ManiphestReplyHandler.php', 'ManiphestReportController' => 'applications/maniphest/controller/ManiphestReportController.php', 'ManiphestSavedQuery' => 'applications/maniphest/storage/ManiphestSavedQuery.php', 'ManiphestSavedQueryDeleteController' => 'applications/maniphest/controller/ManiphestSavedQueryDeleteController.php', @@ -637,6 +641,7 @@ phutil_register_library_map(array( 'ManiphestTaskExtensions' => 'applications/maniphest/extensions/ManiphestTaskExtensions.php', 'ManiphestTaskListController' => 'applications/maniphest/controller/ManiphestTaskListController.php', 'ManiphestTaskListView' => 'applications/maniphest/view/ManiphestTaskListView.php', + 'ManiphestTaskMailReceiver' => 'applications/maniphest/mail/ManiphestTaskMailReceiver.php', 'ManiphestTaskOwner' => 'applications/maniphest/constants/ManiphestTaskOwner.php', 'ManiphestTaskPriority' => 'applications/maniphest/constants/ManiphestTaskPriority.php', 'ManiphestTaskProject' => 'applications/maniphest/storage/ManiphestTaskProject.php', @@ -656,7 +661,7 @@ phutil_register_library_map(array( 'MetaMTANotificationType' => 'applications/metamta/constants/MetaMTANotificationType.php', 'MetaMTAReceivedMailStatus' => 'applications/metamta/constants/MetaMTAReceivedMailStatus.php', 'ObjectHandleLoader' => 'applications/phid/handle/ObjectHandleLoader.php', - 'OwnersPackageReplyHandler' => 'applications/owners/OwnersPackageReplyHandler.php', + 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', 'PHUI' => 'view/phui/PHUI.php', 'PHUIBoxExample' => 'applications/uiexample/examples/PHUIBoxExample.php', 'PHUIBoxView' => 'view/phui/PHUIBoxView.php', @@ -768,9 +773,10 @@ phutil_register_library_map(array( 'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php', 'PhabricatorAuditListController' => 'applications/audit/controller/PhabricatorAuditListController.php', 'PhabricatorAuditListView' => 'applications/audit/view/PhabricatorAuditListView.php', + 'PhabricatorAuditMailReceiver' => 'applications/audit/mail/PhabricatorAuditMailReceiver.php', 'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php', 'PhabricatorAuditQuery' => 'applications/audit/query/PhabricatorAuditQuery.php', - 'PhabricatorAuditReplyHandler' => 'applications/audit/PhabricatorAuditReplyHandler.php', + 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', @@ -1059,6 +1065,7 @@ phutil_register_library_map(array( 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', + 'PhabricatorMacroMailReceiver' => 'applications/macro/mail/PhabricatorMacroMailReceiver.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', @@ -1077,6 +1084,7 @@ phutil_register_library_map(array( 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php', 'PhabricatorMailManagementResendWorkflow' => 'applications/metamta/management/PhabricatorMailManagementResendWorkflow.php', 'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php', + 'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 'PhabricatorMailingListsController' => 'applications/mailinglists/controller/PhabricatorMailingListsController.php', 'PhabricatorMailingListsEditController' => 'applications/mailinglists/controller/PhabricatorMailingListsEditController.php', @@ -1175,6 +1183,7 @@ phutil_register_library_map(array( 'PhabricatorObjectItemListView' => 'view/layout/PhabricatorObjectItemListView.php', 'PhabricatorObjectItemView' => 'view/layout/PhabricatorObjectItemView.php', 'PhabricatorObjectListView' => 'view/control/PhabricatorObjectListView.php', + 'PhabricatorObjectMailReceiver' => 'applications/metamta/receiver/PhabricatorObjectMailReceiver.php', 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', @@ -1574,6 +1583,7 @@ phutil_register_library_map(array( 'PholioMockEmbedView' => 'applications/pholio/view/PholioMockEmbedView.php', 'PholioMockImagesView' => 'applications/pholio/view/PholioMockImagesView.php', 'PholioMockListController' => 'applications/pholio/controller/PholioMockListController.php', + 'PholioMockMailReceiver' => 'applications/pholio/mail/PholioMockMailReceiver.php', 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', 'PholioRemarkupRule' => 'applications/pholio/remarkup/PholioRemarkupRule.php', @@ -1684,12 +1694,13 @@ phutil_register_library_map(array( 'PonderQuestionAskController' => 'applications/ponder/controller/PonderQuestionAskController.php', 'PonderQuestionDetailView' => 'applications/ponder/view/PonderQuestionDetailView.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', + 'PonderQuestionMailReceiver' => 'applications/ponder/mail/PonderQuestionMailReceiver.php', 'PonderQuestionPreviewController' => 'applications/ponder/controller/PonderQuestionPreviewController.php', 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 'PonderQuestionSummaryView' => 'applications/ponder/view/PonderQuestionSummaryView.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', - 'PonderReplyHandler' => 'applications/ponder/PonderReplyHandler.php', + 'PonderReplyHandler' => 'applications/ponder/mail/PonderReplyHandler.php', 'PonderSearchIndexer' => 'applications/ponder/search/PonderSearchIndexer.php', 'PonderUserProfileView' => 'applications/ponder/view/PonderUserProfileView.php', 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', @@ -1752,6 +1763,7 @@ phutil_register_library_map(array( 'ReleephRequestHeaderView' => 'applications/releeph/view/request/header/ReleephRequestHeaderView.php', 'ReleephRequestIntentsView' => 'applications/releeph/view/request/ReleephRequestIntentsView.php', 'ReleephRequestQuery' => 'applications/releeph/query/ReleephRequestQuery.php', + 'ReleephRequestMailReceiver' => 'applications/releeph/mail/ReleephRequestMailReceiver.php', 'ReleephRequestReplyHandler' => 'applications/releeph/mail/ReleephRequestReplyHandler.php', 'ReleephRequestStatus' => 'applications/releeph/constants/ReleephRequestStatus.php', 'ReleephRequestStatusView' => 'applications/releeph/view/request/ReleephRequestStatusView.php', @@ -2015,6 +2027,7 @@ phutil_register_library_map(array( 'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow', 'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions', 'ConpherenceController' => 'PhabricatorController', + 'ConpherenceCreateThreadMailReceiver' => 'PhabricatorMailReceiver', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFileWidgetView' => 'ConpherenceWidgetView', @@ -2039,6 +2052,7 @@ phutil_register_library_map(array( 1 => 'PhabricatorPolicyInterface', ), 'ConpherenceThreadListView' => 'AphrontView', + 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', @@ -2166,6 +2180,7 @@ phutil_register_library_map(array( 'DifferentialRevisionIDFieldSpecification' => 'DifferentialFieldSpecification', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', + 'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver', 'DifferentialRevisionStatsController' => 'DifferentialController', 'DifferentialRevisionStatsView' => 'AphrontView', 'DifferentialRevisionStatusFieldSpecification' => 'DifferentialFieldSpecification', @@ -2345,6 +2360,7 @@ phutil_register_library_map(array( 'ManiphestAuxiliaryFieldValidationException' => 'Exception', 'ManiphestBatchEditController' => 'ManiphestController', 'ManiphestController' => 'PhabricatorController', + 'ManiphestCreateMailReceiver' => 'PhabricatorMailReceiver', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestDefaultTaskExtensions' => 'ManiphestTaskExtensions', 'ManiphestEdgeEventListener' => 'PhutilEventListener', @@ -2377,6 +2393,7 @@ phutil_register_library_map(array( 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListView' => 'ManiphestView', + 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', 'ManiphestTaskOwner' => 'ManiphestConstants', 'ManiphestTaskPriority' => 'ManiphestConstants', 'ManiphestTaskProject' => 'ManiphestDAO', @@ -2519,6 +2536,7 @@ phutil_register_library_map(array( ), 'PhabricatorAuditListController' => 'PhabricatorAuditController', 'PhabricatorAuditListView' => 'AphrontView', + 'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorAuthController' => 'PhabricatorController', @@ -2799,6 +2817,7 @@ phutil_register_library_map(array( 'PhabricatorMacroEditController' => 'PhabricatorMacroController', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMacroListController' => 'PhabricatorMacroController', + 'PhabricatorMacroMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -2898,6 +2917,7 @@ phutil_register_library_map(array( 'PhabricatorObjectItemListView' => 'AphrontView', 'PhabricatorObjectItemView' => 'AphrontTagView', 'PhabricatorObjectListView' => 'AphrontView', + 'PhabricatorObjectMailReceiver' => 'PhabricatorMailReceiver', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorOwnersController' => 'PhabricatorController', @@ -3315,6 +3335,7 @@ phutil_register_library_map(array( 'PholioMockEmbedView' => 'AphrontView', 'PholioMockImagesView' => 'AphrontView', 'PholioMockListController' => 'PholioController', + 'PholioMockMailReceiver' => 'PhabricatorObjectMailReceiver', 'PholioMockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioMockViewController' => 'PholioController', 'PholioRemarkupRule' => 'PhabricatorRemarkupRuleObject', @@ -3457,6 +3478,7 @@ phutil_register_library_map(array( 'PonderQuestionAskController' => 'PonderController', 'PonderQuestionDetailView' => 'AphrontView', 'PonderQuestionEditor' => 'PhabricatorEditor', + 'PonderQuestionMailReceiver' => 'PhabricatorObjectMailReceiver', 'PonderQuestionPreviewController' => 'PonderController', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderQuestionSummaryView' => 'AphrontView', @@ -3528,6 +3550,7 @@ phutil_register_library_map(array( 'ReleephRequestHeaderView' => 'AphrontView', 'ReleephRequestIntentsView' => 'AphrontView', 'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'ReleephRequestMailReceiver' => 'PhabricatorObjectMailReceiver', 'ReleephRequestReplyHandler' => 'PhabricatorMailReplyHandler', 'ReleephRequestStatusView' => 'AphrontView', 'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction', diff --git a/src/applications/audit/mail/PhabricatorAuditMailReceiver.php b/src/applications/audit/mail/PhabricatorAuditMailReceiver.php new file mode 100644 index 0000000000..d0e0c6aede --- /dev/null +++ b/src/applications/audit/mail/PhabricatorAuditMailReceiver.php @@ -0,0 +1,14 @@ +getToAddresses() as $to_address) { + $address = self::stripMailboxPrefix($to_address); + $usernames[] = id(new PhutilEmailAddress($address))->getLocalPart(); + } + + $usernames = array_unique($usernames); + + if (!$usernames) { + return false; + } + + $users = id(new PhabricatorUser())->loadAllWhere( + 'username in (%Ls)', + $usernames); + + if (count($users) != count($usernames)) { + // At least some of the addresses are not users, so don't accept this as + // a new Conpherence thread. + return false; + } + + return true; + } + +} diff --git a/src/applications/conpherence/mail/ConpherenceThreadMailReceiver.php b/src/applications/conpherence/mail/ConpherenceThreadMailReceiver.php new file mode 100644 index 0000000000..6b0acfde30 --- /dev/null +++ b/src/applications/conpherence/mail/ConpherenceThreadMailReceiver.php @@ -0,0 +1,15 @@ +getToAddresses() as $to_address) { + if ($this->matchAddresses($create_address, $to_address)) { + return true; + } + } + + return false; + } + +} diff --git a/src/applications/maniphest/ManiphestReplyHandler.php b/src/applications/maniphest/mail/ManiphestReplyHandler.php similarity index 100% rename from src/applications/maniphest/ManiphestReplyHandler.php rename to src/applications/maniphest/mail/ManiphestReplyHandler.php diff --git a/src/applications/maniphest/mail/ManiphestTaskMailReceiver.php b/src/applications/maniphest/mail/ManiphestTaskMailReceiver.php new file mode 100644 index 0000000000..f74353dba9 --- /dev/null +++ b/src/applications/maniphest/mail/ManiphestTaskMailReceiver.php @@ -0,0 +1,14 @@ +isFormPost()) { $received = new PhabricatorMetaMTAReceivedMail(); $header_content = array( - 'Message-ID' => Filesystem::readRandomBytes(12), + 'Message-ID' => Filesystem::readRandomCharacters(12), ); $from = $request->getStr('sender'); $to = $request->getStr('receiver'); diff --git a/src/applications/metamta/receiver/PhabricatorMailReceiver.php b/src/applications/metamta/receiver/PhabricatorMailReceiver.php new file mode 100644 index 0000000000..8eb906ee38 --- /dev/null +++ b/src/applications/metamta/receiver/PhabricatorMailReceiver.php @@ -0,0 +1,72 @@ + + * alincoln@example.com + * + * "Abraham" # With configured prefix. + * + * @param string Email address. + * @param string Another email address. + * @return bool True if addresses match. + */ + public static function matchAddresses($u, $v) { + $u = id(new PhutilEmailAddress($u))->getAddress(); + $v = id(new PhutilEmailAddress($v))->getAddress(); + + $u = self::stripMailboxPrefix($u); + $v = self::stripMailboxPrefix($v); + + $u = trim(phutil_utf8_strtolower($u)); + $v = trim(phutil_utf8_strtolower($v)); + + return ($u === $v); + } + + + /** + * Strip a global mailbox prefix from an address if it is present. Phabricator + * can be configured to prepend a prefix to all reply addresses, which can + * make forwarding rules easier to write. A prefix looks like: + * + * example@phabricator.example.com # No Prefix + * phabricator+example@phabricator.example.com # Prefix "phabricator" + * + * @param string Email address, possibly with a mailbox prefix. + * @return string Email address with any prefix stripped. + */ + public static function stripMailboxPrefix($address) { + $address = id(new PhutilEmailAddress($address))->getAddress(); + + $prefix_key = 'metamta.single-reply-handler-prefix'; + $prefix = PhabricatorEnv::getEnvConfig($prefix_key); + + $len = strlen($prefix); + + if ($len) { + $prefix = $prefix.'+'; + $len = $len + 1; + } + + if ($len) { + if (!strncasecmp($address, $prefix, $len)) { + $address = substr($address, strlen($prefix)); + } + } + + return $address; + } + + +} diff --git a/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php new file mode 100644 index 0000000000..893e7c36f4 --- /dev/null +++ b/src/applications/metamta/receiver/PhabricatorObjectMailReceiver.php @@ -0,0 +1,37 @@ +getAddressRegexp(); + + foreach ($mail->getToAddresses() as $address) { + $address = self::stripMailboxPrefix($address); + $local = id(new PhutilEmailAddress($address))->getLocalPart(); + if (preg_match($regexp, $local)) { + return true; + } + } + + return false; + } + + private function getAddressRegexp() { + $pattern = $this->getObjectPattern(); + + $regexp = + '(^'. + '(?P'.$pattern.')'. + '\\+'. + '(?P\w+)'. + '\\+'. + '(?P[a-f0-9]{16})'. + '$)U'; + + return $regexp; + } + + +} diff --git a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php index f891275bf6..0554346b7e 100644 --- a/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php +++ b/src/applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php @@ -173,6 +173,9 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO { try { $this->dropMailFromPhabricator(); $this->dropMailAlreadyReceived(); + + $receiver = $this->loadReceiver(); + } catch (PhabricatorMetaMTAReceivedMailProcessingException $ex) { $this ->setStatus($ex->getStatusCode()) @@ -511,4 +514,41 @@ final class PhabricatorMetaMTAReceivedMail extends PhabricatorMetaMTADAO { $message); } + + /** + * Load a concrete instance of the @{class:PhabricatorMailReceiver} which + * accepts this mail, if one exists. + */ + private function loadReceiver() { + $receivers = id(new PhutilSymbolLoader()) + ->setAncestorClass('PhabricatorMailReceiver') + ->loadObjects(); + + $accept = array(); + foreach ($receivers as $key => $receiver) { + if (!$receiver->isEnabled()) { + continue; + } + if ($receiver->canAcceptMail($this)) { + $accept[$key] = $receiver; + } + } + + if (!$accept) { + throw new PhabricatorMetaMTAReceivedMailProcessingException( + MetaMTAReceivedMailStatus::STATUS_NO_RECEIVERS, + "No concrete, enabled subclasses of `PhabricatorMailReceiver` can ". + "accept this mail."); + } + + if (count($accept) > 1) { + $names = implode(', ', array_keys($accept)); + throw new PhabricatorMetaMTAReceivedMailProcessingException( + MetaMTAReceivedMailStatus::STATUS_ABUNDANT_RECEIVERS, + "More than one `PhabricatorMailReceiver` claims to accept this mail."); + } + + return head($accept); + } + } diff --git a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php index d49c08ce18..d734513f38 100644 --- a/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php +++ b/src/applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php @@ -47,6 +47,21 @@ final class PhabricatorMetaMTAReceivedMailTestCase extends PhabricatorTestCase { $mail_b->getStatus()); } + public function testDropUnreceivableMail() { + $mail = new PhabricatorMetaMTAReceivedMail(); + $mail->setHeaders( + array( + 'Message-ID' => 'test@example.com', + 'To' => 'does+not+exist@example.com', + )); + $mail->save(); + + $mail->processReceivedMail(); + + $this->assertEqual( + MetaMTAReceivedMailStatus::STATUS_NO_RECEIVERS, + $mail->getStatus()); + } } diff --git a/src/applications/owners/OwnersPackageReplyHandler.php b/src/applications/owners/mail/OwnersPackageReplyHandler.php similarity index 100% rename from src/applications/owners/OwnersPackageReplyHandler.php rename to src/applications/owners/mail/OwnersPackageReplyHandler.php diff --git a/src/applications/pholio/mail/PholioMockMailReceiver.php b/src/applications/pholio/mail/PholioMockMailReceiver.php new file mode 100644 index 0000000000..66837db0bf --- /dev/null +++ b/src/applications/pholio/mail/PholioMockMailReceiver.php @@ -0,0 +1,14 @@ +