command.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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('GNUSOCIAL')) { 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 ReplyCommand extends Command
  470. {
  471. var $other = null;
  472. var $text = null;
  473. function __construct($user, $other, $text)
  474. {
  475. parent::__construct($user);
  476. $this->other = $other;
  477. $this->text = $text;
  478. }
  479. function handle($channel)
  480. {
  481. $notice = $this->getNotice($this->other);
  482. $recipient = $notice->getProfile();
  483. $len = mb_strlen($this->text);
  484. if ($len == 0) {
  485. // TRANS: Command exception text shown when trying to reply to a notice without providing content for the reply.
  486. $channel->error($this->user, _('No content!'));
  487. return;
  488. }
  489. $this->text = $this->user->shortenLinks($this->text);
  490. if (Notice::contentTooLong($this->text)) {
  491. // XXX: i18n. Needs plural support.
  492. // TRANS: Message given if content of a notice for a reply is too long. %1$d is used for plural.
  493. // TRANS: %1$d is the maximum number of characters, %2$d is the number of submitted characters.
  494. $channel->error($this->user, sprintf(_m('Notice too long - maximum is %1$d character, you sent %2$d.',
  495. 'Notice too long - maximum is %1$d characters, you sent %2$d.',
  496. Notice::maxContent()),
  497. Notice::maxContent(), mb_strlen($this->text)));
  498. return;
  499. }
  500. $notice = Notice::saveNew($this->user->id, $this->text, $channel->source(),
  501. array('reply_to' => $notice->id));
  502. if ($notice) {
  503. // TRANS: Text shown having sent a reply to a notice successfully.
  504. // TRANS: %s is the nickname of the user of the notice the reply was sent to.
  505. $channel->output($this->user, sprintf(_('Reply to %s sent.'), $recipient->nickname));
  506. } else {
  507. // TRANS: Error text shown when a reply to a notice fails with an unknown reason.
  508. $channel->error($this->user, _('Error saving notice.'));
  509. }
  510. }
  511. }
  512. class GetCommand extends Command
  513. {
  514. var $other = null;
  515. function __construct($user, $other)
  516. {
  517. parent::__construct($user);
  518. $this->other = $other;
  519. }
  520. function handle($channel)
  521. {
  522. $target = $this->getProfile($this->other);
  523. $notice = $target->getCurrentNotice();
  524. if (!$notice) {
  525. // TRANS: Error text shown when a last user notice is requested and it does not exist.
  526. $channel->error($this->user, _('User has no last notice.'));
  527. return;
  528. }
  529. $notice_content = $notice->content;
  530. $channel->output($this->user, $target->nickname . ": " . $notice_content);
  531. }
  532. }
  533. class SubCommand extends Command
  534. {
  535. var $other = null;
  536. function __construct($user, $other)
  537. {
  538. parent::__construct($user);
  539. $this->other = $other;
  540. }
  541. function handle($channel)
  542. {
  543. if (!$this->other) {
  544. // TRANS: Error text shown when no username was provided when issuing a subscribe command.
  545. $channel->error($this->user, _('Specify the name of the user to subscribe to.'));
  546. return;
  547. }
  548. $target = $this->getProfile($this->other);
  549. try {
  550. Subscription::start($this->user->getProfile(), $target);
  551. // TRANS: Text shown after having subscribed to another user successfully.
  552. // TRANS: %s is the name of the user the subscription was requested for.
  553. $channel->output($this->user, sprintf(_('Subscribed to %s.'), $this->other));
  554. } catch (Exception $e) {
  555. $channel->error($this->user, $e->getMessage());
  556. }
  557. }
  558. }
  559. class UnsubCommand extends Command
  560. {
  561. var $other = null;
  562. function __construct($user, $other)
  563. {
  564. parent::__construct($user);
  565. $this->other = $other;
  566. }
  567. function handle($channel)
  568. {
  569. if(!$this->other) {
  570. // TRANS: Error text shown when no username was provided when issuing an unsubscribe command.
  571. $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
  572. return;
  573. }
  574. $target = $this->getProfile($this->other);
  575. try {
  576. Subscription::cancel($this->user->getProfile(), $target);
  577. // TRANS: Text shown after having unsubscribed from another user successfully.
  578. // TRANS: %s is the name of the user the unsubscription was requested for.
  579. $channel->output($this->user, sprintf(_('Unsubscribed from %s.'), $this->other));
  580. } catch (Exception $e) {
  581. $channel->error($this->user, $e->getMessage());
  582. }
  583. }
  584. }
  585. class OffCommand extends Command
  586. {
  587. var $other = null;
  588. function __construct($user, $other=null)
  589. {
  590. parent::__construct($user);
  591. $this->other = $other;
  592. }
  593. function handle($channel)
  594. {
  595. if ($this->other) {
  596. // TRANS: Error text shown when issuing the command "off" with a setting which has not yet been implemented.
  597. $channel->error($this->user, _("Command not yet implemented."));
  598. } else {
  599. if ($channel->off($this->user)) {
  600. // TRANS: Text shown when issuing the command "off" successfully.
  601. $channel->output($this->user, _('Notification off.'));
  602. } else {
  603. // TRANS: Error text shown when the command "off" fails for an unknown reason.
  604. $channel->error($this->user, _('Can\'t turn off notification.'));
  605. }
  606. }
  607. }
  608. }
  609. class OnCommand extends Command
  610. {
  611. var $other = null;
  612. function __construct($user, $other=null)
  613. {
  614. parent::__construct($user);
  615. $this->other = $other;
  616. }
  617. function handle($channel)
  618. {
  619. if ($this->other) {
  620. // TRANS: Error text shown when issuing the command "on" with a setting which has not yet been implemented.
  621. $channel->error($this->user, _("Command not yet implemented."));
  622. } else {
  623. if ($channel->on($this->user)) {
  624. // TRANS: Text shown when issuing the command "on" successfully.
  625. $channel->output($this->user, _('Notification on.'));
  626. } else {
  627. // TRANS: Error text shown when the command "on" fails for an unknown reason.
  628. $channel->error($this->user, _('Can\'t turn on notification.'));
  629. }
  630. }
  631. }
  632. }
  633. class LoginCommand extends Command
  634. {
  635. function handle($channel)
  636. {
  637. $disabled = common_config('logincommand','disabled');
  638. $disabled = isset($disabled) && $disabled;
  639. if($disabled) {
  640. // TRANS: Error text shown when issuing the login command while login is disabled.
  641. $channel->error($this->user, _('Login command is disabled.'));
  642. return;
  643. }
  644. try {
  645. $login_token = Login_token::makeNew($this->user);
  646. } catch (Exception $e) {
  647. $channel->error($this->user, $e->getMessage());
  648. }
  649. $channel->output($this->user,
  650. // TRANS: Text shown after issuing the login command successfully.
  651. // TRANS: %s is a logon link..
  652. sprintf(_('This link is useable only once and is valid for only 2 minutes: %s.'),
  653. common_local_url('otp',
  654. array('user_id' => $login_token->user_id, 'token' => $login_token->token))));
  655. }
  656. }
  657. class LoseCommand extends Command
  658. {
  659. var $other = null;
  660. function __construct($user, $other)
  661. {
  662. parent::__construct($user);
  663. $this->other = $other;
  664. }
  665. function execute($channel)
  666. {
  667. if(!$this->other) {
  668. // TRANS: Error text shown when no username was provided when issuing the command.
  669. $channel->error($this->user, _('Specify the name of the user to unsubscribe from.'));
  670. return;
  671. }
  672. $result = Subscription::cancel($this->getProfile($this->other), $this->user->getProfile());
  673. if ($result) {
  674. // TRANS: Text shown after issuing the lose command successfully (stop another user from following the current user).
  675. // TRANS: %s is the name of the user the unsubscription was requested for.
  676. $channel->output($this->user, sprintf(_('Unsubscribed %s.'), $this->other));
  677. } else {
  678. $channel->error($this->user, $result);
  679. }
  680. }
  681. }
  682. class SubscriptionsCommand extends Command
  683. {
  684. function handle($channel)
  685. {
  686. $profile = $this->user->getSubscribed(0);
  687. $nicknames=array();
  688. while ($profile->fetch()) {
  689. $nicknames[]=$profile->nickname;
  690. }
  691. if(count($nicknames)==0){
  692. // TRANS: Text shown after requesting other users a user is subscribed to without having any subscriptions.
  693. $out=_('You are not subscribed to anyone.');
  694. }else{
  695. // TRANS: Text shown after requesting other users a user is subscribed to.
  696. // TRANS: This message supports plural forms. This message is followed by a
  697. // TRANS: hard coded space and a comma separated list of subscribed users.
  698. $out = _m('You are subscribed to this person:',
  699. 'You are subscribed to these people:',
  700. count($nicknames));
  701. $out .= ' ';
  702. $out .= implode(', ',$nicknames);
  703. }
  704. $channel->output($this->user,$out);
  705. }
  706. }
  707. class SubscribersCommand extends Command
  708. {
  709. function handle($channel)
  710. {
  711. $profile = $this->user->getSubscribers();
  712. $nicknames=array();
  713. while ($profile->fetch()) {
  714. $nicknames[]=$profile->nickname;
  715. }
  716. if(count($nicknames)==0){
  717. // TRANS: Text shown after requesting other users that are subscribed to a user
  718. // TRANS: (followers) without having any subscribers.
  719. $out=_('No one is subscribed to you.');
  720. }else{
  721. // TRANS: Text shown after requesting other users that are subscribed to a user (followers).
  722. // TRANS: This message supports plural forms. This message is followed by a
  723. // TRANS: hard coded space and a comma separated list of subscribing users.
  724. $out = _m('This person is subscribed to you:',
  725. 'These people are subscribed to you:',
  726. count($nicknames));
  727. $out .= ' ';
  728. $out .= implode(', ',$nicknames);
  729. }
  730. $channel->output($this->user,$out);
  731. }
  732. }
  733. class GroupsCommand extends Command
  734. {
  735. function handle($channel)
  736. {
  737. $group = $this->user->getGroups();
  738. $groups=array();
  739. while ($group instanceof User_group && $group->fetch()) {
  740. $groups[]=$group->nickname;
  741. }
  742. if(count($groups)==0){
  743. // TRANS: Text shown after requesting groups a user is subscribed to without having
  744. // TRANS: any group subscriptions.
  745. $out=_('You are not a member of any groups.');
  746. }else{
  747. // TRANS: Text shown after requesting groups a user is subscribed to.
  748. // TRANS: This message supports plural forms. This message is followed by a
  749. // TRANS: hard coded space and a comma separated list of subscribed groups.
  750. $out = _m('You are a member of this group:',
  751. 'You are a member of these groups:',
  752. count($nicknames));
  753. $out.=implode(', ',$groups);
  754. }
  755. $channel->output($this->user,$out);
  756. }
  757. }
  758. class HelpCommand extends Command
  759. {
  760. function handle($channel)
  761. {
  762. // TRANS: Header line of help text for commands.
  763. $out = array(_m('COMMANDHELP', "Commands:"));
  764. $commands = array(// TRANS: Help message for IM/SMS command "on".
  765. "on" => _m('COMMANDHELP', "turn on notifications"),
  766. // TRANS: Help message for IM/SMS command "off".
  767. "off" => _m('COMMANDHELP', "turn off notifications"),
  768. // TRANS: Help message for IM/SMS command "help".
  769. "help" => _m('COMMANDHELP', "show this help"),
  770. // TRANS: Help message for IM/SMS command "follow <nickname>".
  771. "follow <nickname>" => _m('COMMANDHELP', "subscribe to user"),
  772. // TRANS: Help message for IM/SMS command "groups".
  773. "groups" => _m('COMMANDHELP', "lists the groups you have joined"),
  774. // TRANS: Help message for IM/SMS command "tag".
  775. "tag <nickname> <tags>" => _m('COMMANDHELP',"tag a user"),
  776. // TRANS: Help message for IM/SMS command "untag".
  777. "untag <nickname> <tags>" => _m('COMMANDHELP',"untag a user"),
  778. // TRANS: Help message for IM/SMS command "subscriptions".
  779. "subscriptions" => _m('COMMANDHELP', "list the people you follow"),
  780. // TRANS: Help message for IM/SMS command "subscribers".
  781. "subscribers" => _m('COMMANDHELP', "list the people that follow you"),
  782. // TRANS: Help message for IM/SMS command "leave <nickname>".
  783. "leave <nickname>" => _m('COMMANDHELP', "unsubscribe from user"),
  784. // TRANS: Help message for IM/SMS command "d <nickname> <text>".
  785. "d <nickname> <text>" => _m('COMMANDHELP', "direct message to user"),
  786. // TRANS: Help message for IM/SMS command "get <nickname>".
  787. "get <nickname>" => _m('COMMANDHELP', "get last notice from user"),
  788. // TRANS: Help message for IM/SMS command "whois <nickname>".
  789. "whois <nickname>" => _m('COMMANDHELP', "get profile info on user"),
  790. // TRANS: Help message for IM/SMS command "lose <nickname>".
  791. "lose <nickname>" => _m('COMMANDHELP', "force user to stop following you"),
  792. // TRANS: Help message for IM/SMS command "reply #<notice_id>".
  793. "reply #<notice_id>" => _m('COMMANDHELP', "reply to notice with a given id"),
  794. // TRANS: Help message for IM/SMS command "reply <nickname>".
  795. "reply <nickname>" => _m('COMMANDHELP', "reply to the last notice from user"),
  796. // TRANS: Help message for IM/SMS command "join <group>".
  797. "join <group>" => _m('COMMANDHELP', "join group"),
  798. // TRANS: Help message for IM/SMS command "login".
  799. "login" => _m('COMMANDHELP', "Get a link to login to the web interface"),
  800. // TRANS: Help message for IM/SMS command "drop <group>".
  801. "drop <group>" => _m('COMMANDHELP', "leave group"),
  802. // TRANS: Help message for IM/SMS command "stats".
  803. "stats" => _m('COMMANDHELP', "get your stats"),
  804. // TRANS: Help message for IM/SMS command "stop".
  805. "stop" => _m('COMMANDHELP', "same as 'off'"),
  806. // TRANS: Help message for IM/SMS command "quit".
  807. "quit" => _m('COMMANDHELP', "same as 'off'"),
  808. // TRANS: Help message for IM/SMS command "sub <nickname>".
  809. "sub <nickname>" => _m('COMMANDHELP', "same as 'follow'"),
  810. // TRANS: Help message for IM/SMS command "unsub <nickname>".
  811. "unsub <nickname>" => _m('COMMANDHELP', "same as 'leave'"),
  812. // TRANS: Help message for IM/SMS command "last <nickname>".
  813. "last <nickname>" => _m('COMMANDHELP', "same as 'get'"),
  814. // TRANS: Help message for IM/SMS command "on <nickname>".
  815. "on <nickname>" => _m('COMMANDHELP', "not yet implemented."),
  816. // TRANS: Help message for IM/SMS command "off <nickname>".
  817. "off <nickname>" => _m('COMMANDHELP', "not yet implemented."),
  818. // TRANS: Help message for IM/SMS command "nudge <nickname>".
  819. "nudge <nickname>" => _m('COMMANDHELP', "remind a user to update."),
  820. // TRANS: Help message for IM/SMS command "invite <phone number>".
  821. "invite <phone number>" => _m('COMMANDHELP', "not yet implemented."),
  822. // TRANS: Help message for IM/SMS command "track <word>".
  823. "track <word>" => _m('COMMANDHELP', "not yet implemented."),
  824. // TRANS: Help message for IM/SMS command "untrack <word>".
  825. "untrack <word>" => _m('COMMANDHELP', "not yet implemented."),
  826. // TRANS: Help message for IM/SMS command "track off".
  827. "track off" => _m('COMMANDHELP', "not yet implemented."),
  828. // TRANS: Help message for IM/SMS command "untrack all".
  829. "untrack all" => _m('COMMANDHELP', "not yet implemented."),
  830. // TRANS: Help message for IM/SMS command "tracks".
  831. "tracks" => _m('COMMANDHELP', "not yet implemented."),
  832. // TRANS: Help message for IM/SMS command "tracking".
  833. "tracking" => _m('COMMANDHELP', "not yet implemented."));
  834. // Give plugins a chance to add or override...
  835. Event::handle('HelpCommandMessages', array($this, &$commands));
  836. ksort($commands);
  837. foreach ($commands as $command => $help) {
  838. $out[] = "$command - $help";
  839. }
  840. $channel->output($this->user, implode("\n", $out));
  841. }
  842. }