irc-info.c 40 KB

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