Commit b683e466 authored by Morbus Iff's avatar Morbus Iff
Browse files

SmartIRC class moved around, forcing all messages to be UTF-8.

parent 1f0337ce
Loading
Loading
Loading
Loading
+2 −0
Changes for CHANGELOG.txt: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@

Bot 7.x-1.3, 2011-xx-xx
-----------------------
  * All incoming messages are forced to UTF-8 (thanks bellHead, nick_vh!).
  * #918966: Rewrote/moved Net_SmartIRC wrapper; hook_irc_access added.
  * All forgotten strlens()s have been changed to drupal_strlen().
  * All forgotten substr()s have been changed to drupal_substr().
  * First release for Drupal 7.x; based on 6.x-1.2 release.

bot.smartirc.inc

0 → 100644
+103 −0
Changes for bot.smartirc.inc: 103 added lines, 0 removed lines.
Original line number Diff line number Diff line
<?php
// $Id$

/**
 * @file
 * Classes and functions that wrap Drupal up for Net_SmartIRC.
 */

/**
 * A Drupal wrapper for the various Net_SmartIRC handlers.
 */
class bot_smartirc_wrapper {

  /**
   * Handle all Net_SmartIRC callbacks.
   *
   * @param &$irc
   *    The Net_SmartIRC $irc object.
   * @param &$data
   *    The Net_SmartIRC data object for this message.
   */
  function invoke(&$irc, &$data = NULL) {
    if (isset($data)) {
      // Net_SmartIRC passes data through in the encoding received from the
      // IRC server. The IRC server, in turn, passes it through as received
      // from the remote client. If the remote client is using a single byte
      // encoding (ISO-8559-1 aka Latin-1), this will result in mangled
      // characters or may raise errors for 8-bit characters. Under Drupal 7
      // and PHP 5.3, this caused an "invalid multibyte sequence" warning
      // from htmlspecialchars() and a PDOException that crashed the bot.
      // (To reproduce: use XChat to connect to a server as latin1, but then
      // send an 8-bit Latin-1 character like a Euro [€]). Since we cannot
      // control the encoding of IRC messages like we can control the encoding
      // of web form submissions, we need to force UTF-8 for all messages.
      if (function_exists('mb_detect_encoding')) {
        $encoding = mb_detect_encoding($data->message, 'UTF-8, ISO-8859-1');
        if ($encoding != 'UTF-8') { // no point of converting it already.
          // we only convert over message related elements and leave the
          // existing parses (nick, ident, host, type, channel, etc.) alone.
          $data->message      = mb_convert_encoding($data->message, 'UTF-8', $encoding);
          $data->rawmessage   = mb_convert_encoding($data->rawmessage, 'UTF-8', $encoding);
          $data->messageex    = explode(' ', $data->message);
          $data->rawmessageex = explode(' ', $data->rawmessage);
          watchdog('bot', 'Converted @encoding to UTF-8: @message.', array('@encoding' => $encoding, '@message' => $data->message), WATCHDOG_INFO);
        }
      }
    }

    // The name of the hook is a substring of the class name.
    $hook = drupal_substr(get_class($this), drupal_strlen('bot_'));

    // Give modules an opportunity to stop message processing.
    foreach (module_implements('irc_access') as $module) {
      $function = "{$module}_irc_access";
      $result = $function($hook, $data);

      // Stop handling this request if FALSE.
      if (isset($result) && $result === FALSE) {
        return;
      }
    }

    // Proceed normally.
    module_invoke_all($hook, $data);
  }
}

// Bot cron sub-classes.
class bot_irc_bot_cron          extends bot_smartirc_wrapper {}
class bot_irc_bot_cron_faster   extends bot_smartirc_wrapper {}
class bot_irc_bot_cron_fastest  extends bot_smartirc_wrapper {}

