]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Merge branch '0.9.x' of git@gitorious.org:statusnet/mainline into 1.0.x
authorBrion Vibber <brion@pobox.com>
Mon, 22 Mar 2010 20:56:16 +0000 (13:56 -0700)
committerBrion Vibber <brion@pobox.com>
Mon, 22 Mar 2010 20:56:16 +0000 (13:56 -0700)
Conflicts:
lib/channel.php
scripts/imdaemon.php

1  2 
actions/shownotice.php
classes/User.php
lib/channel.php
lib/command.php
lib/queuemanager.php
lib/statusnet.php
lib/util.php
scripts/imdaemon.php

diff --combined actions/shownotice.php
index d0528a9f0f6764b9fd84da214faa81d768195118,ca6b60d1f59b15de87d5f047002fffbc5ebd0591..12e1d77f805480b3cb6bc39c6d5bdd75ac5da2a7
@@@ -103,11 -103,6 +103,6 @@@ class ShownoticeAction extends OwnerDes
  
          $this->user = User::staticGet('id', $this->profile->id);
  
-         if ($this->notice->is_local == Notice::REMOTE_OMB) {
-             common_redirect($this->notice->uri);
-             return false;
-         }
          $this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
  
          return true;
      function title()
      {
          if (!empty($this->profile->fullname)) {
-             $base = $this->profile->fullname . ' (' . $this->profile->nickname . ') ';
+             $base = $this->profile->fullname . ' (' . $this->profile->nickname . ')';
          } else {
              $base = $this->profile->nickname;
          }
  
          if ($this->notice->is_local == Notice::REMOTE_OMB) {
              if (!empty($this->notice->url)) {
-                 common_redirect($this->notice->url, 301);
+                 $target = $this->notice->url;
              } else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
-                 common_redirect($this->notice->uri, 301);
+                 // Old OMB posts saved the remote URL only into the URI field.
+                 $target = $this->notice->uri;
+             } else {
+                 // Shouldn't happen.
+                 $target = false;
+             }
+             if ($target && $target != $this->selfUrl()) {
+                 common_redirect($target, 301);
+                 return false;
              }
-         } else {
-             $this->showPage();
          }
+         $this->showPage();
      }
  
      /**
                                           'content' => $id->toString()));
          }
  
 -        if ($user->jabbermicroid && $user->jabber && $this->notice->uri) {
 -            $id = new Microid('xmpp:', $user->jabber,
 -                              $this->notice->uri);
 -            $this->element('meta', array('name' => 'microid',
 -                                         'content' => $id->toString()));
 -        }
          $this->element('link',array('rel'=>'alternate',
              'type'=>'application/json+oembed',
              'href'=>common_local_url(
diff --combined classes/User.php
index 15ec4ad946192896d527b2e0fc4a6c1878c6fb5a,8ad2ec63d5c81d12cbf6c3b35c7eb41b8cac5e60..1ba940a6963600fc2545f167ec199d49656dd411
@@@ -48,6 -48,11 +48,6 @@@ class User extends Memcached_DataObjec
      public $language;                        // varchar(50)
      public $timezone;                        // varchar(50)
      public $emailpost;                       // tinyint(1)   default_1
 -    public $jabber;                          // varchar(255)  unique_key
 -    public $jabbernotify;                    // tinyint(1)
 -    public $jabberreplies;                   // tinyint(1)
 -    public $jabbermicroid;                   // tinyint(1)   default_1
 -    public $updatefrompresence;              // tinyint(1)
      public $sms;                             // varchar(64)  unique_key
      public $carrier;                         // int(4)
      public $smsnotify;                       // tinyint(1)
  
      function getProfile()
      {
-         return Profile::staticGet('id', $this->id);
+         $profile = Profile::staticGet('id', $this->id);
+         if (empty($profile)) {
+             throw new UserNoProfileException($this);
+         }
+         return $profile;
      }
  
      function isSubscribed($other)
@@@ -82,8 -91,9 +86,9 @@@
  
      function updateKeys(&$orig)
      {
+         $this->_connect();
          $parts = array();
 -        foreach (array('nickname', 'email', 'jabber', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
 +        foreach (array('nickname', 'email', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
              if (strcmp($this->$k, $orig->$k) != 0) {
                  $parts[] = $k . ' = ' . $this->_quote($this->$k);
              }
          return !in_array($nickname, $blacklist);
      }
  
-     function getCurrentNotice($dt=null)
+     /**
+      * Get the most recent notice posted by this user, if any.
+      *
+      * @return mixed Notice or null
+      */
+     function getCurrentNotice()
      {
          $profile = $this->getProfile();
-         if (!$profile) {
-             return null;
-         }
-         return $profile->getCurrentNotice($dt);
+         return $profile->getCurrentNotice();
      }
  
      function getCarrier()
          return Sms_carrier::staticGet('id', $this->carrier);
      }
  
