From 055f3fdddb998bfee1a6f6e61d1ca6df4b2fb740 Mon Sep 17 00:00:00 2001 From: Craig Andrews Date: Fri, 8 Jan 2010 18:52:09 -0500 Subject: Add an IMAP daemon so StatusNet can process incoming user posts via catch-all mailbox (in addition to the pre-existing script alias method) --- plugins/Imap/ImapPlugin.php | 85 +++++++++++++++++++++++++ plugins/Imap/README | 32 ++++++++++ plugins/Imap/imapdaemon.php | 147 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 264 insertions(+) create mode 100644 plugins/Imap/ImapPlugin.php create mode 100644 plugins/Imap/README create mode 100755 plugins/Imap/imapdaemon.php (limited to 'plugins') diff --git a/plugins/Imap/ImapPlugin.php b/plugins/Imap/ImapPlugin.php new file mode 100644 index 000000000..034444222 --- /dev/null +++ b/plugins/Imap/ImapPlugin.php @@ -0,0 +1,85 @@ +. + * + * @category Plugin + * @package StatusNet + * @author Zach Copley + * @copyright 2009 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * IMAP plugin to allow StatusNet to grab incoming emails and handle them as new user posts + * + * @category Plugin + * @package StatusNet + * @author Craig Andrews mailbox)){ + throw new Exception("must specify a mailbox"); + } + if(!isset($this->user)){ + throw new Exception("must specify a user"); + } + if(!isset($this->password)){ + throw new Exception("must specify a password"); + } + if(!isset($this->poll_frequency)){ + throw new Exception("must specify a poll_frequency"); + } + + self::$instances[] = $this; + return true; + } + + function cleanup(){ + $index = array_search($this, self::$instances); + unset(self::$instances[$index]); + return true; + } + + function onGetValidDaemons($daemons) + { + if(! self::$daemon_added){ + array_push($daemons, INSTALLDIR . + '/plugins/Imap/imapdaemon.php'); + self::$daemon_added = true; + } + return true; + } +} diff --git a/plugins/Imap/README b/plugins/Imap/README new file mode 100644 index 000000000..640a411a8 --- /dev/null +++ b/plugins/Imap/README @@ -0,0 +1,32 @@ +The IMAP plugin allows for StatusNet to check a POP or IMAP mailbox for +incoming mail containing user posts. + +Installation +============ +addPlugin('imap', array( + 'mailbox' => '...', + 'user' => '...', + 'password' => '...' +)); +to the bottom of your config.php + +Also, make sure: +$config['mail']['domain'] = 'yourdomain.example.net'; +is set in your config.php + +Create a catch-all account for your domain, and use this account with this +plugin. Whenever a user sends a message to their personal notice posting +address, the message should end up in this mailbox, and then the plugin daemon +will pick it up and post the notice on the user's behalf. + +The daemon included with this plugin must be running. It will be started by +the plugin along with their other daemons when you run scripts/startdaemons.sh. +See the StatusNet README for more about queuing and daemons. + +Settings +======== +mailbox*: the mailbox specifier. + See http://www.php.net/manual/en/function.imap-open.php for details +user*: username to use when authenticating to the mailbox +password*: password to use when authenticating to the mailbox +poll_frequency: how often (in seconds) to check for new messages diff --git a/plugins/Imap/imapdaemon.php b/plugins/Imap/imapdaemon.php new file mode 100755 index 000000000..a45c603ce --- /dev/null +++ b/plugins/Imap/imapdaemon.php @@ -0,0 +1,147 @@ +#!/usr/bin/env php +. + */ + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/../..')); + +$shortoptions = 'fi::'; +$longoptions = array('id::', 'foreground'); + +$helptext = <<$value) + { + $this->$attr = $value; + } + + $this->log(LOG_INFO, "INITIALIZE IMAPDaemon {" . $this->name() . "}"); + } + + function name() + { + return strtolower('imapdaemon.'.$this->user.'.'.crc32($this->mailbox)); + } + + function run() + { + $this->connect(); + while(true) + { + if(imap_ping($this->conn) || $this->connect()) + { + $this->check_mailbox(); + } + sleep($this->poll_frequency); + } + } + + function check_mailbox() + { + $count = imap_num_msg($this->conn); + $this->log(LOG_INFO, "Found $count messages"); + if($count > 0){ + $handler = new IMAPMailHandler(); + for($i=1; $i <= $count; $i++) + { + $rawmessage = imap_fetchheader($this->conn, $count, FT_PREFETCHTEXT) . imap_body($this->conn, $i); + $handler->handle_message($rawmessage); + imap_delete($this->conn, $i); + } + imap_expunge($this->conn); + $this->log(LOG_INFO, "Finished processing messages"); + } + } + + function log($level, $msg) + { + $text = $this->name() . ': '.$msg; + common_log($level, $text); + if (!$this->daemonize) + { + $line = common_log_line($level, $text); + echo $line; + echo "\n"; + } + } + + function connect() + { + $this->conn = imap_open($this->mailbox, $this->user, $this->password); + if($this->conn){ + $this->log(LOG_INFO, "Connected"); + return true; + }else{ + $this->log(LOG_INFO, "Failed to connect: " . imap_last_error()); + return false; + } + } +} + +class IMAPMailHandler extends MailHandler +{ + function error($from, $msg) + { + $this->log(LOG_INFO, "Error: $from $msg"); + $headers['To'] = $from; + $headers['Subject'] = "Error"; + + return mail_send(array($from), $headers, $msg); + } +} + +if (have_option('i', 'id')) { + $id = get_option_value('i', 'id'); +} else if (count($args) > 0) { + $id = $args[0]; +} else { + $id = null; +} + +$foreground = have_option('f', 'foreground'); + +foreach(ImapPlugin::$instances as $pluginInstance){ + + $daemon = new IMAPDaemon($id, !$foreground, array( + 'mailbox' => $pluginInstance->mailbox, + 'user' => $pluginInstance->user, + 'password' => $pluginInstance->password, + 'poll_frequency' => $pluginInstance->poll_frequency + )); + + $daemon->runOnce(); + +} -- cgit v1.2.3-54-g00ecf