Page MenuHomePhorge

No OneTemporary

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

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)

Event Timeline