Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2895744
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
36 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/applications/differential/mail/DifferentialReplyHandler.php b/src/applications/differential/mail/DifferentialReplyHandler.php
index 4a773dd2bc..05a92cd4ff 100644
--- a/src/applications/differential/mail/DifferentialReplyHandler.php
+++ b/src/applications/differential/mail/DifferentialReplyHandler.php
@@ -1,129 +1,112 @@
<?php
-/**
- * NOTE: Do not extend this!
- *
- * @concrete-extensible
- */
-class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
-
- private $receivedMail;
+final class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof DifferentialRevision)) {
throw new Exception('Receiver is not a DifferentialRevision!');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'D');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('D');
}
public function getReplyHandlerDomain() {
return $this->getCustomReplyHandlerDomainIfExists(
'metamta.differential.reply-handler-domain');
}
public function getSupportedCommands() {
$actions = array(
DifferentialAction::ACTION_COMMENT,
DifferentialAction::ACTION_REJECT,
DifferentialAction::ACTION_ABANDON,
DifferentialAction::ACTION_RECLAIM,
DifferentialAction::ACTION_RESIGN,
DifferentialAction::ACTION_RETHINK,
'unsubscribe',
);
if (PhabricatorEnv::getEnvConfig('differential.enable-email-accept')) {
$actions[] = DifferentialAction::ACTION_ACCEPT;
}
return $actions;
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
- $this->receivedMail = $mail;
- $this->handleAction($mail->getCleanTextBody(), $mail->getAttachments());
- }
-
- public function handleAction($body, array $attachments) {
- // all commands start with a bang and separated from the body by a newline
- // to make sure that actual feedback text couldn't trigger an action.
- // unrecognized commands will be parsed as part of the comment.
- $command = DifferentialAction::ACTION_COMMENT;
- $supported_commands = $this->getSupportedCommands();
- $regex = "/\A\n*!(".implode('|', $supported_commands).")\n*/";
- $matches = array();
- if (preg_match($regex, $body, $matches)) {
- $command = $matches[1];
- $body = trim(str_replace('!'.$command, '', $body));
- }
-
- $actor = $this->getActor();
- if (!$actor) {
- throw new Exception('No actor is set for the reply action.');
- }
+ $revision = $this->getMailReceiver();
+ $viewer = $this->getActor();
- switch ($command) {
- case 'unsubscribe':
- id(new PhabricatorSubscriptionsEditor())
- ->setActor($actor)
- ->setObject($this->getMailReceiver())
- ->unsubscribe(array($actor->getPHID()))
- ->save();
- // TODO: Send the user a confirmation email?
- return null;
- }
-
- $body = $this->enhanceBodyWithAttachments($body, $attachments);
+ $body_data = $mail->parseBody();
+ $body = $body_data['body'];
+ $body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$xactions = array();
-
- if ($command && ($command != DifferentialAction::ACTION_COMMENT)) {
- $xactions[] = id(new DifferentialTransaction())
- ->setTransactionType(DifferentialTransaction::TYPE_ACTION)
- ->setNewValue($command);
+ $content_source = PhabricatorContentSource::newForSource(
+ PhabricatorContentSource::SOURCE_EMAIL,
+ array(
+ 'id' => $mail->getID(),
+ ));
+
+ $template = id(new DifferentialTransaction());
+
+ $commands = $body_data['commands'];
+ foreach ($commands as $command_argv) {
+ $command = head($command_argv);
+ switch ($command) {
+ case 'unsubscribe':
+ $xactions[] = id(clone $template)
+ ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
+ ->setNewValue(
+ array(
+ '-' => array($viewer->getPHID()),
+ ));
+ break;
+ case DifferentialAction::ACTION_ACCEPT:
+ $accept_key = 'differential.enable-email-accept';
+ $can_accept = PhabricatorEnv::getEnvConfig($accept_key);
+ if (!$can_accept) {
+ throw new Exception(
+ pht(
+ 'You can not !accept revisions over email because '.
+ 'Differential is configured to disallow this.'));
+ }
+ // Fall through...
+ case DifferentialAction::ACTION_REJECT:
+ case DifferentialAction::ACTION_ABANDON:
+ case DifferentialAction::ACTION_RECLAIM:
+ case DifferentialAction::ACTION_RESIGN:
+ case DifferentialAction::ACTION_RETHINK:
+ case DifferentialAction::ACTION_CLAIM:
+ case DifferentialAction::ACTION_REOPEN:
+ $xactions[] = id(clone $template)
+ ->setTransactionType(DifferentialTransaction::TYPE_ACTION)
+ ->setNewValue($command);
+ break;
+ }
}
- if (strlen($body)) {
- $xactions[] = id(new DifferentialTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
- ->attachComment(
- id(new DifferentialTransactionComment())
- ->setContent($body));
- }
+ $xactions[] = id(clone $template)
+ ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
+ ->attachComment(
+ id(new DifferentialTransactionComment())
+ ->setContent($body));
$editor = id(new DifferentialTransactionEditor())
- ->setActor($actor)
+ ->setActor($viewer)
+ ->setContentSource($content_source)
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
->setContinueOnMissingFields(true)
->setContinueOnNoEffect(true);
- // NOTE: We have to be careful about this because Facebook's
- // implementation jumps straight into handleAction() and will not have
- // a PhabricatorMetaMTAReceivedMail object.
- if ($this->receivedMail) {
- $content_source = PhabricatorContentSource::newForSource(
- PhabricatorContentSource::SOURCE_EMAIL,
- array(
- 'id' => $this->receivedMail->getID(),
- ));
- $editor->setContentSource($content_source);
- $editor->setParentMessageID($this->receivedMail->getMessageID());
- } else {
- $content_source = PhabricatorContentSource::newForSource(
- PhabricatorContentSource::SOURCE_LEGACY,
- array());
- $editor->setContentSource($content_source);
- }
-
- $editor->applyTransactions($this->getMailReceiver(), $xactions);
+ $editor->applyTransactions($revision, $xactions);
}
}
diff --git a/src/applications/files/mail/FileReplyHandler.php b/src/applications/files/mail/FileReplyHandler.php
index aafd2fd43b..23a4735e69 100644
--- a/src/applications/files/mail/FileReplyHandler.php
+++ b/src/applications/files/mail/FileReplyHandler.php
@@ -1,69 +1,62 @@
<?php
final class FileReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof PhabricatorFile)) {
throw new Exception('Mail receiver is not a PhabricatorFile.');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'F');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('F');
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$actor = $this->getActor();
$file = $this->getMailReceiver();
$body_data = $mail->parseBody();
$body = $body_data['body'];
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $mail->getID(),
));
$xactions = array();
- $command = $body_data['body'];
-
- switch ($command) {
- case 'unsubscribe':
- $xaction = id(new PhabricatorFileTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
- ->setNewValue(array('-' => array($actor->getPHID())));
- $xactions[] = $xaction;
- break;
+ $commands = $body_data['commands'];
+ 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;
+ }
}
$xactions[] = id(new PhabricatorFileTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
- id(new PhabricatorFileTransactionComment())
- ->setContent($body));
+ id(new PhabricatorFileTransactionComment())
+ ->setContent($body));
$editor = id(new PhabricatorFileEditor())
->setActor($actor)
->setContentSource($content_source)
->setContinueOnNoEffect(true)
->setIsPreview(false);
- try {
- $xactions = $editor->applyTransactions($file, $xactions);
- } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
- // just do nothing, though unclear why you're sending a blank email
- return true;
- }
-
- $head_xaction = head($xactions);
- return $head_xaction->getID();
+ $editor->applyTransactions($file, $xactions);
}
}
diff --git a/src/applications/legalpad/mail/LegalpadReplyHandler.php b/src/applications/legalpad/mail/LegalpadReplyHandler.php
index 9dd6cc8890..35558c4ade 100644
--- a/src/applications/legalpad/mail/LegalpadReplyHandler.php
+++ b/src/applications/legalpad/mail/LegalpadReplyHandler.php
@@ -1,73 +1,66 @@
<?php
final class LegalpadReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof LegalpadDocument)) {
throw new Exception('Mail receiver is not a LegalpadDocument!');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'L');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('L');
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$actor = $this->getActor();
$document = $this->getMailReceiver();
$body_data = $mail->parseBody();
$body = $body_data['body'];
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $mail->getID(),
));
-
$xactions = array();
- $command = $body_data['command'];
- switch ($command) {
- case 'unsubscribe':
- $xaction = id(new LegalpadTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
- ->setNewValue(array('-' => array($actor->getPHID())));
- $xactions[] = $xaction;
- break;
+ $commands = $body_data['commands'];
+ foreach ($commands as $command) {
+ switch (head($command)) {
+ case 'unsubscribe':
+ $xaction = id(new LegalpadTransaction())
+ ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
+ ->setNewValue(array('-' => array($actor->getPHID())));
+ $xactions[] = $xaction;
+ break;
+ }
}
$xactions[] = id(new LegalpadTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new LegalpadTransactionComment())
- ->setDocumentID($document->getID())
- ->setLineNumber(0)
- ->setLineLength(0)
- ->setContent($body));
+ ->setDocumentID($document->getID())
+ ->setLineNumber(0)
+ ->setLineLength(0)
+ ->setContent($body));
$editor = id(new LegalpadDocumentEditor())
->setActor($actor)
->setContentSource($content_source)
->setContinueOnNoEffect(true)
->setIsPreview(false);
- try {
- $xactions = $editor->applyTransactions($document, $xactions);
- } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
- // just do nothing, though unclear why you're sending a blank email
- return true;
- }
-
- $head_xaction = head($xactions);
- return $head_xaction->getID();
+ $editor->applyTransactions($document, $xactions);
}
}
diff --git a/src/applications/maniphest/mail/ManiphestReplyHandler.php b/src/applications/maniphest/mail/ManiphestReplyHandler.php
index 7f74c8a569..e4bfc5c319 100644
--- a/src/applications/maniphest/mail/ManiphestReplyHandler.php
+++ b/src/applications/maniphest/mail/ManiphestReplyHandler.php
@@ -1,180 +1,188 @@
<?php
final class ManiphestReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof ManiphestTask)) {
throw new Exception('Mail receiver is not a ManiphestTask!');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'T');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('T');
}
public function getReplyHandlerDomain() {
return $this->getCustomReplyHandlerDomainIfExists(
'metamta.maniphest.reply-handler-domain');
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
// NOTE: We'll drop in here on both the "reply to a task" and "create a
// new task" workflows! Make sure you test both if you make changes!
$task = $this->getMailReceiver();
$is_new_task = !$task->getID();
$user = $this->getActor();
$body_data = $mail->parseBody();
$body = $body_data['body'];
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$xactions = array();
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $mail->getID(),
));
$template = new ManiphestTransaction();
$is_unsub = false;
if ($is_new_task) {
$task = ManiphestTask::initializeNewTask($user);
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_STATUS)
->setNewValue(ManiphestTaskStatus::getDefaultStatus());
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_TITLE)
->setNewValue(nonempty($mail->getSubject(), pht('Untitled Task')));
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION)
->setNewValue($body);
} else {
- $command = $body_data['command'];
- $command_value = $body_data['command_value'];
+ $commands = $body_data['commands'];
+
+ // TODO: Support multiple commands.
+ if ($commands) {
+ $command_argv = head($commands);
+ } else {
+ $command_argv = array();
+ }
+ $command = idx($command_argv, 0);
+ $command_value = idx($command_argv, 1);
$ttype = PhabricatorTransactions::TYPE_COMMENT;
$new_value = null;
switch ($command) {
case 'close':
$ttype = ManiphestTransaction::TYPE_STATUS;
$new_value = ManiphestTaskStatus::getDefaultClosedStatus();
break;
case 'claim':
$ttype = ManiphestTransaction::TYPE_OWNER;
$new_value = $user->getPHID();
break;
case 'assign':
$ttype = ManiphestTransaction::TYPE_OWNER;
if ($command_value) {
$assign_users = id(new PhabricatorPeopleQuery())
->setViewer($user)
->withUsernames(array($command_value))
->execute();
if ($assign_users) {
$assign_user = head($assign_users);
$new_value = $assign_user->getPHID();
}
}
// assign to the user by default
if (!$new_value) {
$new_value = $user->getPHID();
}
break;
case 'unsubscribe':
$is_unsub = true;
$ttype = PhabricatorTransactions::TYPE_SUBSCRIBERS;
$ccs = $task->getSubscriberPHIDs();
foreach ($ccs as $k => $phid) {
if ($phid == $user->getPHID()) {
unset($ccs[$k]);
}
}
$new_value = array('=' => array_values($ccs));
break;
}
if ($ttype != PhabricatorTransactions::TYPE_COMMENT) {
$xaction = clone $template;
$xaction->setTransactionType($ttype);
$xaction->setNewValue($new_value);
$xactions[] = $xaction;
}
if (strlen($body)) {
$xaction = clone $template;
$xaction->setTransactionType(PhabricatorTransactions::TYPE_COMMENT);
$xaction->attachComment(
id(new ManiphestTransactionComment())
->setContent($body));
$xactions[] = $xaction;
}
}
$ccs = $mail->loadCCPHIDs();
$old_ccs = $task->getSubscriberPHIDs();
$new_ccs = array_merge($old_ccs, $ccs);
if (!$is_unsub) {
$new_ccs[] = $user->getPHID();
}
$new_ccs = array_unique($new_ccs);
if (array_diff($new_ccs, $old_ccs)) {
$cc_xaction = clone $template;
$cc_xaction->setTransactionType(
PhabricatorTransactions::TYPE_SUBSCRIBERS);
$cc_xaction->setNewValue(array('=' => $new_ccs));
$xactions[] = $cc_xaction;
}
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK,
array(
'task' => $task,
'mail' => $mail,
'new' => $is_new_task,
'transactions' => $xactions,
));
$event->setUser($user);
PhutilEventEngine::dispatchEvent($event);
$task = $event->getValue('task');
$xactions = $event->getValue('transactions');
$editor = id(new ManiphestTransactionEditor())
->setActor($user)
->setParentMessageID($mail->getMessageID())
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->setContentSource($content_source);
if ($this->getApplicationEmail()) {
$editor->setApplicationEmail($this->getApplicationEmail());
}
$editor->applyTransactions($task, $xactions);
$event = new PhabricatorEvent(
PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK,
array(
'task' => $task,
'new' => $is_new_task,
'transactions' => $xactions,
));
$event->setUser($user);
PhutilEventEngine::dispatchEvent($event);
}
}
diff --git a/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php b/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php
index f138ba243a..05133777aa 100644
--- a/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php
+++ b/src/applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php
@@ -1,129 +1,159 @@
<?php
final class PhabricatorMetaMTAEmailBodyParser {
/**
* Mails can have bodies such as
*
* !claim
*
* taking this task
*
* Or
*
* !assign epriestley
*
* please, take this task I took; its hard
*
* This function parses such an email body and returns a dictionary
- * containing a clean body text (e.g. "taking this task"), a $command
- * (e.g. !claim, !assign) and a $command_value (e.g. "epriestley" in the
- * !assign example.)
+ * containing a clean body text (e.g. "taking this task"), and a list of
+ * commands. For example, this body above might parse as:
*
- * @return dict
+ * array(
+ * 'body' => 'please, take this task I took; its hard',
+ * 'commands' => array(
+ * array('assign', 'epriestley'),
+ * ),
+ * )
+ *
+ * @param string Raw mail text body.
+ * @return dict Parsed body.
*/
public function parseBody($body) {
$body = $this->stripTextBody($body);
- $lines = explode("\n", trim($body));
- $first_line = head($lines);
-
- $command = null;
- $command_value = null;
- $matches = null;
- if (preg_match('/^!(\w+)\s*(\S+)?/', $first_line, $matches)) {
- $lines = array_slice($lines, 1);
- $body = implode("\n", $lines);
- $body = trim($body);
-
- $command = $matches[1];
- $command_value = idx($matches, 2);
- }
+
+ $commands = array();
+
+ $lines = phutil_split_lines($body, $retain_endings = true);
+
+ // We'll match commands at the beginning and end of the mail, but not
+ // in the middle of the mail body.
+ list($top_commands, $lines) = $this->stripCommands($lines);
+ list($end_commands, $lines) = $this->stripCommands(array_reverse($lines));
+ $lines = array_reverse($lines);
+ $commands = array_merge($top_commands, array_reverse($end_commands));
+
+ $lines = rtrim(implode('', $lines));
return array(
- 'body' => $body,
- 'command' => $command,
- 'command_value' => $command_value,
+ 'body' => $lines,
+ 'commands' => $commands,
);
}
+ private function stripCommands(array $lines) {
+ $saw_command = false;
+ $commands = array();
+ foreach ($lines as $key => $line) {
+ if (!strlen(trim($line)) && $saw_command) {
+ unset($lines[$key]);
+ continue;
+ }
+
+ $matches = null;
+ if (!preg_match('/^\s*!(\w+.*$)/', $line, $matches)) {
+ break;
+ }
+
+ $arg_str = $matches[1];
+ $argv = preg_split('/[,\s]+/', trim($arg_str));
+ $commands[] = $argv;
+ unset($lines[$key]);
+
+ $saw_command = true;
+ }
+
+ return array($commands, $lines);
+ }
+
public function stripTextBody($body) {
return trim($this->stripSignature($this->stripQuotedText($body)));
}
private function stripQuotedText($body) {
// Look for "On <date>, <user> wrote:". This may be split across multiple
// lines. We need to be careful not to remove all of a message like this:
//
// On which day do you want to meet?
//
// On <date>, <user> wrote:
// > Let's set up a meeting.
$start = null;
$lines = phutil_split_lines($body);
foreach ($lines as $key => $line) {
if (preg_match('/^\s*>?\s*On\b/', $line)) {
$start = $key;
}
if ($start !== null) {
if (preg_match('/\bwrote:/', $line)) {
$lines = array_slice($lines, 0, $start);
$body = implode('', $lines);
break;
}
}
}
// Outlook english
$body = preg_replace(
'/^\s*(> )?-----Original Message-----.*?/imsU',
'',
$body);
// Outlook danish
$body = preg_replace(
'/^\s*(> )?-----Oprindelig Meddelelse-----.*?/imsU',
'',
$body);
// See example in T3217.
$body = preg_replace(
'/^________________________________________\s+From:.*?/imsU',
'',
$body);
return rtrim($body);
}
private function stripSignature($body) {
// Quasi-"standard" delimiter, for lols see:
// https://bugzilla.mozilla.org/show_bug.cgi?id=58406
$body = preg_replace(
'/^-- +$.*/sm',
'',
$body);
// Mailbox seems to make an attempt to comply with the "standard" but
// omits the leading newline and uses an em dash?
$body = preg_replace(
"/\s*\xE2\x80\x94 \nSent from Mailbox\s*\z/su",
'',
$body);
// HTC Mail application (mobile)
$body = preg_replace(
'/^\s*^Sent from my HTC smartphone.*/sm',
'',
$body);
// Apple iPhone
$body = preg_replace(
'/^\s*^Sent from my iPhone\s*$.*/sm',
'',
$body);
return rtrim($body);
}
}
diff --git a/src/applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php b/src/applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php
index 94473f498c..435243edd4 100644
--- a/src/applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php
+++ b/src/applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php
@@ -1,189 +1,253 @@
<?php
final class PhabricatorMetaMTAEmailBodyParserTestCase
extends PhabricatorTestCase {
public function testQuotedTextStripping() {
$bodies = $this->getEmailBodies();
foreach ($bodies as $body) {
$parser = new PhabricatorMetaMTAEmailBodyParser();
$stripped = $parser->stripTextBody($body);
$this->assertEqual('OKAY', $stripped);
}
}
public function testEmailBodyCommandParsing() {
$bodies = $this->getEmailBodiesWithFullCommands();
foreach ($bodies as $body) {
$parser = new PhabricatorMetaMTAEmailBodyParser();
$body_data = $parser->parseBody($body);
$this->assertEqual('OKAY', $body_data['body']);
- $this->assertEqual('whatevs', $body_data['command']);
- $this->assertEqual('dude', $body_data['command_value']);
+ $this->assertEqual(
+ array(
+ array('whatevs', 'dude'),
+ ),
+ $body_data['commands']);
}
+
$bodies = $this->getEmailBodiesWithPartialCommands();
foreach ($bodies as $body) {
$parser = new PhabricatorMetaMTAEmailBodyParser();
$body_data = $parser->parseBody($body);
$this->assertEqual('OKAY', $body_data['body']);
- $this->assertEqual('whatevs', $body_data['command']);
- $this->assertEqual(null, $body_data['command_value']);
+ $this->assertEqual(
+ array(
+ array('whatevs'),
+ ),
+ $body_data['commands']);
+ }
+
+ $bodies = $this->getEmailBodiesWithMultipleCommands();
+ foreach ($bodies as $body) {
+ $parser = new PhabricatorMetaMTAEmailBodyParser();
+ $body_data = $parser->parseBody($body);
+ $this->assertEqual("preface\n\nOKAY", $body_data['body']);
+ $this->assertEqual(
+ array(
+ array('top1'),
+ array('top2'),
+ ),
+ $body_data['commands']);
+ }
+
+ $bodies = $this->getEmailBodiesWithSplitCommands();
+ foreach ($bodies as $body) {
+ $parser = new PhabricatorMetaMTAEmailBodyParser();
+ $body_data = $parser->parseBody($body);
+ $this->assertEqual('OKAY', $body_data['body']);
+ $this->assertEqual(
+ array(
+ array('cmd1'),
+ array('cmd2'),
+ ),
+ $body_data['commands']);
+ }
+
+ $bodies = $this->getEmailBodiesWithMiddleCommands();
+ foreach ($bodies as $body) {
+ $parser = new PhabricatorMetaMTAEmailBodyParser();
+ $body_data = $parser->parseBody($body);
+ $this->assertEqual("HEAD\n!cmd2\nTAIL", $body_data['body']);
}
}
public function testFalsePositiveForOnWrote() {
$body = <<<EOEMAIL
On which horse shall you ride?
On Sep 23, alincoln wrote:
> Hey bro do you want to go ride horses tomorrow?
EOEMAIL;
$parser = new PhabricatorMetaMTAEmailBodyParser();
$stripped = $parser->stripTextBody($body);
$this->assertEqual('On which horse shall you ride?', $stripped);
}
private function getEmailBodiesWithFullCommands() {
$bodies = $this->getEmailBodies();
$with_commands = array();
foreach ($bodies as $body) {
$with_commands[] = "!whatevs dude\n".$body;
}
return $with_commands;
}
private function getEmailBodiesWithPartialCommands() {
$bodies = $this->getEmailBodies();
$with_commands = array();
foreach ($bodies as $body) {
$with_commands[] = "!whatevs\n".$body;
}
return $with_commands;
}
+ private function getEmailBodiesWithMultipleCommands() {
+ $bodies = $this->getEmailBodies();
+ $with_commands = array();
+ foreach ($bodies as $body) {
+ $with_commands[] = "!top1\n\n!top2\n\npreface\n\n".$body;
+ }
+ return $with_commands;
+ }
+
+ private function getEmailBodiesWithSplitCommands() {
+ $with_split = array();
+ $with_split[] = "!cmd1\n!cmd2\nOKAY";
+ $with_split[] = "!cmd1\nOKAY\n!cmd2";
+ $with_split[] = "OKAY\n!cmd1\n!cmd2";
+ return $with_split;
+ }
+
+ private function getEmailBodiesWithMiddleCommands() {
+ $with_middle = array();
+ $with_middle[] = "!cmd1\nHEAD\n!cmd2\nTAIL\n!cmd3";
+ $with_middle[] = "!cmd1\nHEAD\n!cmd2\nTAIL";
+ $with_middle[] = "HEAD\n!cmd2\nTAIL\n!cmd3";
+ return $with_middle;
+ }
private function getEmailBodies() {
$trailing_space = ' ';
$emdash = "\xE2\x80\x94";
return array(
<<<EOEMAIL
OKAY
On May 30, 2011, at 8:36 PM, Someone wrote:
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
On Fri, May 27, 2011 at 9:39 AM, Someone <
somebody@somewhere.com> wrote:
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
On Fri, May 27, 2011 at 9:39 AM, Someone
<somebody@somewhere.com> wrote:
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
-----Oprindelig Meddelelse-----
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
-----Original Message-----
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
-----oprindelig meddelelse-----
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
-----original message-----
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
Sent from my HTC smartphone on the Now Network from Sprint!
-Reply message ----- From: "somebody (someone)" <
somebody@somewhere.com>
To: <somebody@somewhere.com>
Subject: Some Text Date: Mon, Apr 2, 2012 1:42 pm
> ...
EOEMAIL
,
<<<EOEMAIL
OKAY
--{$trailing_space}
Abraham Lincoln
Supreme Galactic Emperor
EOEMAIL
,
<<<EOEMAIL
OKAY
Sent from my iPhone
EOEMAIL
,
<<<EOMAIL
OKAY
________________________________________
From: Abraham Lincoln <alincoln@logcab.in>
Subject: Core World Tariffs
EOMAIL
,
<<<EOMAIL
OKAY
> On 17 Oct 2013, at 17:47, "Someone" <somebody@somewhere> wrote:
> ...
EOMAIL
,
<<<EOMAIL
OKAY
> -----Original Message-----
>
> ...
EOMAIL
,
<<<EOMAIL
OKAY {$emdash}{$trailing_space}
Sent from Mailbox
EOMAIL
);
}
}
diff --git a/src/applications/paste/mail/PasteReplyHandler.php b/src/applications/paste/mail/PasteReplyHandler.php
index 1cc5e91d70..523e2ee68d 100644
--- a/src/applications/paste/mail/PasteReplyHandler.php
+++ b/src/applications/paste/mail/PasteReplyHandler.php
@@ -1,72 +1,66 @@
<?php
final class PasteReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof PhabricatorPaste)) {
throw new Exception('Mail receiver is not a PhabricatorPaste.');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'P');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('P');
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$actor = $this->getActor();
$paste = $this->getMailReceiver();
$body_data = $mail->parseBody();
$body = $body_data['body'];
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $mail->getID(),
));
$lines = explode("\n", trim($body));
$first_line = head($lines);
$xactions = array();
- $command = $body_data['command'];
- switch ($command) {
- case 'unsubscribe':
- $xaction = id(new PhabricatorPasteTransaction())
- ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
- ->setNewValue(array('-' => array($actor->getPHID())));
- $xactions[] = $xaction;
- break;
+ $commands = $body_data['commands'];
+ 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;
+ }
}
$xactions[] = id(new PhabricatorPasteTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new PhabricatorPasteTransactionComment())
->setContent($body));
$editor = id(new PhabricatorPasteEditor())
->setActor($actor)
->setContentSource($content_source)
->setContinueOnNoEffect(true)
->setIsPreview(false);
- try {
- $xactions = $editor->applyTransactions($paste, $xactions);
- } catch (PhabricatorApplicationTransactionNoEffectException $ex) {
- // just do nothing, though unclear why you're sending a blank email
- return true;
- }
-
- $head_xaction = head($xactions);
- return $head_xaction->getID();
+ $editor->applyTransactions($paste, $xactions);
}
}
diff --git a/src/applications/releeph/mail/ReleephRequestMailReceiver.php b/src/applications/releeph/mail/ReleephRequestMailReceiver.php
index 2c6646f6e6..6d0e06c5c9 100644
--- a/src/applications/releeph/mail/ReleephRequestMailReceiver.php
+++ b/src/applications/releeph/mail/ReleephRequestMailReceiver.php
@@ -1,32 +1,32 @@
<?php
final class ReleephRequestMailReceiver extends PhabricatorObjectMailReceiver {
public function isEnabled() {
$app_class = 'PhabricatorReleephApplication';
return PhabricatorApplication::isClassInstalled($app_class);
}
protected function getObjectPattern() {
- return 'RQ[1-9]\d*';
+ return 'Y[1-9]\d*';
}
protected function loadObject($pattern, PhabricatorUser $viewer) {
- $id = (int)substr($pattern, 2);
+ $id = (int)substr($pattern, 1);
return id(new ReleephRequestQuery())
->setViewer($viewer)
->withIDs(array($id))
->executeOne();
}
protected function processReceivedObjectMail(
PhabricatorMetaMTAReceivedMail $mail,
PhabricatorLiskDAO $object,
PhabricatorUser $sender) {
// TODO: For now, we just drop this mail on the floor.
}
}
diff --git a/src/applications/releeph/mail/ReleephRequestReplyHandler.php b/src/applications/releeph/mail/ReleephRequestReplyHandler.php
index 4c36078ea5..0a3fa401f4 100644
--- a/src/applications/releeph/mail/ReleephRequestReplyHandler.php
+++ b/src/applications/releeph/mail/ReleephRequestReplyHandler.php
@@ -1,47 +1,46 @@
<?php
final class ReleephRequestReplyHandler extends PhabricatorMailReplyHandler {
public function validateMailReceiver($mail_receiver) {
if (!($mail_receiver instanceof ReleephRequest)) {
throw new Exception('Mail receiver is not a ReleephRequest!');
}
}
public function getPrivateReplyHandlerEmailAddress(
PhabricatorObjectHandle $handle) {
- return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'RERQ');
+ return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'Y');
}
public function getPublicReplyHandlerEmailAddress() {
- return $this->getDefaultPublicReplyHandlerEmailAddress('RERQ');
+ return $this->getDefaultPublicReplyHandlerEmailAddress('Y');
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
$rq = $this->getMailReceiver();
$user = $this->getActor();
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_EMAIL,
array(
'id' => $mail->getID(),
));
- $editor = id(new ReleephRequestTransactionalEditor())
- ->setActor($user)
- ->setContentSource($content_source)
- ->setParentMessageID($mail->getMessageID());
-
$body = $mail->getCleanTextBody();
$xactions = array();
$xactions[] = id(new ReleephRequestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment($body);
- $editor->applyTransactions($rq, $xactions);
+ $editor = id(new ReleephRequestTransactionalEditor())
+ ->setActor($user)
+ ->setContentSource($content_source)
+ ->setContinueOnNoEffect(true)
+ ->setParentMessageID($mail->getMessageID());
- return $rq;
+ $editor->applyTransactions($rq, $xactions);
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Jan 19 2025, 21:59 (6 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1129172
Default Alt Text
(36 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment