command.php 37 KB

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