// IRC message sub-classes.
class bot_irc_msg_unknown       extends bot_smartirc_wrapper {}
class bot_irc_msg_channel       extends bot_smartirc_wrapper {}
class bot_irc_msg_query         extends bot_smartirc_wrapper {}
class bot_irc_msg_ctcp          extends bot_smartirc_wrapper {}
class bot_irc_msg_notice        extends bot_smartirc_wrapper {}
class bot_irc_msg_who           extends bot_smartirc_wrapper {}
class bot_irc_msg_join          extends bot_smartirc_wrapper {}
class bot_irc_msg_invite        extends bot_smartirc_wrapper {}
class bot_irc_msg_action        extends bot_smartirc_wrapper {}
class bot_irc_msg_topicchange   extends bot_smartirc_wrapper {}
class bot_irc_msg_nickchange    extends bot_smartirc_wrapper {}
class bot_irc_msg_kick          extends bot_smartirc_wrapper {}
class bot_irc_msg_quit          extends bot_smartirc_wrapper {}
class bot_irc_msg_login         extends bot_smartirc_wrapper {}
class bot_irc_msg_info          extends bot_smartirc_wrapper {}
class bot_irc_msg_list          extends bot_smartirc_wrapper {}
class bot_irc_msg_name          extends bot_smartirc_wrapper {}
class bot_irc_msg_motd          extends bot_smartirc_wrapper {}
class bot_irc_msg_modechange    extends bot_smartirc_wrapper {}
class bot_irc_msg_part          extends bot_smartirc_wrapper {}
class bot_irc_msg_error         extends bot_smartirc_wrapper {}
class bot_irc_msg_banlist       extends bot_smartirc_wrapper {}
class bot_irc_msg_topic         extends bot_smartirc_wrapper {}
class bot_irc_msg_nonrelevant   extends bot_smartirc_wrapper {}
class bot_irc_msg_whois         extends bot_smartirc_wrapper {}
class bot_irc_msg_whowas        extends bot_smartirc_wrapper {}
class bot_irc_msg_usermode      extends bot_smartirc_wrapper {}
class bot_irc_msg_channelmode   extends bot_smartirc_wrapper {}
class bot_irc_msg_ctcp_request  extends bot_smartirc_wrapper {}
class bot_irc_msg_ctcp_reply    extends bot_smartirc_wrapper {}
+10 −47
Changes for bot_start.php: 10 added lines, 47 removed lines.
Original line number Diff line number Diff line
@@ -36,17 +36,17 @@ while ($param = array_shift($_SERVER['argv'])) {
  }
}

// load in our required libraries.
require_once './includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
require_once('Net/SmartIRC.php');
// load in required libraries.
require_once 'Net/SmartIRC.php';
require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); // gotta bootstrap everything in before d_g_p.
require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'bot') . '/bot.smartirc.inc';

// prevent MySQL timeouts on slow channels.
db_query('SET SESSION wait_timeout = 86400');

// initialize the bot with some sane defaults.
global $irc; // allow it to be slurped by Drupal modules if need be.
$bot = new drupal_wrapper(); // wrapper that integrates with Drupal hooks.
$irc = new Net_SmartIRC(); // MmmmmmM. The IRC object itself. Magick happens here.
$irc->setDebug( variable_get('bot_debugging', 0) ? SMARTIRC_DEBUG_ALL : SMARTIRC_DEBUG_NONE );
// the (boolean) here is required, as Net_SmartIRC doesn't respect a FAPI checkbox value of 1, only TRUE.
@@ -67,14 +67,15 @@ $irc_message_types = array(
);

foreach ($irc_message_types as $irc_message_type) {
  $irc->registerActionhandler(constant('SMARTIRC_TYPE_' . $irc_message_type), '.*', $bot, 'invoke_irc_msg_' . strtolower($irc_message_type));
  $class = 'bot_irc_msg_' . drupal_strtolower($irc_message_type);
  $irc->registerActionhandler(constant('SMARTIRC_TYPE_' . $irc_message_type), '.*', new $class(), 'invoke');
}

// set up a timers similar to Drupal's hook_cron(), multiple types. I would have
// liked to just pass a parameter to a single function, but SmartIRC can't do that.
$irc->registerTimehandler(300000, $bot, 'invoke_irc_bot_cron');           // 5 minutes.
$irc->registerTimehandler(60000, $bot,  'invoke_irc_bot_cron_faster');    // 1 minute.
$irc->registerTimehandler(15000, $bot,  'invoke_irc_bot_cron_fastest');   // 15 seconds.
$irc->registerTimehandler(300000, new bot_irc_bot_cron(),         'invoke'); // 5 minutes.
$irc->registerTimehandler(60000,  new bot_irc_bot_cron_faster(),  'invoke'); // 1 minute.
$irc->registerTimehandler(15000,  new bot_irc_bot_cron_fastest(), 'invoke'); // 15 seconds.

