Advertisement
Guest User

S

a guest
Mar 24th, 2018
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 26.94 KB | None | 0 0
  1. m_whox.c
  2. /* m_whox.c - Add WHOX support to /WHO
  3. * Copyright (C) 1990 Jarkko Oikarinen and
  4. * University of Oulu, Computing Center
  5. *
  6. * See file AUTHORS in IRC package for additional names of
  7. * the programmers.
  8. *
  9. * This program is free softwmare; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation; either version 1, or (at your option)
  12. * any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23.  
  24. /* based heavily on the original m_who.c. Due to the complexity of this
  25. * command, it's easier to override it entirely rather than attempting
  26. * to bolt on WHOX functionality (most of the code would need to be copied
  27. * anyway). */
  28.  
  29. #include "unrealircd.h"
  30.  
  31. #define RPL_WHOSPCRPL 354
  32. #define MSG_WHO "WHO"
  33.  
  34. static int whox(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[]);
  35.  
  36. ModuleHeader MOD_HEADER(m_whox) = {
  37. "whox",
  38. "1.0",
  39. "WHOX support for /who",
  40. "3.2-b8-1",
  41. NULL
  42. };
  43.  
  44. MOD_INIT(m_whox)
  45. {
  46. return MOD_SUCCESS;
  47. }
  48.  
  49. MOD_LOAD(m_whox)
  50. {
  51. if (!CmdoverrideAdd(modinfo->handle, "WHO", whox))
  52. return MOD_FAILED;
  53.  
  54. if (!IsupportAdd(modinfo->handle, "WHOX", NULL))
  55. return MOD_FAILED;
  56.  
  57. return MOD_SUCCESS;
  58. }
  59.  
  60. MOD_UNLOAD(m_whox)
  61. {
  62. return MOD_SUCCESS;
  63. }
  64.  
  65. static void do_channel_who(aClient *sptr, aChannel *channel, char *mask);
  66. static void make_who_status(aClient *, aClient *, aChannel *, Member *, char *, int);
  67. static void do_other_who(aClient *sptr, char *mask);
  68. static void send_who_reply(aClient *, aClient *, char *, char *, char *);
  69. static char *first_visible_channel(aClient *, aClient *, int *);
  70. static int parse_who_options(aClient *, int, char **);
  71. static void who_sendhelp(aClient *);
  72.  
  73. #define WF_OPERONLY 0x01 /**< only show opers */
  74. #define WF_ONCHANNEL 0x02 /**< we're on the channel we're /who'ing */
  75. #define WF_WILDCARD 0x04 /**< a wildcard /who */
  76. #define WF_REALHOST 0x08 /**< want real hostnames */
  77. #define WF_IP 0x10 /**< want IP addresses */
  78.  
  79. static int who_flags;
  80.  
  81. #define WHO_CANTSEE 0x01 /**< set if we can't see them */
  82. #define WHO_CANSEE 0x02 /**< set if we can */
  83. #define WHO_OPERSEE 0x04 /**< set if we only saw them because we're an oper */
  84.  
  85. #define FVC_HIDDEN 0x01
  86.  
  87. #define WHO_WANT 1
  88. #define WHO_DONTWANT 2
  89. #define WHO_DONTCARE 0
  90.  
  91. struct {
  92. int want_away;
  93. int want_channel;
  94. char *channel; /**< if they want one */
  95. int want_gecos;
  96. char *gecos;
  97. int want_server;
  98. char *server;
  99. int want_host;
  100. char *host;
  101. int want_nick;
  102. char *nick;
  103. int want_user;
  104. char *user;
  105. int want_ip;
  106. char *ip;
  107. int want_port;
  108. int port;
  109. int want_umode;
  110. int umodes_dontwant;
  111. int umodes_want;
  112. int common_channels_only;
  113. int whox_querytype;
  114. char whox_fields[13];
  115. } wfl;
  116.  
  117. /** The /who command: retrieves information from users. */
  118. static int whox(Cmdoverride *ovr, aClient *cptr, aClient *sptr, int parc, char *parv[])
  119. {
  120. aChannel *target_channel;
  121. char *mask = parv[1];
  122. char star[] = "*";
  123. int i = 0;
  124.  
  125. if (!MyClient(sptr))
  126. return 0;
  127.  
  128. who_flags = 0;
  129. memset(&wfl, 0, sizeof(wfl));
  130.  
  131. if (parc > 1)
  132. {
  133. i = parse_who_options(sptr, parc - 1, parv + 1);
  134. if (i < 0)
  135. {
  136. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, mask);
  137. return 0;
  138. }
  139. }
  140.  
  141. if (parc-i < 2 || strcmp(parv[1 + i], "0") == 0)
  142. mask = star;
  143. else
  144. mask = parv[1 + i];
  145.  
  146. collapse(mask);
  147.  
  148. if (!i && parc > 2 && *parv[2] == 'o')
  149. who_flags |= WF_OPERONLY;
  150. else if (!i && parc > 2)
  151. {
  152. i = parse_who_options(sptr, parc - 2, parv + 2);
  153. if (i < 0)
  154. {
  155. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, mask);
  156. return 0;
  157. }
  158. }
  159. if (*mask == '\0')
  160. {
  161. /* no mask given */
  162. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, "*");
  163. return 0;
  164. }
  165.  
  166. if ((target_channel = find_channel(mask, NULL)) != NULL)
  167. {
  168. do_channel_who(sptr, target_channel, mask);
  169. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, mask);
  170. return 0;
  171. }
  172.  
  173. if (wfl.channel && wfl.want_channel == WHO_WANT &&
  174. (target_channel = find_channel(wfl.channel, NULL)) != NULL)
  175. {
  176. do_channel_who(sptr, target_channel, mask);
  177. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, mask);
  178. return 0;
  179. }
  180. else
  181. {
  182. do_other_who(sptr, mask);
  183. sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, mask);
  184. return 0;
  185. }
  186.  
  187. return 0;
  188. }
  189.  
  190. static void who_sendhelp(aClient *sptr)
  191. {
  192. char *who_help[] = {
  193. "/WHO [+|-][achmnsuM][%tcuihsnfdlar[,<querytype>]] [args] [mask]",
  194. "Flags are specified like channel modes, the flags chmnsu all have arguments",
  195. "Flags are set to a positive check by +, a negative check by -",
  196. "The flags work as follows:",
  197. "Flag a: user is away",
  198. "Flag c <channel>: user is on <channel>,",
  199. " no wildcards accepted",
  200. "Flag h <host>: user has string <host> in their hostname,",
  201. " wildcards accepted",
  202. "Flag m <usermodes>: user has <usermodes> set, only o is allowed",
  203. "Flag n <nick>: user has string <nick> in their nickname,",
  204. " wildcards accepted",
  205. "Flag s <server>: user is on server <server>,",
  206. " wildcards not accepted",
  207. "Flag u <user>: user has string <user> in their username,",
  208. " wildcards accepted",
  209. "Behavior flags:",
  210. "Flag M: check for user in channels I am a member of",
  211. "Fields begin with the % character. If any fields are specified, the reply",
  212. "uses the 354 numeric instead of 352. Fields not specified are omitted from",
  213. "the reply, while those specified are outputted in the order listed here.",
  214. "The fields work as follows:",
  215. "Field t: outputs the number in <querytype> in reply",
  216. "Field c: channel",
  217. "Field u: username",
  218. "Field i: IP address",
  219. "Field h: host",
  220. "Field s: server",
  221. "Field n: nickname",
  222. "Field f: status",
  223. "Field d: hop count",
  224. "Field l: idle time (0 for users on other servers)",
  225. "Field a: services account name (0 if none)",
  226. "Field r: realname",
  227. NULL
  228. };
  229.  
  230. char *who_oper_help[] = {
  231. "/WHO [+|-][acghimnsuMRI][%tcuihsnfdlar[,<querytype>]] [args] [mask]",
  232. "Flags are specified like channel modes, the flags chigmnsu all have arguments",
  233. "Flags are set to a positive check by +, a negative check by -",
  234. "The flags work as follows:",
  235. "Flag a: user is away",
  236. "Flag c <channel>: user is on <channel>,",
  237. " no wildcards accepted",
  238. "Flag g <gcos/realname>: user has string <gcos> in their GCOS,",
  239. " wildcards accepted",
  240. "Flag h <host>: user has string <host> in their hostname,",
  241. " wildcards accepted",
  242. "Flag i <ip>: user has string <ip> in their IP address,",
  243. " wildcards accepted",
  244. "Flag p <port>: user is connecting on port <port>,",
  245. " local connections only",
  246. "Flag m <usermodes>: user has <usermodes> set",
  247. "Flag n <nick>: user has string <nick> in their nickname,",
  248. " wildcards accepted",
  249. "Flag s <server>: user is on server <server>,",
  250. " wildcards not accepted",
  251. "Flag u <user>: user has string <user> in their username,",
  252. " wildcards accepted",
  253. "Behavior flags:",
  254. "Flag M: check for user in channels I am a member of",
  255. "Flag R: show users' real hostnames",
  256. "Flag I: show users' IP addresses",
  257. "Fields begin with the % character. If any fields are specified, the reply",
  258. "uses the 354 numeric instead of 352. Fields not specified are omitted from",
  259. "the reply, while those specified are outputted in the order listed here.",
  260. "The fields work as follows:",
  261. "Field t: outputs the number in <querytype> in reply",
  262. "Field c: channel",
  263. "Field u: username",
  264. "Field i: IP address",
  265. "Field h: host",
  266. "Field s: server",
  267. "Field n: nickname",
  268. "Field f: status",
  269. "Field d: hop count",
  270. "Field l: idle time (0 for users on other servers)",
  271. "Field a: services account name (0 if none)",
  272. "Field r: realname",
  273. NULL
  274. };
  275. char **s;
  276.  
  277. if (IsOper(sptr))
  278. s = who_oper_help;
  279. else
  280. s = who_help;
  281.  
  282. for (; *s; s++)
  283. sendto_one(sptr, getreply(RPL_LISTSYNTAX), me.name, sptr->name, *s);
  284. }
  285.  
  286. #define WHO_ADD 1
  287. #define WHO_DEL 2
  288.  
  289. static int parse_who_options(aClient *sptr, int argc, char **argv)
  290. {
  291. char *s = argv[0];
  292. int what = WHO_ADD;
  293. int i = 1;
  294.  
  295. /* A few helper macro's because this is used a lot, added during recode by Syzop. */
  296.  
  297. /** function requiress a parameter: check if there's one, if not: return -1. */
  298. #define REQUIRE_PARAM() { if (i >= argc) { \
  299. who_sendhelp(sptr); \
  300. return -1; \
  301. } } while(0);
  302. /** set option 'x' depending on 'what' (add/want or del/dontwant) */
  303. #define SET_OPTION(x) { if (what == WHO_ADD) \
  304. x = WHO_WANT; \
  305. else \
  306. x = WHO_DONTWANT; \
  307. } while(0);
  308. /** Eat a param, set the param in memory and set the option to want or dontwant */
  309. #define DOIT(x,y) { REQUIRE_PARAM(); x = argv[i]; SET_OPTION(y); i++; } while(0);
  310. if (*s != '-' && *s != '+' && *s != '%')
  311. return 0;
  312.  
  313. while (*s)
  314. {
  315. switch (*s)
  316. {
  317. case '+':
  318. what = WHO_ADD;
  319. break;
  320. case '-':
  321. what = WHO_DEL;
  322. break;
  323. case 'a':
  324. SET_OPTION(wfl.want_away);
  325. break;
  326. case 'c':
  327. DOIT(wfl.channel, wfl.want_channel);
  328. break;
  329. case 'g':
  330. REQUIRE_PARAM()
  331. if (!IsOper(sptr))
  332. break; /* oper-only */
  333. wfl.gecos = argv[i];
  334. SET_OPTION(wfl.want_gecos);
  335. i++;
  336. break;
  337. case 's':
  338. DOIT(wfl.server, wfl.want_server);
  339. break;
  340. case 'h':
  341. DOIT(wfl.host, wfl.want_host);
  342. break;
  343. case 'i':
  344. REQUIRE_PARAM()
  345. if (!IsOper(sptr))
  346. break; /* oper-only */
  347. wfl.ip = argv[i];
  348. SET_OPTION(wfl.want_ip);
  349. i++;
  350. break;
  351. case 'n':
  352. DOIT(wfl.nick, wfl.want_nick);
  353. break;
  354. case 'u':
  355. DOIT(wfl.user, wfl.want_user);
  356. break;
  357. case 'm':
  358. REQUIRE_PARAM()
  359. {
  360. char *s = argv[i];
  361. int *umodes;
  362.  
  363. if (what == WHO_ADD)
  364. umodes = &wfl.umodes_want;
  365. else
  366. umodes = &wfl.umodes_dontwant;
  367.  
  368. while (*s)
  369. {
  370. int i;
  371. for (i = 0; i <= Usermode_highest; i++)
  372. if (*s == Usermode_Table[i].flag)
  373. {
  374. *umodes |= Usermode_Table[i].mode;
  375. break;
  376. }
  377. s++;
  378. }
  379.  
  380. if (!IsOper(sptr))
  381. *umodes = *umodes & UMODE_OPER; /* these are usermodes regular users may search for. just oper now. */
  382. if (*umodes == 0)
  383. return -1;
  384. }
  385. i++;
  386. break;
  387. case 'p':
  388. REQUIRE_PARAM()
  389. if (!IsOper(sptr))
  390. break; /* oper-only */
  391. wfl.port = atoi(argv[i]);
  392. SET_OPTION(wfl.want_port);
  393. i++;
  394. break;
  395. case 'M':
  396. SET_OPTION(wfl.common_channels_only);
  397. break;
  398. case 'R':
  399. if (!IsOper(sptr))
  400. break;
  401. if (what == WHO_ADD)
  402. who_flags |= WF_REALHOST;
  403. else
  404. who_flags &= ~WF_REALHOST;
  405. break;
  406. case 'I':
  407. if (!IsOper(sptr))
  408. break;
  409. if (what == WHO_ADD)
  410. who_flags |= WF_IP;
  411.  
  412. else
  413. who_flags &= ~WF_IP;
  414. break;
  415. case '%':
  416. s++;
  417. goto process_whox;
  418. default:
  419. who_sendhelp(sptr);
  420. return -1;
  421. }
  422. s++;
  423. }
  424.  
  425. return i;
  426. process_whox:
  427. while (*s)
  428. {
  429. switch (*s)
  430. {
  431. case 't':
  432. wfl.whox_fields[0] = 1;
  433. wfl.whox_fields[1] = 1;
  434. break;
  435. case 'c':
  436. wfl.whox_fields[0] = 1;
  437. wfl.whox_fields[2] = 1;
  438. break;
  439. case 'u':
  440. wfl.whox_fields[0] = 1;
  441. wfl.whox_fields[3] = 1;
  442. break;
  443. case 'i':
  444. wfl.whox_fields[0] = 1;
  445. wfl.whox_fields[4] = 1;
  446. break;
  447. case 'h':
  448. wfl.whox_fields[0] = 1;
  449. wfl.whox_fields[5] = 1;
  450. break;
  451. case 's':
  452. wfl.whox_fields[0] = 1;
  453. wfl.whox_fields[6] = 1;
  454. break;
  455. case 'n':
  456. wfl.whox_fields[0] = 1;
  457. wfl.whox_fields[7] = 1;
  458. break;
  459. case 'f':
  460. wfl.whox_fields[0] = 1;
  461. wfl.whox_fields[8] = 1;
  462. break;
  463. case 'd':
  464. wfl.whox_fields[0] = 1;
  465. wfl.whox_fields[9] = 1;
  466. break;
  467. case 'l':
  468. wfl.whox_fields[0] = 1;
  469. wfl.whox_fields[10] = 1;
  470. break;
  471. case 'a':
  472. wfl.whox_fields[0] = 1;
  473. wfl.whox_fields[11] = 1;
  474. break;
  475. case 'r':
  476. wfl.whox_fields[0] = 1;
  477. wfl.whox_fields[12] = 1;
  478. break;
  479. case ',':
  480. s++;
  481. goto process_querytype;
  482. default:
  483. who_sendhelp(sptr);
  484. return -1;
  485. }
  486. s++;
  487. }
  488.  
  489. return i;
  490. process_querytype:
  491. /* s points to a string representing an int querytype (could be empty) */
  492. wfl.whox_querytype = strtol(s, NULL, 10);
  493.  
  494. return i;
  495. #undef REQUIRE_PARAM
  496. #undef SET_OPTION
  497. #undef DOIT
  498. }
  499.  
  500. static int can_see(aClient *sptr, aClient *acptr, aChannel *channel)
  501. {
  502. int ret = 0;
  503. int i=0;
  504. Hook *h;
  505. char has_common_chan = 0;
  506. do {
  507. /* can only see people */
  508. if (!IsPerson(acptr))
  509. return WHO_CANTSEE;
  510.  
  511. /* can only see opers if thats what they want */
  512. if (who_flags & WF_OPERONLY)
  513. {
  514. if (!IsOper(acptr))
  515. return ret | WHO_CANTSEE;
  516. if (IsHideOper(acptr)) {
  517. if (IsOper(sptr))
  518. ret |= WHO_OPERSEE;
  519. else
  520. return ret | WHO_CANTSEE;
  521. }
  522. }
  523.  
  524. /* if they only want people who are away */
  525. if ((wfl.want_away == WHO_WANT && !acptr->user->away) ||
  526. (wfl.want_away == WHO_DONTWANT && acptr->user->away))
  527. return WHO_CANTSEE;
  528.  
  529. /* if they only want people on a certain channel. */
  530. if (wfl.want_channel != WHO_DONTCARE)
  531. {
  532. aChannel *chan = find_channel(wfl.channel, NULL);
  533. if (!chan && wfl.want_channel == WHO_WANT)
  534. return WHO_CANTSEE;
  535. if ((wfl.want_channel == WHO_WANT) && !IsMember(acptr, chan))
  536. return WHO_CANTSEE;
  537. if ((wfl.want_channel == WHO_DONTWANT) && IsMember(acptr, chan))
  538. return WHO_CANTSEE;
  539. }
  540.  
  541. /* if they only want people with a certain gecos */
  542. if (wfl.want_gecos != WHO_DONTCARE)
  543. {
  544. if (((wfl.want_gecos == WHO_WANT) && match(wfl.gecos, acptr->info)) ||
  545. ((wfl.want_gecos == WHO_DONTWANT) && !match(wfl.gecos, acptr->info)))
  546. {
  547. return WHO_CANTSEE;
  548. }
  549. }
  550.  
  551. /* if they only want people with a certain server */
  552. if (wfl.want_server != WHO_DONTCARE)
  553. {
  554. if (((wfl.want_server == WHO_WANT) && stricmp(wfl.server, acptr->user->server)) ||
  555. ((wfl.want_server == WHO_DONTWANT) && !stricmp(wfl.server, acptr->user->server)))
  556. {
  557. return WHO_CANTSEE;
  558. }
  559. }
  560.  
  561. /* if they only want people with a certain host */
  562. if (wfl.want_host != WHO_DONTCARE)
  563. {
  564. char *host;
  565.  
  566. if (IsOper(sptr))
  567. host = acptr->user->realhost;
  568. else
  569. host = GetHost(acptr);
  570.  
  571. if (((wfl.want_host == WHO_WANT) && match(wfl.host, host)) ||
  572. ((wfl.want_host == WHO_DONTWANT) && !match(wfl.host, host)))
  573. {
  574. return WHO_CANTSEE;
  575. }
  576. }
  577.  
  578. /* if they only want people with a certain IP */
  579. if (wfl.want_ip != WHO_DONTCARE)
  580. {
  581. char *ip;
  582.  
  583. ip = acptr->ip;
  584. if (!ip)
  585. return WHO_CANTSEE;
  586.  
  587. if (((wfl.want_ip == WHO_WANT) && match(wfl.ip, ip)) ||
  588. ((wfl.want_ip == WHO_DONTWANT) && !match(wfl.ip, ip)))
  589. {
  590. return WHO_CANTSEE;
  591. }
  592. }
  593.  
  594. /* if they only want people connecting on a certain port */
  595. if (wfl.want_port != WHO_DONTCARE)
  596. {
  597. int port;
  598.  
  599. if (!MyClient(acptr))
  600. return WHO_CANTSEE;
  601.  
  602. port = acptr->local->listener->port;
  603.  
  604. if (((wfl.want_port == WHO_WANT) && wfl.port != port) ||
  605. ((wfl.want_port == WHO_DONTWANT) && wfl.port == port))
  606. {
  607. return WHO_CANTSEE;
  608. }
  609. }
  610.  
  611. /* if they only want people with a certain nick.. */
  612. if (wfl.want_nick != WHO_DONTCARE)
  613. {
  614. if (((wfl.want_nick == WHO_WANT) && match(wfl.nick, acptr->name)) ||
  615. ((wfl.want_nick == WHO_DONTWANT) && !match(wfl.nick, acptr->name)))
  616. {
  617. return WHO_CANTSEE;
  618. }
  619. }
  620.  
  621. /* if they only want people with a certain username */
  622. if (wfl.want_user != WHO_DONTCARE)
  623. {
  624. if (((wfl.want_user == WHO_WANT) && match(wfl.user, acptr->user->username)) ||
  625. ((wfl.want_user == WHO_DONTWANT) && !match(wfl.user, acptr->user->username)))
  626. {
  627. return WHO_CANTSEE;
  628. }
  629. }
  630.  
  631. /* if they only want people with a certain umode */
  632. if (wfl.umodes_want)
  633. {
  634. if (!(acptr->umodes & wfl.umodes_want) || (!IsOper(sptr) && (acptr->umodes & UMODE_HIDEOPER)))
  635. return WHO_CANTSEE;
  636. }
  637.  
  638. if (wfl.umodes_dontwant)
  639. {
  640. if ((acptr->umodes & wfl.umodes_dontwant) && (!(acptr->umodes & UMODE_HIDEOPER) || IsOper(sptr)))
  641. return WHO_CANTSEE;
  642. }
  643.  
  644. /* if they only want common channels */
  645. if (wfl.common_channels_only)
  646. {
  647. if (!has_common_channels(sptr, acptr))
  648. return WHO_CANTSEE;
  649. has_common_chan = 1;
  650. }
  651.  
  652. if (channel)
  653. {
  654. int member = who_flags & WF_ONCHANNEL;
  655.  
  656. if (SecretChannel(channel) || HiddenChannel(channel))
  657. {
  658. /* if they aren't on it.. they can't see it */
  659. if (!(who_flags & WF_ONCHANNEL))
  660. break;
  661. }
  662. if (IsInvisible(acptr) && !member)
  663. break;
  664.  
  665. if (!user_can_see_member(sptr, acptr, channel))
  666. continue; /* invisible (eg: due to delayjoin) */
  667. }
  668. else
  669. {
  670. /* a user/mask who */
  671.  
  672. /* If the common channel info hasn't been set, set it now */
  673. if (!wfl.common_channels_only)
  674. has_common_chan = has_common_channels(sptr, acptr);
  675.  
  676. if (IsInvisible(acptr) && !has_common_chan)
  677. {
  678. /* don't show them unless it's an exact match
  679. or it is the user requesting the /who */
  680. if ((who_flags & WF_WILDCARD) && sptr != acptr)
  681. break;
  682. }
  683. }
  684.  
  685. /* phew.. show them. */
  686. return WHO_CANSEE;
  687. } while (0);
  688.  
  689. /* if we get here, it's oper-dependant. */
  690. if (IsOper(sptr))
  691. return ret | WHO_OPERSEE | WHO_CANSEE;
  692. else
  693. {
  694. if (sptr == acptr)
  695. return ret | WHO_CANSEE;
  696. else
  697. return ret | WHO_CANTSEE;
  698. }
  699. }
  700.  
  701. static void do_channel_who(aClient *sptr, aChannel *channel, char *mask)
  702. {
  703. Member *cm = channel->members;
  704. if (IsMember(sptr, channel) || ValidatePermissionsForPath("override:see:who:onchannel",sptr,NULL,channel,NULL))
  705. who_flags |= WF_ONCHANNEL;
  706.  
  707. for (cm = channel->members; cm; cm = cm->next)
  708. {
  709. aClient *acptr = cm->cptr;
  710. char status[32];
  711. int cansee;
  712. if ((cansee = can_see(sptr, acptr, channel)) & WHO_CANTSEE)
  713. continue;
  714.  
  715. make_who_status(sptr, acptr, channel, cm, status, cansee);
  716. send_who_reply(sptr, acptr, channel->chname, status, "");
  717. }
  718. }
  719.  
  720. static void make_who_status(aClient *sptr, aClient *acptr, aChannel *channel,
  721. Member *cm, char *status, int cansee)
  722. {
  723. int i = 0;
  724. Hook *h;
  725.  
  726. if (acptr->user->away)
  727. status[i++] = 'G';
  728. else
  729. status[i++] = 'H';
  730.  
  731. if (IsARegNick(acptr))
  732. status[i++] = 'r';
  733.  
  734. for (h = Hooks[HOOKTYPE_WHO_STATUS]; h; h = h->next)
  735. {
  736. int ret = (*(h->func.intfunc))(sptr, acptr, channel, cm, status, cansee);
  737. if (ret != 0)
  738. status[i++] = (char)ret;
  739. }
  740.  
  741. if (IsOper(acptr) && (!IsHideOper(acptr) || sptr == acptr || IsOper(sptr)))
  742. status[i++] = '*';
  743.  
  744. if (IsOper(acptr) && (IsHideOper(acptr) && sptr != acptr && IsOper(sptr)))
  745. status[i++] = '!';
  746.  
  747. if (cansee & WHO_OPERSEE)
  748. status[i++] = '?';
  749.  
  750. if (cm)
  751. {
  752. if (SupportNAMESX(sptr))
  753. {
  754. #ifdef PREFIX_AQ
  755. if (cm->flags & CHFL_CHANOWNER)
  756. status[i++] = '~';
  757. if (cm->flags & CHFL_CHANPROT)
  758. status[i++] = '&';
  759. #endif
  760. if (cm->flags & CHFL_CHANOP)
  761. status[i++] = '@';
  762. if (cm->flags & CHFL_HALFOP)
  763. status[i++] = '%';
  764. if (cm->flags & CHFL_VOICE)
  765. status[i++] = '+';
  766. } else {
  767. #ifdef PREFIX_AQ
  768. if (cm->flags & CHFL_CHANOWNER)
  769. status[i++] = '~';
  770. else if (cm->flags & CHFL_CHANPROT)
  771. status[i++] = '&';
  772. else
  773. #endif
  774. if (cm->flags & CHFL_CHANOP)
  775. status[i++] = '@';
  776. else if (cm->flags & CHFL_HALFOP)
  777. status[i++] = '%';
  778. else if (cm->flags & CHFL_VOICE)
  779. status[i++] = '+';
  780. }
  781. }
  782.  
  783. status[i] = '\0';
  784. }
  785.  
  786. static void do_other_who(aClient *sptr, char *mask)
  787. {
  788. int oper = IsOper(sptr);
  789.  
  790. if (strchr(mask, '*') || strchr(mask, '?'))
  791. {
  792. int i = 0;
  793. /* go through all users.. */
  794. aClient *acptr;
  795. who_flags |= WF_WILDCARD;
  796.  
  797. list_for_each_entry(acptr, &client_list, client_node)
  798. {
  799. int cansee;
  800. char status[20];
  801. char *channel;
  802. int flg;
  803.  
  804. if (!IsPerson(acptr))
  805. continue;
  806. if (!oper) {
  807. /* non-opers can only search on nick here */
  808. if (match(mask, acptr->name))
  809. continue;
  810. } else {
  811. /* opers can search on name, ident, virthost, ip and realhost.
  812. * Yes, I like readable if's -- Syzop.
  813. */
  814. if (!match(mask, acptr->name) || !match(mask, acptr->user->realhost) ||
  815. !match(mask, acptr->user->username))
  816. goto matchok;
  817. if (IsHidden(acptr) && !match(mask, acptr->user->virthost))
  818. goto matchok;
  819. if (acptr->ip && !match(mask, acptr->ip))
  820. goto matchok;
  821. /* nothing matched... */
  822. continue;
  823. }
  824. matchok:
  825. if ((cansee = can_see(sptr, acptr, NULL)) & WHO_CANTSEE)
  826. continue;
  827. if (WHOLIMIT && !IsOper(sptr) && ++i > WHOLIMIT)
  828. {
  829. sendto_one(sptr, rpl_str(ERR_WHOLIMEXCEED), me.name, sptr->name, WHOLIMIT);
  830. return;
  831. }
  832.  
  833. channel = first_visible_channel(sptr, acptr, &flg);
  834. make_who_status(sptr, acptr, NULL, NULL, status, cansee);
  835. send_who_reply(sptr, acptr, channel, status, (flg & FVC_HIDDEN) ? "~" : "");
  836. }
  837. }
  838. else
  839. {
  840. /* just a single client (no wildcards detected) */
  841. aClient *acptr = find_client(mask, NULL);
  842. int cansee;
  843. char status[20];
  844. char *channel;
  845. int flg;
  846.  
  847. if (!acptr)
  848. return;
  849.  
  850. if ((cansee = can_see(sptr, acptr, NULL)) == WHO_CANTSEE)
  851. return;
  852.  
  853. channel = first_visible_channel(sptr, acptr, &flg);
  854. make_who_status(sptr, acptr, NULL, NULL, status, cansee);
  855. send_who_reply(sptr, acptr, channel, status, (flg & FVC_HIDDEN) ? "~" : "");
  856. }
  857. }
  858.  
  859. static void send_who_reply(aClient *sptr, aClient *acptr,
  860. char *channel, char *status, char *xstat)
  861. {
  862. char *stat;
  863. char *host;
  864. char *ip;
  865. char *account;
  866. int flat = (FLAT_MAP && !IsOper(sptr)) ? 1 : 0;
  867. char *server;
  868. int hops;
  869. char hopsstr[12] = {0};
  870. char querytype[12] = {0}; /* ensure we can comfortably fit the string representation of an int + trailing null */
  871. char idle[12] = {0};
  872.  
  873. /* helper macro for WHOX replies */
  874. #define MAYBE_BLANK(n, x) wfl.whox_fields[n] ? " " : "", wfl.whox_fields[n] ? (x) : ""
  875. #define MAYBE_BLANK_COLON(n, x) wfl.whox_fields[n] ? " :" : "", wfl.whox_fields[n] ? (x) : ""
  876.  
  877. stat = malloc(strlen(status) + strlen(xstat) + 1);
  878. sprintf(stat, "%s%s", status, xstat);
  879.  
  880. if (IsOper(sptr))
  881. {
  882. if (who_flags & WF_REALHOST)
  883. host = acptr->user->realhost;
  884. else if (who_flags & WF_IP)
  885. host = (acptr->ip ? acptr->ip : acptr->user->realhost);
  886. else
  887. host = GetHost(acptr);
  888. }
  889. else
  890. host = GetHost(acptr);
  891.  
  892. if (!IsOper(sptr) && IsHidden(acptr))
  893. ip = "255.255.255.255";
  894. else
  895. ip = (acptr->ip ? acptr->ip : "255.255.255.255");
  896.  
  897. if (IsULine(acptr) && !IsOper(sptr) && !ValidatePermissionsForPath("map:ulines",sptr,acptr,NULL,NULL) && HIDE_ULINES)
  898. {
  899. server = "hidden";
  900. hops = 0;
  901. }
  902. else
  903. {
  904. server = acptr->user->server;
  905. hops = flat ? 0 : acptr->hopcount;
  906. }
  907.  
  908. account = (*acptr->user->svid == '*') ? "0" : acptr->user->svid;
  909. snprintf(querytype, 12, "%d", wfl.whox_querytype);
  910. snprintf(hopsstr, 12, "%d", hops);
  911.  
  912. /* only show idle time if they're local and aren't an oper with +I */
  913. if (MyConnect(acptr) && (IsOper(sptr) || !(acptr->umodes & UMODE_HIDLE)))
  914. snprintf(idle, 12, "%d", TStime() - acptr->local->last);
  915. else
  916. idle[0] = '0';
  917.  
  918. if (wfl.whox_fields[0])
  919. sendto_one(sptr, ":%s 354 %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", me.name, sptr->name,
  920. MAYBE_BLANK(1, querytype),
  921. MAYBE_BLANK(2, channel),
  922. MAYBE_BLANK(3, acptr->user->username),
  923. MAYBE_BLANK(4, ip),
  924. MAYBE_BLANK(5, host),
  925. MAYBE_BLANK(6, server),
  926. MAYBE_BLANK(7, acptr->name),
  927. MAYBE_BLANK(8, stat),
  928. MAYBE_BLANK(9, hopsstr),
  929. MAYBE_BLANK(10, idle),
  930. MAYBE_BLANK(11, account),
  931. MAYBE_BLANK_COLON(12, acptr->info)
  932. );
  933. else
  934. sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
  935. channel, /* channel name */
  936. acptr->user->username, /* user name */
  937. host, /* hostname */
  938. server, /* server name */
  939. acptr->name, /* nick */
  940. stat, /* status */
  941. hops, /* hops */
  942. acptr->info /* realname */
  943. );
  944.  
  945. free(stat);
  946.  
  947. #undef MAYBE_BLANK
  948. #undef MAYBE_BLANK_COLON
  949. }
  950.  
  951. static char *first_visible_channel(aClient *sptr, aClient *acptr, int *flg)
  952. {
  953. Membership *lp;
  954.  
  955. *flg = 0;
  956.  
  957. for (lp = acptr->user->channel; lp; lp = lp->next)
  958. {
  959. aChannel *chptr = lp->chptr;
  960. Hook *h;
  961. int ret = EX_ALLOW;
  962. int operoverride = 0;
  963. int showchannel = 0;
  964.  
  965. /* Note that the code below is almost identical to the one in /WHOIS */
  966.  
  967. if (ShowChannel(sptr, chptr))
  968. showchannel = 1;
  969.  
  970. for (h = Hooks[HOOKTYPE_SEE_CHANNEL_IN_WHOIS]; h; h = h->next)
  971. {
  972. int n = (*(h->func.intfunc))(sptr, acptr, chptr);
  973. /* Hook return values:
  974. * EX_ALLOW means 'yes is ok, as far as modules are concerned'
  975. * EX_DENY means 'hide this channel, unless oper overriding'
  976. * EX_ALWAYS_DENY means 'hide this channel, always'
  977. * ... with the exception that we always show the channel if you /WHOIS yourself
  978. */
  979. if (n == EX_DENY)
  980. {
  981. ret = EX_DENY;
  982. }
  983. else if (n == EX_ALWAYS_DENY)
  984. {
  985. ret = EX_ALWAYS_DENY;
  986. break;
  987. }
  988. }
  989.  
  990. if (ret == EX_DENY)
  991. showchannel = 0;
  992.  
  993. if (!showchannel && (ValidatePermissionsForPath("override:see:who:secret",sptr,NULL,chptr,NULL) || ValidatePermissionsForPath("override:see:whois",sptr,NULL,chptr,NULL)))
  994. {
  995. showchannel = 1; /* OperOverride */
  996. operoverride = 1;
  997. }
  998.  
  999. if ((ret == EX_ALWAYS_DENY) && (acptr != sptr))
  1000. continue; /* a module asked us to really not expose this channel, so we don't (except target==ourselves). */
  1001.  
  1002. if (acptr == sptr)
  1003. showchannel = 1;
  1004.  
  1005. if (operoverride)
  1006. *flg |= FVC_HIDDEN;
  1007.  
  1008. if (showchannel)
  1009. return chptr->chname;
  1010. }
  1011.  
  1012. /* no channels that they can see */
  1013. return "*";
  1014. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement