PageRenderTime 88ms CodeModel.GetById 17ms RepoModel.GetById 2ms app.codeStats 0ms

/Phergie/Plugin/UserInfo.php

https://github.com/markizano/phergie
PHP | 435 lines | 231 code | 47 blank | 157 comment | 43 complexity | d92f28c6d3909a5ccefc7afd736f4e14 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Phergie
  4. *
  5. * PHP version 5
  6. *
  7. * LICENSE
  8. *
  9. * This source file is subject to the new BSD license that is bundled
  10. * with this package in the file LICENSE.
  11. * It is also available through the world-wide-web at this URL:
  12. * http://phergie.org/license
  13. *
  14. * @category Phergie
  15. * @package Phergie_Plugin_UserInfo
  16. * @author Phergie Development Team <team@phergie.org>
  17. * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
  18. * @license http://phergie.org/license New BSD License
  19. * @link http://pear.phergie.org/package/Phergie_Plugin_UserInfo
  20. */
  21. /**
  22. * Provides an API for querying information on users.
  23. *
  24. * @category Phergie
  25. * @package Phergie_Plugin_UserInfo
  26. * @author Phergie Development Team <team@phergie.org>
  27. * @license http://phergie.org/license New BSD License
  28. * @link http://pear.phergie.org/package/Phergie_Plugin_UserInfo
  29. */
  30. class Phergie_Plugin_UserInfo extends Phergie_Plugin_Abstract
  31. {
  32. const REGULAR = 1;
  33. const VOICE = 2;
  34. const HALFOP = 4;
  35. const OP = 8;
  36. const ADMIN = 16;
  37. const OWNER = 32;
  38. /**
  39. * An array containing all the user information for a given channel
  40. *
  41. * @var array
  42. */
  43. protected $store = array();
  44. /**
  45. * Tracks mode changes
  46. *
  47. * @return void
  48. */
  49. public function onMode()
  50. {
  51. $args = $this->event->getArguments();
  52. if (count($args) != 3) {
  53. return;
  54. }
  55. list($chan, $modes, $nicks) = $args;
  56. if (!preg_match('/(?:\+|-)[hovaq+-]+/i', $modes)) {
  57. return;
  58. }
  59. $chan = trim(strtolower($chan));
  60. $modes = str_split(trim(strtolower($modes)), 1);
  61. $nicks = explode(' ', trim(strtolower($nicks)));
  62. $operation = array_shift($modes); // + or -
  63. while ($char = array_shift($modes)) {
  64. $nick = array_shift($nicks);
  65. $mode = null;
  66. switch ($char) {
  67. case 'q':
  68. $mode = self::OWNER;
  69. break;
  70. case 'a':
  71. $mode = self::ADMIN;
  72. break;
  73. case 'o':
  74. $mode = self::OP;
  75. break;
  76. case 'h':
  77. $mode = self::HALFOP;
  78. break;
  79. case 'v':
  80. $mode = self::VOICE;
  81. break;
  82. }
  83. if (!empty($mode)) {
  84. if ($operation == '+') {
  85. $this->store[$chan][$nick] |= $mode;
  86. } else if ($operation == '-') {
  87. $this->store[$chan][$nick] ^= $mode;
  88. }
  89. }
  90. }
  91. }
  92. /**
  93. * Tracks users joining a channel
  94. *
  95. * @return void
  96. */
  97. public function onJoin()
  98. {
  99. $chan = trim(strtolower($this->event->getArgument(0)));
  100. $nick = trim(strtolower($this->event->getNick()));
  101. $this->store[$chan][$nick] = self::REGULAR;
  102. }
  103. /**
  104. * Tracks users leaving a channel
  105. *
  106. * @return void
  107. */
  108. public function onPart()
  109. {
  110. $chan = trim(strtolower($this->event->getArgument(0)));
  111. $nick = trim(strtolower($this->event->getNick()));
  112. if (isset($this->store[$chan][$nick])) {
  113. unset($this->store[$chan][$nick]);
  114. }
  115. }
  116. /**
  117. * Tracks users quitting a server
  118. *
  119. * @return void
  120. */
  121. public function onQuit()
  122. {
  123. $nick = trim(strtolower($this->event->getNick()));
  124. foreach ($this->store as $chan => $store) {
  125. if (isset($store[$nick])) {
  126. unset($this->store[$chan][$nick]);
  127. }
  128. }
  129. }
  130. /**
  131. * Tracks users changing nicks
  132. *
  133. * @return void
  134. */
  135. public function onNick()
  136. {
  137. $nick = trim(strtolower($this->event->getNick()));
  138. $newNick = trim(strtolower($this->event->getArgument(0)));
  139. foreach ($this->store as $chan => $store) {
  140. if (isset($store[$nick])) {
  141. $this->store[$chan][$newNick] = $store[$nick];
  142. unset($this->store[$chan][$nick]);
  143. }
  144. }
  145. }
  146. /**
  147. * Populates the internal user listing for a channel when the bot joins it.
  148. *
  149. * @return void
  150. */
  151. public function onResponse()
  152. {
  153. if ($this->event->getCode() != Phergie_Event_Response::RPL_NAMREPLY) {
  154. return;
  155. }
  156. $desc = preg_split('/[@*=]\s*/', $this->event->getDescription(), 2);
  157. list($chan, $users) = array_pad(explode(' :', trim($desc[1])), 2, null);
  158. $users = explode(' ', trim($users));
  159. $chan = trim(strtolower($chan));
  160. foreach ($users as $user) {
  161. if (empty($user)) {
  162. continue;
  163. }
  164. $user = trim(strtolower($user));
  165. $flag = self::REGULAR;
  166. if ($user[0] == '~') {
  167. $flag |= self::OWNER;
  168. } else if ($user[0] == '&') {
  169. $flag |= self::ADMIN;
  170. } else if ($user[0] == '@') {
  171. $flag |= self::OP;
  172. } else if ($user[0] == '%') {
  173. $flag |= self::HALFOP;
  174. } else if ($user[0] == '+') {
  175. $flag |= self::VOICE;
  176. }
  177. if ($flag != self::REGULAR) {
  178. $user = substr($user, 1);
  179. }
  180. $this->store[$chan][$user] = $flag;
  181. }
  182. }
  183. /**
  184. * Debugging function
  185. *
  186. * @return void
  187. */
  188. public function onPrivmsg()
  189. {
  190. if ($this->getConfig('debug', false) == false) {
  191. return;
  192. }
  193. list($target, $msg) = array_pad($this->event->getArguments(), 2, null);
  194. if (preg_match('#^ishere (\S+)$#', $msg, $m)) {
  195. $this->doPrivmsg(
  196. $target, $this->isIn($m[1], $target) ? 'true' : 'false'
  197. );
  198. } elseif (preg_match('#^isowner (\S+)$#', $msg, $m)) {
  199. $this->doPrivmsg(
  200. $target, $this->isOwner($m[1], $target) ? 'true' : 'false'
  201. );
  202. } elseif (preg_match('#^isadmin (\S+)$#', $msg, $m)) {
  203. $this->doPrivmsg(
  204. $target, $this->isAdmin($m[1], $target) ? 'true' : 'false'
  205. );
  206. } elseif (preg_match('#^isop (\S+)$#', $msg, $m)) {
  207. $this->doPrivmsg(
  208. $target, $this->isOp($m[1], $target) ? 'true' : 'false'
  209. );
  210. } elseif (preg_match('#^ishop (\S+)$#', $msg, $m)) {
  211. $this->doPrivmsg(
  212. $target, $this->isHalfop($m[1], $target) ? 'true' : 'false'
  213. );
  214. } elseif (preg_match('#^isvoice (\S+)$#', $msg, $m)) {
  215. $this->doPrivmsg(
  216. $target, $this->isVoice($m[1], $target) ? 'true' : 'false'
  217. );
  218. } elseif (preg_match('#^channels (\S+)$#', $msg, $m)) {
  219. $channels = $this->getChannels($m[1]);
  220. $this->doPrivmsg(
  221. $target, $channels ? join(', ', $channels) : 'unable to find nick'
  222. );
  223. } elseif (preg_match('#^users (\S+)$#', $msg, $m)) {
  224. $nicks = $this->getUsers($m[1]);
  225. $this->doPrivmsg(
  226. $target, $nicks ? join(', ', $nicks) : 'unable to find channel'
  227. );
  228. } elseif (preg_match('#^random (\S+)$#', $msg, $m)) {
  229. $nick = $this->getrandomuser($m[1]);
  230. $this->doPrivmsg($target, $nick ? $nick : 'unable to find channel');
  231. }
  232. }
  233. /**
  234. * Checks whether or not a given user has a mode
  235. *
  236. * @param int $mode A numeric mode (identified by the class constants)
  237. * @param string $nick The nick to check
  238. * @param string $chan The channel to check in
  239. *
  240. * @return bool
  241. */
  242. public function is($mode, $nick, $chan)
  243. {
  244. $chan = trim(strtolower($chan));
  245. $nick = trim(strtolower($nick));
  246. if (!isset($this->store[$chan][$nick])) {
  247. return false;
  248. }
  249. return ($this->store[$chan][$nick] & $mode) != 0;
  250. }
  251. /**
  252. * Checks whether or not a given user has owner (~) status
  253. *
  254. * @param string $nick The nick to check
  255. * @param string $chan The channel to check in
  256. *
  257. * @return bool
  258. */
  259. public function isOwner($nick, $chan)
  260. {
  261. return $this->is(self::OWNER, $nick, $chan);
  262. }
  263. /**
  264. * Checks whether or not a given user has admin (&) status
  265. *
  266. * @param string $nick The nick to check
  267. * @param string $chan The channel to check in
  268. *
  269. * @return bool
  270. */
  271. public function isAdmin($nick, $chan)
  272. {
  273. return $this->is(self::ADMIN, $nick, $chan);
  274. }
  275. /**
  276. * Checks whether or not a given user has operator (@) status
  277. *
  278. * @param string $nick The nick to check
  279. * @param string $chan The channel to check in
  280. *
  281. * @return bool
  282. */
  283. public function isOp($nick, $chan)
  284. {
  285. return $this->is(self::OP, $nick, $chan);
  286. }
  287. /**
  288. * Checks whether or not a given user has halfop (%) status
  289. *
  290. * @param string $nick The nick to check
  291. * @param string $chan The channel to check in
  292. *
  293. * @return bool
  294. */
  295. public function isHalfop($nick, $chan)
  296. {
  297. return $this->is(self::HALFOP, $nick, $chan);
  298. }
  299. /**
  300. * Checks whether or not a given user has voice (+) status
  301. *
  302. * @param string $nick The nick to check
  303. * @param string $chan The channel to check in
  304. *
  305. * @return bool
  306. */
  307. public function isVoice($nick, $chan)
  308. {
  309. return $this->is(self::VOICE, $nick, $chan);
  310. }
  311. /**
  312. * Checks whether or not a given user is in a channel
  313. *
  314. * @param string $nick The nick to check
  315. * @param string $chan The channel to check in
  316. *
  317. * @return bool
  318. */
  319. public function isIn($nick, $chan)
  320. {
  321. return $this->is(self::REGULAR, $nick, $chan);
  322. }
  323. /**
  324. * Returns the entire user list for a channel or false if the bot is not
  325. * in the channel.
  326. *
  327. * @param string $chan The channel name
  328. *
  329. * @return array|bool
  330. */
  331. public function getUsers($chan)
  332. {
  333. $chan = trim(strtolower($chan));
  334. if (isset($this->store[$chan])) {
  335. return array_keys($this->store[$chan]);
  336. }
  337. return false;
  338. }
  339. /**
  340. * Returns the nick of a random user present in a given channel or false
  341. * if the bot is not present in the channel.
  342. *
  343. * To exclude the bot's current nick, for example:
  344. * $chan = $this->getEvent()->getSource();
  345. * $current_nick = $this->getConnection()->getNick();
  346. * $random_user = $this->plugins->getPlugin('UserInfo')
  347. * ->getRandomUser( $chan, array( $current_nick ) );
  348. *
  349. * @param string $chan The channel name
  350. * @param array $ignore A list of nicks to ignore in the channel.
  351. * Useful for excluding the bot itself.
  352. *
  353. * @return string|bool
  354. */
  355. public function getRandomUser($chan, $ignore = array('chanserv'))
  356. {
  357. $chan = trim(strtolower($chan));
  358. if (isset($this->store[$chan])) {
  359. do {
  360. $nick = array_rand($this->store[$chan], 1);
  361. } while (in_array($nick, $ignore));
  362. return $nick;
  363. }
  364. return false;
  365. }
  366. /**
  367. * Returns a list of channels in which a given user is present.
  368. *
  369. * @param string $nick Nick of the user (optional, defaults to the bot's
  370. * nick)
  371. *
  372. * @return array|bool
  373. */
  374. public function getChannels($nick = null)
  375. {
  376. if (empty($nick)) {
  377. $nick = $this->connection->getNick();
  378. }
  379. $nick = trim(strtolower($nick));
  380. $channels = array();
  381. foreach ($this->store as $chan => $store) {
  382. if (isset($store[$nick])) {
  383. $channels[] = $chan;
  384. }
  385. }
  386. return $channels;
  387. }
  388. }