+     /**
+      * @deprecated use Subscription::start($sub, $other);
+      */
      function subscribeTo($other)
      {
-         $sub = new Subscription();
-         $sub->subscriber = $this->id;
-         $sub->subscribed = $other->id;
-         $sub->created = common_sql_now(); // current time
-         if (!$sub->insert()) {
-             return false;
-         }
-         return true;
+         return Subscription::start($this->getProfile(), $other);
      }
  
      function hasBlocked($other)
                      common_log(LOG_WARNING, sprintf("Default user %s does not exist.", $defnick),
                                 __FILE__);
                  } else {
-                     $defsub = new Subscription();
-                     $defsub->subscriber = $user->id;
-                     $defsub->subscribed = $defuser->id;
-                     $defsub->created = $user->created;
-                     $result = $defsub->insert();
-                     if (!$result) {
-                         common_log_db_error($defsub, 'INSERT', __FILE__);
-                         return false;
-                     }
+                     Subscription::start($user, $defuser);
                  }
              }
  
  
      function getTaggedNotices($tag, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) {
          $profile = $this->getProfile();
-         if (!$profile) {
-             return null;
-         } else {
-             return $profile->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id);
-         }
+         return $profile->getTaggedNotices($tag, $offset, $limit, $since_id, $before_id);
      }
  
      function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0)
      {
          $profile = $this->getProfile();
-         if (!$profile) {
-             return null;
-         } else {
-             return $profile->getNotices($offset, $limit, $since_id, $before_id);
-         }
+         return $profile->getNotices($offset, $limit, $since_id, $before_id);
      }
  
      function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE, $own=false)
      function getSubscriptions($offset=0, $limit=null)
      {
          $profile = $this->getProfile();
-         assert(!empty($profile));
          return $profile->getSubscriptions($offset, $limit);
      }
  
      function getSubscribers($offset=0, $limit=null)
      {
          $profile = $this->getProfile();
-         assert(!empty($profile));
          return $profile->getSubscribers($offset, $limit);
      }
  
      function delete()
      {
          $profile = $this->getProfile();
-         if ($profile) {
-             $profile->delete();
-         }
+         $profile->delete();
  
          $related = array('Fave',
                           'Confirm_address',
diff --combined lib/channel.php
index 05437b4e9eaa44c3720b9ed9a192cbb7cbf43807,689bca0be98a8028966812aa578569dbc3efdb7d..e83960ac5402cc41fbe1867ca2bceea31c7280f6
@@@ -47,6 -47,82 +47,25 @@@ class Channe
      }
  }
  
 -class XMPPChannel extends Channel
 -{
 -
 -    var $conn = null;
 -
 -    function source()
 -    {
 -        return 'xmpp';
 -    }
 -
 -    function __construct($conn)
 -    {
 -        $this->conn = $conn;
 -    }
 -
 -    function on($user)
 -    {
 -        return $this->set_notify($user, 1);
 -    }
 -
 -    function off($user)
 -    {
 -        return $this->set_notify($user, 0);
 -    }
 -
 -    function output($user, $text)
 -    {
 -        $text = '['.common_config('site', 'name') . '] ' . $text;
 -        jabber_send_message($user->jabber, $text);
 -    }
 -
 -    function error($user, $text)
 -    {
 -        $text = '['.common_config('site', 'name') . '] ' . $text;
 -        jabber_send_message($user->jabber, $text);
 -    }
 -
 -    function set_notify(&$user, $notify)
 -    {
 -        $orig = clone($user);
 -        $user->jabbernotify = $notify;
 -        $result = $user->update($orig);
 -        if (!$result) {
 -            $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
 -            common_log(LOG_ERR,
 -                       'Could not set notify flag to ' . $notify .
 -                       ' for user ' . common_log_objstring($user) .
 -                       ': ' . $last_error->message);
 -            return false;
 -        } else {
 -            common_log(LOG_INFO,
 -                       'User ' . $user->nickname . ' set notify flag to ' . $notify);
 -            return true;
 -        }
 -    }
 -}
 -
