irc-info.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271
  1. /*
  2. * ngIRCd -- The Next Generation IRC Daemon
  3. * Copyright (c)2001-2008 Alexander Barton (alex@barton.de)
  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. * IRC info commands
  12. */
  13. #include "portab.h"
  14. #include "imp.h"
  15. #include <assert.h>
  16. #include <errno.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <strings.h>
  21. #include "ngircd.h"
  22. #include "conn-func.h"
  23. #include "conn-zip.h"
  24. #include "client.h"
  25. #include "channel.h"
  26. #include "resolve.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. /* Falsche Anzahl Parameter? */
  44. if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  45. /* Ziel suchen */
  46. if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
  47. else target = Client_ThisServer( );
  48. /* Prefix ermitteln */
  49. if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
  50. else prefix = Client;
  51. if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  52. /* An anderen Server weiterleiten? */
  53. if( target != Client_ThisServer( ))
  54. {
  55. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
  56. /* forwarden */
  57. IRC_WriteStrClientPrefix( target, prefix, "ADMIN %s", Req->argv[0] );
  58. return CONNECTED;
  59. }
  60. /* mit Versionsinfo antworten */
  61. if( ! IRC_WriteStrClient( Client, RPL_ADMINME_MSG, Client_ID( prefix ), Conf_ServerName )) return DISCONNECTED;
  62. if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC1_MSG, Client_ID( prefix ), Conf_ServerAdmin1 )) return DISCONNECTED;
  63. if( ! IRC_WriteStrClient( Client, RPL_ADMINLOC2_MSG, Client_ID( prefix ), Conf_ServerAdmin2 )) return DISCONNECTED;
  64. if( ! IRC_WriteStrClient( Client, RPL_ADMINEMAIL_MSG, Client_ID( prefix ), Conf_ServerAdminMail )) return DISCONNECTED;
  65. IRC_SetPenalty( Client, 1 );
  66. return CONNECTED;
  67. } /* IRC_ADMIN */
  68. /**
  69. * Handler for the IRC command "INFO".
  70. * See RFC 2812 section 3.4.10.
  71. */
  72. GLOBAL bool
  73. IRC_INFO(CLIENT * Client, REQUEST * Req)
  74. {
  75. CLIENT *target, *prefix;
  76. char msg[510];
  77. assert(Client != NULL);
  78. assert(Req != NULL);
  79. /* Wrong number of parameters? */
  80. if (Req->argc > 1)
  81. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
  82. Client_ID(Client), Req->command);
  83. /* Determine prefix */
  84. if (Client_Type(Client) == CLIENT_SERVER)
  85. prefix = Client_Search(Req->prefix);
  86. else
  87. prefix = Client;
  88. if (!prefix)
  89. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
  90. Client_ID(Client), Req->prefix);
  91. /* Look for a target */
  92. if (Req->argc > 0)
  93. target = Client_Search(Req->argv[0]);
  94. else
  95. target = Client_ThisServer();
  96. /* Make sure that the target is a server */
  97. if (target && Client_Type(target) != CLIENT_SERVER)
  98. target = Client_Introducer(target);
  99. if (!target)
  100. return IRC_WriteStrClient(prefix, ERR_NOSUCHSERVER_MSG,
  101. Client_ID(prefix), Req->argv[0]);
  102. /* Pass on to another server? */
  103. if (target != Client_ThisServer()) {
  104. IRC_WriteStrClientPrefix(target, prefix, "INFO %s",
  105. Req->argv[0]);
  106. return CONNECTED;
  107. }
  108. if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix),
  109. NGIRCd_Version))
  110. return DISCONNECTED;
  111. strlcpy(msg, "Server has been started ", sizeof(msg));
  112. strlcat(msg, NGIRCd_StartStr, sizeof(msg));
  113. if (!IRC_WriteStrClient(Client, RPL_INFO_MSG, Client_ID(prefix), msg))
  114. return DISCONNECTED;
  115. if (!IRC_WriteStrClient(Client, RPL_ENDOFINFO_MSG, Client_ID(prefix)))
  116. return DISCONNECTED;
  117. IRC_SetPenalty(Client, 2);
  118. return CONNECTED;
  119. } /* IRC_INFO */
  120. GLOBAL bool
  121. IRC_ISON( CLIENT *Client, REQUEST *Req )
  122. {
  123. char rpl[COMMAND_LEN];
  124. CLIENT *c;
  125. char *ptr;
  126. int i;
  127. assert( Client != NULL );
  128. assert( Req != NULL );
  129. /* Falsche Anzahl Parameter? */
  130. if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  131. strlcpy( rpl, RPL_ISON_MSG, sizeof rpl );
  132. for( i = 0; i < Req->argc; i++ )
  133. {
  134. ptr = strtok( Req->argv[i], " " );
  135. while( ptr )
  136. {
  137. ngt_TrimStr( ptr );
  138. c = Client_Search( ptr );
  139. if( c && ( Client_Type( c ) == CLIENT_USER ))
  140. {
  141. /* Dieser Nick ist "online" */
  142. strlcat( rpl, ptr, sizeof( rpl ));
  143. strlcat( rpl, " ", sizeof( rpl ));
  144. }
  145. ptr = strtok( NULL, " " );
  146. }
  147. }
  148. ngt_TrimLastChr(rpl, ' ');
  149. return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
  150. } /* IRC_ISON */
  151. GLOBAL bool
  152. IRC_LINKS( CLIENT *Client, REQUEST *Req )
  153. {
  154. CLIENT *target, *from, *c;
  155. char *mask;
  156. assert( Client != NULL );
  157. assert( Req != NULL );
  158. /* Falsche Anzahl Parameter? */
  159. if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  160. /* Server-Mask ermitteln */
  161. if( Req->argc > 0 ) mask = Req->argv[Req->argc - 1];
  162. else mask = "*";
  163. /* Absender ermitteln */
  164. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  165. else from = Client;
  166. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  167. /* An anderen Server forwarden? */
  168. if( Req->argc == 2 )
  169. {
  170. target = Client_Search( Req->argv[0] );
  171. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
  172. else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LINKS %s %s", Req->argv[0], Req->argv[1] );
  173. }
  174. /* Wer ist der Absender? */
  175. if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
  176. else target = Client;
  177. if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  178. c = Client_First( );
  179. while( c )
  180. {
  181. if( Client_Type( c ) == CLIENT_SERVER )
  182. {
  183. 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;
  184. }
  185. c = Client_Next( c );
  186. }
  187. IRC_SetPenalty( target, 1 );
  188. return IRC_WriteStrClient( target, RPL_ENDOFLINKS_MSG, Client_ID( target ), mask );
  189. } /* IRC_LINKS */
  190. GLOBAL bool
  191. IRC_LUSERS( CLIENT *Client, REQUEST *Req )
  192. {
  193. CLIENT *target, *from;
  194. assert( Client != NULL );
  195. assert( Req != NULL );
  196. /* Falsche Anzahl Parameter? */
  197. if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  198. /* Absender ermitteln */
  199. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  200. else from = Client;
  201. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  202. /* An anderen Server forwarden? */
  203. if( Req->argc == 2 )
  204. {
  205. target = Client_Search( Req->argv[1] );
  206. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
  207. else if( target != Client_ThisServer( )) return IRC_WriteStrClientPrefix( target, from, "LUSERS %s %s", Req->argv[0], Req->argv[1] );
  208. }
  209. /* Wer ist der Absender? */
  210. if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
  211. else target = Client;
  212. if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  213. IRC_Send_LUSERS( target );
  214. IRC_SetPenalty( target, 1 );
  215. return CONNECTED;
  216. } /* IRC_LUSERS */
  217. GLOBAL bool
  218. IRC_MOTD( CLIENT *Client, REQUEST *Req )
  219. {
  220. CLIENT *from, *target;
  221. assert( Client != NULL );
  222. assert( Req != NULL );
  223. /* Falsche Anzahl Parameter? */
  224. if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  225. /* From aus Prefix ermitteln */
  226. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  227. else from = Client;
  228. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  229. if( Req->argc == 1 )
  230. {
  231. /* an anderen Server forwarden */
  232. target = Client_Search( Req->argv[0] );
  233. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
  234. if( target != Client_ThisServer( ))
  235. {
  236. /* Ok, anderer Server ist das Ziel: forwarden */
  237. return IRC_WriteStrClientPrefix( target, from, "MOTD %s", Req->argv[0] );
  238. }
  239. }
  240. IRC_SetPenalty( from, 3 );
  241. return IRC_Show_MOTD( from );
  242. } /* IRC_MOTD */
  243. GLOBAL bool
  244. IRC_NAMES( CLIENT *Client, REQUEST *Req )
  245. {
  246. char rpl[COMMAND_LEN], *ptr;
  247. CLIENT *target, *from, *c;
  248. CHANNEL *chan;
  249. assert( Client != NULL );
  250. assert( Req != NULL );
  251. /* Falsche Anzahl Parameter? */
  252. if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  253. /* From aus Prefix ermitteln */
  254. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  255. else from = Client;
  256. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  257. if( Req->argc == 2 )
  258. {
  259. /* an anderen Server forwarden */
  260. target = Client_Search( Req->argv[1] );
  261. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
  262. if( target != Client_ThisServer( ))
  263. {
  264. /* Ok, anderer Server ist das Ziel: forwarden */
  265. return IRC_WriteStrClientPrefix( target, from, "NAMES %s :%s", Req->argv[0], Req->argv[1] );
  266. }
  267. }
  268. if( Req->argc > 0 )
  269. {
  270. /* bestimmte Channels durchgehen */
  271. ptr = strtok( Req->argv[0], "," );
  272. while( ptr )
  273. {
  274. chan = Channel_Search( ptr );
  275. if( chan )
  276. {
  277. /* Namen ausgeben */
  278. if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
  279. }
  280. if( ! IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), ptr )) return DISCONNECTED;
  281. /* naechsten Namen ermitteln */
  282. ptr = strtok( NULL, "," );
  283. }
  284. return CONNECTED;
  285. }
  286. /* alle Channels durchgehen */
  287. chan = Channel_First( );
  288. while( chan )
  289. {
  290. /* Namen ausgeben */
  291. if( ! IRC_Send_NAMES( from, chan )) return DISCONNECTED;
  292. /* naechster Channel */
  293. chan = Channel_Next( chan );
  294. }
  295. /* Nun noch alle Clients ausgeben, die in keinem Channel sind */
  296. c = Client_First( );
  297. snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
  298. while( c )
  299. {
  300. if(( Client_Type( c ) == CLIENT_USER ) && ( Channel_FirstChannelOf( c ) == NULL ) && ( ! strchr( Client_Modes( c ), 'i' )))
  301. {
  302. /* Okay, das ist ein User: anhaengen */
  303. if( rpl[strlen( rpl ) - 1] != ':' ) strlcat( rpl, " ", sizeof( rpl ));
  304. strlcat( rpl, Client_ID( c ), sizeof( rpl ));
  305. if( strlen( rpl ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
  306. {
  307. /* Zeile wird zu lang: senden! */
  308. if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
  309. snprintf( rpl, sizeof( rpl ), RPL_NAMREPLY_MSG, Client_ID( from ), "*", "*" );
  310. }
  311. }
  312. /* naechster Client */
  313. c = Client_Next( c );
  314. }
  315. if( rpl[strlen( rpl ) - 1] != ':')
  316. {
  317. /* es wurden User gefunden */
  318. if( ! IRC_WriteStrClient( from, "%s", rpl )) return DISCONNECTED;
  319. }
  320. IRC_SetPenalty( from, 1 );
  321. return IRC_WriteStrClient( from, RPL_ENDOFNAMES_MSG, Client_ID( from ), "*" );
  322. } /* IRC_NAMES */
  323. static unsigned int
  324. t_diff(time_t *t, const time_t div)
  325. {
  326. time_t diff, remain;
  327. diff = *t / div;
  328. remain = diff * div;
  329. *t -= remain;
  330. return diff;
  331. }
  332. static unsigned int
  333. uptime_days(time_t *now)
  334. {
  335. return t_diff(now, 60 * 60 * 24);
  336. }
  337. static unsigned int
  338. uptime_hrs(time_t *now)
  339. {
  340. return t_diff(now, 60 * 60);
  341. }
  342. static unsigned int
  343. uptime_mins(time_t *now)
  344. {
  345. return t_diff(now, 60);
  346. }
  347. GLOBAL bool
  348. IRC_STATS( CLIENT *Client, REQUEST *Req )
  349. {
  350. CLIENT *from, *target, *cl;
  351. CONN_ID con;
  352. char query;
  353. COMMAND *cmd;
  354. time_t time_now;
  355. unsigned int days, hrs, mins;
  356. assert( Client != NULL );
  357. assert( Req != NULL );
  358. /* Falsche Anzahl Parameter? */
  359. if (Req->argc > 2)
  360. return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
  361. /* From aus Prefix ermitteln */
  362. if (Client_Type(Client) == CLIENT_SERVER)
  363. from = Client_Search(Req->prefix);
  364. else
  365. from = Client;
  366. if (! from)
  367. return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix);
  368. if (Req->argc == 2) {
  369. /* an anderen Server forwarden */
  370. target = Client_Search( Req->argv[1] );
  371. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
  372. return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[1] );
  373. if( target != Client_ThisServer()) {
  374. /* Ok, anderer Server ist das Ziel: forwarden */
  375. return IRC_WriteStrClientPrefix( target, from, "STATS %s %s", Req->argv[0], Req->argv[1] );
  376. }
  377. }
  378. if (Req->argc > 0)
  379. query = Req->argv[0][0] ? Req->argv[0][0] : '*';
  380. else
  381. query = '*';
  382. switch (query) {
  383. case 'l': /* Links */
  384. case 'L':
  385. time_now = time(NULL);
  386. for (con = Conn_First(); con != NONE ;con = Conn_Next(con)) {
  387. cl = Conn_GetClient(con);
  388. if (!cl)
  389. continue;
  390. if ((Client_Type(cl) == CLIENT_SERVER) || (cl == Client)) {
  391. /* Server link or our own connection */
  392. #ifdef ZLIB
  393. if (Conn_Options(con) & CONN_ZIP) {
  394. if (!IRC_WriteStrClient(from, RPL_STATSLINKINFOZIP_MSG,
  395. Client_ID(from), Client_Mask(cl), Conn_SendQ(con),
  396. Conn_SendMsg(con), Zip_SendBytes(con), Conn_SendBytes(con),
  397. Conn_RecvMsg(con), Zip_RecvBytes(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
  398. return DISCONNECTED;
  399. continue;
  400. }
  401. #endif
  402. if (!IRC_WriteStrClient(from, RPL_STATSLINKINFO_MSG, Client_ID(from),
  403. Client_Mask(cl), Conn_SendQ(con), Conn_SendMsg(con), Conn_SendBytes(con),
  404. Conn_RecvMsg(con), Conn_RecvBytes(con), (long)(time_now - Conn_StartTime(con))))
  405. return DISCONNECTED;
  406. }
  407. }
  408. break;
  409. case 'm': /* IRC-Commands */
  410. case 'M':
  411. cmd = Parse_GetCommandStruct( );
  412. for (; cmd->name ; cmd++) {
  413. if (cmd->lcount == 0 && cmd->rcount == 0)
  414. continue;
  415. if (!IRC_WriteStrClient(from, RPL_STATSCOMMANDS_MSG, Client_ID(from),
  416. cmd->name, cmd->lcount, cmd->bytes, cmd->rcount))
  417. return DISCONNECTED;
  418. }
  419. break;
  420. case 'u': /* server uptime */
  421. case 'U':
  422. time_now = time(NULL) - NGIRCd_Start;
  423. days = uptime_days(&time_now);
  424. hrs = uptime_hrs(&time_now);
  425. mins = uptime_mins(&time_now);
  426. if (!IRC_WriteStrClient(from, RPL_STATSUPTIME, Client_ID(from),
  427. days, hrs, mins, (unsigned int) time_now))
  428. return DISCONNECTED;
  429. break;
  430. }
  431. IRC_SetPenalty(from, 2);
  432. return IRC_WriteStrClient(from, RPL_ENDOFSTATS_MSG, Client_ID(from), query);
  433. } /* IRC_STATS */
  434. /**
  435. * Handler for the IRC command "SUMMON".
  436. * See RFC 2812 section 4.5. ngIRCd doesn't implement this functionality and
  437. * therefore answers with ERR_SUMMONDISABLED.
  438. */
  439. GLOBAL bool
  440. IRC_SUMMON(CLIENT * Client, REQUEST * Req)
  441. {
  442. return IRC_WriteStrClient(Client, ERR_SUMMONDISABLED_MSG,
  443. Client_ID(Client), Req->command);
  444. } /* IRC_SUMMON */
  445. GLOBAL bool
  446. IRC_TIME( CLIENT *Client, REQUEST *Req )
  447. {
  448. CLIENT *from, *target;
  449. char t_str[64];
  450. time_t t;
  451. assert( Client != NULL );
  452. assert( Req != NULL );
  453. /* Falsche Anzahl Parameter? */
  454. if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  455. /* From aus Prefix ermitteln */
  456. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  457. else from = Client;
  458. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  459. if( Req->argc == 1 )
  460. {
  461. /* an anderen Server forwarden */
  462. target = Client_Search( Req->argv[0] );
  463. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[0] );
  464. if( target != Client_ThisServer( ))
  465. {
  466. /* Ok, anderer Server ist das Ziel: forwarden */
  467. return IRC_WriteStrClientPrefix( target, from, "TIME %s", Req->argv[0] );
  468. }
  469. }
  470. t = time( NULL );
  471. (void)strftime( t_str, 60, "%A %B %d %Y -- %H:%M %Z", localtime( &t ));
  472. return IRC_WriteStrClient( from, RPL_TIME_MSG, Client_ID( from ), Client_ID( Client_ThisServer( )), t_str );
  473. } /* IRC_TIME */
  474. GLOBAL bool
  475. IRC_USERHOST( CLIENT *Client, REQUEST *Req )
  476. {
  477. char rpl[COMMAND_LEN];
  478. CLIENT *c;
  479. int max, i;
  480. assert( Client != NULL );
  481. assert( Req != NULL );
  482. /* Falsche Anzahl Parameter? */
  483. if(( Req->argc < 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  484. if( Req->argc > 5 ) max = 5;
  485. else max = Req->argc;
  486. strlcpy( rpl, RPL_USERHOST_MSG, sizeof rpl );
  487. for( i = 0; i < max; i++ )
  488. {
  489. c = Client_Search( Req->argv[i] );
  490. if( c && ( Client_Type( c ) == CLIENT_USER ))
  491. {
  492. /* Dieser Nick ist "online" */
  493. strlcat( rpl, Client_ID( c ), sizeof( rpl ));
  494. if( Client_HasMode( c, 'o' )) strlcat( rpl, "*", sizeof( rpl ));
  495. strlcat( rpl, "=", sizeof( rpl ));
  496. if( Client_HasMode( c, 'a' )) strlcat( rpl, "-", sizeof( rpl ));
  497. else strlcat( rpl, "+", sizeof( rpl ));
  498. strlcat( rpl, Client_User( c ), sizeof( rpl ));
  499. strlcat( rpl, "@", sizeof( rpl ));
  500. strlcat( rpl, Client_Hostname( c ), sizeof( rpl ));
  501. strlcat( rpl, " ", sizeof( rpl ));
  502. }
  503. }
  504. ngt_TrimLastChr( rpl, ' ');
  505. return IRC_WriteStrClient( Client, rpl, Client_ID( Client ) );
  506. } /* IRC_USERHOST */
  507. /**
  508. * Handler for the IRC command "USERS".
  509. * See RFC 2812 section 4.6. As suggested there the command is disabled.
  510. */
  511. GLOBAL bool
  512. IRC_USERS(CLIENT * Client, REQUEST * Req)
  513. {
  514. return IRC_WriteStrClient(Client, ERR_USERSDISABLED_MSG,
  515. Client_ID(Client), Req->command);
  516. } /* IRC_USERS */
  517. GLOBAL bool
  518. IRC_VERSION( CLIENT *Client, REQUEST *Req )
  519. {
  520. CLIENT *target, *prefix;
  521. assert( Client != NULL );
  522. assert( Req != NULL );
  523. /* Falsche Anzahl Parameter? */
  524. if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  525. /* Ziel suchen */
  526. if( Req->argc == 1 ) target = Client_Search( Req->argv[0] );
  527. else target = Client_ThisServer( );
  528. /* Prefix ermitteln */
  529. if( Client_Type( Client ) == CLIENT_SERVER ) prefix = Client_Search( Req->prefix );
  530. else prefix = Client;
  531. if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  532. /* An anderen Server weiterleiten? */
  533. if( target != Client_ThisServer( ))
  534. {
  535. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER )) return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG, Client_ID( prefix ), Req->argv[0] );
  536. /* forwarden */
  537. IRC_WriteStrClientPrefix( target, prefix, "VERSION %s", Req->argv[0] );
  538. return CONNECTED;
  539. }
  540. /* send version information */
  541. IRC_SetPenalty(Client, 1);
  542. return IRC_WriteStrClient(Client, RPL_VERSION_MSG, Client_ID(prefix),
  543. PACKAGE_NAME, PACKAGE_VERSION,
  544. NGIRCd_DebugLevel, Conf_ServerName,
  545. NGIRCd_VersionAddition);
  546. } /* IRC_VERSION */
  547. static bool
  548. write_whoreply(CLIENT *Client, CLIENT *c, const char *channelname, const char *flags)
  549. {
  550. return IRC_WriteStrClient(Client, RPL_WHOREPLY_MSG, Client_ID(Client), channelname,
  551. Client_User(c), Client_Hostname(c), Client_ID(Client_Introducer(c)), Client_ID(c),
  552. flags, Client_Hops(c), Client_Info(c));
  553. }
  554. static const char *
  555. who_flags_status(const char *client_modes)
  556. {
  557. if (strchr(client_modes, 'a'))
  558. return "G"; /* away */
  559. return "H";
  560. }
  561. static const char *
  562. who_flags_qualifier(const char *chan_user_modes)
  563. {
  564. if (strchr(chan_user_modes, 'o'))
  565. return "@";
  566. else if (strchr(chan_user_modes, 'v'))
  567. return "+";
  568. return "";
  569. }
  570. static bool
  571. IRC_Send_WHO(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
  572. {
  573. bool is_visible, is_member, is_ircop;
  574. CL2CHAN *cl2chan;
  575. const char *client_modes;
  576. const char *chan_user_modes;
  577. char flags[8];
  578. CLIENT *c;
  579. assert( Client != NULL );
  580. assert( Chan != NULL );
  581. is_member = Channel_IsMemberOf(Chan, Client);
  582. /* Secret channel? */
  583. if (!is_member && strchr(Channel_Modes(Chan), 's'))
  584. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
  585. cl2chan = Channel_FirstMember(Chan);
  586. for (; cl2chan ; cl2chan = Channel_NextMember(Chan, cl2chan)) {
  587. c = Channel_GetClient(cl2chan);
  588. client_modes = Client_Modes(c);
  589. is_ircop = strchr(client_modes, 'o') != NULL;
  590. if (OnlyOps && !is_ircop)
  591. continue;
  592. is_visible = strchr(client_modes, 'i') == NULL;
  593. if (is_member || is_visible) {
  594. strcpy(flags, who_flags_status(client_modes));
  595. if (is_ircop)
  596. strlcat(flags, "*", sizeof(flags));
  597. chan_user_modes = Channel_UserModes(Chan, c);
  598. strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
  599. if (!write_whoreply(Client, c, Channel_Name(Chan), flags))
  600. return DISCONNECTED;
  601. }
  602. }
  603. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), Channel_Name(Chan));
  604. } /* IRC_Send_WHO */
  605. static bool
  606. MatchCaseInsensitive(const char *pattern, const char *searchme)
  607. {
  608. char haystack[COMMAND_LEN];
  609. strlcpy(haystack, searchme, sizeof(haystack));
  610. ngt_LowerStr(haystack);
  611. return Match(pattern, haystack);
  612. }
  613. GLOBAL bool
  614. IRC_WHO( CLIENT *Client, REQUEST *Req )
  615. {
  616. bool only_ops, have_arg, client_match;
  617. const char *channelname, *client_modes, *chan_user_modes;
  618. char pattern[COMMAND_LEN];
  619. char flags[4];
  620. CL2CHAN *cl2chan;
  621. CHANNEL *chan, *cn;
  622. CLIENT *c;
  623. assert( Client != NULL );
  624. assert( Req != NULL );
  625. if (Req->argc > 2)
  626. return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  627. only_ops = false;
  628. have_arg = false;
  629. if (Req->argc == 2) {
  630. if (strcmp(Req->argv[1], "o") == 0)
  631. only_ops = true;
  632. #ifdef STRICT_RFC
  633. else return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG, Client_ID(Client), Req->command);
  634. #endif
  635. }
  636. IRC_SetPenalty(Client, 1);
  637. if (Req->argc >= 1) { /* Channel or Mask. */
  638. chan = Channel_Search(Req->argv[0]);
  639. if (chan)
  640. return IRC_Send_WHO(Client, chan, only_ops);
  641. if (strcmp(Req->argv[0], "0") != 0) { /* RFC stupidity, same as no arguments */
  642. have_arg = true;
  643. strlcpy(pattern, Req->argv[0], sizeof(pattern));
  644. ngt_LowerStr(pattern);
  645. IRC_SetPenalty(Client, 3);
  646. }
  647. }
  648. for (c = Client_First(); c != NULL; c = Client_Next(c)) {
  649. if (Client_Type(c) != CLIENT_USER)
  650. continue;
  651. /*
  652. * RFC 2812, 3.6.1:
  653. * In the absence of the parameter, all visible (users who aren't
  654. * invisible (user mode +i) and who don't have a common channel
  655. * with the requesting client) are listed.
  656. *
  657. * The same result can be achieved by using a [sic] of "0"
  658. * or any wildcard which will end up matching every visible user.
  659. *
  660. * The [sic] passed to WHO is matched against users' host, server, real name and
  661. * nickname if the channel cannot be found.
  662. */
  663. client_modes = Client_Modes(c);
  664. if (strchr(client_modes, 'i'))
  665. continue;
  666. if (only_ops && !strchr(client_modes, 'o'))
  667. continue;
  668. if (have_arg) { /* match pattern against user host/server/name/nick */
  669. client_match = MatchCaseInsensitive(pattern, Client_Hostname(c)); /* user's host */
  670. if (!client_match)
  671. client_match = MatchCaseInsensitive(pattern, Client_ID(Client_Introducer(c))); /* server */
  672. if (!client_match)
  673. client_match = Match(Req->argv[0], Client_Info(c)); /* realname */
  674. if (!client_match)
  675. client_match = MatchCaseInsensitive(pattern, Client_ID(c)); /* nick name */
  676. if (!client_match) /* This isn't the client you're looking for */
  677. continue;
  678. }
  679. strcpy(flags, who_flags_status(client_modes));
  680. if (strchr(client_modes, 'o')) /* this client is an operator */
  681. strlcat(flags, "*", sizeof(flags));
  682. /* Search suitable channel */
  683. cl2chan = Channel_FirstChannelOf(c);
  684. while (cl2chan) {
  685. cn = Channel_GetChannel(cl2chan);
  686. if (Channel_IsMemberOf(cn, Client) ||
  687. !strchr(Channel_Modes(cn), 's'))
  688. {
  689. channelname = Channel_Name(cn);
  690. break;
  691. }
  692. cl2chan = Channel_NextChannelOf(c, cl2chan);
  693. }
  694. if (cl2chan) {
  695. chan = Channel_GetChannel(cl2chan);
  696. chan_user_modes = Channel_UserModes(chan, c);
  697. strlcat(flags, who_flags_qualifier(chan_user_modes), sizeof(flags));
  698. } else
  699. channelname = "*";
  700. if (!write_whoreply(Client, c, channelname, flags))
  701. return DISCONNECTED;
  702. }
  703. if (Req->argc > 0)
  704. channelname = Req->argv[0];
  705. else
  706. channelname = "*";
  707. return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client), channelname);
  708. } /* IRC_WHO */
  709. GLOBAL bool
  710. IRC_WHOIS( CLIENT *Client, REQUEST *Req )
  711. {
  712. CLIENT *from, *target, *c;
  713. char str[LINE_LEN + 1];
  714. CL2CHAN *cl2chan;
  715. CHANNEL *chan;
  716. assert( Client != NULL );
  717. assert( Req != NULL );
  718. /* Bad number of parameters? */
  719. if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
  720. /* Search client */
  721. c = Client_Search( Req->argv[Req->argc - 1] );
  722. if(( ! c ) || ( Client_Type( c ) != CLIENT_USER )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[Req->argc - 1] );
  723. /* Search sender of the WHOIS */
  724. if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
  725. else from = Client;
  726. if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
  727. /* Forward to other server? */
  728. if( Req->argc > 1 )
  729. {
  730. /* Search target server (can be specified as nick of that server!) */
  731. target = Client_Search( Req->argv[0] );
  732. if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( from ), Req->argv[0] );
  733. }
  734. else target = Client_ThisServer( );
  735. assert( target != NULL );
  736. if(( Client_NextHop( target ) != Client_ThisServer( )) && ( Client_Type( Client_NextHop( target )) == CLIENT_SERVER )) return IRC_WriteStrClientPrefix( target, from, "WHOIS %s :%s", Req->argv[0], Req->argv[1] );
  737. /* Nick, user and name */
  738. if( ! IRC_WriteStrClient( from, RPL_WHOISUSER_MSG, Client_ID( from ), Client_ID( c ), Client_User( c ), Client_Hostname( c ), Client_Info( c ))) return DISCONNECTED;
  739. /* Server */
  740. if( ! IRC_WriteStrClient( from, RPL_WHOISSERVER_MSG, Client_ID( from ), Client_ID( c ), Client_ID( Client_Introducer( c )), Client_Info( Client_Introducer( c )))) return DISCONNECTED;
  741. /* Channels */
  742. snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
  743. cl2chan = Channel_FirstChannelOf( c );
  744. while( cl2chan )
  745. {
  746. chan = Channel_GetChannel( cl2chan );
  747. assert( chan != NULL );
  748. /* next */
  749. cl2chan = Channel_NextChannelOf( c, cl2chan );
  750. /* Secret channel? */
  751. if( strchr( Channel_Modes( chan ), 's' ) && ! Channel_IsMemberOf( chan, Client )) continue;
  752. /* Concatenate channel names */
  753. if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
  754. if( strchr( Channel_UserModes( chan, c ), 'o' )) strlcat( str, "@", sizeof( str ));
  755. else if( strchr( Channel_UserModes( chan, c ), 'v' )) strlcat( str, "+", sizeof( str ));
  756. strlcat( str, Channel_Name( chan ), sizeof( str ));
  757. if( strlen( str ) > ( LINE_LEN - CHANNEL_NAME_LEN - 4 ))
  758. {
  759. /* Line becomes too long: send it! */
  760. if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
  761. snprintf( str, sizeof( str ), RPL_WHOISCHANNELS_MSG, Client_ID( from ), Client_ID( c ));
  762. }
  763. }
  764. if( str[strlen( str ) - 1] != ':')
  765. {
  766. /* There is data left to send: */
  767. if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
  768. }
  769. /* IRC-Operator? */
  770. if( Client_HasMode( c, 'o' ))
  771. {
  772. if( ! IRC_WriteStrClient( from, RPL_WHOISOPERATOR_MSG, Client_ID( from ), Client_ID( c ))) return DISCONNECTED;
  773. }
  774. /* Idle and signon time (local clients only!) */
  775. if (Client_Conn(c) > NONE ) {
  776. if (! IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
  777. Client_ID(from), Client_ID(c),
  778. (unsigned long)Conn_GetIdle(Client_Conn(c)),
  779. (unsigned long)Conn_GetSignon(Client_Conn(c))))
  780. return DISCONNECTED;
  781. }
  782. /* Away? */
  783. if( Client_HasMode( c, 'a' ))
  784. {
  785. if( ! IRC_WriteStrClient( from, RPL_AWAY_MSG, Client_ID( from ), Client_ID( c ), Client_Away( c ))) return DISCONNECTED;
  786. }
  787. /* End of Whois */
  788. return IRC_WriteStrClient( from, RPL_ENDOFWHOIS_MSG, Client_ID( from ), Client_ID( c ));
  789. } /* IRC_WHOIS */
  790. /**
  791. * IRC "WHOWAS" function.
  792. * This function implements the IRC command "WHOWHAS". It handles local
  793. * requests and request that should be forwarded to other servers.
  794. */
  795. GLOBAL bool
  796. IRC_WHOWAS( CLIENT *Client, REQUEST *Req )
  797. {
  798. CLIENT *target, *prefix;
  799. WHOWAS *whowas;
  800. int max, last, count, i;
  801. char t_str[60];
  802. assert( Client != NULL );
  803. assert( Req != NULL );
  804. /* Wrong number of parameters? */
  805. if(( Req->argc < 1 ) || ( Req->argc > 3 ))
  806. return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
  807. Client_ID( Client ), Req->command );
  808. /* Search taget */
  809. if( Req->argc == 3 )
  810. target = Client_Search( Req->argv[2] );
  811. else
  812. target = Client_ThisServer( );
  813. /* Get prefix */
  814. if( Client_Type( Client ) == CLIENT_SERVER )
  815. prefix = Client_Search( Req->prefix );
  816. else
  817. prefix = Client;
  818. if( ! prefix )
  819. return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG,
  820. Client_ID( Client ), Req->prefix );
  821. /* Forward to other server? */
  822. if( target != Client_ThisServer( ))
  823. {
  824. if(( ! target ) || ( Client_Type( target ) != CLIENT_SERVER ))
  825. return IRC_WriteStrClient( prefix, ERR_NOSUCHSERVER_MSG,
  826. Client_ID( prefix ),
  827. Req->argv[2] );
  828. /* Forward */
  829. IRC_WriteStrClientPrefix( target, prefix, "WHOWAS %s %s %s",
  830. Req->argv[0], Req->argv[1],
  831. Req->argv[2] );
  832. return CONNECTED;
  833. }
  834. whowas = Client_GetWhowas( );
  835. last = Client_GetLastWhowasIndex( );
  836. if( last < 0 ) last = 0;
  837. if( Req->argc > 1 )
  838. {
  839. max = atoi( Req->argv[1] );
  840. if( max < 1 ) max = MAX_WHOWAS;
  841. }
  842. else
  843. max = DEFAULT_WHOWAS;
  844. i = last;
  845. count = 0;
  846. do
  847. {
  848. /* Used entry? */
  849. if( whowas[i].time > 0 &&
  850. strcasecmp( Req->argv[0], whowas[i].id ) == 0 )
  851. {
  852. (void)strftime( t_str, sizeof(t_str),
  853. "%a %b %d %H:%M:%S %Y",
  854. localtime( &whowas[i].time ));
  855. if( ! IRC_WriteStrClient( prefix, RPL_WHOWASUSER_MSG,
  856. Client_ID( prefix ),
  857. whowas[i].id,
  858. whowas[i].user,
  859. whowas[i].host,
  860. whowas[i].info ))
  861. return DISCONNECTED;
  862. if( ! IRC_WriteStrClient( prefix, RPL_WHOISSERVER_MSG,
  863. Client_ID( prefix ),
  864. whowas[i].id,
  865. whowas[i].server, t_str ))
  866. return DISCONNECTED;
  867. count++;
  868. if( count >= max ) break;
  869. }
  870. /* previos entry */
  871. i--;
  872. /* "underflow", wrap around */
  873. if( i < 0 ) i = MAX_WHOWAS - 1;
  874. } while( i != last );
  875. return IRC_WriteStrClient( prefix, RPL_ENDOFWHOWAS_MSG,
  876. Client_ID( prefix ), Req->argv[0] );
  877. } /* IRC_WHOWAS */
  878. GLOBAL bool
  879. IRC_Send_LUSERS( CLIENT *Client )
  880. {
  881. unsigned long cnt;
  882. #ifndef STRICT_RFC
  883. unsigned long max;
  884. #endif
  885. assert( Client != NULL );
  886. /* Users, services and serevers in the network */
  887. if( ! IRC_WriteStrClient( Client, RPL_LUSERCLIENT_MSG, Client_ID( Client ), Client_UserCount( ), Client_ServiceCount( ), Client_ServerCount( ))) return DISCONNECTED;
  888. /* Number of IRC operators */
  889. cnt = Client_OperCount( );
  890. if( cnt > 0 )
  891. {
  892. if( ! IRC_WriteStrClient( Client, RPL_LUSEROP_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
  893. }
  894. /* Unknown connections */
  895. cnt = Client_UnknownCount( );
  896. if( cnt > 0 )
  897. {
  898. if( ! IRC_WriteStrClient( Client, RPL_LUSERUNKNOWN_MSG, Client_ID( Client ), cnt )) return DISCONNECTED;
  899. }
  900. /* Number of created channels */
  901. if( ! IRC_WriteStrClient( Client, RPL_LUSERCHANNELS_MSG, Client_ID( Client ), Channel_Count( ))) return DISCONNECTED;
  902. /* Number of local users, services and servers */
  903. if( ! IRC_WriteStrClient( Client, RPL_LUSERME_MSG, Client_ID( Client ), Client_MyUserCount( ), Client_MyServiceCount( ), Client_MyServerCount( ))) return DISCONNECTED;
  904. #ifndef STRICT_RFC
  905. /* Maximum number of local users */
  906. cnt = Client_MyUserCount();
  907. max = Client_MyMaxUserCount();
  908. if (! IRC_WriteStrClient(Client, RPL_LOCALUSERS_MSG, Client_ID(Client),
  909. cnt, max, cnt, max))
  910. return DISCONNECTED;
  911. /* Maximum number of users in the network */
  912. cnt = Client_UserCount();
  913. max = Client_MaxUserCount();
  914. if(! IRC_WriteStrClient(Client, RPL_NETUSERS_MSG, Client_ID(Client),
  915. cnt, max, cnt, max))
  916. return DISCONNECTED;
  917. #endif
  918. return CONNECTED;
  919. } /* IRC_Send_LUSERS */
  920. static bool
  921. Show_MOTD_Start(CLIENT *Client)
  922. {
  923. return IRC_WriteStrClient(Client, RPL_MOTDSTART_MSG,
  924. Client_ID( Client ), Client_ID( Client_ThisServer( )));
  925. }
  926. static bool
  927. Show_MOTD_Sendline(CLIENT *Client, const char *msg)
  928. {
  929. return IRC_WriteStrClient(Client, RPL_MOTD_MSG, Client_ID( Client ), msg);
  930. }
  931. static bool
  932. Show_MOTD_End(CLIENT *Client)
  933. {
  934. return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
  935. }
  936. GLOBAL bool
  937. IRC_Show_MOTD( CLIENT *Client )
  938. {
  939. char line[127];
  940. FILE *fd;
  941. assert( Client != NULL );
  942. if (Conf_MotdPhrase[0]) {
  943. if (!Show_MOTD_Start(Client))
  944. return DISCONNECTED;
  945. if (!Show_MOTD_Sendline(Client, Conf_MotdPhrase))
  946. return DISCONNECTED;
  947. return Show_MOTD_End(Client);
  948. }
  949. fd = fopen( Conf_MotdFile, "r" );
  950. if( ! fd ) {
  951. Log( LOG_WARNING, "Can't read MOTD file \"%s\": %s", Conf_MotdFile, strerror( errno ));
  952. return IRC_WriteStrClient( Client, ERR_NOMOTD_MSG, Client_ID( Client ) );
  953. }
  954. if (!Show_MOTD_Start( Client )) {
  955. fclose(fd);
  956. return false;
  957. }
  958. while (fgets( line, (int)sizeof line, fd )) {
  959. ngt_TrimLastChr( line, '\n');
  960. if( ! Show_MOTD_Sendline( Client, line)) {
  961. fclose( fd );
  962. return false;
  963. }
  964. }
  965. fclose(fd);
  966. return Show_MOTD_End(Client);
  967. } /* IRC_Show_MOTD */
  968. GLOBAL bool
  969. IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
  970. {
  971. bool is_visible, is_member;
  972. char str[LINE_LEN + 1];
  973. CL2CHAN *cl2chan;
  974. CLIENT *cl;
  975. assert( Client != NULL );
  976. assert( Chan != NULL );
  977. if( Channel_IsMemberOf( Chan, Client )) is_member = true;
  978. else is_member = false;
  979. /* Secret channel? */
  980. if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
  981. /* Alle Mitglieder suchen */
  982. snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
  983. cl2chan = Channel_FirstMember( Chan );
  984. while( cl2chan )
  985. {
  986. cl = Channel_GetClient( cl2chan );
  987. if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
  988. else is_visible = true;
  989. if( is_member || is_visible )
  990. {
  991. /* Nick anhaengen */
  992. if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
  993. if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
  994. else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
  995. strlcat( str, Client_ID( cl ), sizeof( str ));
  996. if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
  997. {
  998. /* Zeile wird zu lang: senden! */
  999. if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
  1000. snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
  1001. }
  1002. }
  1003. /* naechstes Mitglied suchen */
  1004. cl2chan = Channel_NextMember( Chan, cl2chan );
  1005. }
  1006. if( str[strlen( str ) - 1] != ':')
  1007. {
  1008. /* Es sind noch Daten da, die gesendet werden muessen */
  1009. if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
  1010. }
  1011. return CONNECTED;
  1012. } /* IRC_Send_NAMES */
  1013. /**
  1014. * Send the ISUPPORT numeric (005).
  1015. * This numeric indicates the features that are supported by this server.
  1016. * See <http://www.irc.org/tech_docs/005.html> for details.
  1017. */
  1018. GLOBAL bool
  1019. IRC_Send_ISUPPORT PARAMS((CLIENT * Client))
  1020. {
  1021. if (!IRC_WriteStrClient(Client, RPL_ISUPPORT1_MSG, Client_ID(Client),
  1022. Conf_MaxJoins))
  1023. return DISCONNECTED;
  1024. return IRC_WriteStrClient(Client, RPL_ISUPPORT2_MSG, Client_ID(Client),
  1025. CHANNEL_NAME_LEN - 1, Conf_MaxNickLength - 1,
  1026. COMMAND_LEN - 23, CLIENT_AWAY_LEN - 1,
  1027. COMMAND_LEN - 113);
  1028. } /* IRC_Send_ISUPPORT */
  1029. /* -eof- */