irc-info.c 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2013 Alexander Barton (alex@barton.de) and Contributors.
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * Please read the file COPYING, README and AUTHORS for more information.
  10. */
  11. #include "portab.h"
  12. /**
  13. * @file
  14. * IRC info commands
  15. */
  16. #include "imp.h"
  17. #include <assert.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <strings.h>
  23. #include "ngircd.h"
  24. #include "conn-func.h"
  25. #include "conn-zip.h"
  26. #include "channel.h"
  27. #include "class.h"
  28. #include "conf.h"
  29. #include "defines.h"
  30. #include "lists.h"
  31. #include "log.h"
  32. #include "messages.h"
  33. #include "match.h"
  34. #include "tool.h"
  35. #include "parse.h"
  36. #include "irc.h"
  37. #include "irc-macros.h"
  38. #include "irc-write.h"
  39. #include "client-cap.h"
  40. #include "op.h"
  41. #include "exp.h"
  42. #include "irc-info.h"
  43. /* Local functions */
  44. static unsigned int
  45. t_diff(time_t *t, const time_t d)
  46. {
  47. time_t diff, remain;
  48. diff = *t / d;
  49. remain = diff * d;
  50. *t -= remain;
  51. return (unsigned int)diff;
  52. }
  53. static unsigned int
  54. uptime_days(time_t *now)
  55. {
  56. return t_diff(now, 60 * 60 * 24);
  57. }
  58. static unsigned int
  59. uptime_hrs(time_t *now)
  60. {
  61. return t_diff(now, 60 * 60);
  62. }
  63. static unsigned int
  64. uptime_mins(time_t *now)
  65. {
  66. return t_diff(now, 60);
  67. }
  68. static bool
  69. write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
  70. {
  71. return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client),
  72. channelname, Client_User(c),
  73. Client_HostnameDisplayed(c),
  74. Client_ID(Client_Introducer(c)), Client_ID(c),
  75. flags, Client_Hops(c), Client_Info(c));
  76. }
  77. /**
  78. * Return channel user mode prefix(es).
  79. *
  80. * @param Client The client requesting the mode prefixes.
  81. * @param chan_user_modes String with channel user modes.
  82. * @param str String buffer to which the prefix(es) will be appended.
  83. * @param len Size of "str" buffer.
  84. * @return Pointer to "str".
  85. */
  86. static char *
  87. who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
  88. char *str, size_t len)
  89. {
  90. assert(Client != NULL);
  91. if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
  92. if (strchr(chan_user_modes, 'q'))
  93. strlcat(str, "~", len);
  94. if (strchr(chan_user_modes, 'a'))
  95. strlcat(str, "&", len);
  96. if (strchr(chan_user_modes, 'o'))
  97. strlcat(str, "@", len);
  98. if (strchr(chan_user_modes, 'h'))
  99. strlcat(str, "%", len);
  100. if (strchr(chan_user_modes, 'v'))
  101. strlcat(str, "+", len);
  102. return str;
  103. }
  104. if (strchr(chan_user_modes, 'q'))
  105. strlcat(str, "~", len);
  106. else if (strchr(chan_user_modes, 'a'))
  107. strlcat(str, "&", len);
  108. else if (strchr(chan_user_modes, 'o'))
  109. strlcat(str, "@", len);
  110. else if (strchr(chan_user_modes, 'h'))
  111. strlcat(str, "%", len);
  112. else if (strchr(chan_user_modes, 'v'))
  113. strlcat(str, "+", len);
  114. return str;
  115. }
  116. /**
  117. * Send WHO reply for a "channel target" ("WHO #channel").
  118. *
  119. * @param Client Client requesting the information.
  120. * @param Chan Channel being requested.
  121. * @param OnlyOps Only display IRC operators.
  122. * @return CONNECTED or DISCONNECTED.
  123. */
  124. static bool
  125. IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
  126. {
  127. bool is_visible, is_member, is_ircop;
  128. CL2CHAN *cl2chan;
  129. char flags[10];
  130. CLIENT *c;
  131. int count = 0;
  132. assert( Client != NULL );
  133. assert( Chan != NULL );
  134. IRC_SetPenalty(Client, 1);
  135. is_member = Channel_IsMemberOf(Chan, Client);
  136. /* Secret channel? */
  137. if (!is_member && Channel_HasMode(Chan, 's'))
  138. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG,
  139. Client_ID(Client), Channel_Name(Chan));
  140. cl2chan = Channel_FirstMember(Chan);
  141. for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
  142. c = Channel_GetClient(cl2chan);
  143. is_ircop = Client_HasMode(c, 'o');
  144. if (OnlyOps && !is_ircop)
  145. continue;
  146. is_visible = Client_HasMode(c, 'i');
  147. if (is_member || is_visible) {
  148. memset(flags, 0, sizeof(flags));
  149. if (Client_HasMode(c, 'a'))
  150. flags[0] = 'G'; /* away */
  151. else
  152. flags[0] = 'H';
  153. if (is_ircop)
  154. flags[1] = '*';
  155. who_flags_qualifier(Client, Channel_UserModes(Chan, c),
  156. flags, sizeof(flags));
  157. if (!write_whoreply(Client, c, Channel_Name(Chan),
  158. flags))
  159. return DISCONNECTED;
  160. count++;
  161. }
  162. }
  163. /* If there are a lot of clients, augment penalty a bit */
  164. if (count > MAX_RPL_WHO)
  165. IRC_SetPenalty(Client, 1);
  166. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
  167. Channel_Name(Chan));
  168. }
  169. /**
  170. * Send WHO reply for a "mask target" ("WHO m*sk").
  171. *
  172. * @param Client Client requesting the information.
  173. * @param Mask Mask being requested or NULL for "all" clients.
  174. * @param OnlyOps Only display IRC operators.
  175. * @return CONNECTED or DISCONNECTED.
  176. */
  177. static bool
  178. IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps)
  179. {
  180. CLIENT *c;
  181. CL2CHAN *cl2chan;
  182. CHANNEL *chan;
  183. bool client_match, is_visible;
  184. char flags[3];
  185. int count = 0;
  186. assert (Client != NULL);
  187. if (Mask)
  188. ngt_LowerStr(Mask);
  189. IRC_SetPenalty(Client, 3);
  190. for (c = Client_First(); c != NULL; c = Client_Next(c)) {
  191. if (Client_Type(c) != CLIENT_USER)
  192. continue;
  193. if (OnlyOps && !Client_HasMode(c, 'o'))
  194. continue;
  195. if (Mask) {
  196. /* Match pattern against user host/server/name/nick */
  197. client_match = MatchCaseInsensitive(Mask,
  198. Client_Hostname(c));
  199. if (!client_match)
  200. client_match = MatchCaseInsensitive(Mask,
  201. Client_ID(Client_Introducer(c)));
  202. if (!client_match)
  203. client_match = MatchCaseInsensitive(Mask,
  204. Client_Info(c));
  205. if (!client_match)
  206. client_match = MatchCaseInsensitive(Mask,
  207. Client_ID(c));
  208. if (!client_match)
  209. continue; /* no match: skip this client */
  210. }
  211. is_visible = !Client_HasMode(c, 'i');
  212. /* Target client is invisible, but mask matches exactly? */
  213. if (!is_visible && Mask && strcasecmp(Client_ID(c), Mask) == 0)
  214. is_visible = true;
  215. /* Target still invisible, but are both on the same channel? */
  216. if (!is_visible) {
  217. cl2chan = Channel_FirstChannelOf(Client);
  218. while (cl2chan && !is_visible) {
  219. chan = Channel_GetChannel(cl2chan);
  220. if (Channel_IsMemberOf(chan, c))
  221. is_visible = true;
  222. cl2chan = Channel_NextChannelOf(Client, cl2chan);
  223. }
  224. }
  225. if (!is_visible) /* target user is not visible */
  226. continue;
  227. if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
  228. break;
  229. memset(flags, 0, sizeof(flags));
  230. if (Client_HasMode(c, 'a'))
  231. flags[0] = 'G'; /* away */
  232. else
  233. flags[0] = 'H';
  234. if (Client_HasMode(c, 'o'))
  235. flags[1] = '*';
  236. if (!write_whoreply(Client, c, "*", flags))
  237. return DISCONNECTED;
  238. count++;
  239. }
  240. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
  241. Mask ? Mask : "*");
  242. }
  243. /**
  244. * Generate WHOIS reply of one actual client.
  245. *
  246. * @param Client The client from which this command has been received.
  247. * @param from The client requesting the information ("originator").
  248. * @param c The client of which information should be returned.
  249. * @return CONNECTED or DISCONNECTED.
  250. */
  251. static bool
  252. IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
  253. {
  254. char str[COMMAND_LEN];
  255. CL2CHAN *cl2chan;
  256. CHANNEL *chan;
  257. assert(Client != NULL);
  258. assert(from != NULL);
  259. assert(c != NULL);
  260. /* Nick, user, hostname and client info */
  261. if (!IRC_WriteStrClient(from, RPL_WHOISUSER_MSG, Client_ID(from),
  262. Client_ID(c), Client_User(c),
  263. Client_HostnameDisplayed(c), Client_Info(c)))
  264. return DISCONNECTED;
  265. /* Server */
  266. if (!IRC_WriteStrClient(from, RPL_WHOISSERVER_MSG, Client_ID(from),
  267. Client_ID(c), Client_ID(Client_Introducer(c)),
  268. Client_Info(Client_Introducer(c))))
  269. return DISCONNECTED;
  270. /* Channels */
  271. snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
  272. Client_ID(from), Client_ID(c));
  273. cl2chan = Channel_FirstChannelOf(c);
  274. while (cl2chan) {
  275. chan = Channel_GetChannel(cl2chan);
  276. assert(chan != NULL);
  277. /* next */
  278. cl2chan = Channel_NextChannelOf(c, cl2chan);
  279. /* Secret channel? */
  280. if (Channel_HasMode(chan, 's')
  281. && !Channel_IsMemberOf(chan, Client))
  282. continue;
  283. /* Local channel and request is not from a user? */
  284. if (Client_Type(Client) == CLIENT_SERVER
  285. && Channel_IsLocal(chan))
  286. continue;
  287. /* Concatenate channel names */
  288. if (str[strlen(str) - 1] != ':')
  289. strlcat(str, " ", sizeof(str));
  290. who_flags_qualifier(Client, Channel_UserModes(chan, c),
  291. str, sizeof(str));
  292. strlcat(str, Channel_Name(chan), sizeof(str));
  293. if (strlen(str) > (COMMAND_LEN - CHANNEL_NAME_LEN - 4)) {
  294. /* Line becomes too long: send it! */
  295. if (!IRC_WriteStrClient(Client, "%s", str))
  296. return DISCONNECTED;
  297. snprintf(str, sizeof(str), RPL_WHOISCHANNELS_MSG,
  298. Client_ID(from), Client_ID(c));
  299. }
  300. }
  301. if(str[strlen(str) - 1] != ':') {
  302. /* There is data left to send: */
  303. if (!IRC_WriteStrClient(Client, "%s", str))
  304. return DISCONNECTED;
  305. }
  306. /* IRC-Services? */
  307. if (Client_Type(c) == CLIENT_SERVICE &&
  308. !IRC_WriteStrClient(from, RPL_WHOISSERVICE_MSG,
  309. Client_ID(from), Client_ID(c)))
  310. return DISCONNECTED;
  311. /* IRC-Operator? */
  312. if (Client_Type(c) != CLIENT_SERVICE &&
  313. Client_HasMode(c, 'o') &&
  314. !IRC_WriteStrClient(from, RPL_WHOISOPERATOR_MSG,
  315. Client_ID(from), Client_ID(c)))
  316. return DISCONNECTED;
  317. /* IRC-Bot? */
  318. if (Client_HasMode(c, 'B') &&
  319. !IRC_WriteStrClient(from, RPL_WHOISBOT_MSG,
  320. Client_ID(from), Client_ID(c)))
  321. return DISCONNECTED;
  322. /* Connected using SSL? */
  323. if (Conn_UsesSSL(Client_Conn(c))) {
  324. if (!IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from),
  325. Client_ID(c)))
  326. return DISCONNECTED;
  327. /* Certificate fingerprint? */
  328. if (Conn_GetCertFp(Client_Conn(c)) &&
  329. from == c &&
  330. !IRC_WriteStrClient(from, RPL_WHOISCERTFP_MSG,
  331. Client_ID(from), Client_ID(c),
  332. Conn_GetCertFp(Client_Conn(c))))
  333. return DISCONNECTED;
  334. }
  335. /* Registered nickname? */
  336. if (Client_HasMode(c, 'R') &&
  337. !IRC_WriteStrClient(from, RPL_WHOISREGNICK_MSG,
  338. Client_ID(from), Client_ID(c)))
  339. return DISCONNECTED;
  340. /* Local client and requester is the user itself or an IRC Op? */
  341. if (Client_Conn(c) > NONE &&
  342. (from == c || (!Conf_MorePrivacy && Client_HasMode(from, 'o')))) {
  343. /* Client hostname */
  344. if (!IRC_WriteStrClient(from, RPL_WHOISHOST_MSG,
  345. Client_ID(from), Client_ID(c),
  346. Client_Hostname(c), Client_IPAText(c)))
  347. return DISCONNECTED;
  348. /* Client modes */
  349. if (!IRC_WriteStrClient(from, RPL_WHOISMODES_MSG,
  350. Client_ID(from), Client_ID(c), Client_Modes(c)))
  351. return DISCONNECTED;
  352. }
  353. /* Idle and signon time (local clients only!) */
  354. if (!Conf_MorePrivacy && Client_Conn(c) > NONE &&
  355. !IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
  356. Client_ID(from), Client_ID(c),
  357. (unsigned long)Conn_GetIdle(Client_Conn(c)),
  358. (unsigned long)Conn_GetSignon(Client_Conn(c))))
  359. return DISCONNECTED;
  360. /* Away? */
  361. if (Client_HasMode(c, 'a') &&
  362. !IRC_WriteStrClient(from, RPL_AWAY_MSG,
  363. Client_ID(from), Client_ID(c), Client_Away(c)))
  364. return DISCONNECTED;
  365. return CONNECTED;
  366. }
  367. static bool
  368. WHOWAS_EntryWrite(CLIENT *prefix, WHOWAS *entry)
  369. {
  370. char t_str[60];
  371. (void)strftime(t_str, sizeof(t_str), "%a %b %d %H:%M:%S %Y",
  372. localtime(&entry->time));
  373. if (!IRC_WriteStrClient(prefix, RPL_WHOWASUSER_MSG, Client_ID(prefix),
  374. entry->id, entry->user, entry->host, entry->info))
  375. return DISCONNECTED;
  376. return IRC_WriteStrClient(prefix, RPL_WHOISSERVER_MSG, Client_ID(prefix),
  377. entry->id, entry->server, t_str);
  378. }
  379. #ifdef SSL_SUPPORT
  380. static bool
  381. Show_MOTD_SSLInfo(CLIENT *Client)
  382. {
  383. char buf[COMMAND_LEN];
  384. char c_str[128];
  385. if (Conn_GetCipherInfo(Client_Conn(Client), c_str, sizeof(c_str))) {
  386. snprintf(buf, sizeof(buf), "Connected using Cipher %s", c_str);
  387. if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
  388. Client_ID(Client), buf))
  389. return false;
  390. }
  391. if (Conn_GetCertFp(Client_Conn(Client))) {
  392. snprintf(buf, sizeof(buf),
  393. "Your client certificate fingerprint is: %s",
  394. Conn_GetCertFp(Client_Conn(Client)));
  395. if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG,
  396. Client_ID(Client), buf))
  397. return false;
  398. }
  399. return true;
  400. }
  401. #else
  402. static bool
  403. Show_MOTD_SSLInfo(UNUSED CLIENT *c)
  404. {
  405. return true;
  406. }
  407. #endif
  408. /* Global functions */
  409. /**
  410. * Handler for the IRC command "ADMIN".
  411. *
  412. * @param Client The client from which this command has been received.
  413. * @param Req Request structure with prefix and all parameters.
  414. * @return CONNECTED or DISCONNECTED.
  415. */
  416. GLOBAL bool
  417. IRC_ADMIN(CLIENT *Client, REQUEST *Req )
  418. {
  419. CLIENT *target, *prefix;
  420. assert( Client != NULL );
  421. assert( Req != NULL );
  422. IRC_SetPenalty(Client, 1);
  423. _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
  424. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
  425. /* Forward? */
  426. if(target != Client_ThisServer()) {
  427. IRC_WriteStrClientPrefix(target, prefix,
  428. "ADMIN %s", Client_ID(target));
  429. return CONNECTED;
  430. }
  431. if (!IRC_WriteStrClient(Client, RPL_ADMINME_MSG, Client_ID(prefix),
  432. Conf_ServerName))
  433. return DISCONNECTED;
  434. if (!IRC_WriteStrClient(Client, RPL_ADMINLOC1_MSG, Client_ID(prefix),
  435. Conf_ServerAdmin1))
  436. return DISCONNECTED;
  437. if (!IRC_WriteStrClient(Client, RPL_ADMINLOC2_MSG, Client_ID(prefix),
  438. Conf_ServerAdmin2))
  439. return DISCONNECTED;
  440. if (!IRC_WriteStrClient(Client, RPL_ADMINEMAIL_MSG, Client_ID(prefix),
  441. Conf_ServerAdminMail))
  442. return DISCONNECTED;
  443. return CONNECTED;
  444. } /* IRC_ADMIN */
  445. /**
  446. * Handler for the IRC command "INFO".
  447. *
  448. * @param Client The client from which this command has been received.
  449. * @param Req Request structure with prefix and all parameters.
  450. * @return CONNECTED or DISCONNECTED.
  451. */
  452. GLOBAL bool
  453. IRC_INFO(CLIENT * Client, REQUEST * Req)
  454. {
  455. CLIENT *target, *prefix;
  456. char msg[510];
  457. assert(Client != NULL);
  458. assert(Req != NULL);
  459. IRC_SetPenalty(Client, 2);
  460. _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
  461. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
  462. /* Forward? */
  463. if (target != Client_ThisServer()) {
  464. IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
  465. Client_ID(target));
  466. return CONNECTED;
  467. }
  468. if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
  469. NGIRCd_Version))
  470. return DISCONNECTED;
  471. #if defined(__DATE__) && defined(__TIME__)
  472. snprintf(msg, sizeof(msg), "Birth Date: %s at %s", __DATE__, __TIME__);
  473. if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
  474. return DISCONNECTED;
  475. #endif
  476. strlcpy(msg, "On-line since ", sizeof(msg));
  477. strlcat(msg, NGIRCd_StartStr, sizeof(msg));
  478. if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
  479. return DISCONNECTED;
  480. if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
  481. return DISCONNECTED;
  482. return CONNECTED;
  483. } /* IRC_INFO */
  484. /**
  485. * Handler for the IRC "ISON" command.
  486. *
  487. * @param Client The client from which this command has been received.
  488. * @param Req Request structure with prefix and all parameters.
  489. * @return CONNECTED or DISCONNECTED.
  490. */
  491. GLOBAL bool
  492. IRC_ISON( CLIENT *Client, REQUEST *Req )
  493. {
  494. char rpl[COMMAND_LEN];
  495. CLIENT *c;
  496. char *ptr;
  497. int i;
  498. assert(Client != NULL);
  499. assert(Req != NULL);
  500. strlcpy(rpl, RPL_ISON_MSG, sizeof rpl);
  501. for (i = 0; i < Req->argc; i++) {
  502. /* "All" ircd even parse ":<x> <y> ..." arguments and split
  503. * them up; so we do the same ... */
  504. ptr = strtok(Req->argv[i], " ");
  505. while (ptr) {
  506. ngt_TrimStr(ptr);
  507. c = Client_Search(ptr);
  508. if (c && Client_Type(c) == CLIENT_USER) {
  509. strlcat(rpl, Client_ID(c), sizeof(rpl));
  510. strlcat(rpl, " ", sizeof(rpl));
  511. }
  512. ptr = strtok(NULL, " ");
  513. }
  514. }
  515. ngt_TrimLastChr(rpl, ' ');
  516. return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
  517. } /* IRC_ISON */
  518. /**
  519. * Handler for the IRC "LINKS" command.
  520. *
  521. * @param Client The client from which this command has been received.
  522. * @param Req Request structure with prefix and all parameters.
  523. * @return CONNECTED or DISCONNECTED.
  524. */
  525. GLOBAL bool
  526. IRC_LINKS(CLIENT *Client, REQUEST *Req)
  527. {
  528. CLIENT *target, *from, *c;
  529. char *mask;
  530. assert(Client != NULL);
  531. assert(Req != NULL);
  532. IRC_SetPenalty(Client, 1);
  533. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  534. /* Get pointer to server mask or "*", if none given */
  535. if (Req->argc > 0)
  536. mask = Req->argv[Req->argc - 1];
  537. else
  538. mask = "*";
  539. /* Forward? */
  540. if (Req->argc == 2) {
  541. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
  542. if (target != Client_ThisServer()) {
  543. IRC_WriteStrClientPrefix(target, from,
  544. "LINKS %s %s", Client_ID(target),
  545. Req->argv[1]);
  546. return CONNECTED;
  547. }
  548. }
  549. c = Client_First();
  550. while (c) {
  551. if (Client_Type(c) == CLIENT_SERVER
  552. && MatchCaseInsensitive(mask, Client_ID(c))) {
  553. if (!IRC_WriteStrClient(from, RPL_LINKS_MSG,
  554. Client_ID(from), Client_ID(c),
  555. Client_ID(Client_TopServer(c)
  556. ? Client_TopServer(c)
  557. : Client_ThisServer()),
  558. Client_Hops(c), Client_Info(c)))
  559. return DISCONNECTED;
  560. }
  561. c = Client_Next(c);
  562. }
  563. return IRC_WriteStrClient(from, RPL_ENDOFLINKS_MSG,
  564. Client_ID(from), mask);
  565. } /* IRC_LINKS */
  566. /**
  567. * Handler for the IRC "LUSERS" command.
  568. *
  569. * @param Client The client from which this command has been received.
  570. * @param Req Request structure with prefix and all parameters.
  571. * @return CONNECTED or DISCONNECTED.
  572. */
  573. GLOBAL bool
  574. IRC_LUSERS( CLIENT *Client, REQUEST *Req )
  575. {
  576. CLIENT *target, *from;
  577. assert( Client != NULL );
  578. assert( Req != NULL );
  579. IRC_SetPenalty(Client, 1);
  580. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  581. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
  582. /* Forward? */
  583. if (target != Client_ThisServer()) {
  584. IRC_WriteStrClientPrefix(target, from,
  585. "LUSERS %s %s", Req->argv[0],
  586. Client_ID(target));
  587. return CONNECTED;
  588. }
  589. return IRC_Send_LUSERS(from);
  590. } /* IRC_LUSERS */
  591. /**
  592. * Handler for the IRC command "SERVLIST".
  593. *
  594. * @param Client The client from which this command has been received.
  595. * @param Req Request structure with prefix and all parameters.
  596. * @return CONNECTED or DISCONNECTED.
  597. */
  598. GLOBAL bool
  599. IRC_SERVLIST(CLIENT *Client, REQUEST *Req)
  600. {
  601. CLIENT *c;
  602. assert(Client != NULL);
  603. assert(Req != NULL);
  604. IRC_SetPenalty(Client, 1);
  605. if (Req->argc < 2 || strcmp(Req->argv[1], "0") == 0) {
  606. for (c = Client_First(); c!= NULL; c = Client_Next(c)) {
  607. if (Client_Type(c) != CLIENT_SERVICE)
  608. continue;
  609. if (Req->argc > 0 && !MatchCaseInsensitive(Req->argv[0],
  610. Client_ID(c)))
  611. continue;
  612. if (!IRC_WriteStrClient(Client, RPL_SERVLIST_MSG,
  613. Client_ID(Client), Client_Mask(c),
  614. Client_Mask(Client_Introducer(c)), "*",
  615. 0, Client_Hops(c), Client_Info(c)))
  616. return DISCONNECTED;
  617. }
  618. }
  619. return IRC_WriteStrClient(Client, RPL_SERVLISTEND_MSG, Client_ID(Client),
  620. Req->argc > 0 ? Req->argv[0] : "*",
  621. Req->argc > 1 ? Req->argv[1] : "0");
  622. } /* IRC_SERVLIST */
  623. /**
  624. * Handler for the IRC command "MOTD".
  625. *
  626. * @param Client The client from which this command has been received.
  627. * @param Req Request structure with prefix and all parameters.
  628. * @return CONNECTED or DISCONNECTED.
  629. */
  630. GLOBAL bool
  631. IRC_MOTD( CLIENT *Client, REQUEST *Req )
  632. {
  633. CLIENT *from, *target;
  634. assert( Client != NULL );
  635. assert( Req != NULL );
  636. IRC_SetPenalty(Client, 3);
  637. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  638. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
  639. /* Forward? */
  640. if (target != Client_ThisServer()) {
  641. IRC_WriteStrClientPrefix(target, from, "MOTD %s",
  642. Client_ID(target));
  643. return CONNECTED;
  644. }
  645. return IRC_Show_MOTD(from);
  646. } /* IRC_MOTD */
  647. /**
  648. * Handler for the IRC command "NAMES".
  649. *
  650. * @param Client The client from which this command has been received.
  651. * @param Req Request structure with prefix and all parameters.
  652. * @return CONNECTED or DISCONNECTED.
  653. */
  654. GLOBAL bool
  655. IRC_NAMES( CLIENT *Client, REQUEST *Req )
  656. {
  657. char rpl[COMMAND_LEN], *ptr;
  658. CLIENT *target, *from, *c;
  659. CHANNEL *chan;
  660. assert( Client != NULL );
  661. assert( Req != NULL );
  662. IRC_SetPenalty(Client, 1);
  663. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  664. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
  665. /* Forward? */
  666. if (target != Client_ThisServer()) {
  667. IRC_WriteStrClientPrefix(target, from, "NAMES %s :%s",
  668. Req->argv[0], Client_ID(target));
  669. return CONNECTED;
  670. }
  671. if (Req->argc > 0) {
  672. /* Return NAMES list for specific channels */
  673. ptr = strtok(Req->argv[0], ",");
  674. while(ptr) {
  675. chan = Channel_Search(ptr);
  676. if (chan && !IRC_Send_NAMES(from, chan))
  677. return DISCONNECTED;
  678. if (!IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG,
  679. Client_ID(from), ptr))
  680. return DISCONNECTED;
  681. ptr = strtok( NULL, "," );
  682. }
  683. return CONNECTED;
  684. }
  685. chan = Channel_First();
  686. while (chan) {
  687. if (!IRC_Send_NAMES(from, chan))
  688. return DISCONNECTED;
  689. chan = Channel_Next(chan);
  690. }
  691. /* Now print all clients which are not in any channel */
  692. c = Client_First();
  693. snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG, Client_ID(from), "*", "*");
  694. while (c) {
  695. if (Client_Type(c) == CLIENT_USER
  696. && Channel_FirstChannelOf(c) == NULL
  697. && !Client_HasMode(c, 'i'))
  698. {
  699. /* its a user, concatenate ... */
  700. if (rpl[strlen(rpl) - 1] != ':')
  701. strlcat(rpl, " ", sizeof(rpl));
  702. strlcat(rpl, Client_ID(c), sizeof(rpl));
  703. if (strlen(rpl) > COMMAND_LEN - CLIENT_NICK_LEN - 4) {
  704. /* Line is gwoing too long, send now */
  705. if (!IRC_WriteStrClient(from, "%s", rpl))
  706. return DISCONNECTED;
  707. snprintf(rpl, sizeof(rpl), RPL_NAMREPLY_MSG,
  708. Client_ID(from), "*", "*");
  709. }
  710. }
  711. c = Client_Next(c);
  712. }
  713. if (rpl[strlen(rpl) - 1] != ':' && !IRC_WriteStrClient(from, "%s", rpl))
  714. return DISCONNECTED;
  715. return IRC_WriteStrClient(from, RPL_ENDOFNAMES_MSG, Client_ID(from), "*");
  716. } /* IRC_NAMES */
  717. /**
  718. * Handler for the IRC command "STATS".
  719. *
  720. * @param Client The client from which this command has been received.
  721. * @param Req Request structure with prefix and all parameters.
  722. * @return CONNECTED or DISCONNECTED.
  723. */
  724. GLOBAL bool
  725. IRC_STATS( CLIENT *Client, REQUEST *Req )
  726. {
  727. CLIENT *from, *target, *cl;
  728. CONN_ID con;
  729. char query;
  730. COMMAND *cmd;
  731. time_t time_now;
  732. unsigned int days, hrs, mins;
  733. struct list_head *list;
  734. struct list_elem *list_item;
  735. bool more_links = false;
  736. assert(Client != NULL);
  737. assert(Req != NULL);
  738. IRC_SetPenalty(Client, 2);
  739. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  740. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 1, from)
  741. /* Forward? */
  742. if (target != Client_ThisServer()) {
  743. IRC_WriteStrClientPrefix(target, from, "STATS %s %s",
  744. Req->argv[0], Client_ID(target));
  745. return CONNECTED;
  746. }
  747. if (Req->argc > 0)
  748. query = Req->argv[0][0] ? Req->argv[0][0] : '*';
  749. else
  750. query = '*';
  751. switch (query) {
  752. case 'g': /* Network-wide bans ("G-Lines") */
  753. case 'G':
  754. case 'k': /* Server-local bans ("K-Lines") */
  755. case 'K':
  756. if (!Client_HasMode(from, 'o'))
  757. return IRC_WriteErrClient(from, ERR_NOPRIVILEGES_MSG,
  758. Client_ID(from));
  759. if (query == 'g' || query == 'G')
  760. list = Class_GetList(CLASS_GLINE);
  761. else
  762. list = Class_GetList(CLASS_KLINE);
  763. list_item = Lists_GetFirst(list);
  764. while (list_item) {
  765. if (!IRC_WriteStrClient(from, RPL_STATSXLINE_MSG,
  766. Client_ID(from), query,
  767. Lists_GetMask(list_item),
  768. Lists_GetValidity(list_item),
  769. Lists_GetReason(list_item)))
  770. return DISCONNECTED;
  771. list_item = Lists_GetNext(list_item);
  772. }
  773. break;
  774. case 'L': /* Link status (servers and user links) */
  775. if (!Op_Check(from, Req))
  776. return Op_NoPrivileges(from, Req);
  777. more_links = true;
  778. case 'l': /* Link status (servers and own link) */
  779. time_now = time(NULL);
  780. for (con = Conn_First(); con != NONE; con = Conn_Next(con)) {
  781. cl = Conn_GetClient(con);
  782. if (!cl)
  783. continue;
  784. if (Client_Type(cl) == CLIENT_SERVER ||
  785. cl == Client ||
  786. (more_links && Client_Type(cl) == CLIENT_USER)) {
  787. #ifdef ZLIB
  788. if (Conn_Options(con) & CONN_ZIP) {
  789. if (!IRC_WriteStrClient
  790. (from, RPL_STATSLINKINFOZIP_MSG,
  791. Client_ID(from), Client_Mask(cl),
  792. Conn_SendQ(con), Conn_SendMsg(con),
  793. Zip_SendBytes(con),
  794. Conn_SendBytes(con),
  795. Conn_RecvMsg(con),
  796. Zip_RecvBytes(con),
  797. Conn_RecvBytes(con),
  798. (long)(time_now - Conn_StartTime(con))))
  799. return DISCONNECTED;
  800. continue;
  801. }
  802. #endif
  803. if (!IRC_WriteStrClient
  804. (from, RPL_STATSLINKINFO_MSG,
  805. Client_ID(from), Client_Mask(cl),
  806. Conn_SendQ(con), Conn_SendMsg(con),
  807. Conn_SendBytes(con), Conn_RecvMsg(con),
  808. Conn_RecvBytes(con),
  809. (long)(time_now - Conn_StartTime(con))))
  810. return DISCONNECTED;
  811. }
  812. }
  813. break;
  814. case 'm': /* IRC command status (usage count) */
  815. case 'M':
  816. cmd = Parse_GetCommandStruct();
  817. for (; cmd->name; cmd++) {
  818. if (cmd->lcount == 0 && cmd->rcount == 0)
  819. continue;
  820. if (!IRC_WriteStrClient
  821. (from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
  822. cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
  823. return DISCONNECTED;
  824. }
  825. break;
  826. case 'u': /* Server uptime */
  827. case 'U':
  828. time_now = time(NULL) - NGIRCd_Start;
  829. days = uptime_days(&time_now);
  830. hrs = uptime_hrs(&time_now);
  831. mins = uptime_mins(&time_now);
  832. if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
  833. days, hrs, mins, (unsigned int)time_now))
  834. return DISCONNECTED;
  835. break;
  836. }
  837. return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG,
  838. Client_ID(from), query);
  839. } /* IRC_STATS */
  840. /**
  841. * Handler for the IRC command "SUMMON".
  842. *
  843. * @param Client The client from which this command has been received.
  844. * @param Req Request structure with prefix and all parameters.
  845. * @return CONNECTED or DISCONNECTED.
  846. */
  847. GLOBAL bool
  848. IRC_SUMMON(CLIENT * Client, UNUSED REQUEST * Req)
  849. {
  850. assert(Client != NULL);
  851. return IRC_WriteErrClient(Client, ERR_SUMMONDISABLED_MSG,
  852. Client_ID(Client));
  853. } /* IRC_SUMMON */
  854. /**
  855. * Handler for the IRC command "TIME".
  856. *
  857. * @param Client The client from which this command has been received.
  858. * @param Req Request structure with prefix and all parameters.
  859. * @return CONNECTED or DISCONNECTED.
  860. */
  861. GLOBAL bool
  862. IRC_TIME( CLIENT *Client, REQUEST *Req )
  863. {
  864. CLIENT *from, *target;
  865. char t_str[64];
  866. time_t t;
  867. assert(Client != NULL);
  868. assert(Req != NULL);
  869. IRC_SetPenalty(Client, 1);
  870. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  871. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, from)
  872. /* Forward? */
  873. if (target != Client_ThisServer()) {
  874. IRC_WriteStrClientPrefix(target, from, "TIME %s",
  875. Client_ID(target));
  876. return CONNECTED;
  877. }
  878. t = time( NULL );
  879. (void)strftime(t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime(&t));
  880. return IRC_WriteStrClient(from, RPL_TIME_MSG, Client_ID(from),
  881. Client_ID(Client_ThisServer()), t_str);
  882. } /* IRC_TIME */
  883. /**
  884. * Handler for the IRC command "USERHOST".
  885. *
  886. * @param Client The client from which this command has been received.
  887. * @param Req Request structure with prefix and all parameters.
  888. * @return CONNECTED or DISCONNECTED.
  889. */
  890. GLOBAL bool
  891. IRC_USERHOST(CLIENT *Client, REQUEST *Req)
  892. {
  893. char rpl[COMMAND_LEN];
  894. CLIENT *c;
  895. int max, i;
  896. assert(Client != NULL);
  897. assert(Req != NULL);
  898. IRC_SetPenalty(Client, 1);
  899. if (Req->argc > 5)
  900. max = 5;
  901. else
  902. max = Req->argc;
  903. strlcpy(rpl, RPL_USERHOST_MSG, sizeof rpl);
  904. for (i = 0; i < max; i++) {
  905. c = Client_Search(Req->argv[i]);
  906. if (c && (Client_Type(c) == CLIENT_USER)) {
  907. /* This Nick is "online" */
  908. strlcat(rpl, Client_ID(c), sizeof(rpl));
  909. if (Client_HasMode(c, 'o'))
  910. strlcat(rpl, "*", sizeof(rpl));
  911. strlcat(rpl, "=", sizeof(rpl));
  912. if (Client_HasMode(c, 'a'))
  913. strlcat(rpl, "-", sizeof(rpl));
  914. else
  915. strlcat(rpl, "+", sizeof(rpl));
  916. strlcat(rpl, Client_User(c), sizeof(rpl));
  917. strlcat(rpl, "@", sizeof(rpl));
  918. strlcat(rpl, Client_HostnameDisplayed(c), sizeof(rpl));
  919. strlcat(rpl, " ", sizeof(rpl));
  920. }
  921. }
  922. ngt_TrimLastChr(rpl, ' ');
  923. return IRC_WriteStrClient(Client, rpl, Client_ID(Client));
  924. } /* IRC_USERHOST */
  925. /**
  926. * Handler for the IRC command "USERS".
  927. *
  928. * @param Client The client from which this command has been received.
  929. * @param Req Request structure with prefix and all parameters.
  930. * @return CONNECTED or DISCONNECTED.
  931. */
  932. GLOBAL bool
  933. IRC_USERS(CLIENT * Client, UNUSED REQUEST * Req)
  934. {
  935. assert(Client != NULL);
  936. return IRC_WriteErrClient(Client, ERR_USERSDISABLED_MSG,
  937. Client_ID(Client));
  938. } /* IRC_USERS */
  939. /**
  940. * Handler for the IRC command "VERSION".
  941. *
  942. * @param Client The client from which this command has been received.
  943. * @param Req Request structure with prefix and all parameters.
  944. * @return CONNECTED or DISCONNECTED.
  945. */
  946. GLOBAL bool
  947. IRC_VERSION( CLIENT *Client, REQUEST *Req )
  948. {
  949. CLIENT *target, *prefix;
  950. assert( Client != NULL );
  951. assert( Req != NULL );
  952. IRC_SetPenalty(Client, 1);
  953. _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
  954. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, prefix)
  955. /* Forward? */
  956. if (target != Client_ThisServer()) {
  957. IRC_WriteStrClientPrefix(target, prefix, "VERSION %s",
  958. Client_ID(target));
  959. return CONNECTED;
  960. }
  961. /* send version information */
  962. return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
  963. PACKAGE_NAME, PACKAGE_VERSION,
  964. NGIRCd_DebugLevel, Conf_ServerName,
  965. NGIRCd_VersionAddition);
  966. } /* IRC_VERSION */
  967. /**
  968. * Handler for the IRC "WHO" command.
  969. *
  970. * @param Client The client from which this command has been received.
  971. * @param Req Request structure with prefix and all parameters.
  972. * @return CONNECTED or DISCONNECTED.
  973. */
  974. GLOBAL bool
  975. IRC_WHO(CLIENT *Client, REQUEST *Req)
  976. {
  977. bool only_ops;
  978. CHANNEL *chan;
  979. assert (Client != NULL);
  980. assert (Req != NULL);
  981. IRC_SetPenalty(Client, 1);
  982. only_ops = false;
  983. if (Req->argc == 2) {
  984. if (strcmp(Req->argv[1], "o") == 0)
  985. only_ops = true;
  986. #ifdef STRICT_RFC
  987. else {
  988. IRC_SetPenalty(Client, 2);
  989. return IRC_WriteErrClient(Client,
  990. ERR_NEEDMOREPARAMS_MSG,
  991. Client_ID(Client),
  992. Req->command);
  993. }
  994. #endif
  995. }
  996. if (Req->argc >= 1) {
  997. /* Channel or mask given */
  998. chan = Channel_Search(Req->argv[0]);
  999. if (chan) {
  1000. /* Members of a channel have been requested */
  1001. return IRC_WHO_Channel(Client, chan, only_ops);
  1002. }
  1003. if (strcmp(Req->argv[0], "0") != 0) {
  1004. /* A mask has been given. But please note this RFC
  1005. * stupidity: "0" is same as no arguments ... */
  1006. return IRC_WHO_Mask(Client, Req->argv[0], only_ops);
  1007. }
  1008. }
  1009. /* No channel or (valid) mask given */
  1010. IRC_SetPenalty(Client, 2);
  1011. return IRC_WHO_Mask(Client, NULL, only_ops);
  1012. } /* IRC_WHO */
  1013. /**
  1014. * Handler for the IRC "WHOIS" command.
  1015. *
  1016. * @param Client The client from which this command has been received.
  1017. * @param Req Request structure with prefix and all parameters.
  1018. * @return CONNECTED or DISCONNECTED.
  1019. */
  1020. GLOBAL bool
  1021. IRC_WHOIS( CLIENT *Client, REQUEST *Req )
  1022. {
  1023. CLIENT *from, *target, *c;
  1024. unsigned int match_count = 0, found = 0;
  1025. bool has_wildcards, is_remote;
  1026. bool got_wildcard = false;
  1027. char mask[COMMAND_LEN], *query;
  1028. assert( Client != NULL );
  1029. assert( Req != NULL );
  1030. IRC_SetPenalty(Client, 1);
  1031. /* Wrong number of parameters? */
  1032. if (Req->argc < 1)
  1033. return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
  1034. Client_ID(Client));
  1035. _IRC_ARGC_LE_OR_RETURN_(Client, Req, 2)
  1036. _IRC_GET_SENDER_OR_RETURN_(from, Req, Client)
  1037. /* Get target server for this command */
  1038. if (Req->argc > 1) {
  1039. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 0, Client)
  1040. } else
  1041. target = Client_ThisServer();
  1042. assert(target != NULL);
  1043. /* Forward? */
  1044. if (target != Client_ThisServer()) {
  1045. IRC_WriteStrClientPrefix(target, from, "WHOIS %s :%s",
  1046. Req->argv[0], Req->argv[1]);
  1047. return CONNECTED;
  1048. }
  1049. is_remote = Client_Conn(from) < 0;
  1050. strlcpy(mask, Req->argv[Req->argc - 1], sizeof(mask));
  1051. for (query = strtok(ngt_LowerStr(mask), ",");
  1052. query && found < 3;
  1053. query = strtok(NULL, ","), found++)
  1054. {
  1055. has_wildcards = query[strcspn(query, "*?")] != 0;
  1056. /*
  1057. * follows ircd 2.10 implementation:
  1058. * - handle up to 3 targets
  1059. * - no wildcards for remote clients
  1060. * - only one wildcard target per local client
  1061. *
  1062. * Also, at most MAX_RPL_WHOIS matches are returned.
  1063. */
  1064. if (!has_wildcards || is_remote) {
  1065. c = Client_Search(query);
  1066. if (c && (Client_Type(c) == CLIENT_USER
  1067. || Client_Type(c) == CLIENT_SERVICE)) {
  1068. if (!IRC_WHOIS_SendReply(Client, from, c))
  1069. return DISCONNECTED;
  1070. } else {
  1071. if (!IRC_WriteErrClient(Client,
  1072. ERR_NOSUCHNICK_MSG,
  1073. Client_ID(Client),
  1074. query))
  1075. return DISCONNECTED;
  1076. }
  1077. continue;
  1078. }
  1079. if (got_wildcard) {
  1080. /* we already handled one wildcard query */
  1081. if (!IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
  1082. Client_ID(Client), query))
  1083. return DISCONNECTED;
  1084. continue;
  1085. }
  1086. got_wildcard = true;
  1087. IRC_SetPenalty(Client, 3);
  1088. for (c = Client_First(); c; c = Client_Next(c)) {
  1089. if (IRC_CheckListTooBig(Client, match_count,
  1090. MAX_RPL_WHOIS, "WHOIS"))
  1091. break;
  1092. if (Client_Type(c) != CLIENT_USER)
  1093. continue;
  1094. if (!MatchCaseInsensitive(query, Client_ID(c)))
  1095. continue;
  1096. if (!IRC_WHOIS_SendReply(Client, from, c))
  1097. return DISCONNECTED;
  1098. match_count++;
  1099. }
  1100. if (match_count == 0)
  1101. IRC_WriteErrClient(Client, ERR_NOSUCHNICK_MSG,
  1102. Client_ID(Client),
  1103. Req->argv[Req->argc - 1]);
  1104. }
  1105. return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG,
  1106. Client_ID(from), Req->argv[Req->argc - 1]);
  1107. } /* IRC_WHOIS */
  1108. /**
  1109. * Handler for the IRC "WHOWAS" command.
  1110. *
  1111. * @param Client The client from which this command has been received.
  1112. * @param Req Request structure with prefix and all parameters.
  1113. * @return CONNECTED or DISCONNECTED.
  1114. */
  1115. GLOBAL bool
  1116. IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
  1117. {
  1118. CLIENT *target, *prefix;
  1119. WHOWAS *whowas;
  1120. char tok_buf[COMMAND_LEN];
  1121. int max, last, count, i, nc;
  1122. const char *nick;
  1123. assert( Client != NULL );
  1124. assert( Req != NULL );
  1125. /* Wrong number of parameters? */
  1126. if (Req->argc < 1)
  1127. return IRC_WriteErrClient(Client, ERR_NONICKNAMEGIVEN_MSG,
  1128. Client_ID(Client));
  1129. _IRC_ARGC_LE_OR_RETURN_(Client, Req, 3)
  1130. _IRC_GET_SENDER_OR_RETURN_(prefix, Req, Client)
  1131. _IRC_GET_TARGET_SERVER_OR_RETURN_(target, Req, 2, prefix)
  1132. /* Do not reveal any info on disconnected users? */
  1133. if (Conf_MorePrivacy)
  1134. return CONNECTED;
  1135. /* Forward? */
  1136. if (target != Client_ThisServer()) {
  1137. IRC_WriteStrClientPrefix(target, prefix, "WHOWAS %s %s %s",
  1138. Req->argv[0], Req->argv[1],
  1139. Client_ID(target));
  1140. return CONNECTED;
  1141. }
  1142. whowas = Client_GetWhowas( );
  1143. last = Client_GetLastWhowasIndex( );
  1144. if (last < 0)
  1145. last = 0;
  1146. max = DEF_RPL_WHOWAS;
  1147. if (Req->argc > 1) {
  1148. max = atoi(Req->argv[1]);
  1149. if (max < 1)
  1150. max = MAX_RPL_WHOWAS;
  1151. }
  1152. /*
  1153. * Break up the nick argument into a list of nicks, if applicable
  1154. * Can't modify Req->argv[0] because we need it for RPL_ENDOFWHOWAS_MSG.
  1155. */
  1156. strlcpy(tok_buf, Req->argv[0], sizeof(tok_buf));
  1157. nick = strtok(tok_buf, ",");
  1158. for (i=last, count=0; nick != NULL ; nick = strtok(NULL, ",")) {
  1159. nc = 0;
  1160. do {
  1161. /* Used entry? */
  1162. if (whowas[i].time > 0 && strcasecmp(nick, whowas[i].id) == 0) {
  1163. if (!WHOWAS_EntryWrite(prefix, &whowas[i]))
  1164. return DISCONNECTED;
  1165. nc++;
  1166. count++;
  1167. }
  1168. /* previous entry */
  1169. i--;
  1170. /* "underflow", wrap around */
  1171. if (i < 0)
  1172. i = MAX_WHOWAS - 1;
  1173. if (nc && count >= max)
  1174. break;
  1175. } while (i != last);
  1176. if (nc == 0 && !IRC_WriteErrClient(prefix, ERR_WASNOSUCHNICK_MSG,
  1177. Client_ID(prefix), nick))
  1178. return DISCONNECTED;
  1179. }
  1180. return IRC_WriteStrClient(prefix, RPL_ENDOFWHOWAS_MSG,
  1181. Client_ID(prefix), Req->argv[0]);
  1182. } /* IRC_WHOWAS */
  1183. /**
  1184. * Send LUSERS reply to a client.
  1185. *
  1186. * @param Client The receipient of the information.
  1187. * @return CONNECTED or DISCONNECTED.
  1188. */
  1189. GLOBAL bool
  1190. IRC_Send_LUSERS(CLIENT *Client)
  1191. {
  1192. unsigned long cnt;
  1193. #ifndef STRICT_RFC
  1194. unsigned long max;
  1195. #endif
  1196. assert(Client != NULL);
  1197. /* Users, services and servers in the network */
  1198. if (!IRC_WriteStrClient(Client, RPL_LUSERCLIENT_MSG, Client_ID(Client),
  1199. Client_UserCount(), Client_ServiceCount(),
  1200. Client_ServerCount()))
  1201. return DISCONNECTED;
  1202. /* Number of IRC operators */
  1203. cnt = Client_OperCount( );
  1204. if (cnt > 0) {
  1205. if (!IRC_WriteStrClient(Client, RPL_LUSEROP_MSG,
  1206. Client_ID(Client), cnt))
  1207. return DISCONNECTED;
  1208. }
  1209. /* Unknown connections */
  1210. cnt = Client_UnknownCount( );
  1211. if (cnt > 0) {
  1212. if (!IRC_WriteStrClient(Client, RPL_LUSERUNKNOWN_MSG,
  1213. Client_ID(Client), cnt))
  1214. return DISCONNECTED;
  1215. }
  1216. /* Number of created channels */
  1217. if (!IRC_WriteStrClient(Client, RPL_LUSERCHANNELS_MSG,
  1218. Client_ID(Client),
  1219. Channel_CountVisible(Client)))
  1220. return DISCONNECTED;
  1221. /* Number of local users, services and servers */
  1222. if (!IRC_WriteStrClient(Client, RPL_LUSERME_MSG, Client_ID(Client),
  1223. Client_MyUserCount(), Client_MyServiceCount(),
  1224. Client_MyServerCount()))
  1225. return DISCONNECTED;
  1226. #ifndef STRICT_RFC
  1227. /* Maximum number of local users */
  1228. cnt = Client_MyUserCount();
  1229. max = Client_MyMaxUserCount();
  1230. if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
  1231. cnt, max, cnt, max))
  1232. return DISCONNECTED;
  1233. /* Maximum number of users in the network */
  1234. cnt = Client_UserCount();
  1235. max = Client_MaxUserCount();
  1236. if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
  1237. cnt, max, cnt, max))
  1238. return DISCONNECTED;
  1239. /* Connection counters */
  1240. if (! IRC_WriteStrClient(Client, RPL_STATSCONN_MSG, Client_ID(Client),
  1241. Conn_CountMax(), Conn_CountAccepted()))
  1242. return DISCONNECTED;
  1243. #endif
  1244. return CONNECTED;
  1245. } /* IRC_Send_LUSERS */
  1246. GLOBAL bool
  1247. IRC_Show_MOTD( CLIENT *Client )
  1248. {
  1249. const char *line;
  1250. size_t len_tot, len_str;
  1251. assert( Client != NULL );
  1252. len_tot = array_bytes(&Conf_Motd);
  1253. if (len_tot == 0 && !Conn_UsesSSL(Client_Conn(Client)))
  1254. return IRC_WriteErrClient(Client, ERR_NOMOTD_MSG, Client_ID(Client));
  1255. if (!IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG, Client_ID(Client),
  1256. Client_ID(Client_ThisServer())))
  1257. return DISCONNECTED;
  1258. line = array_start(&Conf_Motd);
  1259. while (len_tot > 0) {
  1260. len_str = strlen(line) + 1;
  1261. assert(len_tot >= len_str);
  1262. len_tot -= len_str;
  1263. if (!IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID(Client), line))
  1264. return DISCONNECTED;
  1265. line += len_str;
  1266. }
  1267. if (!Show_MOTD_SSLInfo(Client))
  1268. return DISCONNECTED;
  1269. if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
  1270. return DISCONNECTED;
  1271. if (*Conf_CloakHost)
  1272. return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
  1273. Client_ID(Client),
  1274. Client_Hostname(Client));
  1275. return CONNECTED;
  1276. } /* IRC_Show_MOTD */
  1277. /**
  1278. * Send NAMES reply for a specific client and channel.
  1279. *
  1280. * @param Client The client requesting the NAMES information.
  1281. * @param Chan The channel
  1282. * @return CONNECTED or DISCONNECTED.
  1283. */
  1284. GLOBAL bool
  1285. IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
  1286. {
  1287. bool is_visible, is_member;
  1288. char str[COMMAND_LEN];
  1289. CL2CHAN *cl2chan;
  1290. CLIENT *cl;
  1291. assert(Client != NULL);
  1292. assert(Chan != NULL);
  1293. if (Channel_IsMemberOf(Chan, Client))
  1294. is_member = true;
  1295. else
  1296. is_member = false;
  1297. /* Do not print info on channel memberships to anyone that is not member? */
  1298. if (Conf_MorePrivacy && !is_member)
  1299. return CONNECTED;
  1300. /* Secret channel? */
  1301. if (!is_member && Channel_HasMode(Chan, 's'))
  1302. return CONNECTED;
  1303. snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
  1304. Channel_Name(Chan));
  1305. cl2chan = Channel_FirstMember(Chan);
  1306. while (cl2chan) {
  1307. cl = Channel_GetClient(cl2chan);
  1308. if (Client_HasMode(cl, 'i'))
  1309. is_visible = false;
  1310. else
  1311. is_visible = true;
  1312. if (is_member || is_visible) {
  1313. if (str[strlen(str) - 1] != ':')
  1314. strlcat(str, " ", sizeof(str));
  1315. who_flags_qualifier(Client, Channel_UserModes(Chan, cl),
  1316. str, sizeof(str));
  1317. strlcat(str, Client_ID(cl), sizeof(str));
  1318. if (strlen(str) > (COMMAND_LEN - CLIENT_NICK_LEN - 4)) {
  1319. if (!IRC_WriteStrClient(Client, "%s", str))
  1320. return DISCONNECTED;
  1321. snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
  1322. Client_ID(Client), "=",
  1323. Channel_Name(Chan));
  1324. }
  1325. }
  1326. cl2chan = Channel_NextMember(Chan, cl2chan);
  1327. }
  1328. if (str[strlen(str) - 1] != ':') {
  1329. if (!IRC_WriteStrClient(Client, "%s", str))
  1330. return DISCONNECTED;
  1331. }
  1332. return CONNECTED;
  1333. } /* IRC_Send_NAMES */
  1334. /**
  1335. * Send the ISUPPORT numeric (005).
  1336. * This numeric indicates the features that are supported by this server.
  1337. * See <http://www.irc.org/tech_docs/005.html> for details.
  1338. */
  1339. GLOBAL bool
  1340. IRC_Send_ISUPPORT(CLIENT * Client)
  1341. {
  1342. if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
  1343. CHANTYPES, CHANTYPES, Conf_MaxJoins))
  1344. return DISCONNECTED;
  1345. return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
  1346. CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
  1347. COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
  1348. COMMAND_LEN - 113, MAX_HNDL_MODES_ARG,
  1349. MAX_HNDL_CHANNEL_LISTS);
  1350. } /* IRC_Send_ISUPPORT */
  1351. /* -eof- */