// connect and begin listening.
$irc->connect(variable_get('bot_server', 'irc.freenode.net'), variable_get('bot_server_port', 6667));
@@ -85,41 +86,3 @@ $irc->login(variable_get('bot_nickname', 'bot_module'), variable_get('bot_nickna

$irc->listen(); // go into the forever loop - no code after this is run.
$irc->disconnect(); // if we stop listening, disconnect properly.

// pass off IRC messages to our modules via Drupal's hook system.
class drupal_wrapper {
  function invoke_irc_bot_cron(&$irc)                 { module_invoke_all('irc_bot_cron'); }
  function invoke_irc_bot_cron_faster(&$irc)          { module_invoke_all('irc_bot_cron_faster'); }
  function invoke_irc_bot_cron_fastest(&$irc)         { module_invoke_all('irc_bot_cron_fastest'); }
  function invoke_irc_msg_unknown(&$irc, &$data)      { module_invoke_all('irc_msg_unknown', $data); }
  function invoke_irc_msg_channel(&$irc, &$data)      { module_invoke_all('irc_msg_channel', $data); }
  function invoke_irc_msg_query(&$irc, &$data)        { module_invoke_all('irc_msg_query', $data); }
  function invoke_irc_msg_ctcp(&$irc, &$data)         { module_invoke_all('irc_msg_ctcp', $data); }
  function invoke_irc_msg_notice(&$irc, &$data)       { module_invoke_all('irc_msg_notice', $data); }
  function invoke_irc_msg_who(&$irc, &$data)          { module_invoke_all('irc_msg_who', $data); }
  function invoke_irc_msg_join(&$irc, &$data)         { module_invoke_all('irc_msg_join', $data); }
  function invoke_irc_msg_invite(&$irc, &$data)       { module_invoke_all('irc_msg_invite', $data); }
  function invoke_irc_msg_action(&$irc, &$data)       { module_invoke_all('irc_msg_action', $data); }
  function invoke_irc_msg_topicchange(&$irc, &$data)  { module_invoke_all('irc_msg_topicchange', $data); }
  function invoke_irc_msg_nickchange(&$irc, &$data)   { module_invoke_all('irc_msg_nickchange', $data); }
  function invoke_irc_msg_kick(&$irc, &$data)         { module_invoke_all('irc_msg_kick', $data); }
  function invoke_irc_msg_quit(&$irc, &$data)         { module_invoke_all('irc_msg_quit', $data); }
  function invoke_irc_msg_login(&$irc, &$data)        { module_invoke_all('irc_msg_login', $data); }
  function invoke_irc_msg_info(&$irc, &$data)         { module_invoke_all('irc_msg_info', $data); }
  function invoke_irc_msg_list(&$irc, &$data)         { module_invoke_all('irc_msg_list', $data); }
  function invoke_irc_msg_name(&$irc, &$data)         { module_invoke_all('irc_msg_name', $data); }
  function invoke_irc_msg_motd(&$irc, &$data)         { module_invoke_all('irc_msg_motd', $data); }
  function invoke_irc_msg_modechange(&$irc, &$data)   { module_invoke_all('irc_msg_modechange', $data); }
  function invoke_irc_msg_part(&$irc, &$data)         { module_invoke_all('irc_msg_part', $data); }
  function invoke_irc_msg_error(&$irc, &$data)        { module_invoke_all('irc_msg_error', $data); }
  function invoke_irc_msg_banlist(&$irc, &$data)      { module_invoke_all('irc_msg_banlist', $data); }
  function invoke_irc_msg_topic(&$irc, &$data)        { module_invoke_all('irc_msg_topic', $data); }
  function invoke_irc_msg_nonrelevant(&$irc, &$data)  { module_invoke_all('irc_msg_nonrelevant', $data); }
  function invoke_irc_msg_whois(&$irc, &$data)        { module_invoke_all('irc_msg_whois', $data); }
  function invoke_irc_msg_whowas(&$irc, &$data)       { module_invoke_all('irc_msg_whowas', $data); }
  function invoke_irc_msg_usermode(&$irc, &$data)     { module_invoke_all('irc_msg_usermode', $data); }
  function invoke_irc_msg_channelmode(&$irc, &$data)  { module_invoke_all('irc_msg_channelmode', $data); }
  function invoke_irc_msg_ctcp_request(&$irc, &$data) { module_invoke_all('irc_msg_ctcp_request', $data); }
  function invoke_irc_msg_ctcp_reply(&$irc, &$data)   { module_invoke_all('irc_msg_ctcp_reply', $data); }
}