]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
move command-line scripts to their own dir
authorEvan Prodromou <evan@prodromou.name>
Wed, 13 Aug 2008 15:46:03 +0000 (11:46 -0400)
committerEvan Prodromou <evan@prodromou.name>
Wed, 13 Aug 2008 15:46:03 +0000 (11:46 -0400)
darcs-hash:20080813154603-84dde-fc1cf32ab5617c11b6cbe9ad084dac32b0db315a.gz

12 files changed:
fixup_hashtags.php [deleted file]
fixup_notices_rendered.php [deleted file]
fixup_replies.php [deleted file]
maildaemon.php [deleted file]
scripts/fixup_hashtags.php [new file with mode: 0755]
scripts/fixup_notices_rendered.php [new file with mode: 0755]
scripts/fixup_replies.php [new file with mode: 0755]
scripts/maildaemon.php [new file with mode: 0755]
scripts/sitemap.php [new file with mode: 0644]
scripts/xmppdaemon.php [new file with mode: 0755]
sitemap.php [deleted file]
xmppdaemon.php [deleted file]

diff --git a/fixup_hashtags.php b/fixup_hashtags.php
deleted file mode 100755 (executable)
index 04f50af..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-# Abort if called from a web server
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-
-common_log(LOG_INFO, 'Starting to do old notices.');
-
-$notice = new Notice();
-$cnt = $notice->find();
-
-while ($notice->fetch()) {
-    common_log(LOG_INFO, 'Getting tags for notice #' . $notice->id);
-    $notice->saveTags();
-       $original = clone($notice);
-       $notice->rendered = common_render_content($notice->content, $notice);
-       $result = $notice->update($original);
-       if (!$result) {
-               common_log_db_error($notice, 'UPDATE', __FILE__);
-       }
-}
diff --git a/fixup_notices_rendered.php b/fixup_notices_rendered.php
deleted file mode 100755 (executable)
index 53f9b1b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-# Abort if called from a web server
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-       print "This script must be run from the command line\n";
-       exit();
-}
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-
-common_log(LOG_INFO, 'Starting to render old notices.');
-
-$notice = new Notice();
-$cnt = $notice->find();
-
-while ($notice->fetch()) {
-       common_log(LOG_INFO, 'Pre-rendering notice #' . $notice->id);
-       $original = clone($notice);
-       $notice->rendered = common_render_content($notice->content, $notice);
-       $result = $notice->update($original);
-       if (!$result) {
-               common_log_db_error($notice, 'UPDATE', __FILE__);
-       }
-}
diff --git a/fixup_replies.php b/fixup_replies.php
deleted file mode 100755 (executable)
index 51ecf7a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-# Abort if called from a web server
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-    print "This script must be run from the command line\n";
-    exit();
-}
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-
-common_log(LOG_INFO, 'Starting to do old notices.');
-
-$notice = new Notice();
-$cnt = $notice->find();
-
-while ($notice->fetch()) {
-    common_log(LOG_INFO, 'Getting replies for notice #' . $notice->id);
-    common_save_replies($notice);
-}
diff --git a/maildaemon.php b/maildaemon.php
deleted file mode 100755 (executable)
index 0a96bfe..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-# Abort if called from a web server
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-       print "This script must be run from the command line\n";
-       exit();
-}
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-require_once(INSTALLDIR . '/lib/mail.php');
-require_once('Mail/mimeDecode.php');
-
-# FIXME: we use both Mail_mimeDecode and mailparse
-# Need to move everything to mailparse
-
-class MailerDaemon {
-
-       function __construct() {
-       }
-
-       function handle_message($fname='php://stdin') {
-               list($from, $to, $msg) = $this->parse_message($fname);
-               if (!$from || !$to || !$msg) {
-                       $this->error(NULL, _t('Could not parse message.'));
-               }
-               common_log(LOG_INFO, "Mail from $from to $to: " .substr($msg, 0, 20));
-               $user = $this->user_from($from);
-               if (!$user) {
-                       $this->error($from, _('Not a registered user.'));
-                       return false;
-               }
-               if (!$this->user_match_to($user, $to)) {
-                       $this->error($from, _('Sorry, that is not your incoming email address.'));
-                       return false;
-               }
-               if (!$user->emailpost) {
-                       $this->error($from, _('Sorry, no incoming email allowed.'));
-                       return false;
-               }
-               $response = $this->handle_command($user, $msg);
-               if ($response) {
-                       $this->respond($from, $to, $response);
-                       return true;
-               }
-               $msg = $this->cleanup_msg($msg);
-               $this->add_notice($user, $msg);
-       }
-
-       function error($from, $msg) {
-               file_put_contents("php://stderr", $msg . "\n");
-               exit(1);
-       }
-
-       function user_from($from_hdr) {
-               $froms = mailparse_rfc822_parse_addresses($from_hdr);
-               if (!$froms) {
-                       return NULL;
-               }
-               $from = $froms[0];
-               $addr = common_canonical_email($from['address']);
-               $user = User::staticGet('email', $addr);
-               if (!$user) {
-                       $user = User::staticGet('smsemail', $addr);
-               }
-               return $user;
-       }
-
-       function user_match_to($user, $to_hdr) {
-               $incoming = $user->incomingemail;
-               $tos = mailparse_rfc822_parse_addresses($to_hdr);
-               foreach ($tos as $to) {
-                       if (strcasecmp($incoming, $to['address']) == 0) {
-                               return true;
-                       }
-               }
-               return false;
-       }
-
-       function handle_command($user, $msg) {
-               $cmd = trim(strtolower($msg));
-               switch ($cmd) {
-                case 'off':
-                       $this->set_notify($user, false);
-                       return true;
-                case 'on':
-                       $this->set_notify($user, true);
-                       return true;
-                default:
-                       return false;
-               }
-       }
-
-       function set_notify($user, $value) {
-               $orig = clone($user);
-               $user->smsnotify = $value;
-               $result = $user->update($orig);
-               if (!$result) {
-                       common_log_db_error($user, 'UPDATE', __FILE__);
-                       return false;
-               }
-               return true;
-       }
-       
-       function respond($from, $to, $response) {
-
-               $headers['From'] = $to;
-               $headers['To'] = $from;
-               $headers['Subject'] = "Command complete";
-
-               return mail_send(array($from), $headers, $response);
-       }
-
-       function log($level, $msg) {
-               common_log($level, 'MailDaemon: '.$msg);
-       }
-
-       function add_notice($user, $msg) {
-               $notice = Notice::saveNew($user->id, $msg, 'mail');
-               if (is_string($notice)) {
-                       $this->log(LOG_ERR, $notice);
-                       return;
-               }
-               common_broadcast_notice($notice);
-               $this->log(LOG_INFO,
-                                  'Added notice ' . $notice->id . ' from user ' . $user->nickname);
-       }
-
-       function parse_message($fname) {
-               $contents = file_get_contents($fname);
-               $parsed = Mail_mimeDecode::decode(array('input' => $contents,
-                                                                                               'include_bodies' => true,
-                                                                                               'decode_headers' => true,
-                                                                                               'decode_bodies' => true));
-               if (!$parsed) {
-                       return NULL;
-               }
-
-               $from = $parsed->headers['from'];
-
-               $to = $parsed->headers['to'];
-
-               $type = $parsed->ctype_primary . '/' . $parsed->ctype_secondary;
-
-               if ($parsed->ctype_primary == 'multipart') {
-                       foreach ($parsed->parts as $part) {
-                               if ($part->ctype_primary == 'text' &&
-                                       $part->ctype_secondary == 'plain') {
-                                       $msg = $part->body;
-                                       break;
-                               }
-                       }
-               } else if ($type == 'text/plain') {
-                       $msg = $parsed->body;
-               } else {
-                       $this->unsupported_type($type);
-               }
-
-               return array($from, $to, $msg);
-       }
-
-       function unsupported_type($type) {
-               $this->error(NULL, "Unsupported message type: " . $type);
-       }
-
-       function cleanup_msg($msg) {
-               $lines = explode("\n", $msg);
-
-               $output = '';
-
-               foreach ($lines as $line) {
-                       // skip quotes
-                       if (preg_match('/^\s*>.*$/', $line)) {
-                               continue;
-                       }
-                       // skip start of quote
-                       if (preg_match('/^\s*On.*wrote:\s*$/', $line)) {
-                               continue;
-                       }
-                       // probably interesting to someone, not us
-                       if (preg_match('/^\s*Sent via/', $line)) {
-                               continue;
-                       }
-                       // skip everything after a sig
-                       if (preg_match('/^\s*--+\s*$/', $line) ||
-                               preg_match('/^\s*__+\s*$/', $line))
-                       {
-                               break;
-                       }
-                       // skip everything after Outlook quote
-                       if (preg_match('/^\s*-+\s*Original Message\s*-+\s*$/', $line)) {
-                               break;
-                       }
-                       // skip everything after weird forward
-                       if (preg_match('/^\s*Begin\s+forward/', $line)) {
-                               break;
-                       }
-
-                       $output .= ' ' . $line;
-               }
-
-               preg_replace('/\s+/', ' ', $output);
-               return trim($output);
-       }
-}
-
-$md = new MailerDaemon();
-$md->handle_message('php://stdin');
\ No newline at end of file
diff --git a/scripts/fixup_hashtags.php b/scripts/fixup_hashtags.php
new file mode 100755 (executable)
index 0000000..88f3857
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+    print "This script must be run from the command line\n";
+    exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+
+common_log(LOG_INFO, 'Starting to do old notices.');
+
+$notice = new Notice();
+$cnt = $notice->find();
+
+while ($notice->fetch()) {
+    common_log(LOG_INFO, 'Getting tags for notice #' . $notice->id);
+    $notice->saveTags();
+       $original = clone($notice);
+       $notice->rendered = common_render_content($notice->content, $notice);
+       $result = $notice->update($original);
+       if (!$result) {
+               common_log_db_error($notice, 'UPDATE', __FILE__);
+       }
+}
diff --git a/scripts/fixup_notices_rendered.php b/scripts/fixup_notices_rendered.php
new file mode 100755 (executable)
index 0000000..7b29f0d
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+       print "This script must be run from the command line\n";
+       exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+
+common_log(LOG_INFO, 'Starting to render old notices.');
+
+$notice = new Notice();
+$cnt = $notice->find();
+
+while ($notice->fetch()) {
+       common_log(LOG_INFO, 'Pre-rendering notice #' . $notice->id);
+       $original = clone($notice);
+       $notice->rendered = common_render_content($notice->content, $notice);
+       $result = $notice->update($original);
+       if (!$result) {
+               common_log_db_error($notice, 'UPDATE', __FILE__);
+       }
+}
diff --git a/scripts/fixup_replies.php b/scripts/fixup_replies.php
new file mode 100755 (executable)
index 0000000..6010e21
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+    print "This script must be run from the command line\n";
+    exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+
+common_log(LOG_INFO, 'Starting to do old notices.');
+
+$notice = new Notice();
+$cnt = $notice->find();
+
+while ($notice->fetch()) {
+    common_log(LOG_INFO, 'Getting replies for notice #' . $notice->id);
+    common_save_replies($notice);
+}
diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php
new file mode 100755 (executable)
index 0000000..3d3b309
--- /dev/null
@@ -0,0 +1,228 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+       print "This script must be run from the command line\n";
+       exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+require_once(INSTALLDIR . '/lib/mail.php');
+require_once('Mail/mimeDecode.php');
+
+# FIXME: we use both Mail_mimeDecode and mailparse
+# Need to move everything to mailparse
+
+class MailerDaemon {
+
+       function __construct() {
+       }
+
+       function handle_message($fname='php://stdin') {
+               list($from, $to, $msg) = $this->parse_message($fname);
+               if (!$from || !$to || !$msg) {
+                       $this->error(NULL, _t('Could not parse message.'));
+               }
+               common_log(LOG_INFO, "Mail from $from to $to: " .substr($msg, 0, 20));
+               $user = $this->user_from($from);
+               if (!$user) {
+                       $this->error($from, _('Not a registered user.'));
+                       return false;
+               }
+               if (!$this->user_match_to($user, $to)) {
+                       $this->error($from, _('Sorry, that is not your incoming email address.'));
+                       return false;
+               }
+               if (!$user->emailpost) {
+                       $this->error($from, _('Sorry, no incoming email allowed.'));
+                       return false;
+               }
+               $response = $this->handle_command($user, $msg);
+               if ($response) {
+                       $this->respond($from, $to, $response);
+                       return true;
+               }
+               $msg = $this->cleanup_msg($msg);
+               $this->add_notice($user, $msg);
+       }
+
+       function error($from, $msg) {
+               file_put_contents("php://stderr", $msg . "\n");
+               exit(1);
+       }
+
+       function user_from($from_hdr) {
+               $froms = mailparse_rfc822_parse_addresses($from_hdr);
+               if (!$froms) {
+                       return NULL;
+               }
+               $from = $froms[0];
+               $addr = common_canonical_email($from['address']);
+               $user = User::staticGet('email', $addr);
+               if (!$user) {
+                       $user = User::staticGet('smsemail', $addr);
+               }
+               return $user;
+       }
+
+       function user_match_to($user, $to_hdr) {
+               $incoming = $user->incomingemail;
+               $tos = mailparse_rfc822_parse_addresses($to_hdr);
+               foreach ($tos as $to) {
+                       if (strcasecmp($incoming, $to['address']) == 0) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       function handle_command($user, $msg) {
+               $cmd = trim(strtolower($msg));
+               switch ($cmd) {
+                case 'off':
+                       $this->set_notify($user, false);
+                       return true;
+                case 'on':
+                       $this->set_notify($user, true);
+                       return true;
+                default:
+                       return false;
+               }
+       }
+
+       function set_notify($user, $value) {
+               $orig = clone($user);
+               $user->smsnotify = $value;
+               $result = $user->update($orig);
+               if (!$result) {
+                       common_log_db_error($user, 'UPDATE', __FILE__);
+                       return false;
+               }
+               return true;
+       }
+       
+       function respond($from, $to, $response) {
+
+               $headers['From'] = $to;
+               $headers['To'] = $from;
+               $headers['Subject'] = "Command complete";
+
+               return mail_send(array($from), $headers, $response);
+       }
+
+       function log($level, $msg) {
+               common_log($level, 'MailDaemon: '.$msg);
+       }
+
+       function add_notice($user, $msg) {
+               $notice = Notice::saveNew($user->id, $msg, 'mail');
+               if (is_string($notice)) {
+                       $this->log(LOG_ERR, $notice);
+                       return;
+               }
+               common_broadcast_notice($notice);
+               $this->log(LOG_INFO,
+                                  'Added notice ' . $notice->id . ' from user ' . $user->nickname);
+       }
+
+       function parse_message($fname) {
+               $contents = file_get_contents($fname);
+               $parsed = Mail_mimeDecode::decode(array('input' => $contents,
+                                                                                               'include_bodies' => true,
+                                                                                               'decode_headers' => true,
+                                                                                               'decode_bodies' => true));
+               if (!$parsed) {
+                       return NULL;
+               }
+
+               $from = $parsed->headers['from'];
+
+               $to = $parsed->headers['to'];
+
+               $type = $parsed->ctype_primary . '/' . $parsed->ctype_secondary;
+
+               if ($parsed->ctype_primary == 'multipart') {
+                       foreach ($parsed->parts as $part) {
+                               if ($part->ctype_primary == 'text' &&
+                                       $part->ctype_secondary == 'plain') {
+                                       $msg = $part->body;
+                                       break;
+                               }
+                       }
+               } else if ($type == 'text/plain') {
+                       $msg = $parsed->body;
+               } else {
+                       $this->unsupported_type($type);
+               }
+
+               return array($from, $to, $msg);
+       }
+
+       function unsupported_type($type) {
+               $this->error(NULL, "Unsupported message type: " . $type);
+       }
+
+       function cleanup_msg($msg) {
+               $lines = explode("\n", $msg);
+
+               $output = '';
+
+               foreach ($lines as $line) {
+                       // skip quotes
+                       if (preg_match('/^\s*>.*$/', $line)) {
+                               continue;
+                       }
+                       // skip start of quote
+                       if (preg_match('/^\s*On.*wrote:\s*$/', $line)) {
+                               continue;
+                       }
+                       // probably interesting to someone, not us
+                       if (preg_match('/^\s*Sent via/', $line)) {
+                               continue;
+                       }
+                       // skip everything after a sig
+                       if (preg_match('/^\s*--+\s*$/', $line) ||
+                               preg_match('/^\s*__+\s*$/', $line))
+                       {
+                               break;
+                       }
+                       // skip everything after Outlook quote
+                       if (preg_match('/^\s*-+\s*Original Message\s*-+\s*$/', $line)) {
+                               break;
+                       }
+                       // skip everything after weird forward
+                       if (preg_match('/^\s*Begin\s+forward/', $line)) {
+                               break;
+                       }
+
+                       $output .= ' ' . $line;
+               }
+
+               preg_replace('/\s+/', ' ', $output);
+               return trim($output);
+       }
+}
+
+$md = new MailerDaemon();
+$md->handle_message('php://stdin');
\ No newline at end of file
diff --git a/scripts/sitemap.php b/scripts/sitemap.php
new file mode 100644 (file)
index 0000000..fbfd14e
--- /dev/null
@@ -0,0 +1,376 @@
+<?php
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+require_once(INSTALLDIR . '/lib/util.php');
+
+$output_paths = parse_args();
+
+standard_map();
+notices_map();
+user_map();
+index_map();
+
+# ------------------------------------------------------------------------------
+# Main functions: get data out and turn them into sitemaps
+# ------------------------------------------------------------------------------
+
+# Generate index sitemap of all other sitemaps.
+function index_map() {
+       global $output_paths;
+       $output_dir = $output_paths['output_dir'];
+       $output_url = $output_paths['output_url'];
+
+       foreach (glob("$output_dir*.xml") as $file_name) {
+
+               # Just the file name please.
+               $file_name = preg_replace("|$output_dir|", '', $file_name);
+
+               $index_urls .= sitemap(
+                                                  array(
+                                                                'url' => $output_url . $file_name,
+                                                                'changefreq' => 'daily'
+                                                                )
+                                                  );
+       }
+
+       write_file($output_paths['index_file'], sitemapindex($index_urls));
+}
+
+# Generate sitemap of standard site elements.
+function standard_map() {
+       global $output_paths;
+
+       $standard_map_urls .= url(
+                                                         array(
+                                                                       'url' => common_local_url('public'),
+                                                                       'changefreq' => 'daily',
+                                                                       'priority' => '1',
+                                                                       )
+                                                         );
+
+       $standard_map_urls .= url(
+                                                         array(
+                                                                       'url' => common_local_url('publicrss'),
+                                                                       'changefreq' => 'daily',
+                                                                       'priority' => '0.3',
+                                                                       )
+                                                         );
+
+       $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', 'privacy', 'source');
+
+       foreach($docs as $title) {
+               $standard_map_urls .= url(
+                                                                 array(
+                                                                               'url' => common_local_url('doc', array('title' => $title)),
+                                                                               'changefreq' => 'monthly',
+                                                                               'priority'   => '0.2',
+                                                                               )
+                                                                 );
+       }
+
+       $urlset_path = $output_paths['output_dir'] . 'standard.xml';
+
+       write_file($urlset_path, urlset($standard_map_urls));
+}
+
+# Generate sitemaps of all notices.
+function notices_map() {
+       global $output_paths;
+
+       $notices = DB_DataObject::factory('notice');
+
+       $notices->query('SELECT id, uri, url, modified FROM notice');
+
+       $notice_count = 0;
+       $map_count = 1;
+
+       while ($notices->fetch()) {
+
+               # Maximum 50,000 URLs per sitemap file.
+               if ($notice_count == 50000) {
+                       $notice_count = 0;
+                       $map_count++;
+               }
+
+               # remote notices have an URL
+               
+               if (!$notices->url && $notices->uri) {
+                       $notice = array(
+                                               'url'        => ($notices->uri) ? $notices->uri : common_local_url('shownotice', array('notice' => $notices->id)),
+                                               'lastmod'    => common_date_w3dtf($notices->modified),
+                                               'changefreq' => 'never',
+                                               'priority'   => '1',
+                                               );
+
+                       $notice_list[$map_count] .= url($notice);
+                       $notice_count++;
+               }
+       }
+
+       # Make full sitemaps from the lists and save them.
+       array_to_map($notice_list, 'notice');
+}
+
+# Generate sitemaps of all users.
+function user_map() {
+       global $output_paths;
+
+       $users = DB_DataObject::factory('user');
+
+       $users->query('SELECT id, nickname FROM user');
+
+       $user_count = 0;
+       $map_count = 1;
+
+       while ($users->fetch()) {
+
+               # Maximum 50,000 URLs per sitemap file.
+               if ($user_count == 50000) {
+                       $user_count = 0;
+                       $map_count++;
+               }
+
+               $user_args = array('nickname' => $users->nickname);
+
+               # Define parameters for generating <url></url> elements.
+               $user = array(
+                                         'url'        => common_local_url('showstream', $user_args),
+                                         'changefreq' => 'daily',
+                                         'priority'   => '1',
+                                         );
+
+               $user_rss = array(
+                                                 'url'        => common_local_url('userrss', $user_args),
+                                                 'changefreq' => 'daily',
+                                                 'priority'   => '0.3',
+                                                 );
+
+               $all = array(
+                                        'url'        => common_local_url('all', $user_args),
+                                        'changefreq' => 'daily',
+                                        'priority'   => '1',
+                                        );
+
+               $all_rss = array(
+                                                'url'        => common_local_url('allrss', $user_args),
+                                                'changefreq' => 'daily',
+                                                'priority'   => '0.3',
+                                                );
+
+               $replies = array(
+                                                'url'        => common_local_url('replies', $user_args),
+                                                'changefreq' => 'daily',
+                                                'priority'   => '1',
+                                                );
+
+               $replies_rss = array(
+                                                        'url'        => common_local_url('repliesrss', $user_args),
+                                                        'changefreq' => 'daily',
+                                                        'priority'   => '0.3',
+                                                        );
+
+               $foaf = array(
+                                         'url'        => common_local_url('foaf', $user_args),
+                                         'changefreq' => 'weekly',
+                                         'priority'   => '0.5',
+                                         );
+
+               # Construct a <url></url> element for each user facet and add it
+               # to our existing list of those.
+               $user_list[$map_count]        .= url($user);
+               $user_rss_list[$map_count]    .= url($user_rss);
+               $all_list[$map_count]         .= url($all);
+               $all_rss_list[$map_count]     .= url($all_rss);
+               $replies_list[$map_count]     .= url($replies);
+               $replies_rss_list[$map_count] .= url($replies_rss);
+               $foaf_list[$map_count]        .= url($foaf);
+
+               $user_count++;
+       }
+
+       # Make full sitemaps from the lists and save them.
+       # Possible factoring: put all the lists into a master array, thus allowing
+       # calling with single argument (i.e., array_to_map('user')).
+       array_to_map($user_list, 'user');
+       array_to_map($user_rss_list, 'user_rss');
+       array_to_map($all_list, 'all');
+       array_to_map($all_rss_list, 'all_rss');
+       array_to_map($replies_list, 'replies');
+       array_to_map($replies_rss_list, 'replies_rss');
+       array_to_map($foaf_list, 'foaf');
+}
+
+# ------------------------------------------------------------------------------
+# XML generation functions
+# ------------------------------------------------------------------------------
+
+# Generate a <url></url> element.
+function url($url_args) {
+       $url        = preg_replace('/&/', '&amp;', $url_args['url']); # escape ampersands for XML
+       $lastmod    = $url_args['lastmod'];
+       $changefreq = $url_args['changefreq'];
+       $priority   = $url_args['priority'];
+
+       if (is_null($url)) {
+               error("url() arguments require 'url' value.");
+       }
+
+       $url_out = "\t<url>\n";
+       $url_out .= "\t\t<loc>$url</loc>\n";
+
+       if ($changefreq) {
+               $url_out .= "\t\t<changefreq>$changefreq</changefreq>\n";
+       }
+
+       if ($lastmod) {
+               $url_out .= "\t\t<lastmod>$lastmod</lastmod>\n";
+       }
+
+       if ($priority) {
+               $url_out .= "\t\t<priority>$priority</priority>\n";
+       }
+
+       $url_out .= "\t</url>\n";
+
+       return $url_out;
+}
+
+function sitemap($sitemap_args) {
+       $url        = preg_replace('/&/', '&amp;', $sitemap_args['url']); # escape ampersands for XML
+       $lastmod    = $sitemap_args['lastmod'];
+
+       if (is_null($url)) {
+               error("url() arguments require 'url' value.");
+       }
+
+       $sitemap_out = "\t<sitemap>\n";
+       $sitemap_out .= "\t\t<loc>$url</loc>\n";
+
+       if ($lastmod) {
+               $sitemap_out .= "\t\t<lastmod>$lastmod</lastmod>\n";
+       }
+
+       $sitemap_out .= "\t</sitemap>\n";
+
+       return $sitemap_out;
+}
+
+# Generate a <urlset></urlset> element.
+function urlset($urlset_text) {
+       $urlset = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
+         '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n" .
+         $urlset_text .
+         '</urlset>';
+
+       return $urlset;
+}
+
+# Generate a <urlset></urlset> element.
+function sitemapindex($sitemapindex_text) {
+       $sitemapindex = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
+         '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n" .
+         $sitemapindex_text .
+         '</sitemapindex>';
+
+       return $sitemapindex;
+}
+
+# Generate a sitemap from an array containing <url></url> elements and write it to a file.
+function array_to_map($url_list, $filename_prefix) {
+       global $output_paths;
+
+       if ($url_list) {
+               # $map_urls is a long string containing concatenated <url></url> elements.
+               while (list($map_idx, $map_urls) = each($url_list)) {
+                       $urlset_path = $output_paths['output_dir'] . "$filename_prefix-$map_idx.xml";
+                       
+                       write_file($urlset_path, urlset($map_urls));
+               }
+       }
+}
+
+# ------------------------------------------------------------------------------
+# Internal functions
+# ------------------------------------------------------------------------------
+
+# Parse command line arguments.
+function parse_args() {
+       $args = getopt('f:d:u:');
+
+       if (is_null($args[f]) && is_null($args[d]) && is_null($args[u])) {
+               error('Mandatory arguments: -f <index file path> -d <output directory path> -u <URL of sitemaps directory>');
+       }
+
+       if (is_null($args[f])) {
+               error('You must specify an index file name with the -f option.');
+       }
+
+       if (is_null($args[d])) {
+               error('You must specify a directory for the output file with the -d option.');
+       }
+
+       if (is_null($args[u])) {
+               error('You must specify a URL for the directory where the sitemaps will be kept with the -u option.');
+       }
+
+       $index_file = $args[f];
+       $output_dir = $args[d];
+       $output_url = $args[u];
+
+       if (file_exists($output_dir)) {
+               if (is_writable($output_dir) === FALSE) {
+                       error("$output_dir is not writable.");
+               }
+       }        else {
+               error("output directory $output_dir does not exist.");
+       }
+
+       $paths = array(
+                                  'index_file' => $index_file,
+                                  'output_dir' => trailing_slash($output_dir),
+                                  'output_url' => trailing_slash($output_url),
+                                  );
+
+       return $paths;
+}
+
+# Ensure paths end with a "/".
+function trailing_slash($path) {
+       if (preg_match('/\/$/', $path) == 0) {
+               $path .= '/';
+       }
+
+       return $path;
+}
+
+# Write data to disk.
+function write_file($path, $data) {
+       if (is_null($path)) {
+               error('No path specified for writing to.');
+       }        elseif (is_null($data)) {
+               error('No data specified for writing.');
+       }
+
+       if (($fh_out = fopen($path,'w')) === FALSE) {
+               error("couldn't open $path for writing.");
+       }
+
+       if (fwrite($fh_out, $data) === FALSE) {
+               error("couldn't write to $path.");
+       }
+}
+
+# Display an error message and exit.
+function error ($error_msg) {
+       if (is_null($error_msg)) {
+               $error_msg = 'error() was called without any explanation!';
+       }
+
+       echo "Error: $error_msg\n";
+       exit(1);
+}
+
+?>
\ No newline at end of file
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
new file mode 100755 (executable)
index 0000000..43f2b6a
--- /dev/null
@@ -0,0 +1,442 @@
+#!/usr/bin/env php
+<?php
+/*
+ * Laconica - a distributed open-source microblogging tool
+ * Copyright (C) 2008, Controlez-Vous, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function xmppdaemon_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
+    switch ($errno) {
+     case E_USER_ERROR:
+       echo "ERROR: [$errno] $errstr ($errfile:$errline)\n";
+       echo "  Fatal error on line $errline in file $errfile";
+       echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n";
+       echo "Aborting...\n";
+       exit(1);
+       break;
+
+    case E_USER_WARNING:
+       echo "WARNING [$errno] $errstr ($errfile:$errline)\n";
+       break;
+
+     case E_USER_NOTICE:
+       echo "My NOTICE [$errno] $errstr ($errfile:$errline)\n";
+       break;
+
+     default:
+       echo "Unknown error type: [$errno] $errstr ($errfile:$errline)\n";
+       break;
+    }
+
+    /* Don't execute PHP internal error handler */
+    return true;
+}
+
+set_error_handler('xmppdaemon_error_handler');
+
+# Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+       print "This script must be run from the command line\n";
+       exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+require_once(INSTALLDIR . '/lib/jabber.php');
+
+# This is kind of clunky; we create a class to call the global functions
+# in jabber.php, which create a new XMPP class. A more elegant (?) solution
+# might be to use make this a subclass of XMPP.
+
+class XMPPDaemon {
+
+       function XMPPDaemon($resource=NULL) {
+               static $attrs = array('server', 'port', 'user', 'password', 'host');
+
+               foreach ($attrs as $attr)
+               {
+                       $this->$attr = common_config('xmpp', $attr);
+               }
+
+               if ($resource) {
+                       $this->resource = $resource;
+               } else {
+                       $this->resource = common_config('xmpp', 'resource') . 'daemon';
+               }
+
+               $this->log(LOG_INFO, "{$this->user}@{$this->server}/{$this->resource}");
+       }
+
+       function connect() {
+
+               $connect_to = ($this->host) ? $this->host : $this->server;
+
+               $this->log(LOG_INFO, "Connecting to $connect_to on port $this->port");
+
+               $this->conn = jabber_connect($this->resource);
+
+               if (!$this->conn) {
+                       return false;
+               }
+
+               return !$this->conn->isDisconnected();
+       }
+
+       function handle() {
+
+               static $parts = array('message', 'presence',
+                                                         'end_stream', 'session_start');
+
+               while(!$this->conn->isDisconnected()) {
+
+                       $payloads = $this->conn->processUntil($parts, 10);
+
+                       if ($payloads) {
+                               foreach($payloads as $event) {
+                                       $pl = $event[1];
+                                       switch($event[0]) {
+                                        case 'message':
+                                               $this->handle_message($pl);
+                                               break;
+                                        case 'presence':
+                                               $this->handle_presence($pl);
+                                               break;
+                                        case 'session_start':
+                                               $this->handle_session($pl);
+                                               break;
+                                       }
+                               }
+                       }
+
+                       $this->broadcast_queue();
+                       $this->confirmation_queue();
+               }
+       }
+
+       function handle_session($pl) {
+               # XXX what to do here?
+               return true;
+       }
+
+       function get_user($from) {
+               $user = User::staticGet('jabber', jabber_normalize_jid($from));
+               return $user;
+       }
+
+       function get_confirmation($from) {
+               $confirm = new Confirm_address();
+               $confirm->address = $from;
+               $confirm->address_type = 'jabber';
+               if ($confirm->find(TRUE)) {
+                       return $confirm;
+               } else {
+                       return NULL;
+               }
+       }
+
+       function handle_message(&$pl) {
+               if ($pl['type'] != 'chat') {
+                       return;
+               }
+               if (strlen($pl['body']) == 0) {
+                       return;
+               }
+
+               $from = jabber_normalize_jid($pl['from']);
+               $user = $this->get_user($from);
+
+               if (!$user) {
+                       $this->from_site($from, 'Unknown user; go to ' .
+                                                        common_local_url('imsettings') .
+                                                        ' to add your address to your account');
+                       $this->log(LOG_WARNING, 'Message from unknown user ' . $from);
+                       return;
+               }
+               if ($this->handle_command($user, $pl['body'])) {
+                       return;
+               } else if ($this->is_autoreply($pl['body'])) {
+                       $this->log(LOG_INFO, 'Ignoring auto reply from ' . $from);
+                       return;
+               } else if ($this->is_otr($pl['body'])) {
+                       $this->log(LOG_INFO, 'Ignoring OTR from ' . $from);
+                       return;
+               } else {
+                       $this->add_notice($user, $pl);
+               }
+       }
+
+       function is_autoreply($txt) {
+               if (preg_match('/[\[\(]?[Aa]uto-?[Rr]eply[\]\)]/', $txt)) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       function is_otr($txt) {
+               if (preg_match('/^\?OTR/', $txt)) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+       
+       function from_site($address, $msg) {
+               $text = '['.common_config('site', 'name') . '] ' . $msg;
+               jabber_send_message($address, $text);
+       }
+
+       function handle_command($user, $body) {
+               # XXX: localise
+               switch(trim($body)) {
+                case 'on':
+                       $this->set_notify($user, true);
+                       $this->from_site($user->jabber, 'notifications on');
+                       return true;
+                case 'off':
+                       $this->set_notify($user, false);
+                       $this->from_site($user->jabber, 'notifications off');
+                       return true;
+                default:
+                       return false;
+               }
+       }
+
+       function set_notify(&$user, $notify) {
+               $orig = clone($user);
+               $user->jabbernotify = $notify;
+               $result = $user->update($orig);
+               if (!$id) {
+                       $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
+                       $this->log(LOG_ERR,
+                                          'Could not set notify flag to ' . $notify .
+                                          ' for user ' . common_log_objstring($user) .
+                                          ': ' . $last_error->message);
+               } else {
+                       $this->log(LOG_INFO,
+                                          'User ' . $user->nickname . ' set notify flag to ' . $notify);
+               }
+       }
+
+       function add_notice(&$user, &$pl) {
+               $notice = Notice::saveNew($user->id, trim(substr($pl['body'], 0, 140)), 'xmpp');
+               if (is_string($notice)) {
+                       $this->log(LOG_ERR, $notice);
+                       return;
+               }
+               common_real_broadcast($notice);
+               $this->log(LOG_INFO,
+                                  'Added notice ' . $notice->id . ' from user ' . $user->nickname);
+       }
+
+       function handle_presence(&$pl) {
+               $from = jabber_normalize_jid($pl['from']);
+               switch ($pl['type']) {
+                case 'subscribe':
+                       # We let anyone subscribe
+                       $this->subscribed($from);
+                       $this->log(LOG_INFO,
+                                          'Accepted subscription from ' . $from);
+                       break;
+                case 'subscribed':
+                case 'unsubscribed':
+                case 'unsubscribe':
+                       $this->log(LOG_INFO,
+                                          'Ignoring  "' . $pl['type'] . '" from ' . $from);
+                       break;
+                default:
+                       if (!$pl['type']) {
+                               $user = User::staticGet('jabber', $from);
+                               if (!$user) {
+                                       $this->log(LOG_WARNING, 'Presence from unknown user ' . $from);
+                                       return;
+                               }
+                               if ($user->updatefrompresence) {
+                                       $this->log(LOG_INFO, 'Updating ' . $user->nickname .
+                                                          ' status from presence.');
+                                       $this->add_notice($user, $pl);
+                               }
+                       }
+                       break;
+               }
+       }
+
+       function log($level, $msg) {
+               common_log($level, 'XMPPDaemon('.$this->resource.'): '.$msg);
+       }
+
+       function subscribed($to) {
+               jabber_special_presence('subscribed', $to);
+       }
+
+       function set_status($status) {
+               $this->log(LOG_INFO, 'Setting status to "' . $status . '"');
+               jabber_send_presence($status);
+       }
+
+       function top_queue_item() {
+
+               $qi = new Queue_item();
+               $qi->orderBy('created');
+               $qi->whereAdd('claimed is NULL');
+
+               $qi->limit(1);
+
+               $cnt = $qi->find(TRUE);
+
+               if ($cnt) {
+                       # XXX: potential race condition
+                       # can we force it to only update if claimed is still NULL
+                       # (or old)?
+                       $this->log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id);
+                       $orig = clone($qi);
+                       $qi->claimed = DB_DataObject_Cast::dateTime();
+                       $result = $qi->update($orig);
+                       if ($result) {
+                               $this->log(LOG_INFO, 'claim succeeded.');
+                               return $qi;
+                       } else {
+                               $this->log(LOG_INFO, 'claim failed.');
+                       }
+               }
+               $qi = NULL;
+               return NULL;
+       }
+
+       function broadcast_queue() {
+               $this->clear_old_claims();
+               $this->log(LOG_INFO, 'checking for queued notices');
+               do {
+                       $qi = $this->top_queue_item();
+                       if ($qi) {
+                               $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($qi->created));
+                               $notice = Notice::staticGet($qi->notice_id);
+                               if ($notice) {
+                                       $this->log(LOG_INFO, 'broadcasting notice ID = ' . $notice->id);
+                                       # XXX: what to do if broadcast fails?
+                                       $result = common_real_broadcast($notice, $this->is_remote($notice));
+                                       if (!$result) {
+                                               $this->log(LOG_WARNING, 'Failed broadcast for notice ID = ' . $notice->id);
+                                               $orig = $qi;
+                                               $qi->claimed = NULL;
+                                               $qi->update($orig);
+                                               $this->log(LOG_WARNING, 'Abandoned claim for notice ID = ' . $notice->id);
+                                               continue;
+                                       }
+                                       $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
+                                       $notice = NULL;
+                               } else {
+                                       $this->log(LOG_WARNING, 'queue item for notice that does not exist');
+                               }
+                               $qi->delete();
+                       }
+               } while ($qi);
+       }
+
+       function clear_old_claims() {
+               $qi = new Queue_item();
+               $qi->claimed = NULL;
+               $qi->whereAdd('now() - claimed > '.CLAIM_TIMEOUT);
+               $qi->update(DB_DATAOBJECT_WHEREADD_ONLY);
+       }
+
+       function is_remote($notice) {
+               $user = User::staticGet($notice->profile_id);
+               return !$user;
+       }
+
+       function confirmation_queue() {
+           # $this->clear_old_confirm_claims();
+               $this->log(LOG_INFO, 'checking for queued confirmations');
+               do {
+                       $confirm = $this->next_confirm();
+                       if ($confirm) {
+                               $this->log(LOG_INFO, 'Sending confirmation for ' . $confirm->address);
+                               $user = User::staticGet($confirm->user_id);
+                               if (!$user) {
+                                       $this->log(LOG_WARNING, 'Confirmation for unknown user ' . $confirm->user_id);
+                                       continue;
+                               }
+                               $success = jabber_confirm_address($confirm->code,
+                                                                 $user->nickname,
+                                                                 $confirm->address);
+                               if (!$success) {
+                                       $this->log(LOG_ERR, 'Confirmation failed for ' . $confirm->address);
+                                       # Just let the claim age out; hopefully things work then
+                                       continue;
+                               } else {
+                                       $this->log(LOG_INFO, 'Confirmation sent for ' . $confirm->address);
+                                       # Mark confirmation sent
+                                       $original = clone($confirm);
+                                       $confirm->sent = $confirm->claimed;
+                                       $result = $confirm->update($original);
+                                       if (!$result) {
+                                               $this->log(LOG_ERR, 'Cannot mark sent for ' . $confirm->address);
+                                               # Just let the claim age out; hopefully things work then
+                                               continue;
+                                       }
+                               }
+                       }
+               } while ($confirm);
+       }
+
+       function next_confirm() {
+               $confirm = new Confirm_address();
+               $confirm->whereAdd('claimed IS NULL');
+               $confirm->whereAdd('sent IS NULL');
+               # XXX: eventually we could do other confirmations in the queue, too
+               $confirm->address_type = 'jabber';
+               $confirm->orderBy('modified DESC');
+               $confirm->limit(1);
+               if ($confirm->find(TRUE)) {
+                       $this->log(LOG_INFO, 'Claiming confirmation for ' . $confirm->address);
+                       # working around some weird DB_DataObject behaviour
+                       $confirm->whereAdd(''); # clears where stuff
+                       $original = clone($confirm);
+                       $confirm->claimed = DB_DataObject_Cast::dateTime();
+                       $result = $confirm->update($original);
+                       if ($result) {
+                               $this->log(LOG_INFO, 'Succeeded in claim! '. $result);
+                               return $confirm;
+                       } else {
+                               $this->log(LOG_INFO, 'Failed in claim!');
+                               return false;
+                       }
+               }
+               return NULL;
+       }
+
+       function clear_old_confirm_claims() {
+               $confirm = new Confirm();
+               $confirm->claimed = NULL;
+               $confirm->whereAdd('now() - claimed > '.CLAIM_TIMEOUT);
+               $confirm->update(DB_DATAOBJECT_WHEREADD_ONLY);
+       }
+
+}
+
+$resource = ($argc > 1) ? $argv[1] : NULL;
+
+$daemon = new XMPPDaemon($resource);
+
+if ($daemon->connect()) {
+       $daemon->set_status("Send me a message to post a notice");
+       $daemon->handle();
+}
+
+?>
diff --git a/sitemap.php b/sitemap.php
deleted file mode 100644 (file)
index c35a382..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-<?php
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-require_once(INSTALLDIR . '/lib/util.php');
-
-$output_paths = parse_args();
-
-standard_map();
-notices_map();
-user_map();
-index_map();
-
-# ------------------------------------------------------------------------------
-# Main functions: get data out and turn them into sitemaps
-# ------------------------------------------------------------------------------
-
-# Generate index sitemap of all other sitemaps.
-function index_map() {
-       global $output_paths;
-       $output_dir = $output_paths['output_dir'];
-       $output_url = $output_paths['output_url'];
-
-       foreach (glob("$output_dir*.xml") as $file_name) {
-
-               # Just the file name please.
-               $file_name = preg_replace("|$output_dir|", '', $file_name);
-
-               $index_urls .= sitemap(
-                                                  array(
-                                                                'url' => $output_url . $file_name,
-                                                                'changefreq' => 'daily'
-                                                                )
-                                                  );
-       }
-
-       write_file($output_paths['index_file'], sitemapindex($index_urls));
-}
-
-# Generate sitemap of standard site elements.
-function standard_map() {
-       global $output_paths;
-
-       $standard_map_urls .= url(
-                                                         array(
-                                                                       'url' => common_local_url('public'),
-                                                                       'changefreq' => 'daily',
-                                                                       'priority' => '1',
-                                                                       )
-                                                         );
-
-       $standard_map_urls .= url(
-                                                         array(
-                                                                       'url' => common_local_url('publicrss'),
-                                                                       'changefreq' => 'daily',
-                                                                       'priority' => '0.3',
-                                                                       )
-                                                         );
-
-       $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', 'privacy', 'source');
-
-       foreach($docs as $title) {
-               $standard_map_urls .= url(
-                                                                 array(
-                                                                               'url' => common_local_url('doc', array('title' => $title)),
-                                                                               'changefreq' => 'monthly',
-                                                                               'priority'   => '0.2',
-                                                                               )
-                                                                 );
-       }
-
-       $urlset_path = $output_paths['output_dir'] . 'standard.xml';
-
-       write_file($urlset_path, urlset($standard_map_urls));
-}
-
-# Generate sitemaps of all notices.
-function notices_map() {
-       global $output_paths;
-
-       $notices = DB_DataObject::factory('notice');
-
-       $notices->query('SELECT id, uri, url, modified FROM notice');
-
-       $notice_count = 0;
-       $map_count = 1;
-
-       while ($notices->fetch()) {
-
-               # Maximum 50,000 URLs per sitemap file.
-               if ($notice_count == 50000) {
-                       $notice_count = 0;
-                       $map_count++;
-               }
-
-               # remote notices have an URL
-               
-               if (!$notices->url && $notices->uri) {
-                       $notice = array(
-                                               'url'        => ($notices->uri) ? $notices->uri : common_local_url('shownotice', array('notice' => $notices->id)),
-                                               'lastmod'    => common_date_w3dtf($notices->modified),
-                                               'changefreq' => 'never',
-                                               'priority'   => '1',
-                                               );
-
-                       $notice_list[$map_count] .= url($notice);
-                       $notice_count++;
-               }
-       }
-
-       # Make full sitemaps from the lists and save them.
-       array_to_map($notice_list, 'notice');
-}
-
-# Generate sitemaps of all users.
-function user_map() {
-       global $output_paths;
-
-       $users = DB_DataObject::factory('user');
-
-       $users->query('SELECT id, nickname FROM user');
-
-       $user_count = 0;
-       $map_count = 1;
-
-       while ($users->fetch()) {
-
-               # Maximum 50,000 URLs per sitemap file.
-               if ($user_count == 50000) {
-                       $user_count = 0;
-                       $map_count++;
-               }
-
-               $user_args = array('nickname' => $users->nickname);
-
-               # Define parameters for generating <url></url> elements.
-               $user = array(
-                                         'url'        => common_local_url('showstream', $user_args),
-                                         'changefreq' => 'daily',
-                                         'priority'   => '1',
-                                         );
-
-               $user_rss = array(
-                                                 'url'        => common_local_url('userrss', $user_args),
-                                                 'changefreq' => 'daily',
-                                                 'priority'   => '0.3',
-                                                 );
-
-               $all = array(
-                                        'url'        => common_local_url('all', $user_args),
-                                        'changefreq' => 'daily',
-                                        'priority'   => '1',
-                                        );
-
-               $all_rss = array(
-                                                'url'        => common_local_url('allrss', $user_args),
-                                                'changefreq' => 'daily',
-                                                'priority'   => '0.3',
-                                                );
-
-               $replies = array(
-                                                'url'        => common_local_url('replies', $user_args),
-                                                'changefreq' => 'daily',
-                                                'priority'   => '1',
-                                                );
-
-               $replies_rss = array(
-                                                        'url'        => common_local_url('repliesrss', $user_args),
-                                                        'changefreq' => 'daily',
-                                                        'priority'   => '0.3',
-                                                        );
-
-               $foaf = array(
-                                         'url'        => common_local_url('foaf', $user_args),
-                                         'changefreq' => 'weekly',
-                                         'priority'   => '0.5',
-                                         );
-
-               # Construct a <url></url> element for each user facet and add it
-               # to our existing list of those.
-               $user_list[$map_count]        .= url($user);
-               $user_rss_list[$map_count]    .= url($user_rss);
-               $all_list[$map_count]         .= url($all);
-               $all_rss_list[$map_count]     .= url($all_rss);
-               $replies_list[$map_count]     .= url($replies);
-               $replies_rss_list[$map_count] .= url($replies_rss);
-               $foaf_list[$map_count]        .= url($foaf);
-
-               $user_count++;
-       }
-
-       # Make full sitemaps from the lists and save them.
-       # Possible factoring: put all the lists into a master array, thus allowing
-       # calling with single argument (i.e., array_to_map('user')).
-       array_to_map($user_list, 'user');
-       array_to_map($user_rss_list, 'user_rss');
-       array_to_map($all_list, 'all');
-       array_to_map($all_rss_list, 'all_rss');
-       array_to_map($replies_list, 'replies');
-       array_to_map($replies_rss_list, 'replies_rss');
-       array_to_map($foaf_list, 'foaf');
-}
-
-# ------------------------------------------------------------------------------
-# XML generation functions
-# ------------------------------------------------------------------------------
-
-# Generate a <url></url> element.
-function url($url_args) {
-       $url        = preg_replace('/&/', '&amp;', $url_args['url']); # escape ampersands for XML
-       $lastmod    = $url_args['lastmod'];
-       $changefreq = $url_args['changefreq'];
-       $priority   = $url_args['priority'];
-
-       if (is_null($url)) {
-               error("url() arguments require 'url' value.");
-       }
-
-       $url_out = "\t<url>\n";
-       $url_out .= "\t\t<loc>$url</loc>\n";
-
-       if ($changefreq) {
-               $url_out .= "\t\t<changefreq>$changefreq</changefreq>\n";
-       }
-
-       if ($lastmod) {
-               $url_out .= "\t\t<lastmod>$lastmod</lastmod>\n";
-       }
-
-       if ($priority) {
-               $url_out .= "\t\t<priority>$priority</priority>\n";
-       }
-
-       $url_out .= "\t</url>\n";
-
-       return $url_out;
-}
-
-function sitemap($sitemap_args) {
-       $url        = preg_replace('/&/', '&amp;', $sitemap_args['url']); # escape ampersands for XML
-       $lastmod    = $sitemap_args['lastmod'];
-
-       if (is_null($url)) {
-               error("url() arguments require 'url' value.");
-       }
-
-       $sitemap_out = "\t<sitemap>\n";
-       $sitemap_out .= "\t\t<loc>$url</loc>\n";
-
-       if ($lastmod) {
-               $sitemap_out .= "\t\t<lastmod>$lastmod</lastmod>\n";
-       }
-
-       $sitemap_out .= "\t</sitemap>\n";
-
-       return $sitemap_out;
-}
-
-# Generate a <urlset></urlset> element.
-function urlset($urlset_text) {
-       $urlset = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
-         '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n" .
-         $urlset_text .
-         '</urlset>';
-
-       return $urlset;
-}
-
-# Generate a <urlset></urlset> element.
-function sitemapindex($sitemapindex_text) {
-       $sitemapindex = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" .
-         '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n" .
-         $sitemapindex_text .
-         '</sitemapindex>';
-
-       return $sitemapindex;
-}
-
-# Generate a sitemap from an array containing <url></url> elements and write it to a file.
-function array_to_map($url_list, $filename_prefix) {
-       global $output_paths;
-
-       if ($url_list) {
-               # $map_urls is a long string containing concatenated <url></url> elements.
-               while (list($map_idx, $map_urls) = each($url_list)) {
-                       $urlset_path = $output_paths['output_dir'] . "$filename_prefix-$map_idx.xml";
-                       
-                       write_file($urlset_path, urlset($map_urls));
-               }
-       }
-}
-
-# ------------------------------------------------------------------------------
-# Internal functions
-# ------------------------------------------------------------------------------
-
-# Parse command line arguments.
-function parse_args() {
-       $args = getopt('f:d:u:');
-
-       if (is_null($args[f]) && is_null($args[d]) && is_null($args[u])) {
-               error('Mandatory arguments: -f <index file path> -d <output directory path> -u <URL of sitemaps directory>');
-       }
-
-       if (is_null($args[f])) {
-               error('You must specify an index file name with the -f option.');
-       }
-
-       if (is_null($args[d])) {
-               error('You must specify a directory for the output file with the -d option.');
-       }
-
-       if (is_null($args[u])) {
-               error('You must specify a URL for the directory where the sitemaps will be kept with the -u option.');
-       }
-
-       $index_file = $args[f];
-       $output_dir = $args[d];
-       $output_url = $args[u];
-
-       if (file_exists($output_dir)) {
-               if (is_writable($output_dir) === FALSE) {
-                       error("$output_dir is not writable.");
-               }
-       }        else {
-               error("output directory $output_dir does not exist.");
-       }
-
-       $paths = array(
-                                  'index_file' => $index_file,
-                                  'output_dir' => trailing_slash($output_dir),
-                                  'output_url' => trailing_slash($output_url),
-                                  );
-
-       return $paths;
-}
-
-# Ensure paths end with a "/".
-function trailing_slash($path) {
-       if (preg_match('/\/$/', $path) == 0) {
-               $path .= '/';
-       }
-
-       return $path;
-}
-
-# Write data to disk.
-function write_file($path, $data) {
-       if (is_null($path)) {
-               error('No path specified for writing to.');
-       }        elseif (is_null($data)) {
-               error('No data specified for writing.');
-       }
-
-       if (($fh_out = fopen($path,'w')) === FALSE) {
-               error("couldn't open $path for writing.");
-       }
-
-       if (fwrite($fh_out, $data) === FALSE) {
-               error("couldn't write to $path.");
-       }
-}
-
-# Display an error message and exit.
-function error ($error_msg) {
-       if (is_null($error_msg)) {
-               $error_msg = 'error() was called without any explanation!';
-       }
-
-       echo "Error: $error_msg\n";
-       exit(1);
-}
-
-?>
\ No newline at end of file
diff --git a/xmppdaemon.php b/xmppdaemon.php
deleted file mode 100755 (executable)
index 37b349f..0000000
+++ /dev/null
@@ -1,442 +0,0 @@
-#!/usr/bin/env php
-<?php
-/*
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, Controlez-Vous, Inc.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-function xmppdaemon_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
-    switch ($errno) {
-     case E_USER_ERROR:
-       echo "ERROR: [$errno] $errstr ($errfile:$errline)\n";
-       echo "  Fatal error on line $errline in file $errfile";
-       echo ", PHP " . PHP_VERSION . " (" . PHP_OS . ")\n";
-       echo "Aborting...\n";
-       exit(1);
-       break;
-
-    case E_USER_WARNING:
-       echo "WARNING [$errno] $errstr ($errfile:$errline)\n";
-       break;
-
-     case E_USER_NOTICE:
-       echo "My NOTICE [$errno] $errstr ($errfile:$errline)\n";
-       break;
-
-     default:
-       echo "Unknown error type: [$errno] $errstr ($errfile:$errline)\n";
-       break;
-    }
-
-    /* Don't execute PHP internal error handler */
-    return true;
-}
-
-set_error_handler('xmppdaemon_error_handler');
-
-# Abort if called from a web server
-if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
-       print "This script must be run from the command line\n";
-       exit();
-}
-
-define('INSTALLDIR', dirname(__FILE__));
-define('LACONICA', true);
-
-require_once(INSTALLDIR . '/lib/common.php');
-require_once(INSTALLDIR . '/lib/jabber.php');
-
-# This is kind of clunky; we create a class to call the global functions
-# in jabber.php, which create a new XMPP class. A more elegant (?) solution
-# might be to use make this a subclass of XMPP.
-
-class XMPPDaemon {
-
-       function XMPPDaemon($resource=NULL) {
-               static $attrs = array('server', 'port', 'user', 'password', 'host');
-
-               foreach ($attrs as $attr)
-               {
-                       $this->$attr = common_config('xmpp', $attr);
-               }
-
-               if ($resource) {
-                       $this->resource = $resource;
-               } else {
-                       $this->resource = common_config('xmpp', 'resource') . 'daemon';
-               }
-
-               $this->log(LOG_INFO, "{$this->user}@{$this->server}/{$this->resource}");
-       }
-
-       function connect() {
-
-               $connect_to = ($this->host) ? $this->host : $this->server;
-
-               $this->log(LOG_INFO, "Connecting to $connect_to on port $this->port");
-
-               $this->conn = jabber_connect($this->resource);
-
-               if (!$this->conn) {
-                       return false;
-               }
-
-               return !$this->conn->isDisconnected();
-       }
-
-       function handle() {
-
-               static $parts = array('message', 'presence',
-                                                         'end_stream', 'session_start');
-
-               while(!$this->conn->isDisconnected()) {
-
-                       $payloads = $this->conn->processUntil($parts, 10);
-
-                       if ($payloads) {
-                               foreach($payloads as $event) {
-                                       $pl = $event[1];
-                                       switch($event[0]) {
-                                        case 'message':
-                                               $this->handle_message($pl);
-                                               break;
-                                        case 'presence':
-                                               $this->handle_presence($pl);
-                                               break;
-                                        case 'session_start':
-                                               $this->handle_session($pl);
-                                               break;
-                                       }
-                               }
-                       }
-
-                       $this->broadcast_queue();
-                       $this->confirmation_queue();
-               }
-       }
-
-       function handle_session($pl) {
-               # XXX what to do here?
-               return true;
-       }
-
-       function get_user($from) {
-               $user = User::staticGet('jabber', jabber_normalize_jid($from));
-               return $user;
-       }
-
-       function get_confirmation($from) {
-               $confirm = new Confirm_address();
-               $confirm->address = $from;
-               $confirm->address_type = 'jabber';
-               if ($confirm->find(TRUE)) {
-                       return $confirm;
-               } else {
-                       return NULL;
-               }
-       }
-
-       function handle_message(&$pl) {
-               if ($pl['type'] != 'chat') {
-                       return;
-               }
-               if (strlen($pl['body']) == 0) {
-                       return;
-               }
-
-               $from = jabber_normalize_jid($pl['from']);
-               $user = $this->get_user($from);
-
-               if (!$user) {
-                       $this->from_site($from, 'Unknown user; go to ' .
-                                                        common_local_url('imsettings') .
-                                                        ' to add your address to your account');
-                       $this->log(LOG_WARNING, 'Message from unknown user ' . $from);
-                       return;
-               }
-               if ($this->handle_command($user, $pl['body'])) {
-                       return;
-               } else if ($this->is_autoreply($pl['body'])) {
-                       $this->log(LOG_INFO, 'Ignoring auto reply from ' . $from);
-                       return;
-               } else if ($this->is_otr($pl['body'])) {
-                       $this->log(LOG_INFO, 'Ignoring OTR from ' . $from);
-                       return;
-               } else {
-                       $this->add_notice($user, $pl);
-               }
-       }
-
-       function is_autoreply($txt) {
-               if (preg_match('/[\[\(]?[Aa]uto-?[Rr]eply[\]\)]/', $txt)) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       function is_otr($txt) {
-               if (preg_match('/^\?OTR/', $txt)) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
-       function from_site($address, $msg) {
-               $text = '['.common_config('site', 'name') . '] ' . $msg;
-               jabber_send_message($address, $text);
-       }
-
-       function handle_command($user, $body) {
-               # XXX: localise
-               switch(trim($body)) {
-                case 'on':
-                       $this->set_notify($user, true);
-                       $this->from_site($user->jabber, 'notifications on');
-                       return true;
-                case 'off':
-                       $this->set_notify($user, false);
-                       $this->from_site($user->jabber, 'notifications off');
-                       return true;
-                default:
-                       return false;
-               }
-       }
-
-       function set_notify(&$user, $notify) {
-               $orig = clone($user);
-               $user->jabbernotify = $notify;
-               $result = $user->update($orig);
-               if (!$id) {
-                       $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
-                       $this->log(LOG_ERR,
-                                          'Could not set notify flag to ' . $notify .
-                                          ' for user ' . common_log_objstring($user) .
-                                          ': ' . $last_error->message);
-               } else {
-                       $this->log(LOG_INFO,
-                                          'User ' . $user->nickname . ' set notify flag to ' . $notify);
-               }
-       }
-
-       function add_notice(&$user, &$pl) {
-               $notice = Notice::saveNew($user->id, trim(substr($pl['body'], 0, 140)), 'xmpp');
-               if (is_string($notice)) {
-                       $this->log(LOG_ERR, $notice);
-                       return;
-               }
-               common_real_broadcast($notice);
-               $this->log(LOG_INFO,
-                                  'Added notice ' . $notice->id . ' from user ' . $user->nickname);
-       }
-
-       function handle_presence(&$pl) {
-               $from = jabber_normalize_jid($pl['from']);
-               switch ($pl['type']) {
-                case 'subscribe':
-                       # We let anyone subscribe
-                       $this->subscribed($from);
-                       $this->log(LOG_INFO,
-                                          'Accepted subscription from ' . $from);
-                       break;
-                case 'subscribed':
-                case 'unsubscribed':
-                case 'unsubscribe':
-                       $this->log(LOG_INFO,
-                                          'Ignoring  "' . $pl['type'] . '" from ' . $from);
-                       break;
-                default:
-                       if (!$pl['type']) {
-                               $user = User::staticGet('jabber', $from);
-                               if (!$user) {
-                                       $this->log(LOG_WARNING, 'Presence from unknown user ' . $from);
-                                       return;
-                               }
-                               if ($user->updatefrompresence) {
-                                       $this->log(LOG_INFO, 'Updating ' . $user->nickname .
-                                                          ' status from presence.');
-                                       $this->add_notice($user, $pl);
-                               }
-                       }
-                       break;
-               }
-       }
-
-       function log($level, $msg) {
-               common_log($level, 'XMPPDaemon('.$this->resource.'): '.$msg);
-       }
-
-       function subscribed($to) {
-               jabber_special_presence('subscribed', $to);
-       }
-
-       function set_status($status) {
-               $this->log(LOG_INFO, 'Setting status to "' . $status . '"');
-               jabber_send_presence($status);
-       }
-
-       function top_queue_item() {
-
-               $qi = new Queue_item();
-               $qi->orderBy('created');
-               $qi->whereAdd('claimed is NULL');
-
-               $qi->limit(1);
-
-               $cnt = $qi->find(TRUE);
-
-               if ($cnt) {
-                       # XXX: potential race condition
-                       # can we force it to only update if claimed is still NULL
-                       # (or old)?
-                       $this->log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id);
-                       $orig = clone($qi);
-                       $qi->claimed = DB_DataObject_Cast::dateTime();
-                       $result = $qi->update($orig);
-                       if ($result) {
-                               $this->log(LOG_INFO, 'claim succeeded.');
-                               return $qi;
-                       } else {
-                               $this->log(LOG_INFO, 'claim failed.');
-                       }
-               }
-               $qi = NULL;
-               return NULL;
-       }
-
-       function broadcast_queue() {
-               $this->clear_old_claims();
-               $this->log(LOG_INFO, 'checking for queued notices');
-               do {
-                       $qi = $this->top_queue_item();
-                       if ($qi) {
-                               $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($qi->created));
-                               $notice = Notice::staticGet($qi->notice_id);
-                               if ($notice) {
-                                       $this->log(LOG_INFO, 'broadcasting notice ID = ' . $notice->id);
-                                       # XXX: what to do if broadcast fails?
-                                       $result = common_real_broadcast($notice, $this->is_remote($notice));
-                                       if (!$result) {
-                                               $this->log(LOG_WARNING, 'Failed broadcast for notice ID = ' . $notice->id);
-                                               $orig = $qi;
-                                               $qi->claimed = NULL;
-                                               $qi->update($orig);
-                                               $this->log(LOG_WARNING, 'Abandoned claim for notice ID = ' . $notice->id);
-                                               continue;
-                                       }
-                                       $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
-                                       $notice = NULL;
-                               } else {
-                                       $this->log(LOG_WARNING, 'queue item for notice that does not exist');
-                               }
-                               $qi->delete();
-                       }
-               } while ($qi);
-       }
-
-       function clear_old_claims() {
-               $qi = new Queue_item();
-               $qi->claimed = NULL;
-               $qi->whereAdd('now() - claimed > '.CLAIM_TIMEOUT);
-               $qi->update(DB_DATAOBJECT_WHEREADD_ONLY);
-       }
-
-       function is_remote($notice) {
-               $user = User::staticGet($notice->profile_id);
-               return !$user;
-       }
-
-       function confirmation_queue() {
-           # $this->clear_old_confirm_claims();
-               $this->log(LOG_INFO, 'checking for queued confirmations');
-               do {
-                       $confirm = $this->next_confirm();
-                       if ($confirm) {
-                               $this->log(LOG_INFO, 'Sending confirmation for ' . $confirm->address);
-                               $user = User::staticGet($confirm->user_id);
-                               if (!$user) {
-                                       $this->log(LOG_WARNING, 'Confirmation for unknown user ' . $confirm->user_id);
-                                       continue;
-                               }
-                               $success = jabber_confirm_address($confirm->code,
-                                                                 $user->nickname,
-                                                                 $confirm->address);
-                               if (!$success) {
-                                       $this->log(LOG_ERR, 'Confirmation failed for ' . $confirm->address);
-                                       # Just let the claim age out; hopefully things work then
-                                       continue;
-                               } else {
-                                       $this->log(LOG_INFO, 'Confirmation sent for ' . $confirm->address);
-                                       # Mark confirmation sent
-                                       $original = clone($confirm);
-                                       $confirm->sent = $confirm->claimed;
-                                       $result = $confirm->update($original);
-                                       if (!$result) {
-                                               $this->log(LOG_ERR, 'Cannot mark sent for ' . $confirm->address);
-                                               # Just let the claim age out; hopefully things work then
-                                               continue;
-                                       }
-                               }
-                       }
-               } while ($confirm);
-       }
-
-       function next_confirm() {
-               $confirm = new Confirm_address();
-               $confirm->whereAdd('claimed IS NULL');
-               $confirm->whereAdd('sent IS NULL');
-               # XXX: eventually we could do other confirmations in the queue, too
-               $confirm->address_type = 'jabber';
-               $confirm->orderBy('modified DESC');
-               $confirm->limit(1);
-               if ($confirm->find(TRUE)) {
-                       $this->log(LOG_INFO, 'Claiming confirmation for ' . $confirm->address);
-                       # working around some weird DB_DataObject behaviour
-                       $confirm->whereAdd(''); # clears where stuff
-                       $original = clone($confirm);
-                       $confirm->claimed = DB_DataObject_Cast::dateTime();
-                       $result = $confirm->update($original);
-                       if ($result) {
-                               $this->log(LOG_INFO, 'Succeeded in claim! '. $result);
-                               return $confirm;
-                       } else {
-                               $this->log(LOG_INFO, 'Failed in claim!');
-                               return false;
-                       }
-               }
-               return NULL;
-       }
-
-       function clear_old_confirm_claims() {
-               $confirm = new Confirm();
-               $confirm->claimed = NULL;
-               $confirm->whereAdd('now() - claimed > '.CLAIM_TIMEOUT);
-               $confirm->update(DB_DATAOBJECT_WHEREADD_ONLY);
-       }
-
-}
-
-$resource = ($argc > 1) ? $argv[1] : NULL;
-
-$daemon = new XMPPDaemon($resource);
-
-if ($daemon->connect()) {
-       $daemon->set_status("Send me a message to post a notice");
-       $daemon->handle();
-}
-
-?>