+ class CLIChannel extends Channel
+ {
+     function source()
+     {
+         return 'cli';
+     }
+     function output($user, $text)
+     {
+         $site = common_config('site', 'name');
+         print "[{$user->nickname}@{$site}] $text\n";
+     }
+     function error($user, $text)
+     {
+         $this->output($user, $text);
+     }
+ }
  class WebChannel extends Channel
  {
      var $out = null;
diff --combined lib/command.php
index 5be9cd6e85bdc161145a345796ba53d1084b1c3f,f7421269d0aad3c4bc4771fe2b32e85d458c609e..c2116828c00914de1c1669932355c129bfaf84cb
@@@ -1,7 -1,7 +1,7 @@@
  <?php
  /*
   * StatusNet - the distributed open-source microblogging tool
-  * Copyright (C) 2008, 2009, StatusNet, Inc.
+  * Copyright (C) 2008, 2009, 2010 StatusNet, 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
@@@ -31,15 -31,147 +31,147 @@@ class Comman
          $this->user = $user;
      }
  
-     function execute($channel)
+     /**
+      * Execute the command and send success or error results
+      * back via the given communications channel.
+      *
+      * @param Channel
+      */
+     public function execute($channel)
+     {
+         try {
+             $this->handle($channel);
+         } catch (CommandException $e) {
+             $channel->error($this->user, $e->getMessage());
+         } catch (Exception $e) {
+             common_log(LOG_ERR, "Error handling " . get_class($this) . ": " . $e->getMessage());
+             $channel->error($this->user, $e->getMessage());
+         }
+     }
+     
+     /**
+      * Override this with the meat!
+      *
+      * An error to send back to the user may be sent by throwing
+      * a CommandException with a formatted message.
+      *
+      * @param Channel
+      * @throws CommandException
+      */
+     function handle($channel)
      {
          return false;
      }
+     /**
+      * Look up a notice from an argument, by poster's name to get last post
+      * or notice_id prefixed with #.
+      *
+      * @return Notice
+      * @throws CommandException
+      */
+     function getNotice($arg)
+     {
+         $notice = null;
+         if (Event::handle('StartCommandGetNotice', array($this, $arg, &$notice))) {
+             if(substr($this->other,0,1)=='#'){
+                 // A specific notice_id #123
+                 $notice = Notice::staticGet(substr($arg,1));
+                 if (!$notice) {
+                     throw new CommandException(_('Notice with that id does not exist'));
+                 }
+             }
+             
+             if (Validate::uri($this->other)) {
+                 // A specific notice by URI lookup
+                 $notice = Notice::staticGet('uri', $arg);
+             }
+             
+             if (!$notice) {
+                 // Local or remote profile name to get their last notice.
+                 // May throw an exception and report 'no such user'
+                 $recipient = $this->getProfile($arg);
+                 $notice = $recipient->getCurrentNotice();
+                 if (!$notice) {
+                     throw new CommandException(_('User has no last notice'));
+                 }
+             }
+         }
+         Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
+         if (!$notice) {
+             throw new CommandException(_('Notice with that id does not exist'));
+         }
+         return $notice;
+     }
+     /**
+      * Look up a local or remote profile by nickname.
+      *
+      * @return Profile
+      * @throws CommandException
+      */
+     function getProfile($arg)
+     {
+         $profile = null;
+         if (Event::handle('StartCommandGetProfile', array($this, $arg, &$profile))) {
+             $profile =
+               common_relative_profile($this->user, common_canonical_nickname($arg));
+         }
+         Event::handle('EndCommandGetProfile', array($this, $arg, &$profile));
+         if (!$profile) {
+             throw new CommandException(sprintf(_('Could not find a user with nickname %s'), $arg));
+         }
+         return $profile;
+     }
+     /**
+      * Get a local user by name
+      * @return User
+      * @throws CommandException
+      */
+     function getUser($arg)
+     {
+         $user = null;
+         if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
+             $user = User::staticGet('nickname', $arg);
+         }
+         Event::handle('EndCommandGetUser', array($this, $arg, &$user));
+         if (!$user){
+             throw new CommandException(sprintf(_('Could not find a local user with nickname %s'),
+                                $arg));
+         }
+         return $user;
+     }
+     /**
+      * Get a local or remote group by name.
+      * @return User_group
+      * @throws CommandException
+      */
+     function getGroup($arg)
+     {
+         $group = null;
+         if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) {
+             $group = User_group::getForNickname($arg, $this->user->getProfile());
+         }
+         Event::handle('EndCommandGetGroup', array($this, $arg, &$group));
+         if (!$group) {
+             throw new CommandException(_('No such group.'));
+         }
+         return $group;
+     }
+ }
+ class CommandException extends Exception
+ {
  }
  
  class UnimplementedCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $channel->error($this->user, _("Sorry, this command is not yet implemented."));
      }
