irc-info.c 42 KB

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