public function receiveMessage(PhabricatorBotMessage $message) { switch ($message->getCommand()) { case 'MESSAGE': $text = $message->getBody(); $matches = null; if (!preg_match('/where(?: in the world)? is (\\S+?)\\?/i', $text, $matches)) { break; } $symbol = $matches[1]; $results = $this->getConduit()->callMethodSynchronous('diffusion.findsymbols', array('name' => $symbol)); $default_uri = $this->getURI('/diffusion/symbol/' . $symbol . '/'); if (count($results) > 1) { $response = "Multiple symbols named '{$symbol}': {$default_uri}"; } else { if (count($results) == 1) { $result = head($results); $response = $result['type'] . ' ' . $result['name'] . ' ' . '(' . $result['language'] . '): ' . nonempty($result['uri'], $default_uri); } else { $response = "No symbol '{$symbol}' found anywhere."; } } $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 writeMessage(PhabricatorBotMessage $message) { switch ($message->getCommand()) { case 'MESSAGE': $this->speak($message->getBody(), $message->getTarget()); break; } }
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 $message) { switch ($message->getCommand()) { case 'MESSAGE': $message_body = $message->getBody(); $now = time(); $prompt = '~what( i|\')?s new\\?~i'; if (preg_match($prompt, $message_body)) { if ($now < $this->floodblock) { return; } $this->floodblock = $now + 60; $this->reportNew($message); } 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 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); }
private function routeMessage(PhabricatorBotMessage $message) { $ignore = $this->getConfig('ignore'); if ($ignore) { $sender = $message->getSender(); if ($sender && in_array($sender->getName(), $ignore)) { return; } } if ($message->getCommand() == 'LOG') { $this->log('[LOG] ' . $message->getBody()); } foreach ($this->handlers as $handler) { try { $handler->receiveMessage($message); } catch (Exception $ex) { phlog($ex); } } }
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; } }