bot_seen.module

Tracking 6.x-1.x branch
  1. drupal
    1. 6 contributions/bot/bot_seen/bot_seen.module

Enables users to find out the last time a channel member was active.

Functions & methods

NameDescription
bot_seen_all_nicks_for_regexpReturn an array of all current nicks.
bot_seen_helpImplementation of hook_help().
bot_seen_irc_msg_actionCatch user actions too.
bot_seen_irc_msg_channelListen for conversation directed at, or around, the bot.
bot_seen_irc_msg_queryAll responses are available via a query.

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * Enables users to find out the last time a channel member was active.
  5. */
  6. /**
  7. * Implementation of hook_help().
  8. */
  9. function bot_seen_help($path, $arg) {
  10. switch ($path) {
  11. case 'irc:features':
  12. return array(t('Seen'));
  13. case 'irc:features#seen':
  14. return t('If someone asks "seen Morbus", the bot will report the last time they\'ve been seen, where, and what their last known message was. Directly addressing the bot will also allow the more complex syntax of "seen Morbus? seen d8uv?", "have you seen sbp?" and similar forms. * can be used as a wildcard, but only with a minimum of three other characters. A maximum of three results are displayed for any one request.');
  15. }
  16. }
  17. /**
  18. * Listen for conversation directed at, or around, the bot.
  19. *
  20. * @param $data
  21. * The regular $data object prepared by the IRC library.
  22. * @param $from_query
  23. * Boolean; whether this was a queried request.
  24. */
  25. function bot_seen_irc_msg_channel($data, $from_query = FALSE) {
  26. $to = $from_query ? $data->nick : $data->channel;
  27. $nicks = array(); // list of nicks to search for.
  28. $addressed = bot_name_regexp();
  29. // log the message, whatever it is. no UPDATEs; just start anew, eh?
  30. if (!$from_query) { // we only want to record public activity, not private messages.
  31. db_query("DELETE FROM {bot_seen} WHERE LOWER(nick) = '%s'", drupal_strtolower($data->nick));
  32. $seen = new stdClass(); // we don't UPDATE cos it's "cheaper" to just trash the old one.
  33. $seen->nick = $data->nick;
  34. $seen->channel = $data->channel;
  35. $seen->message = $data->message;
  36. $seen->timestamp = time();
  37. drupal_write_record('bot_seen', $seen);
  38. }
  39. // Match 'seen foo' in any mode, regardless if the bot was addressed.
  40. if (preg_match("/^seen ([a-zA-Z0-9\[\]\{\}\\\|\^\`\-\_\*]*)( ?\?|$)/i", trim($data->message), $matches)) {
  41. $nicks[] = $matches[1]; // the bot will listen to the first request only when unaddressed.
  42. }
  43. // Our more complicated regexp allows multiple types of syntax and
  44. // more than one lookup per query, but require direct addressing.
  45. if (preg_match("/^$addressed/i", $data->message) || $from_query) {
  46. if (preg_match_all('!.*?seen ([a-zA-Z0-9\[\]\{\}\\\|\^\`\-\_\*]*)( ?\?|$| ?\,)!i', trim($data->message), $matches)) {
  47. foreach ($matches[1] as $match) { // for every construct we've found in our message, find the user.
  48. $nicks[] = $match; // the bot will respond addressed to multiple requests and styles in one query.
  49. }
  50. }
  51. }
  52. // An array of all current nicks so that we can regexp them
  53. // away to prevent "seen pings" (when Person B's nick is in
  54. // the last message of Person A, Person C's "seen Person A"
  55. // will ping Person B, which is slightly annoying.
  56. $all_nicks = bot_seen_all_nicks_for_regexp();
  57. // fetch 'em.
  58. $messages = array();
  59. foreach (array_unique($nicks) as $nick) {
  60. // allow % SQL matching, but only if the nick is three non-* characters or longer.
  61. if (strlen(str_replace('*', '', $nick)) >= 3) { $nick = str_replace('*', '%', $nick); }
  62. $results = db_query("SELECT nick, channel, message, timestamp FROM {bot_seen} WHERE LOWER(nick) LIKE '%s' ORDER BY timestamp DESC", drupal_strtolower($nick));
  63. while ($result = db_fetch_object($results)) { // throw 'em on the bar-b... we'll shrink the result set later. to keep it relevant, we order by timestamp.
  64. $message = preg_replace($all_nicks, '\1_\2', $result->message); // prevent seen-pings by obfuscating the nick and hope they're not pattern matching on anything but exact.
  65. $messages[] = t("!nick was last seen in !channel !this_long ago saying '!message'.", array('!nick' => $result->nick, '!this_long' => format_interval(time() - $result->timestamp), '!channel' => $result->channel, '!message' => $message, ));
  66. } if (count($messages) == 0) { $messages[] = t("Sorry, I haven't seen !match.", array('!match' => str_replace('%', '*', $nick), )); }
  67. }
  68. // three results only to prevent flooding.
  69. $count = count($messages); // just for fun.
  70. $messages = array_splice($messages, 0, 3);
  71. foreach ($messages as $message) { bot_message($to, $message); }
  72. // @todo include a message stating number of results not shown.
  73. }
  74. /**
  75. * All responses are available via a query.
  76. */
  77. function bot_seen_irc_msg_query($data) {
  78. bot_seen_irc_msg_channel($data, TRUE);
  79. }
  80. /**
  81. * Catch user actions too.
  82. */
  83. function bot_seen_irc_msg_action($data) {
  84. if (strpos($data->channel, '#') === FALSE) { return; } // ignore actions PM'd to the bot.
  85. db_query("DELETE FROM {bot_seen} WHERE LOWER(nick) = '%s'", drupal_strtolower($data->nick));
  86. $seen = new stdClass(); // we don't UPDATE cos it's "cheaper" to just trash the old one.
  87. $seen->nick = $data->nick;
  88. $seen->channel = $data->channel; // there's lots of garbagey odd bits for actions.
  89. $seen->message = preg_replace('/^ACTION/', '* ' . $data->nick, trim($data->message, ''));
  90. $seen->timestamp = time();
  91. drupal_write_record('bot_seen', $seen);
  92. }
  93. /**
  94. * Return an array of all current nicks.
  95. */
  96. function bot_seen_all_nicks_for_regexp() {
  97. global $irc; $nicks = array();
  98. foreach ($irc->channel as $channel_name => $data) {
  99. foreach ($irc->channel[$channel_name]->users as $nick_name => $data) {
  100. $nick_name = preg_quote($nick_name, '/');
  101. $nick_name = preg_replace('/^(\\\\?.)(.*)/', '(\1)(\2)', $nick_name);
  102. $nicks[] = '/\b' . $nick_name . '\b/i';
  103. }
  104. }
  105. return array_unique($nicks);
  106. }