public function writeMessage(PhabricatorBotMessage $message)
 {
     switch ($message->getCommand()) {
         case 'MESSAGE':
             $this->speak($message->getBody(), $message->getTarget());
             break;
         case 'SOUND':
             $this->speak($message->getBody(), $message->getTarget(), 'SoundMessage');
             break;
         case 'PASTE':
             $this->speak($message->getBody(), $message->getTarget(), 'PasteMessage');
             break;
     }
 }
 public function receiveMessage(PhabricatorBotMessage $message)
 {
     switch ($message->getCommand()) {
         case 'MESSAGE':
             $target = $message->getTarget();
             if (!$target->isPublic()) {
                 // Don't log private messages, although maybe we should for debugging?
                 break;
             }
             $target_name = $target->getName();
             $logs = array(array('channel' => $target_name, 'type' => 'mesg', 'epoch' => time(), 'author' => $message->getSender()->getName(), 'message' => $message->getBody(), 'serviceName' => $this->getServiceName(), 'serviceType' => $this->getServiceType()));
             $this->futures[] = $this->getConduit()->callMethod('chatlog.record', array('logs' => $logs));
             $prompts = array('/where is the (chat)?log\\?/i', '/where am i\\?/i', '/what year is (this|it)\\?/i');
             $tell = false;
             foreach ($prompts as $prompt) {
                 if (preg_match($prompt, $message->getBody())) {
                     $tell = true;
                     break;
                 }
             }
             if ($tell) {
                 $response = $this->getURI('/chatlog/channel/' . phutil_escape_uri($target_name) . '/');
                 $this->replyTo($message, $response);
             }
             break;
     }
 }
 public function receiveMessage(PhabricatorBotMessage $message)
 {
     if (!$this->init()) {
         return;
     }
     switch ($message->getCommand()) {
         case 'MESSAGE':
             $message_body = $message->getBody();
             $matches = null;
             if (!preg_match($this->regexp, trim($message_body), $matches)) {
                 return;
             }
             $macro = $matches[1];
             $ascii = idx($this->macros[$macro], 'ascii');
             if ($ascii === false) {
                 return;
             }
             if (!$ascii) {
                 $this->macros[$macro]['ascii'] = $this->rasterize($this->macros[$macro], $this->getConfig('macro.size', 48), $this->getConfig('macro.aspect', 0.66));
                 $ascii = $this->macros[$macro]['ascii'];
             }
             if ($ascii === false) {
                 // If we failed to rasterize the macro, bail out.
                 return;
             }
             $target_name = $message->getTarget()->getName();
             foreach ($ascii as $line) {
                 $this->replyTo($message, $line);
             }
             break;
     }
 }
 public function replyTo(PhabricatorBotMessage $original_message, $body)
 {
     if ($original_message->getCommand() != 'MESSAGE') {
         throw new Exception('Handler is trying to reply to something which is not a message!');
     }
     $reply = id(new PhabricatorBotMessage())->setCommand('MESSAGE');
     if ($original_message->getTarget()->isPublic()) {
         // This is a public target, like a chatroom. Send the response to the
         // chatroom.
         $reply->setTarget($original_message->getTarget());
     } else {
         // This is a private target, like a private message. Send the response
         // back to the sender (presumably, we are the target).
         $reply->setTarget($original_message->getSender());
     }
     $reply->setBody($body);
     return $this->writeMessage($reply);
 }
 public function receiveMessage(PhabricatorBotMessage $message)
 {
     switch ($message->getCommand()) {
         case 'MESSAGE':
             $matches = null;
             $text = $message->getBody();
             $target_name = $message->getTarget()->getName();
             if (empty($this->recentlyMentioned[$target_name])) {
                 $this->recentlyMentioned[$target_name] = array();
             }
             $pattern = '@^' . '(?:' . $this->getConfig('nick', 'phabot') . ')?' . '.?\\s*tell me about ' . '(.*)' . '$@';
             if (preg_match($pattern, $text, $matches)) {
                 $slug = $matches[1];
                 $quiet_until = idx($this->recentlyMentioned[$target_name], $slug, 0) + 60 * 10;
                 if (time() < $quiet_until) {
                     // Remain quiet on this channel.
                     break;
                 } else {
                     $this->recentlyMentioned[$target_name][$slug] = time();
                 }
                 try {
                     $result = $this->getConduit()->callMethodSynchronous('phriction.info', array('slug' => 'docbot/docs/' . $slug));
                 } catch (ConduitClientException $ex) {
                     phlog($ex);
                     $result = null;
                 }
                 $response = array();
                 if ($result) {
                     $content = phutil_split_lines($result['content'], $retain_newlines = false);
                     foreach ($content as $line) {
                         $response = array_merge($response, str_split($line, 400));
                         if (count($response) >= 3) {
                             break;
                         }
                     }
                 } else {
                     $response[] = "Nothing to say about " . $slug;
                 }
                 foreach (array_slice($response, 0, 3) as $output) {
                     $this->replyTo($message, html_entity_decode($output));
                 }
                 break;
             }
             $pattern = '@' . $this->getConfig('nick', 'phabot') . ' remember ' . '(.*?)' . ' as:' . '(.*)$' . '@';
             if (preg_match($pattern, $text, $matches)) {
                 $result = $this->getConduit()->callMethodSynchronous('phriction.edit', array('slug' => 'docbot/docs/' . $matches[1], 'content' => $matches[2]));
                 $slug = explode('/', trim($result['slug'], '/'), 3);
                 $output = "Saved as '{$slug[2]}' at {$result['uri']}";
                 $this->replyTo($message, $output);
                 unset($this->recentlyMentioned[$target_name][$slug[2]]);
                 unset($this->recentlyMentioned[$target_name][$matches[1]]);
                 break;
             }
             break;
     }
 }
 public function receiveMessage(PhabricatorBotMessage $original_message)
 {
     switch ($original_message->getCommand()) {
         case 'MESSAGE':
             $message = $original_message->getBody();
             $matches = null;
             $paste_ids = array();
             $commit_names = array();
             $vote_ids = array();
             $file_ids = array();
             $object_names = array();
             $output = array();
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '(R2D2)' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     switch ($match[1]) {
                         case 'R2D2':
                             $output[$match[1]] = pht('beep hoop bop');
                             break;
                     }
                 }
             }
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '([A-Z])(\\d+)' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     switch ($match[1]) {
                         case 'P':
                             $paste_ids[] = $match[2];
                             break;
                         case 'V':
                             $vote_ids[] = $match[2];
                             break;
                         case 'F':
                             $file_ids[] = $match[2];
                             break;
                         default:
                             $name = $match[1] . $match[2];
                             switch ($name) {
                                 case 'T1000':
                                     $output[$name] = pht('T1000: A mimetic poly-alloy assassin controlled by ' . 'Skynet');
                                     break;
                                 default:
                                     $object_names[] = $name;
                                     break;
                             }
                             break;
                     }
                 }
             }
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '(r[A-Z]+)([0-9a-z]{0,40})' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     if ($match[2]) {
                         $commit_names[] = $match[1] . $match[2];
                     } else {
                         $object_names[] = $match[1];
                     }
                 }
             }
             if ($object_names) {
                 $objects = $this->getConduit()->callMethodSynchronous('phid.lookup', array('names' => $object_names));
                 foreach ($objects as $object) {
                     $output[$object['phid']] = $object['fullName'] . ' - ' . $object['uri'];
                 }
             }
             if ($vote_ids) {
                 foreach ($vote_ids as $vote_id) {
                     $vote = $this->getConduit()->callMethodSynchronous('slowvote.info', array('poll_id' => $vote_id));
                     $output[$vote['phid']] = 'V' . $vote['id'] . ': ' . $vote['question'] . ' Come Vote ' . $vote['uri'];
                 }
             }
             if ($file_ids) {
                 foreach ($file_ids as $file_id) {
                     $file = $this->getConduit()->callMethodSynchronous('file.info', array('id' => $file_id));
                     $output[$file['phid']] = $file['objectName'] . ': ' . $file['uri'] . ' - ' . $file['name'];
                 }
             }
             if ($paste_ids) {
                 foreach ($paste_ids as $paste_id) {
                     $paste = $this->getConduit()->callMethodSynchronous('paste.info', array('paste_id' => $paste_id));
                     // Eventually I'd like to show the username of the paster as well,
                     // however that will need something like a user.username_from_phid
                     // since we (ideally) want to keep the bot to Conduit calls...and
                     // not call to Phabricator-specific stuff (like actually loading
                     // the User object and fetching his/her username.)
                     $output[$paste['phid']] = 'P' . $paste['id'] . ': ' . $paste['uri'] . ' - ' . $paste['title'];
                     if ($paste['language']) {
                         $output[$paste['phid']] .= ' (' . $paste['language'] . ')';
                     }
                 }
             }
             if ($commit_names) {
                 $commits = $this->getConduit()->callMethodSynchronous('diffusion.getcommits', array('commits' => $commit_names));
                 foreach ($commits as $commit) {
                     if (isset($commit['error'])) {
                         continue;
                     }
                     $output[$commit['commitPHID']] = $commit['uri'];
                 }
             }
             foreach ($output as $phid => $description) {
                 // Don't mention the same object more than once every 10 minutes
                 // in public channels, so we avoid spamming the chat over and over
                 // again for discsussions of a specific revision, for example.
                 $target_name = $original_message->getTarget()->getName();
                 if (empty($this->recentlyMentioned[$target_name])) {
                     $this->recentlyMentioned[$target_name] = array();
                 }
                 $quiet_until = idx($this->recentlyMentioned[$target_name], $phid, 0) + 60 * 10;
                 if (time() < $quiet_until) {
                     // Remain quiet on this channel.
                     continue;
                 }
                 $this->recentlyMentioned[$target_name][$phid] = time();
                 $this->replyTo($original_message, $description);
             }
             break;
     }
 }
 public function writeMessage(PhabricatorBotMessage $message)
 {
     switch ($message->getCommand()) {
         case 'MESSAGE':
         case 'PASTE':
             $name = $message->getTarget()->getName();
             $body = $message->getBody();
             $this->write("PRIVMSG {$name} :{$body}");
             return true;
         default:
             return false;
     }
 }
 public function receiveMessage(PhabricatorBotMessage $original_message)
 {
     switch ($original_message->getCommand()) {
         case 'MESSAGE':
             $message = $original_message->getBody();
             $matches = null;
             $paste_ids = array();
             $commit_names = array();
             $vote_ids = array();
             $file_ids = array();
             $object_names = array();
             $output = array();
             $pattern = '@' . '(?<![/:#-])(?:^|\\b)' . '(R2D2)' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     switch ($match[1]) {
                         case 'R2D2':
                             $output[$match[1]] = pht('beep boop bop');
                             break;
                     }
                 }
             }
             // Use a negative lookbehind to prevent matching "/D123", "#D123",
             // ":D123", etc.
             $pattern = '@' . '(?<![/:#-])(?:^|\\b)' . '([A-Z])(\\d+)' . '(?:\\b|$)' . '@';
             $regex = trim(PhabricatorEnv::getEnvConfig('remarkup.ignored-object-names'));
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     if ($regex && preg_match($regex, $match[0])) {
                         continue;
                     }
                     switch ($match[1]) {
                         case 'P':
                             $paste_ids[] = $match[2];
                             break;
                         case 'V':
                             $vote_ids[] = $match[2];
                             break;
                         case 'F':
                             $file_ids[] = $match[2];
                             break;
                         default:
                             $name = $match[1] . $match[2];
                             switch ($name) {
                                 case 'T1000':
                                     $output[$name] = pht('T1000: A mimetic poly-alloy assassin controlled by ' . 'Skynet');
                                     break;
                                 default:
                                     $object_names[] = $name;
                                     break;
                             }
                             break;
                     }
                 }
             }
             $pattern = '@' . '(?<!/)(?:^|\\b)' . '(r[A-Z]+)([0-9a-z]{0,40})' . '(?:\\b|$)' . '@';
             if (preg_match_all($pattern, $message, $matches, PREG_SET_ORDER)) {
                 foreach ($matches as $match) {
                     if ($match[2]) {
                         $commit_names[] = $match[1] . $match[2];
                     } else {
                         $object_names[] = $match[1];
                     }
                 }
             }
             if ($object_names) {
                 $objects = $this->getConduit()->callMethodSynchronous('phid.lookup', array('names' => $object_names));
                 foreach ($objects as $object) {
                     $output[$object['phid']] = $object['fullName'] . ' - ' . $object['uri'];
                 }
             }
             if ($vote_ids) {
                 foreach ($vote_ids as $vote_id) {
                     $vote = $this->getConduit()->callMethodSynchronous('slowvote.info', array('poll_id' => $vote_id));
                     $output[$vote['phid']] = 'V' . $vote['id'] . ': ' . $vote['question'] . ' ' . pht('Come Vote') . ' ' . $vote['uri'];
                 }
             }
             if ($file_ids) {
                 foreach ($file_ids as $file_id) {
                     $file = $this->getConduit()->callMethodSynchronous('file.info', array('id' => $file_id));
                     $output[$file['phid']] = $file['objectName'] . ': ' . $file['uri'] . ' - ' . $file['name'];
                 }
             }
             if ($paste_ids) {
                 foreach ($paste_ids as $paste_id) {
                     $paste = $this->getConduit()->callMethodSynchronous('paste.query', array('ids' => array($paste_id)));
                     $paste = head($paste);
                     $output[$paste['phid']] = 'P' . $paste['id'] . ': ' . $paste['uri'] . ' - ' . $paste['title'];
                     if ($paste['language']) {
                         $output[$paste['phid']] .= ' (' . $paste['language'] . ')';
                     }
                     $user = $this->getConduit()->callMethodSynchronous('user.query', array('phids' => array($paste['authorPHID'])));
                     $user = head($user);
                     if ($user) {
                         $output[$paste['phid']] .= ' by ' . $user['userName'];
                     }
                 }
             }
             if ($commit_names) {
                 $commits = $this->getConduit()->callMethodSynchronous('diffusion.querycommits', array('names' => $commit_names));
                 foreach ($commits['data'] as $commit) {
                     $output[$commit['phid']] = $commit['uri'];
                 }
             }
             foreach ($output as $phid => $description) {
                 // Don't mention the same object more than once every 10 minutes
                 // in public channels, so we avoid spamming the chat over and over
                 // again for discussions of a specific revision, for example.
                 $target_name = $original_message->getTarget()->getName();
                 if (empty($this->recentlyMentioned[$target_name])) {
                     $this->recentlyMentioned[$target_name] = array();
                 }
                 $quiet_until = idx($this->recentlyMentioned[$target_name], $phid, 0) + 60 * 10;
                 if (time() < $quiet_until) {
                     // Remain quiet on this channel.
                     continue;
                 }
                 $this->recentlyMentioned[$target_name][$phid] = time();
                 $this->replyTo($original_message, $description);
             }
             break;
     }
 }