irc-info.c 40 KB

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