irc-info.c 44 KB

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