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