@@@ -81,24 -213,20 +213,20 @@@ class NudgeCommand extends Comman
          parent::__construct($user);
          $this->other = $other;
      }
-     function execute($channel)
+     function handle($channel)
      {
-         $recipient = User::staticGet('nickname', $this->other);
-         if(! $recipient){
-             $channel->error($this->user, sprintf(_('Could not find a user with nickname %s'),
-                                $this->other));
-         }else{
-             if ($recipient->id == $this->user->id) {
-                 $channel->error($this->user, _('It does not make a lot of sense to nudge yourself!'));
-             }else{
-                 if ($recipient->email && $recipient->emailnotifynudge) {
-                     mail_notify_nudge($this->user, $recipient);
-                 }
-                 // XXX: notify by IM
-                 // XXX: notify by SMS
-                 $channel->output($this->user, sprintf(_('Nudge sent to %s'),
-                                $recipient->nickname));
+         $recipient = $this->getUser($this->other);
+         if ($recipient->id == $this->user->id) {
+             throw new CommandException(_('It does not make a lot of sense to nudge yourself!'));
+         } else {
+             if ($recipient->email && $recipient->emailnotifynudge) {
+                 mail_notify_nudge($this->user, $recipient);
              }
+             // XXX: notify by IM
+             // XXX: notify by SMS
+             $channel->output($this->user, sprintf(_('Nudge sent to %s'),
+                            $recipient->nickname));
          }
      }
  }
@@@ -115,7 -243,7 +243,7 @@@ class InviteCommand extends Unimplement
  
  class StatsCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $profile = $this->user->getProfile();
  
@@@ -142,34 -270,9 +270,9 @@@ class FavCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         if(substr($this->other,0,1)=='#'){
-             //favoriting a specific notice_id
-             $notice = Notice::staticGet(substr($this->other,1));
-             if (!$notice) {
-                 $channel->error($this->user, _('Notice with that id does not exist'));
-                 return;
-             }
-             $recipient = $notice->getProfile();
-         }else{
-             //favoriting a given user's last notice
-             $recipient =
-               common_relative_profile($this->user, common_canonical_nickname($this->other));
-             if (!$recipient) {
-                 $channel->error($this->user, _('No such user.'));
-                 return;
-             }
-             $notice = $recipient->getCurrentNotice();
-             if (!$notice) {
-                 $channel->error($this->user, _('User has no last notice'));
-                 return;
-             }
-         }
+         $notice = $this->getNotice($this->other);
          $fave = Fave::addNew($this->user, $notice);
  
          if (!$fave) {
              return;
          }
  
-         $other = User::staticGet('id', $recipient->id);
+         // @fixme favorite notification should be triggered
+         // at a lower level
+         $other = User::staticGet('id', $notice->profile_id);
  
          if ($other && $other->id != $user->id) {
              if ($other->email && $other->emailnotifyfav) {
      }
  
  }
  class JoinCommand extends Command
  {
      var $other = null;
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         $nickname = common_canonical_nickname($this->other);
-         $group    = User_group::staticGet('nickname', $nickname);
-         $cur      = $this->user;
-         if (!$group) {
-             $channel->error($cur, _('No such group.'));
-             return;
-         }
+         $group = $this->getGroup($this->other);
+         $cur   = $this->user;
  
          if ($cur->isMember($group)) {
              $channel->error($cur, _('You are already a member of that group'));
@@@ -249,12 -349,10 +349,10 @@@ class DropCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         $nickname = common_canonical_nickname($this->other);
-         $group    = User_group::staticGet('nickname', $nickname);
-         $cur      = $this->user;
+         $group = $this->getGroup($this->other);
+         $cur   = $this->user;
  
          if (!$group) {
              $channel->error($cur, _('No such group.'));
@@@ -293,15 -391,9 +391,9 @@@ class WhoisCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         $recipient =
-           common_relative_profile($this->user, common_canonical_nickname($this->other));
-         if (!$recipient) {
-             $channel->error($this->user, _('No such user.'));
-             return;
-         }
+         $recipient = $this->getProfile($this->other);
  
          $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname,
                           $recipient->profileurl);
@@@ -332,9 -424,18 +424,18 @@@ class MessageCommand extends Comman
          $this->text = $text;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         $other = User::staticGet('nickname', common_canonical_nickname($this->other));
+         try {
+             $other = $this->getUser($this->other);
+         } catch (CommandException $e) {
+             try {
+                 $profile = $this->getProfile($this->other);
+             } catch (CommandException $f) {
+                 throw $e;
+             }
+             throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other));
+         }
  
          $len = mb_strlen($this->text);
  
@@@ -380,33 -481,9 +481,9 @@@ class RepeatCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         if(substr($this->other,0,1)=='#'){
-             //repeating a specific notice_id
-             $notice = Notice::staticGet(substr($this->other,1));
-             if (!$notice) {
-                 $channel->error($this->user, _('Notice with that id does not exist'));
-                 return;
-             }
-             $recipient = $notice->getProfile();
-         }else{
-             //repeating a given user's last notice
-             $recipient =
-               common_relative_profile($this->user, common_canonical_nickname($this->other));
-             if (!$recipient) {
-                 $channel->error($this->user, _('No such user.'));
-                 return;
-             }
-             $notice = $recipient->getCurrentNotice();
-             if (!$notice) {
-                 $channel->error($this->user, _('User has no last notice'));
-                 return;
-             }
-         }
+         $notice = $this->getNotice($this->other);
  
          if($this->user->id == $notice->profile_id)
          {
              return;
          }
  
-         if ($recipient->hasRepeated($notice->id)) {
+         if ($this->user->getProfile()->hasRepeated($notice->id)) {
              $channel->error($this->user, _('Already repeated that notice'));
              return;
          }
@@@ -441,33 -518,10 +518,10 @@@ class ReplyCommand extends Comman
          $this->text = $text;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         if(substr($this->other,0,1)=='#'){
-             //replying to a specific notice_id
-             $notice = Notice::staticGet(substr($this->other,1));
-             if (!$notice) {
-                 $channel->error($this->user, _('Notice with that id does not exist'));
-                 return;
-             }
-             $recipient = $notice->getProfile();
-         }else{
-             //replying to a given user's last notice
-             $recipient =
-               common_relative_profile($this->user, common_canonical_nickname($this->other));
-             if (!$recipient) {
-                 $channel->error($this->user, _('No such user.'));
-                 return;
-             }
-             $notice = $recipient->getCurrentNotice();
-             if (!$notice) {
-                 $channel->error($this->user, _('User has no last notice'));
-                 return;
-             }
-         }
+         $notice = $this->getNotice($this->other);
+         $recipient = $notice->getProfile();
  
          $len = mb_strlen($this->text);
  
@@@ -507,17 -561,10 +561,10 @@@ class GetCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
-         $target_nickname = common_canonical_nickname($this->other);
-         $target =
-           common_relative_profile($this->user, $target_nickname);
+         $target = $this->getProfile($this->other);
  
-         if (!$target) {
-             $channel->error($this->user, _('No such user.'));
-             return;
-         }
          $notice = $target->getCurrentNotice();
          if (!$notice) {
              $channel->error($this->user, _('User has no last notice'));
          }
          $notice_content = $notice->content;
  
-         $channel->output($this->user, $target_nickname . ": " . $notice_content);
+         $channel->output($this->user, $target->nickname . ": " . $notice_content);
      }
  }
  
