]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - lib/command.php
Merge branch 'master' into 0.9.x
[quix0rs-gnu-social.git] / lib / command.php
1 <?php
2 /*
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2008, 2009, 2010 StatusNet, Inc.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
21
22 require_once(INSTALLDIR.'/lib/channel.php');
23
24 class Command
25 {
26     var $user = null;
27
28     function __construct($user=null)
29     {
30         $this->user = $user;
31     }
32
33     /**
34      * Execute the command and send success or error results
35      * back via the given communications channel.
36      *
37      * @param Channel
38      */
39     public function execute($channel)
40     {
41         try {
42             $this->handle($channel);
43         } catch (CommandException $e) {
44             $channel->error($this->user, $e->getMessage());
45         } catch (Exception $e) {
46             common_log(LOG_ERR, "Error handling " . get_class($this) . ": " . $e->getMessage());
47             $channel->error($this->user, $e->getMessage());
48         }
49     }
50
51     /**
52      * Override this with the meat!
53      *
54      * An error to send back to the user may be sent by throwing
55      * a CommandException with a formatted message.
56      *
57      * @param Channel
58      * @throws CommandException
59      */
60     function handle($channel)
61     {
62         return false;
63     }
64
65     /**
66      * Look up a notice from an argument, by poster's name to get last post
67      * or notice_id prefixed with #.
68      *
69      * @return Notice
70      * @throws CommandException
71      */
72     function getNotice($arg)
73     {
74         $notice = null;
75         if (Event::handle('StartCommandGetNotice', array($this, $arg, &$notice))) {
76             if(substr($this->other,0,1)=='#'){
77                 // A specific notice_id #123
78
79                 $notice = Notice::staticGet(substr($arg,1));
80                 if (!$notice) {
81                     // TRANS: Command exception text shown when a notice ID is requested that does not exist.
82                     throw new CommandException(_('Notice with that id does not exist.'));
83                 }
84             }
85
86             if (Validate::uri($this->other)) {
87                 // A specific notice by URI lookup
88                 $notice = Notice::staticGet('uri', $arg);
89             }
90
91             if (!$notice) {
92                 // Local or remote profile name to get their last notice.
93                 // May throw an exception and report 'no such user'
94                 $recipient = $this->getProfile($arg);
95
96                 $notice = $recipient->getCurrentNotice();
97                 if (!$notice) {
98                     // TRANS: Command exception text shown when a last user notice is requested and it does not exist.
99                     throw new CommandException(_('User has no last notice.'));
100                 }
101             }
102         }
103         Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
104         if (!$notice) {
105             // TRANS: Command exception text shown when a notice ID is requested that does not exist.
106             throw new CommandException(_('Notice with that id does not exist.'));
107         }
108         return $notice;
109     }
110
111     /**
112      * Look up a local or remote profile by nickname.
113      *
114      * @return Profile
115      * @throws CommandException
116      */
117     function getProfile($arg)
118     {
119         $profile = null;
120         if (Event::handle('StartCommandGetProfile', array($this, $arg, &$profile))) {
121             $profile =
122               common_relative_profile($this->user, common_canonical_nickname($arg));
123         }
124         Event::handle('EndCommandGetProfile', array($this, $arg, &$profile));
125         if (!$profile) {
126             // TRANS: Message given requesting a profile for a non-existing user.
127             // TRANS: %s is the nickname of the user for which the profile could not be found.
128             throw new CommandException(sprintf(_('Could not find a user with nickname %s.'), $arg));
129         }
130         return $profile;
131     }
132
133     /**
134      * Get a local user by name
135      * @return User
136      * @throws CommandException
137      */
138     function getUser($arg)
139     {
140         $user = null;
141         if (Event::handle('StartCommandGetUser', array($this, $arg, &$user))) {
142             $user = User::staticGet('nickname', Nickname::normalize($arg));
143         }
144         Event::handle('EndCommandGetUser', array($this, $arg, &$user));
145         if (!$user){
146             // TRANS: Message given getting a non-existing user.
147             // TRANS: %s is the nickname of the user that could not be found.
148             throw new CommandException(sprintf(_('Could not find a local user with nickname %s.'),
149                                $arg));
150         }
151         return $user;
152     }
153
154     /**
155      * Get a local or remote group by name.
156      * @return User_group
157      * @throws CommandException
158      */
159     function getGroup($arg)
160     {
161         $group = null;
162         if (Event::handle('StartCommandGetGroup', array($this, $arg, &$group))) {
163             $group = User_group::getForNickname($arg, $this->user->getProfile());
164         }
165         Event::handle('EndCommandGetGroup', array($this, $arg, &$group));
166         if (!$group) {
167             // TRANS: Command exception text shown when a group is requested that does not exist.
168             throw new CommandException(_('No such group.'));
169         }
170         return $group;
171     }
172 }
173
174 class CommandException extends Exception
175 {
176 }
177
178 class UnimplementedCommand extends Command
179 {
180     function handle($channel)
181     {
182         // TRANS: Error text shown when an unimplemented command is given.
183         $channel->error($this->user, _("Sorry, this command is not yet implemented."));
184     }
185 }
186
187 class TrackingCommand extends UnimplementedCommand
188 {
189 }
190
191 class TrackOffCommand extends UnimplementedCommand
192 {
193 }
194
195 class TrackCommand extends UnimplementedCommand
196 {
197     var $word = null;
198     function __construct($user, $word)
199     {
200         parent::__construct($user);
201         $this->word = $word;
202     }
203 }
204
205 class UntrackCommand extends UnimplementedCommand
206 {
207     var $word = null;
208     function __construct($user, $word)
209     {
210         parent::__construct($user);
211         $this->word = $word;
212     }
213 }
214
215 class NudgeCommand extends Command
216 {
217     var $other = null;
218     function __construct($user, $other)
219     {
220         parent::__construct($user);
221         $this->other = $other;
222     }
223
224     function handle($channel)
225     {
226         $recipient = $this->getUser($this->other);
227         if ($recipient->id == $this->user->id) {
228             // TRANS: Command exception text shown when a user tries to nudge themselves.
229             throw new CommandException(_('It does not make a lot of sense to nudge yourself!'));
230         } else {
231             if ($recipient->email && $recipient->emailnotifynudge) {
232                 mail_notify_nudge($this->user, $recipient);
233             }
234             // XXX: notify by IM
235             // XXX: notify by SMS
236             // TRANS: Message given having nudged another user.
237             // TRANS: %s is the nickname of the user that was nudged.
238             $channel->output($this->user, sprintf(_('Nudge sent to %s.'),
239                            $recipient->nickname));
240         }
241     }
242 }
243
244 class InviteCommand extends UnimplementedCommand
245 {
246     var $other = null;
247     function __construct($user, $other)
248     {
249         parent::__construct($user);
250         $this->other = $other;
251     }
252 }
253
254 class StatsCommand extends Command
255 {
256     function handle($channel)
257     {
258         $profile = $this->user->getProfile();
259
260         $subs_count   = $profile->subscriptionCount();
261         $subbed_count = $profile->subscriberCount();
262         $notice_count = $profile->noticeCount();
263
264         // TRANS: User statistics text.
265         // TRANS: %1$s is the number of other user the user is subscribed to.
266         // TRANS: %2$s is the number of users that are subscribed to the user.
267         // TRANS: %3$s is the number of notices the user has sent.
268         $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n".
269                                    "Subscribers: %2\$s\n".
270                                    "Notices: %3\$s"),
271                                  $subs_count,
272                                  $subbed_count,
273                                  $notice_count));
274     }
275 }
276
277 class FavCommand extends Command
278 {
279     var $other = null;
280
281     function __construct($user, $other)
282     {
283         parent::__construct($user);
284         $this->other = $other;
285     }
286
287     function handle($channel)
288     {
289         $notice = $this->getNotice($this->other);
290         $fave = Fave::addNew($this->user->getProfile(), $notice);
291
292         if (!$fave) {
293             // TRANS: Error message text shown when a favorite could not be set.
294             $channel->error($this->user, _('Could not create favorite.'));
295             return;
296         }
297
298         // @fixme favorite notification should be triggered
299         // at a lower level
300
301         $other = User::staticGet('id', $notice->profile_id);
302
303         if ($other && $other->id != $user->id) {
304             if ($other->email && $other->emailnotifyfav) {
305                 mail_notify_fave($other, $this->user, $notice);
306             }
307         }
308
309         $this->user->blowFavesCache();
310
311         // TRANS: Text shown when a notice has been marked as favourite successfully.
312         $channel->output($this->user, _('Notice marked as fave.'));
313     }
314 }
315
316 class JoinCommand extends Command
317 {
318     var $other = null;
319
320     function __construct($user, $other)
321     {
322         parent::__construct($user);
323         $this->other = $other;
324     }
325
326     function handle($channel)
327     {
328         $group = $this->getGroup($this->other);
329         $cur   = $this->user;
330
331         if ($cur->isMember($group)) {
332             // TRANS: Error text shown a user tries to join a group they already are a member of.
333             $channel->error($cur, _('You are already a member of that group.'));
334             return;
335         }
336         if (Group_block::isBlocked($group, $cur->getProfile())) {
337             // TRANS: Error text shown when a user tries to join a group they are blocked from joining.
338           $channel->error($cur, _('You have been blocked from that group by the admin.'));
339             return;
340         }
341
342         try {
343             if (Event::handle('StartJoinGroup', array($group, $cur))) {
344                 Group_member::join($group->id, $cur->id);
345                 Event::handle('EndJoinGroup', array($group, $cur));
346             }
347         } catch (Exception $e) {
348             // TRANS: Message given having failed to add a user to a group.
349             // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
350             $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s.'),
351                                           $cur->nickname, $group->nickname));
352             return;
353         }
354
355         // TRANS: Message given having added a user to a group.
356         // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
357         $channel->output($cur, sprintf(_('%1$s joined group %2$s.'),
358                                               $cur->nickname,
359                                               $group->nickname));
360     }
361 }
362
363 class DropCommand extends Command
364 {
365     var $other = null;
366
367     function __construct($user, $other)
368     {
369         parent::__construct($user);
370         $this->other = $other;
371     }
372
373     function handle($channel)
374     {
375         $group = $this->getGroup($this->other);
376         $cur   = $this->user;
377
378         if (!$group) {
379             // TRANS: Error text shown when trying to leave a group that does not exist.
380             $channel->error($cur, _('No such group.'));
381             return;
382         }
383
384         if (!$cur->isMember($group)) {
385             // TRANS: Error text shown when trying to leave an existing group the user is not a member of.
386             $channel->error($cur, _('You are not a member of that group.'));
387             return;
388         }
389
390         try {
391             if (Event::handle('StartLeaveGroup', array($group, $cur))) {
392                 Group_member::leave($group->id, $cur->id);
393                 Event::handle('EndLeaveGroup', array($group, $cur));
394             }
395         } catch (Exception $e) {
396             // TRANS: Message given having failed to remove a user from a group.
397             // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
398             $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s.'),
399                                           $cur->nickname, $group->nickname));
400             return;
401         }
402
403         // TRANS: Message given having removed a user from a group.
404         // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
405         $channel->output($cur, sprintf(_('%1$s left group %2$s.'),
406                                               $cur->nickname,
407                                               $group->nickname));
408     }
409 }
410
411 class WhoisCommand extends Command
412 {
413     var $other = null;
414     function __construct($user, $other)
415     {
416         parent::__construct($user);
417         $this->other = $other;
418     }
419
420     function handle($channel)
421     {
422         $recipient = $this->getProfile($this->other);
423
424         // TRANS: Whois output.
425         // TRANS: %1$s nickname of the queried user, %2$s is their profile URL.
426         $whois = sprintf(_m('WHOIS',"%1\$s (%2\$s)"), $recipient->nickname,
427                          $recipient->profileurl);
428         if ($recipient->fullname) {
429             // TRANS: Whois output. %s is the full name of the queried user.
430             $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname);
431         }
432         if ($recipient->location) {
433             // TRANS: Whois output. %s is the location of the queried user.
434             $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location);
435         }
436         if ($recipient->homepage) {
437             // TRANS: Whois output. %s is the homepage of the queried user.
438             $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage);
439         }
440         if ($recipient->bio) {
441             // TRANS: Whois output. %s is the bio information of the queried user.
442             $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio);
443         }
444         $channel->output($this->user, $whois);
445     }
446 }
447
448 class MessageCommand extends Command
449 {
450     var $other = null;
451     var $text = null;
452     function __construct($user, $other, $text)
453     {
454         parent::__construct($user);
455         $this->other = $other;
456         $this->text = $text;
457     }
458
459     function handle($channel)
460     {
461         try {
462             $other = $this->getUser($this->other);
463         } catch (CommandException $e) {
464             try {
465                 $profile = $this->getProfile($this->other);
466             } catch (CommandException $f) {
467                 throw $e;
468             }
469             // TRANS: Command exception text shown when trying to send a direct message to a remote user (a user not registered at the current server).
470             // TRANS: %s is a remote profile.
471             throw new CommandException(sprintf(_('%s is a remote profile; you can only send direct messages to users on the same server.'), $this->other));
472         }
473
474         $len = mb_strlen($this->text);
475
476         if ($len == 0) {
477             // TRANS: Command exception text shown when trying to send a direct message to another user without content.
478             $channel->error($this->user, _('No content!'));
479             return;
480         }
481
482         $this->text = $this->user->shortenLinks($this->text);
483
484         if (Message::contentTooLong($this->text)) {
485             // XXX: i18n. Needs plural support.
486             // TRANS: Message given if content is too long. %1$sd is used for plural.
487             // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
488             $channel->error($this->user, sprintf(_m('Message too long - maximum is %1$d character, you sent %2$d.',
489                                                     'Message too long - maximum is %1$d characters, you sent %2$d.',
490                                                     Message::maxContent()),
491                                                  Message::maxContent(), mb_strlen($this->text)));
492             return;
493         }
494
495         if (!$other) {
496             // TRANS: Error text shown when trying to send a direct message to a user that does not exist.
497             $channel->error($this->user, _('No such user.'));
498             return;
499         } else if (!$this->user->mutuallySubscribed($other)) {
500             // TRANS: Error text shown when trying to send a direct message to a user without a mutual subscription (each user must be subscribed to the other).
501             $channel->error($this->user, _('You can\'t send a message to this user.'));
502             return;
503         } else if ($this->user->id == $other->id) {
504             // TRANS: Error text shown when trying to send a direct message to self.
505             $channel->error($this->user, _('Don\'t send a message to yourself; just say it to yourself quietly instead.'));
506             return;
507         }
508         $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source());
509         if ($message) {
510             $message->notify();
511             // TRANS: Message given have sent a direct message to another user.
512             // TRANS: %s is the name of the other user.
513             $channel->output($this->user, sprintf(_('Direct message to %s sent.'), $this->other));
514         } else {
515             // TRANS: Error text shown sending a direct message fails with an unknown reason.
516             $channel->error($this->user, _('Error sending direct message.'));
517         }
518     }
519 }
520
521 class RepeatCommand extends Command
522 {
523     var $other = null;
524     function __construct($user, $other)
525     {
526         parent::__construct($user);
527         $this->other = $other;
528     }
529
530     function handle($channel)
531     {
532         $notice = $this->getNotice($this->other);
533
534         if($this->user->id == $notice->profile_id)
535         {
536             // TRANS: Error text shown when trying to repeat an own notice.
537             $channel->error($this->user, _('Cannot repeat your own notice.'));
538             return;
539         }
540
541         if ($this->user->getProfile()->hasRepeated($notice->id)) {
542             // TRANS: Error text shown when trying to repeat an notice that was already repeated by the user.
543             $channel->error($this->user, _('Already repeated that notice.'));
544             return;
545         }
546
547         $repeat = $notice->repeat($this->user->id, $channel->source);
548
549         if ($repeat) {
550
551             // TRANS: Message given having repeated a notice from another user.
552             // TRANS: %s is the name of the user for which the notice was repeated.
553             $channel->output($this->user, sprintf(_('Notice from %s repeated.'), $recipient->nickname));
554         } else {
555             // TRANS: Error text shown when repeating a notice fails with an unknown reason.
556             $channel->error($this->user, _('Error repeating notice.'));
557         }
558     }
559 }
560
561 class ReplyCommand extends Command
562 {
563     var $other = null;
564     var $text = null;
565     function __construct($user, $other, $text)
566     {
567         parent::__construct($user);
568         $this->other = $other;
569         $this->text = $text;
570     }
571
572     function handle($channel)
573     {
574         $notice = $this->getNotice($this->other);
575         $recipient = $notice->getProfile();
576
577         $len = mb_strlen($this->text);
578
579         if ($len == 0) {
580             // TRANS: Command exception text shown when trying to reply to a notice without providing content for the reply.
581             $channel->error($this->user, _('No content!'));
582             return;
583         }
584
585         $this->text = $this->user->shortenLinks($this->text);
586
587         if (Notice::contentTooLong($this->text)) {
588             // XXX: i18n. Needs plural support.
589             // TRANS: Message given if content of a notice for a reply is too long. %1$d is used for plural.
590             // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
591             $channel->error($this->user, sprintf(_m('Notice too long - maximum is %1$d character, you sent %2$d.',
592                                                     'Notice too long - maximum is %1$d characters, you sent %2$d.',
593                                                     Notice::maxContent()),
594                                                  Notice::maxContent(), mb_strlen($this->text)));
595             return;
596         }
597
598         $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
599                                   array('reply_to' => $notice->id));
600
601         if ($notice) {
602             // TRANS: Text shown having sent a reply to a notice successfully.
603             // TRANS: %s is the nickname of the user of the notice the reply was sent to.
604             $channel->output($this->user, sprintf(_('Reply to %s sent.'), $recipient->nickname));
605         } else {
606             // TRANS: Error text shown when a reply to a notice fails with an unknown reason.
607             $channel->error($this->user, _('Error saving notice.'));
608         }
609
610     }
611 }
612
613 class GetCommand extends Command
614 {
615     var $other = null;
616
617     function __construct($user, $other)
618     {
619         parent::__construct($user);
620         $this->other = $other;
621     }
622
623     function handle($channel)
624     {
625         $target = $this->getProfile($this->other);
626
627         $notice = $target->getCurrentNotice();
628         if (!$notice) {
629             // TRANS: Error text shown when a last user notice is requested and it does not exist.
630             $channel->error($this->user, _('User has no last notice.'));
631             return;
632         }
633         $notice_content = $notice->content;
634
635         $channel->output($this->user, $target->nickname . ": " . $notice_content);
636     }
637 }
638
639 class SubCommand extends Command
640 {
641     var $other = null;
642
643     function __construct($user, $other)
644     {
645         parent::__construct($user);
646         $this->other = $other;
647     }
648
649     function handle($channel)
650     {
651
652         if (!$this->other) {
653             // TRANS: Error text shown when no username was provided when issuing a subscribe command.
654             $channel->error($this->user, _('Specify the name of the user to subscribe to.'));
655             return;
656         }
657
658         $target = $this->getProfile($this->other);
659
660         $remote = Remote_profile::staticGet('id', $target->id);
661         if ($remote) {
662             // TRANS: Command exception text shown when trying to subscribe to an OMB profile using the subscribe command.
663             throw new CommandException(_("Can't subscribe to OMB profiles by command."));
664         }
665
666         try {
667             Subscription::start($this->user->getProfile(),
668                                 $target);
669             // TRANS: Text shown after having subscribed to another user successfully.
670             // TRANS: %s is the name of the user the subscription was requested for.
671             $channel->output($this->user, sprintf(_('Subscribed to %s.'), $this->other));
672         } catch (Exception $e) {
673             $channel->error($this->user, $e->getMessage());
674         }
675     }
676 }
677
678 class UnsubCommand extends Command
679 {
680     var $other = null;
681
682     function __construct($user, $other)
683     {
684         parent::__construct($user);
685         $this->other = $other;
686     }
687
688     function handle($channel)
689     {
690         if(!$this->other) {
691             // TRANS: Error text shown when no username was provided when issuing an unsubscribe command.
692             $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
693             return;
694         }
695
696         $target = $this->getProfile($this->other);
697
698         try {
699             Subscription::cancel($this->user->getProfile(),
700                                  $target);
701             // TRANS: Text shown after having unsubscribed from another user successfully.
702             // TRANS: %s is the name of the user the unsubscription was requested for.
703             $channel->output($this->user, sprintf(_('Unsubscribed from %s.'), $this->other));
704         } catch (Exception $e) {
705             $channel->error($this->user, $e->getMessage());
706         }
707     }
708 }
709
710 class OffCommand extends Command
711 {
712     var $other = null;
713
714     function __construct($user, $other=null)
715     {
716         parent::__construct($user);
717         $this->other = $other;
718     }
719     function handle($channel)
720     {
721         if ($other) {
722             // TRANS: Error text shown when issuing the command "off" with a setting which has not yet been implemented.
723             $channel->error($this->user, _("Command not yet implemented."));
724         } else {
725             if ($channel->off($this->user)) {
726                 // TRANS: Text shown when issuing the command "off" successfully.
727                 $channel->output($this->user, _('Notification off.'));
728             } else {
729                 // TRANS: Error text shown when the command "off" fails for an unknown reason.
730                 $channel->error($this->user, _('Can\'t turn off notification.'));
731             }
732         }
733     }
734 }
735
736 class OnCommand extends Command
737 {
738     var $other = null;
739     function __construct($user, $other=null)
740     {
741         parent::__construct($user);
742         $this->other = $other;
743     }
744
745     function handle($channel)
746     {
747         if ($other) {
748             // TRANS: Error text shown when issuing the command "on" with a setting which has not yet been implemented.
749             $channel->error($this->user, _("Command not yet implemented."));
750         } else {
751             if ($channel->on($this->user)) {
752                 // TRANS: Text shown when issuing the command "on" successfully.
753                 $channel->output($this->user, _('Notification on.'));
754             } else {
755                 // TRANS: Error text shown when the command "on" fails for an unknown reason.
756                 $channel->error($this->user, _('Can\'t turn on notification.'));
757             }
758         }
759     }
760 }
761
762 class LoginCommand extends Command
763 {
764     function handle($channel)
765     {
766         $disabled = common_config('logincommand','disabled');
767         $disabled = isset($disabled) && $disabled;
768         if($disabled) {
769             // TRANS: Error text shown when issuing the login command while login is disabled.
770             $channel->error($this->user, _('Login command is disabled.'));
771             return;
772         }
773
774         try {
775             $login_token = Login_token::makeNew($this->user);
776         } catch (Exception $e) {
777             $channel->error($this->user, $e->getMessage());
778         }
779
780         $channel->output($this->user,
781             // TRANS: Text shown after issuing the login command successfully.
782             // TRANS: %s is a logon link..
783             sprintf(_('This link is useable only once and is valid for only 2 minutes: %s.'),
784                     common_local_url('otp',
785                         array('user_id' => $login_token->user_id, 'token' => $login_token->token))));
786     }
787 }
788
789 class LoseCommand extends Command
790 {
791     var $other = null;
792
793     function __construct($user, $other)
794     {
795         parent::__construct($user);
796         $this->other = $other;
797     }
798
799     function execute($channel)
800     {
801         if(!$this->other) {
802             // TRANS: Error text shown when no username was provided when issuing the command.
803             $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
804             return;
805         }
806
807         $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());
808
809         if ($result) {
810             // TRANS: Text shown after issuing the lose command successfully (stop another user from following the current user).
811             // TRANS: %s is the name of the user the unsubscription was requested for.
812             $channel->output($this->user, sprintf(_('Unsubscribed %s.'), $this->other));
813         } else {
814             $channel->error($this->user, $result);
815         }
816     }
817 }
818
819 class SubscriptionsCommand extends Command
820 {
821     function handle($channel)
822     {
823         $profile = $this->user->getSubscriptions(0);
824         $nicknames=array();
825         while ($profile->fetch()) {
826             $nicknames[]=$profile->nickname;
827         }
828         if(count($nicknames)==0){
829             // TRANS: Text shown after requesting other users a user is subscribed to without having any subscriptions.
830             $out=_('You are not subscribed to anyone.');
831         }else{
832             // TRANS: Text shown after requesting other users a user is subscribed to.
833             // TRANS: This message supports plural forms. This message is followed by a
834             // TRANS: hard coded space and a comma separated list of subscribed users.
835             $out = ngettext('You are subscribed to this person:',
836                 'You are subscribed to these people:',
837                 count($nicknames));
838             $out .= ' ';
839             $out .= implode(', ',$nicknames);
840         }
841         $channel->output($this->user,$out);
842     }
843 }
844
845 class SubscribersCommand extends Command
846 {
847     function handle($channel)
848     {
849         $profile = $this->user->getSubscribers();
850         $nicknames=array();
851         while ($profile->fetch()) {
852             $nicknames[]=$profile->nickname;
853         }
854         if(count($nicknames)==0){
855             // TRANS: Text shown after requesting other users that are subscribed to a user
856             // TRANS: (followers) without having any subscribers.
857             $out=_('No one is subscribed to you.');
858         }else{
859             // TRANS: Text shown after requesting other users that are subscribed to a user (followers).
860             // TRANS: This message supports plural forms. This message is followed by a
861             // TRANS: hard coded space and a comma separated list of subscribing users.
862             $out = ngettext('This person is subscribed to you:',
863                 'These people are subscribed to you:',
864                 count($nicknames));
865             $out .= ' ';
866             $out .= implode(', ',$nicknames);
867         }
868         $channel->output($this->user,$out);
869     }
870 }
871
872 class GroupsCommand extends Command
873 {
874     function handle($channel)
875     {
876         $group = $this->user->getGroups();
877         $groups=array();
878         while ($group->fetch()) {
879             $groups[]=$group->nickname;
880         }
881         if(count($groups)==0){
882             // TRANS: Text shown after requesting groups a user is subscribed to without having
883             // TRANS: any group subscriptions.
884             $out=_('You are not a member of any groups.');
885         }else{
886             // TRANS: Text shown after requesting groups a user is subscribed to.
887             // TRANS: This message supports plural forms. This message is followed by a
888             // TRANS: hard coded space and a comma separated list of subscribed groups.
889             $out = ngettext('You are a member of this group:',
890                 'You are a member of these groups:',
891                 count($nicknames));
892             $out.=implode(', ',$groups);
893         }
894         $channel->output($this->user,$out);
895     }
896 }
897
898 class HelpCommand extends Command
899 {
900     function handle($channel)
901     {
902         $channel->output($this->user,
903                          // TRANS: Help text for commands. Do not translate the command names themselves; they are fixed strings.
904                          _("Commands:\n".
905                            "on - turn on notifications\n".
906                            "off - turn off notifications\n".
907                            "help - show this help\n".
908                            "follow <nickname> - subscribe to user\n".
909                            "groups - lists the groups you have joined\n".
910                            "subscriptions - list the people you follow\n".
911                            "subscribers - list the people that follow you\n".
912                            "leave <nickname> - unsubscribe from user\n".
913                            "d <nickname> <text> - direct message to user\n".
914                            "get <nickname> - get last notice from user\n".
915                            "whois <nickname> - get profile info on user\n".
916                            "lose <nickname> - force user to stop following you\n".
917                            "fav <nickname> - add user's last notice as a 'fave'\n".
918                            "fav #<notice_id> - add notice with the given id as a 'fave'\n".
919                            "repeat #<notice_id> - repeat a notice with a given id\n".
920                            "repeat <nickname> - repeat the last notice from user\n".
921                            "reply #<notice_id> - reply to notice with a given id\n".
922                            "reply <nickname> - reply to the last notice from user\n".
923                            "join <group> - join group\n".
924                            "login - Get a link to login to the web interface\n".
925                            "drop <group> - leave group\n".
926                            "stats - get your stats\n".
927                            "stop - same as 'off'\n".
928                            "quit - same as 'off'\n".
929                            "sub <nickname> - same as 'follow'\n".
930                            "unsub <nickname> - same as 'leave'\n".
931                            "last <nickname> - same as 'get'\n".
932                            "on <nickname> - not yet implemented.\n".
933                            "off <nickname> - not yet implemented.\n".
934                            "nudge <nickname> - remind a user to update.\n".
935                            "invite <phone number> - not yet implemented.\n".
936                            "track <word> - not yet implemented.\n".
937                            "untrack <word> - not yet implemented.\n".
938                            "track off - not yet implemented.\n".
939                            "untrack all - not yet implemented.\n".
940                            "tracks - not yet implemented.\n".
941                            "tracking - not yet implemented.\n"));
942     }
943 }