command.php 35.5 KB
Newer Older
1 2
<?php
/*
3
 * StatusNet - the distributed open-source microblogging tool
4
 * Copyright (C) 2008, 2009, 2010 StatusNet, Inc.
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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/>.
 */

mmn's avatar
mmn committed
20
if (!defined('GNUSOCIAL')) { exit(1); }
21

Evan Prodromou's avatar
Evan Prodromou committed
22
require_once(INSTALLDIR.'/lib/channel.php');
23

24 25
class Command
{
26
    protected $scoped = null;   // The Profile of the user performing the command
Evan Prodromou's avatar
Evan Prodromou committed
27
    var $user = null;
Evan Prodromou's avatar
Evan Prodromou committed
28

29 30
    function __construct($user=null)
    {
31
        $this->scoped = $user->getProfile();
32 33
        $this->user = $user;
    }
Evan Prodromou's avatar
Evan Prodromou committed
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
    /**
     * 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)
63
    {
64 65
        return false;
    }
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80

    /**
     * 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

81
                $notice = Notice::getKV(substr($arg,1));
82
                if (!$notice) {
83 84
                    // TRANS: Command exception text shown when a notice ID is requested that does not exist.
                    throw new CommandException(_('Notice with that id does not exist.'));
85 86
                }
            }
87

88 89
            if (Validate::uri($this->other)) {
                // A specific notice by URI lookup
90
                $notice = Notice::getKV('uri', $arg);
91
            }
92

93 94 95 96 97 98 99
            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) {
100 101
                    // TRANS: Command exception text shown when a last user notice is requested and it does not exist.
                    throw new CommandException(_('User has no last notice.'));
102 103 104 105 106
                }
            }
        }
        Event::handle('EndCommandGetNotice', array($this, $arg, &$notice));
        if (!$notice) {
107 108
            // TRANS: Command exception text shown when a notice ID is requested that does not exist.
            throw new CommandException(_('Notice with that id does not exist.'));
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
        }
        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) {
128 129
            // TRANS: Message given requesting a profile for a non-existing user.
            // 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 133 134 135 136 137 138 139 140 141 142 143
        }
        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))) {
144
            $user = User::getKV('nickname', Nickname::normalize($arg));
145 146 147
        }
        Event::handle('EndCommandGetUser', array($this, $arg, &$user));
        if (!$user){
148 149
            // TRANS: Message given getting a non-existing user.
            // 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 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
                               $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) {
169
            // TRANS: Command exception text shown when a group is requested that does not exist.
170 171 172 173 174 175 176 177
            throw new CommandException(_('No such group.'));
        }
        return $group;
    }
}

class CommandException extends Exception
{
178 179
}

180 181
class UnimplementedCommand extends Command
{
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 190
class TrackingCommand extends UnimplementedCommand
{
191 192
}

193 194
class TrackOffCommand extends UnimplementedCommand
{
195 196
}

197 198
class TrackCommand extends UnimplementedCommand
{
Evan Prodromou's avatar
Evan Prodromou committed
199
    var $word = null;
200 201
    function __construct($user, $word)
    {
202 203 204
        parent::__construct($user);
        $this->word = $word;
    }
205 206
}

207 208
class UntrackCommand extends UnimplementedCommand
{
Evan Prodromou's avatar
Evan Prodromou committed
209
    var $word = null;
210 211
    function __construct($user, $word)
    {
212 213 214
        parent::__construct($user);
        $this->word = $word;
    }
215 216
}

217
class NudgeCommand extends Command
218
{
Evan Prodromou's avatar
Evan Prodromou committed
219
    var $other = null;
220 221
    function __construct($user, $other)
    {
222 223 224
        parent::__construct($user);
        $this->other = $other;
    }
225 226

    function handle($channel)
227
    {
228 229
        $recipient = $this->getUser($this->other);
        if ($recipient->id == $this->user->id) {
230
            // TRANS: Command exception text shown when a user tries to nudge themselves.
231 232 233 234
            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);
235
            }
236 237
            // XXX: notify by IM
            // XXX: notify by SMS
238 239
            // TRANS: Message given having nudged another user.
            // 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 247
class InviteCommand extends UnimplementedCommand
{
Evan Prodromou's avatar
Evan Prodromou committed
248
    var $other = null;
249 250
    function __construct($user, $other)
    {
251 252 253
        parent::__construct($user);
        $this->other = $other;
    }
254 255
}

256 257
class StatsCommand extends Command
{
258
    function handle($channel)
259
    {
260
        $profile = $this->user->getProfile();
261

262 263 264
        $subs_count   = $profile->subscriptionCount();
        $subbed_count = $profile->subscriberCount();
        $notice_count = $profile->noticeCount();
Evan Prodromou's avatar
Evan Prodromou committed
265

266 267 268 269
        // TRANS: User statistics text.
        // TRANS: %1$s is the number of other user the user is subscribed to.
        // TRANS: %2$s is the number of users that are subscribed to the user.
        // TRANS: %3$s is the number of notices the user has sent.
270 271 272 273 274 275 276
        $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n".
                                   "Subscribers: %2\$s\n".
                                   "Notices: %3\$s"),
                                 $subs_count,
                                 $subbed_count,
                                 $notice_count));
    }
277 278
}

279 280 281 282 283 284 285 286 287 288
class JoinCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

289
    function handle($channel)
290
    {
291 292
        $group = $this->getGroup($this->other);
        $cur   = $this->user;
293 294

        if ($cur->isMember($group)) {
295 296
            // TRANS: Error text shown a user tries to join a group they already are a member of.
            $channel->error($cur, _('You are already a member of that group.'));
297 298 299
            return;
        }
        if (Group_block::isBlocked($group, $cur->getProfile())) {
300
            // TRANS: Error text shown when a user tries to join a group they are blocked from joining.
301 302 303 304
          $channel->error($cur, _('You have been blocked from that group by the admin.'));
            return;
        }

305
        try {
306
            $cur->joinGroup($group);
307
        } catch (Exception $e) {
308 309
            // TRANS: Message given having failed to add a user to a group.
            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
310
            $channel->error($cur, sprintf(_('Could not join user %1$s to group %2$s.'),
311 312
                                          $cur->nickname, $group->nickname));
            return;
313 314
        }

315 316
        // TRANS: Message given having added a user to a group.
        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
317
        $channel->output($cur, sprintf(_('%1$s joined group %2$s.'),
318 319 320 321
                                              $cur->nickname,
                                              $group->nickname));
    }
}
322

323 324 325 326 327 328 329 330 331 332
class DropCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

333
    function handle($channel)
334
    {
335 336
        $group = $this->getGroup($this->other);
        $cur   = $this->user;
337 338

        if (!$group) {
339
            // TRANS: Error text shown when trying to leave a group that does not exist.
340 341 342 343 344
            $channel->error($cur, _('No such group.'));
            return;
        }

        if (!$cur->isMember($group)) {
345
            // TRANS: Error text shown when trying to leave an existing group the user is not a member of.
346 347 348 349
            $channel->error($cur, _('You are not a member of that group.'));
            return;
        }

350
        try {
351
            $cur->leaveGroup($group);
352
        } catch (Exception $e) {
353 354
            // TRANS: Message given having failed to remove a user from a group.
            // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
355
            $channel->error($cur, sprintf(_('Could not remove user %1$s from group %2$s.'),
356 357
                                          $cur->nickname, $group->nickname));
            return;
358 359
        }

360 361
        // TRANS: Message given having removed a user from a group.
        // TRANS: %1$s is the nickname of the user, %2$s is the nickname of the group.
362
        $channel->output($cur, sprintf(_('%1$s left group %2$s.'),
363 364 365
                                              $cur->nickname,
                                              $group->nickname));
    }
366 367
}

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
class TagCommand extends Command
{
    var $other = null;
    var $tags = null;
    function __construct($user, $other, $tags)
    {
        parent::__construct($user);
        $this->other = $other;
        $this->tags = $tags;
    }

    function handle($channel)
    {
        $profile = $this->getProfile($this->other);
        $cur     = $this->user->getProfile();

        if (!$profile) {
385
            // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
386 387 388 389
            $channel->error($cur, _('No such profile.'));
            return;
        }
        if (!$cur->canTag($profile)) {
390
            // TRANS: Error displayed when trying to tag a user that cannot be tagged.
391 392 393 394 395 396 397 398 399 400 401 402 403
            $channel->error($cur, _('You cannot tag this user.'));
            return;
        }

        $privs = array();
        $tags = preg_split('/[\s,]+/', $this->tags);
        $clean_tags = array();

        foreach ($tags as $tag) {
            $private = @$tag[0] === '.';
            $tag = $clean_tags[] = common_canonical_tag($tag);

            if (!common_valid_profile_tag($tag)) {
404 405 406
                // TRANS: Error displayed if a given tag is invalid.
                // TRANS: %s is the invalid tag.
                $channel->error($cur, sprintf(_('Invalid tag: "%s".'), $tag));
407 408 409 410 411 412 413 414 415 416
                return;
            }
            $privs[$tag] = $private;
        }

        try {
            foreach ($clean_tags as $tag) {
                Profile_tag::setTag($cur->id, $profile->id, $tag, null, $privs[$tag]);
            }
        } catch (Exception $e) {
417 418 419
            // TRANS: Error displayed if tagging a user fails.
            // TRANS: %1$s is the tagged user, %2$s is the error message (no punctuation).
            $channel->error($cur, sprintf(_('Error tagging %1$s: %2$s'),
420 421 422 423
                                          $profile->nickname, $e->getMessage()));
            return;
        }

424 425
        // TRANS: Succes message displayed if tagging a user succeeds.
        // TRANS: %1$s is the tagged user's nickname, %2$s is a list of tags.
426 427 428 429 430 431 432
        // TRANS: Plural is decided based on the number of tags added (not part of message).
        $channel->output($cur, sprintf(_m('%1$s was tagged %2$s',
                                          '%1$s was tagged %2$s',
                                          count($clean_tags)),
                                       $profile->nickname,
                                       // TRANS: Separator for list of tags.
                                       implode(_(', '), $clean_tags)));
433 434 435 436 437 438 439 440 441 442 443
    }
}

class UntagCommand extends TagCommand
{
    function handle($channel)
    {
        $profile = $this->getProfile($this->other);
        $cur     = $this->user->getProfile();

        if (!$profile) {
444
            // TRANS: Client error displayed trying to perform an action related to a non-existing profile.
445 446 447 448
            $channel->error($cur, _('No such profile.'));
            return;
        }
        if (!$cur->canTag($profile)) {
449
            // TRANS: Error displayed when trying to tag a user that cannot be tagged.
450 451 452 453 454 455 456 457
            $channel->error($cur, _('You cannot tag this user.'));
            return;
        }

        $tags = array_map('common_canonical_tag', preg_split('/[\s,]+/', $this->tags));

        foreach ($tags as $tag) {
            if (!common_valid_profile_tag($tag)) {
458 459
                // TRANS: Error displayed if a given tag is invalid.
                // TRANS: %s is the invalid tag.
460 461 462 463 464 465 466 467 468 469
                $channel->error($cur, sprintf(_('Invalid tag: "%s"'), $tag));
                return;
            }
        }

        try {
            foreach ($tags as $tag) {
                Profile_tag::unTag($cur->id, $profile->id, $tag);
            }
        } catch (Exception $e) {
470 471 472
            // TRANS: Error displayed if untagging a user fails.
            // TRANS: %1$s is the untagged user, %2$s is the error message (no punctuation).
            $channel->error($cur, sprintf(_('Error untagging %1$s: %2$s'),
473 474 475 476
                                          $profile->nickname, $e->getMessage()));
            return;
        }

477 478
        // TRANS: Succes message displayed if untagging a user succeeds.
        // TRANS: %1$s is the untagged user's nickname, %2$s is a list of tags.
479 480 481 482 483 484 485
        // TRANS: Plural is decided based on the number of tags removed (not part of message).
        $channel->output($cur, sprintf(_m('The following tag was removed from user %1$s: %2$s.',
                                         'The following tags were removed from user %1$s: %2$s.',
                                         count($tags)),
                                       $profile->nickname,
                                       // TRANS: Separator for list of tags.
                                       implode(_(', '), $tags)));
486 487 488
    }
}

489 490
class WhoisCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
491
    var $other = null;
492 493
    function __construct($user, $other)
    {
494 495 496
        parent::__construct($user);
        $this->other = $other;
    }
Evan Prodromou's avatar
Evan Prodromou committed
497

498
    function handle($channel)
499
    {
500
        $recipient = $this->getProfile($this->other);
Evan Prodromou's avatar
Evan Prodromou committed
501

502 503
        // TRANS: Whois output.
        // TRANS: %1$s nickname of the queried user, %2$s is their profile URL.
504
        $whois = sprintf(_m('WHOIS',"%1\$s (%2\$s)"), $recipient->nickname,
505 506
                         $recipient->profileurl);
        if ($recipient->fullname) {
507
            // TRANS: Whois output. %s is the full name of the queried user.
508 509 510
            $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname);
        }
        if ($recipient->location) {
511
            // TRANS: Whois output. %s is the location of the queried user.
512 513 514
            $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location);
        }
        if ($recipient->homepage) {
515
            // TRANS: Whois output. %s is the homepage of the queried user.
516 517 518
            $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage);
        }
        if ($recipient->bio) {
519
            // TRANS: Whois output. %s is the bio information of the queried user.
520 521 522 523
            $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio);
        }
        $channel->output($this->user, $whois);
    }
524 525
}

526 527 528 529 530 531 532 533 534 535 536
class ReplyCommand extends Command
{
    var $other = null;
    var $text = null;
    function __construct($user, $other, $text)
    {
        parent::__construct($user);
        $this->other = $other;
        $this->text = $text;
    }

537
    function handle($channel)
538
    {
539 540
        $notice = $this->getNotice($this->other);
        $recipient = $notice->getProfile();
541 542 543 544

        $len = mb_strlen($this->text);

        if ($len == 0) {
545
            // TRANS: Command exception text shown when trying to reply to a notice without providing content for the reply.
546 547 548 549
            $channel->error($this->user, _('No content!'));
            return;
        }

550
        $this->text = $this->user->shortenLinks($this->text);
551 552

        if (Notice::contentTooLong($this->text)) {
553
            // XXX: i18n. Needs plural support.
554
            // TRANS: Message given if content of a notice for a reply is too long. %1$d is used for plural.
555
            // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
556 557 558
            $channel->error($this->user, sprintf(_m('Notice too long - maximum is %1$d character, you sent %2$d.',
                                                    'Notice too long - maximum is %1$d characters, you sent %2$d.',
                                                    Notice::maxContent()),
559 560 561 562
                                                 Notice::maxContent(), mb_strlen($this->text)));
            return;
        }

563 564 565
        $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
                                  array('reply_to' => $notice->id));

566
        if ($notice) {
567 568 569
            // TRANS: Text shown having sent a reply to a notice successfully.
            // TRANS: %s is the nickname of the user of the notice the reply was sent to.
            $channel->output($this->user, sprintf(_('Reply to %s sent.'), $recipient->nickname));
570
        } else {
571
            // TRANS: Error text shown when a reply to a notice fails with an unknown reason.
572 573
            $channel->error($this->user, _('Error saving notice.'));
        }
574

575 576 577
    }
}

578 579
class GetCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
580
    var $other = null;
Evan Prodromou's avatar
Evan Prodromou committed
581

582 583
    function __construct($user, $other)
    {
584 585 586
        parent::__construct($user);
        $this->other = $other;
    }
Evan Prodromou's avatar
Evan Prodromou committed
587

588
    function handle($channel)
589
    {
590
        $target = $this->getProfile($this->other);
591

592 593
        $notice = $target->getCurrentNotice();
        if (!$notice) {
594 595
            // TRANS: Error text shown when a last user notice is requested and it does not exist.
            $channel->error($this->user, _('User has no last notice.'));
596 597 598
            return;
        }
        $notice_content = $notice->content;
Evan Prodromou's avatar
Evan Prodromou committed
599

600
        $channel->output($this->user, $target->nickname . ": " . $notice_content);
601
    }
602 603
}

604 605
class SubCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
606
    var $other = null;
Evan Prodromou's avatar
Evan Prodromou committed
607

608 609
    function __construct($user, $other)
    {
610 611 612
        parent::__construct($user);
        $this->other = $other;
    }
Evan Prodromou's avatar
Evan Prodromou committed
613

614
    function handle($channel)
615
    {
Evan Prodromou's avatar
Evan Prodromou committed
616

617
        if (!$this->other) {
618 619
            // TRANS: Error text shown when no username was provided when issuing a subscribe command.
            $channel->error($this->user, _('Specify the name of the user to subscribe to.'));
620 621
            return;
        }
Evan Prodromou's avatar
Evan Prodromou committed
622

623
        $target = $this->getProfile($this->other);
Evan Prodromou's avatar
Evan Prodromou committed
624

625
        try {
626
            Subscription::start($this->user->getProfile(), $target);
627 628 629
            // TRANS: Text shown after having subscribed to another user successfully.
            // TRANS: %s is the name of the user the subscription was requested for.
            $channel->output($this->user, sprintf(_('Subscribed to %s.'), $this->other));
630 631
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
632 633
        }
    }
634 635
}

636 637
class UnsubCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
638
    var $other = null;
Evan Prodromou's avatar
Evan Prodromou committed
639

640 641
    function __construct($user, $other)
    {
642 643 644
        parent::__construct($user);
        $this->other = $other;
    }
645

646
    function handle($channel)
647
    {
648
        if(!$this->other) {
649 650
            // TRANS: Error text shown when no username was provided when issuing an unsubscribe command.
            $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
651 652
            return;
        }
Evan Prodromou's avatar
Evan Prodromou committed
653

654
        $target = $this->getProfile($this->other);
655 656

        try {
657
            Subscription::cancel($this->user->getProfile(), $target);
658 659 660
            // TRANS: Text shown after having unsubscribed from another user successfully.
            // TRANS: %s is the name of the user the unsubscription was requested for.
            $channel->output($this->user, sprintf(_('Unsubscribed from %s.'), $this->other));
661 662
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
663 664
        }
    }
665 666
}

667 668
class OffCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
669
    var $other = null;
670

671 672
    function __construct($user, $other=null)
    {
673 674 675
        parent::__construct($user);
        $this->other = $other;
    }
676
    function handle($channel)
677
    {
678
        if ($this->other) {
679
            // TRANS: Error text shown when issuing the command "off" with a setting which has not yet been implemented.
680 681 682
            $channel->error($this->user, _("Command not yet implemented."));
        } else {
            if ($channel->off($this->user)) {
683
                // TRANS: Text shown when issuing the command "off" successfully.
684 685
                $channel->output($this->user, _('Notification off.'));
            } else {
686
                // TRANS: Error text shown when the command "off" fails for an unknown reason.
687 688 689 690
                $channel->error($this->user, _('Can\'t turn off notification.'));
            }
        }
    }
691 692
}

693 694
class OnCommand extends Command
{
Evan Prodromou's avatar
Evan Prodromou committed
695
    var $other = null;
696 697
    function __construct($user, $other=null)
    {
698 699 700
        parent::__construct($user);
        $this->other = $other;
    }
Evan Prodromou's avatar
Evan Prodromou committed
701

702
    function handle($channel)
703
    {
704
        if ($this->other) {
705
            // TRANS: Error text shown when issuing the command "on" with a setting which has not yet been implemented.
706 707 708
            $channel->error($this->user, _("Command not yet implemented."));
        } else {
            if ($channel->on($this->user)) {
709
                // TRANS: Text shown when issuing the command "on" successfully.
710 711
                $channel->output($this->user, _('Notification on.'));
            } else {
712
                // TRANS: Error text shown when the command "on" fails for an unknown reason.
713 714 715 716
                $channel->error($this->user, _('Can\'t turn on notification.'));
            }
        }
    }
717 718
}

719 720
class LoginCommand extends Command
{
721
    function handle($channel)
722
    {
723
        $disabled = common_config('logincommand','disabled');
724 725
        $disabled = isset($disabled) && $disabled;
        if($disabled) {
726 727
            // TRANS: Error text shown when issuing the login command while login is disabled.
            $channel->error($this->user, _('Login command is disabled.'));
728 729
            return;
        }
730 731 732 733 734

        try {
            $login_token = Login_token::makeNew($this->user);
        } catch (Exception $e) {
            $channel->error($this->user, $e->getMessage());
735
        }
736

737
        $channel->output($this->user,
738 739 740
            // TRANS: Text shown after issuing the login command successfully.
            // TRANS: %s is a logon link..
            sprintf(_('This link is useable only once and is valid for only 2 minutes: %s.'),
741 742
                    common_local_url('otp',
                        array('user_id' => $login_token->user_id, 'token' => $login_token->token))));
743 744 745
    }
}

746 747 748 749 750 751 752 753 754 755 756 757 758
class LoseCommand extends Command
{
    var $other = null;

    function __construct($user, $other)
    {
        parent::__construct($user);
        $this->other = $other;
    }

    function execute($channel)
    {
        if(!$this->other) {
759 760
            // TRANS: Error text shown when no username was provided when issuing the command.
            $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
761 762 763
            return;
        }

764
        $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());
765 766

        if ($result) {
767 768 769
            // TRANS: Text shown after issuing the lose command successfully (stop another user from following the current user).
            // TRANS: %s is the name of the user the unsubscription was requested for.
            $channel->output($this->user, sprintf(_('Unsubscribed %s.'), $this->other));
770 771 772 773 774 775
        } else {
            $channel->error($this->user, $result);
        }
    }
}

776
class SubscriptionsCommand extends Command
777
{
778
    function handle($channel)
779
    {
780
        $profile = $this->user->getSubscribed(0);
781 782 783 784 785
        $nicknames=array();
        while ($profile->fetch()) {
            $nicknames[]=$profile->nickname;
        }
        if(count($nicknames)==0){
786
            // TRANS: Text shown after requesting other users a user is subscribed to without having any subscriptions.
787 788
            $out=_('You are not subscribed to anyone.');
        }else{
789
            // TRANS: Text shown after requesting other users a user is subscribed to.
790
            // TRANS: This message supports plural forms. This message is followed by a
791
            // TRANS: hard coded space and a comma separated list of subscribed users.
792
            $out = _m('You are subscribed to this person:',
793 794 795 796
                'You are subscribed to these people:',
                count($nicknames));
            $out .= ' ';
            $out .= implode(', ',$nicknames);
797 798 799 800 801
        }
        $channel->output($this->user,$out);
    }
}

802
class SubscribersCommand extends Command
803
{
804
    function handle($channel)
805 806 807 808 809 810 811
    {
        $profile = $this->user->getSubscribers();
        $nicknames=array();
        while ($profile->fetch()) {
            $nicknames[]=$profile->nickname;
        }
        if(count($nicknames)==0){
812 813
            // TRANS: Text shown after requesting other users that are subscribed to a user
            // TRANS: (followers) without having any subscribers.
814 815
            $out=_('No one is subscribed to you.');
        }else{
816
            // TRANS: Text shown after requesting other users that are subscribed to a user (followers).
817
            // TRANS: This message supports plural forms. This message is followed by a
818
            // TRANS: hard coded space and a comma separated list of subscribing users.
819
            $out = _m('This person is subscribed to you:',
820 821 822 823
                'These people are subscribed to you:',
                count($nicknames));
            $out .= ' ';
            $out .= implode(', ',$nicknames);
824 825 826 827 828
        }
        $channel->output($this->user,$out);
    }
}

Craig Andrews's avatar
Craig Andrews committed
829 830
class GroupsCommand extends Command
{
831
    function handle($channel)
Craig Andrews's avatar
Craig Andrews committed
832 833 834
    {
        $group = $this->user->getGroups();
        $groups=array();
835
        while ($group instanceof User_group && $group->fetch()) {
Craig Andrews's avatar
Craig Andrews committed
836 837 838
            $groups[]=$group->nickname;
        }
        if(count($groups)==0){
839 840
            // TRANS: Text shown after requesting groups a user is subscribed to without having
            // TRANS: any group subscriptions.
Craig Andrews's avatar
Craig Andrews committed
841 842
            $out=_('You are not a member of any groups.');
        }else{
843
            // TRANS: Text shown after requesting groups a user is subscribed to.
844
            // TRANS: This message supports plural forms. This message is followed by a
845
            // TRANS: hard coded space and a comma separated list of subscribed groups.
846
            $out = _m('You are a member of this group:',
847 848
                'You are a member of these groups:',
                count($nicknames));
Craig Andrews's avatar
Craig Andrews committed
849 850 851 852 853 854
            $out.=implode(', ',$groups);
        }
        $channel->output($this->user,$out);
    }
}

855 856
class HelpCommand extends Command
{
857
    function handle($channel)
858
    {
859 860
        // TRANS: Header line of help text for commands.
        $out = array(_m('COMMANDHELP', "Commands:"));
861
        $commands = array(// TRANS: Help message for IM/SMS command "on".
862
                          "on" => _m('COMMANDHELP', "turn on notifications"),
863
                          // TRANS: Help message for IM/SMS command "off".
864
                          "off" => _m('COMMANDHELP', "turn off notifications"),
865
                          // TRANS: Help message for IM/SMS command "help".
866
                          "help" => _m('COMMANDHELP', "show this help"),
867
                          // TRANS: Help message for IM/SMS command "follow <nickname>".
868
                          "follow <nickname>" => _m('COMMANDHELP', "subscribe to user"),
869
                          // TRANS: Help message for IM/SMS command "groups".
870
                          "groups" => _m('COMMANDHELP', "lists the groups you have joined"),
871
                          // TRANS: Help message for IM/SMS command "tag".
872
                          "tag <nickname> <tags>" => _m('COMMANDHELP',"tag a user"),
873
                          // TRANS: Help message for IM/SMS command "untag".
874
                          "untag <nickname> <tags>" => _m('COMMANDHELP',"untag a user"),
875
                          // TRANS: Help message for IM/SMS command "subscriptions".
876
                          "subscriptions" => _m('COMMANDHELP', "list the people you follow"),
877
                          // TRANS: Help message for IM/SMS command "subscribers".
878
                          "subscribers" => _m('COMMANDHELP', "list the people that follow you"),
879
                          // TRANS: Help message for IM/SMS command "leave <nickname>".
880
                          "leave <nickname>" => _m('COMMANDHELP', "unsubscribe from user"),
881
                          // TRANS: Help message for IM/SMS command "d <nickname> <text>".
882
                          "d <nickname> <text>" => _m('COMMANDHELP', "direct message to user"),
883
                          // TRANS: Help message for IM/SMS command "get <nickname>".
884
                          "get <nickname>" => _m('COMMANDHELP', "get last notice from user"),
885
                          // TRANS: Help message for IM/SMS command "whois <nickname>".
886
                          "whois <nickname>" => _m('COMMANDHELP', "get profile info on user"),
887
                          // TRANS: Help message for IM/SMS command "lose <nickname>".
888
                          "lose <nickname>" => _m('COMMANDHELP', "force user to stop following you"),
889
                          // TRANS: Help message for IM/SMS command "reply #<notice_id>".
890
                          "reply #<notice_id>" => _m('COMMANDHELP', "reply to notice with a given id"),
891
                          // TRANS: Help message for IM/SMS command "reply <nickname>".
892
                          "reply <nickname>" => _m('COMMANDHELP', "reply to the last notice from user"),
893
                          // TRANS: Help message for IM/SMS command "join <group>".
894
                          "join <group>" => _m('COMMANDHELP', "join group"),
895
                          // TRANS: Help message for IM/SMS command "login".
896
                          "login" => _m('COMMANDHELP', "Get a link to login to the web interface"),
897
                          // TRANS: Help message for IM/SMS command "drop <group>".
898
                          "drop <group>" => _m('COMMANDHELP', "leave group"),
899
                          // TRANS: Help message for IM/SMS command "stats".
900
                          "stats" => _m('COMMANDHELP', "get your stats"),
901
                          // TRANS: Help message for IM/SMS command "stop".
902
                          "stop" => _m('COMMANDHELP', "same as 'off'"),
903
                          // TRANS: Help message for IM/SMS command "quit".
904
                          "quit" => _m('COMMANDHELP', "same as 'off'"),
905
                          // TRANS: Help message for IM/SMS command "sub <nickname>".
906
                          "sub <nickname>" => _m('COMMANDHELP', "same as 'follow'"),
907
                          // TRANS: Help message for IM/SMS command "unsub <nickname>".
908
                          "unsub <nickname>" => _m('COMMANDHELP', "same as 'leave'"),
909
                          // TRANS: Help message for IM/SMS command "last <nickname>".
910
                          "last <nickname>" => _m('COMMANDHELP', "same as 'get'"),
911
                          // TRANS: Help message for IM/SMS command "on <nickname>".
912
                          "on <nickname>" => _m('COMMANDHELP', "not yet implemented."),
913
                          // TRANS: Help message for IM/SMS command "off <nickname>".
914
                          "off <nickname>" => _m('COMMANDHELP', "not yet implemented."),
915
                          // TRANS: Help message for IM/SMS command "nudge <nickname>".
916
                          "nudge <nickname>" => _m('COMMANDHELP', "remind a user to update."),
917
                          // TRANS: Help message for IM/SMS command "invite <phone number>".
918
                          "invite <phone number>" => _m('COMMANDHELP', "not yet implemented."),
919
                          // TRANS: Help message for IM/SMS command "track <word>".
920
                          "track <word>" => _m('COMMANDHELP', "not yet implemented."),
921
                          // TRANS: Help message for IM/SMS command "untrack <word>".
922
                          "untrack <word>" => _m('COMMANDHELP', "not yet implemented."),
923
                          // TRANS: Help message for IM/SMS command "track off".
924
                          "track off" => _m('COMMANDHELP', "not yet implemented."),
925
                          // TRANS: Help message for IM/SMS command "untrack all".
926
                          "untrack all" => _m('COMMANDHELP', "not yet implemented."),
927
                          // TRANS: Help message for IM/SMS command "tracks".
928
                          "tracks" => _m('COMMANDHELP', "not yet implemented."),
929
                          // TRANS: Help message for IM/SMS command "tracking".
930 931 932 933
                          "tracking" => _m('COMMANDHELP', "not yet implemented."));

        // Give plugins a chance to add or override...
        Event::handle('HelpCommandMessages', array($this, &$commands));
934

935
        ksort($commands);
936 937 938 939
        foreach ($commands as $command => $help) {
            $out[] = "$command - $help";
        }
        $channel->output($this->user, implode("\n", $out));
940
    }
941
}