@@@ -540,7 -587,7 +587,7 @@@ class SubCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
  
          if (!$this->other) {
              return;
          }
  
-         $otherUser = User::staticGet('nickname', $this->other);
+         $target = $this->getProfile($this->other);
  
-         if (empty($otherUser)) {
-             $channel->error($this->user, _('No such user'));
-             return;
+         $remote = Remote_profile::staticGet('id', $target->id);
+         if ($remote) {
+             throw new CommandException(_("Can't subscribe to OMB profiles by command."));
          }
  
          try {
              Subscription::start($this->user->getProfile(),
-                                 $otherUser->getProfile());
+                                 $target);
              $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other));
          } catch (Exception $e) {
              $channel->error($this->user, $e->getMessage());
@@@ -576,22 -623,18 +623,18 @@@ class UnsubCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
          if(!$this->other) {
              $channel->error($this->user, _('Specify the name of the user to unsubscribe from'));
              return;
          }
  
-         $otherUser = User::staticGet('nickname', $this->other);
-         if (empty($otherUser)) {
-             $channel->error($this->user, _('No such user'));
-         }
+         $target = $this->getProfile($this->other);
  
          try {
              Subscription::cancel($this->user->getProfile(),
-                                  $otherUser->getProfile());
+                                  $target);
              $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other));
          } catch (Exception $e) {
              $channel->error($this->user, $e->getMessage());
@@@ -607,9 -650,9 +650,9 @@@ class OffCommand extends Comman
          parent::__construct($user);
          $this->other = $other;
      }
-     function execute($channel)
+     function handle($channel)
      {
 -        if ($other) {
 +        if ($this->other) {
              $channel->error($this->user, _("Command not yet implemented."));
          } else {
              if ($channel->off($this->user)) {
@@@ -630,9 -673,9 +673,9 @@@ class OnCommand extends Comman
          $this->other = $other;
      }
  
-     function execute($channel)
+     function handle($channel)
      {
 -        if ($other) {
 +        if ($this->other) {
              $channel->error($this->user, _("Command not yet implemented."));
          } else {
              if ($channel->on($this->user)) {
  
  class LoginCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $disabled = common_config('logincommand','disabled');
          $disabled = isset($disabled) && $disabled;
@@@ -686,7 -729,7 +729,7 @@@ class LoseCommand extends Comman
              return;
          }
  
-         $result=subs_unsubscribe_from($this->user, $this->other);
+         $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());
  
          if ($result) {
              $channel->output($this->user, sprintf(_('Unsubscribed  %s'), $this->other));
  
  class SubscriptionsCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $profile = $this->user->getSubscriptions(0);
          $nicknames=array();
  
  class SubscribersCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $profile = $this->user->getSubscribers();
          $nicknames=array();
  
  class GroupsCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $group = $this->user->getGroups();
          $groups=array();
  
  class HelpCommand extends Command
  {
-     function execute($channel)
+     function handle($channel)
      {
          $channel->output($this->user,
                           _("Commands:\n".
diff --combined lib/queuemanager.php
index fe45e8bbff8079981b7064996b3afc06925101dc,0829c8a8bcb8321d1aba5deaa55d8e4640d4d9eb..6666a6cb5a69974a61783a842ac3b106860998b4
@@@ -156,14 -156,21 +156,14 @@@ abstract class QueueManager extends IoM
      }
  
      /**
 -     * Encode an object or variable for queued storage.
 -     * Notice objects are currently stored as an id reference;
 -     * other items are serialized.
 +     * Encode an object for queued storage.
       *
       * @param mixed $item
       * @return string
       */
      protected function encode($item)
      {
 -        if ($item instanceof Notice) {
 -            // Backwards compat
 -            return $item->id;
 -        } else {
 -            return serialize($item);
 -        }
 +        return serialize($item);
      }
  
      /**
       */
      protected function decode($frame)
      {
 -        if (is_numeric($frame)) {
 -            // Back-compat for notices...
 -            return Notice::staticGet(intval($frame));
 -        } elseif (substr($frame, 0, 1) == '<') {
 -            // Back-compat for XML source
 -            return $frame;
 -        } else {
 -            // Deserialize!
 -            #$old = error_reporting();
 -            #error_reporting($old & ~E_NOTICE);
 -            $out = unserialize($frame);
 -            #error_reporting($old);
 -
 -            if ($out === false && $frame !== 'b:0;') {
 -                common_log(LOG_ERR, "Couldn't unserialize queued frame: $frame");
 -                return false;
 -            }
 -            return $out;
 -        }
 +        return unserialize($frame);
      }
  
      /**
                  $this->connect('sms', 'SmsQueueHandler');
              }
  
+             // Background user management tasks...
+             $this->connect('deluser', 'DelUserQueueHandler');
              // Broadcasting profile updates to OMB remote subscribers
              $this->connect('profile', 'ProfileQueueHandler');
  
 -            // XMPP output handlers...
 -            if (common_config('xmpp', 'enabled')) {
 -                // Delivery prep, read by queuedaemon.php:
 -                $this->connect('jabber', 'JabberQueueHandler');
 -                $this->connect('public', 'PublicQueueHandler');
 -
 -                // Raw output, read by xmppdaemon.php:
 -                $this->connect('xmppout', 'XmppOutQueueHandler', 'xmpp');
 -            }
 -
              // For compat with old plugins not registering their own handlers.
              $this->connect('plugin', 'PluginQueueHandler');
          }
diff --combined lib/statusnet.php
index afb8f5af02f4ad830d496c633dbfd61ef7a17caf,eba9ab9b8eef799f20567efa82cb905e6fa420bd..776cfb579b807f70c069e38416025b77779e637b
@@@ -339,34 -339,16 +339,30 @@@ class StatusNe
          }
  
          // Backwards compatibility
 -
          if (array_key_exists('memcached', $config)) {
              if ($config['memcached']['enabled']) {
-                 if(class_exists('Memcached')) {
-                     addPlugin('Memcached', array('servers' => $config['memcached']['server']));
-                 } else {
-                     addPlugin('Memcache', array('servers' => $config['memcached']['server']));
-                 }
+                 addPlugin('Memcache', array('servers' => $config['memcached']['server']));
              }
  
              if (!empty($config['memcached']['base'])) {
                  $config['cache']['base'] = $config['memcached']['base'];
              }
          }
 +        if (array_key_exists('xmpp', $config)) {
 +            if ($config['xmpp']['enabled']) {
 +                addPlugin('xmpp', array(
 +                    'server' => $config['xmpp']['server'],
 +                    'port' => $config['xmpp']['port'],
 +                    'user' => $config['xmpp']['user'],
 +                    'resource' => $config['xmpp']['resource'],
 +                    'encryption' => $config['xmpp']['encryption'],
 +                    'password' => $config['xmpp']['password'],
 +                    'host' => $config['xmpp']['host'],
 +                    'debug' => $config['xmpp']['debug'],
 +                    'public' => $config['xmpp']['public']
 +                ));
 +            }
 +        }
      }
  }
  
diff --combined lib/util.php
index 6a849427584c21c22245af8ba0d8ef1f0500d355,a30d69100289f08a94ba8e850bbcb1ed6f127e2e..0f639df388e0a7a740833ae68f145ae9c9d25ecf
@@@ -52,17 -52,43 +52,43 @@@ function common_init_language(
  {
      mb_internal_encoding('UTF-8');
  
-     // gettext seems very picky... We first need to setlocale()
-     // to a locale which _does_ exist on the system, and _then_
-     // we can set in another locale that may not be set up
-     // (say, ga_ES for Galego/Galician) it seems to take it.
-     common_init_locale("en_US");
      // Note that this setlocale() call may "fail" but this is harmless;
      // gettext will still select the right language.
      $language = common_language();
      $locale_set = common_init_locale($language);
  
+     if (!$locale_set) {
+         // The requested locale doesn't exist on the system.
+         //
+         // gettext seems very picky... We first need to setlocale()
+         // to a locale which _does_ exist on the system, and _then_
+         // we can set in another locale that may not be set up
+         // (say, ga_ES for Galego/Galician) it seems to take it.
+         //
+         // For some reason C and POSIX which are guaranteed to work
+         // don't do the job. en_US.UTF-8 should be there most of the
+         // time, but not guaranteed.
+         $ok = common_init_locale("en_US");
+         if (!$ok) {
+             // Try to find a complete, working locale...
+             // @fixme shelling out feels awfully inefficient
+             // but I don't think there's a more standard way.
+             $all = `locale -a`;
+             foreach (explode("\n", $all) as $locale) {
+                 if (preg_match('/\.utf[-_]?8$/i', $locale)) {
+                     $ok = setlocale(LC_ALL, $locale);
+                     if ($ok) {
+                         break;
+                     }
+                 }
+             }
+             if (!$ok) {
+                 common_log(LOG_ERR, "Unable to find a UTF-8 locale on this system; UI translations may not work.");
+             }
+         }
+         $locale_set = common_init_locale($language);
+     }
      setlocale(LC_CTYPE, 'C');
      // So we do not have to make people install the gettext locales
      $path = common_config('site','locale_path');
@@@ -133,6 -159,11 +159,11 @@@ function common_munge_password($passwor
  
  function common_check_user($nickname, $password)
  {
+     // empty nickname always unacceptable
+     if (empty($nickname)) {
+         return false;
+     }
      $authenticatedUser = false;
  
      if (Event::handle('StartCheckPassword', array($nickname, $password, &$authenticatedUser))) {
@@@ -1145,10 -1176,19 +1176,10 @@@ function common_enqueue_notice($notice
          $transports[] = 'plugin';
      }
  
 -    $xmpp = common_config('xmpp', 'enabled');
 -
 -    if ($xmpp) {
 -        $transports[] = 'jabber';
 -    }
 -
      // @fixme move these checks into QueueManager and/or individual handlers
      if ($notice->is_local == Notice::LOCAL_PUBLIC ||
          $notice->is_local == Notice::LOCAL_NONPUBLIC) {
          $transports = array_merge($transports, $localTransports);
 -        if ($xmpp) {
 -            $transports[] = 'public';
 -        }
      }
  
      if (Event::handle('StartEnqueueNotice', array($notice, &$transports))) {
@@@ -1453,7 -1493,15 +1484,15 @@@ function common_copy_args($from
      $to = array();
      $strip = get_magic_quotes_gpc();
      foreach ($from as $k => $v) {
-         $to[$k] = ($strip) ? stripslashes($v) : $v;
+         if($strip) {
+             if(is_array($v)) {
+                 $to[$k] = common_copy_args($v);
+             } else {
+                 $to[$k] = stripslashes($v);
+             }
+         } else {
+             $to[$k] = $v;
+         }
      }
      return $to;
  }
diff --combined scripts/imdaemon.php
index 4a2c942234f6112d19f017aaf64e1de61fcfdbff,0000000000000000000000000000000000000000..0ce74667c5d0178e2aeea7daa7b5f86d0cec3121
mode 100755,000000..100755
--- /dev/null
@@@ -1,101 -1,0 +1,118 @@@
-         $master = new ImMaster($this->get_id());
 +#!/usr/bin/env php
 +<?php
 +/*
 + * StatusNet - the distributed open-source microblogging tool
 + * Copyright (C) 2008, 2009, StatusNet, 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/>.
 + */
 +
 +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
 +
 +$shortoptions = 'fi::a';
 +$longoptions = array('id::', 'foreground', 'all');
 +
 +$helptext = <<<END_OF_IM_HELP
 +Daemon script for receiving new notices from IM users.
 +
 +    -i --id           Identity (default none)
 +    -a --all          Handle XMPP for all local sites
 +                      (requires Stomp queue handler, status_network setup)
 +    -f --foreground   Stay in the foreground (default background)
 +
 +END_OF_IM_HELP;
 +
 +require_once INSTALLDIR.'/scripts/commandline.inc';
 +
 +class ImDaemon extends SpawningDaemon
 +{
 +    protected $allsites = false;
 +
 +    function __construct($id=null, $daemonize=true, $threads=1, $allsites=false)
 +    {
 +        if ($threads != 1) {
 +            // This should never happen. :)
 +            throw new Exception("IMDaemon can must run single-threaded");
 +        }
 +        parent::__construct($id, $daemonize, $threads);
 +        $this->allsites = $allsites;
 +    }
 +
 +    function runThread()
 +    {
 +        common_log(LOG_INFO, 'Waiting to listen to IM connections and queues');
 +
++        $master = new ImMaster($this->get_id(), $this->processManager());
 +        $master->init($this->allsites);
 +        $master->service();
 +
 +        common_log(LOG_INFO, 'terminating normally');
 +
 +        return $master->respawn ? self::EXIT_RESTART : self::EXIT_SHUTDOWN;
 +    }
 +
 +}
 +
 +class ImMaster extends IoMaster
 +{
++    protected $processManager;
++
++    function __construct($id, $processManager)
++    {
++        parent::__construct($id);
++        $this->processManager = $processManager;
++    }
++
 +    /**
 +     * Initialize IoManagers for the currently configured site
 +     * which are appropriate to this instance.
 +     */
 +    function initManagers()
 +    {
 +        $classes = array();
 +        if (Event::handle('StartImDaemonIoManagers', array(&$classes))) {
 +            $qm = QueueManager::get();
 +            $qm->setActiveGroup('im');
 +            $classes[] = $qm;
++            $classes[] = $this->processManager;
 +        }
 +        Event::handle('EndImDaemonIoManagers', array(&$classes));
 +        foreach ($classes as $class) {
 +            $this->instantiate($class);
 +        }
 +    }
 +}
 +
++if (version_compare(PHP_VERSION, '5.2.6', '<')) {
++    $arch = php_uname('m');
++    if ($arch == 'x86_64' || $arch == 'amd64') {
++        print "Aborting daemon - 64-bit PHP prior to 5.2.6 has known bugs in stream_select; you are running " . PHP_VERSION . " on $arch.\n";
++        exit(1);
++    }
++}
++
 +if (have_option('i', 'id')) {
 +    $id = get_option_value('i', 'id');
 +} else if (count($args) > 0) {
 +    $id = $args[0];
 +} else {
 +    $id = null;
 +}
 +
 +$foreground = have_option('f', 'foreground');
 +$all = have_option('a') || have_option('--all');
 +
 +$daemon = new ImDaemon($id, !$foreground, 1, $all);
 +
 +$daemon->runOnce();