client.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167
  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. * Client management.
  12. */
  13. #define __client_c__
  14. #include "portab.h"
  15. #include "imp.h"
  16. #include <assert.h>
  17. #include <unistd.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <strings.h>
  22. #include <netdb.h>
  23. #include "defines.h"
  24. #include "conn.h"
  25. #include "exp.h"
  26. #include "client.h"
  27. #include <imp.h>
  28. #include "ngircd.h"
  29. #include "channel.h"
  30. #include "resolve.h"
  31. #include "conf.h"
  32. #include "hash.h"
  33. #include "irc-write.h"
  34. #include "log.h"
  35. #include "messages.h"
  36. #include <exp.h>
  37. #define GETID_LEN (CLIENT_NICK_LEN-1) + 1 + (CLIENT_USER_LEN-1) + 1 + (CLIENT_HOST_LEN-1) + 1
  38. static CLIENT *This_Server, *My_Clients;
  39. static WHOWAS My_Whowas[MAX_WHOWAS];
  40. static int Last_Whowas = -1;
  41. static long Max_Users, My_Max_Users;
  42. static unsigned long Count PARAMS(( CLIENT_TYPE Type ));
  43. static unsigned long MyCount PARAMS(( CLIENT_TYPE Type ));
  44. static CLIENT *New_Client_Struct PARAMS(( void ));
  45. static void Generate_MyToken PARAMS(( CLIENT *Client ));
  46. static void Adjust_Counters PARAMS(( CLIENT *Client ));
  47. static CLIENT *Init_New_Client PARAMS((CONN_ID Idx, CLIENT *Introducer,
  48. CLIENT *TopServer, int Type, const char *ID,
  49. const char *User, const char *Hostname, const char *Info,
  50. int Hops, int Token, const char *Modes,
  51. bool Idented));
  52. static void Destroy_UserOrService PARAMS((CLIENT *Client,const char *Txt, const char *FwdMsg,
  53. bool SendQuit));
  54. GLOBAL void
  55. Client_Init( void )
  56. {
  57. struct hostent *h;
  58. This_Server = New_Client_Struct( );
  59. if( ! This_Server )
  60. {
  61. Log( LOG_EMERG, "Can't allocate client structure for server! Going down." );
  62. Log( LOG_ALERT, "%s exiting due to fatal errors!", PACKAGE_NAME );
  63. exit( 1 );
  64. }
  65. /* Client-Struktur dieses Servers */
  66. This_Server->next = NULL;
  67. This_Server->type = CLIENT_SERVER;
  68. This_Server->conn_id = NONE;
  69. This_Server->introducer = This_Server;
  70. This_Server->mytoken = 1;
  71. This_Server->hops = 0;
  72. gethostname( This_Server->host, CLIENT_HOST_LEN );
  73. if (!Conf_NoDNS) {
  74. h = gethostbyname( This_Server->host );
  75. if (h) strlcpy(This_Server->host, h->h_name, sizeof(This_Server->host));
  76. }
  77. Client_SetID( This_Server, Conf_ServerName );
  78. Client_SetInfo( This_Server, Conf_ServerInfo );
  79. My_Clients = This_Server;
  80. memset( &My_Whowas, 0, sizeof( My_Whowas ));
  81. } /* Client_Init */
  82. GLOBAL void
  83. Client_Exit( void )
  84. {
  85. CLIENT *c, *next;
  86. int cnt;
  87. if( NGIRCd_SignalRestart ) Client_Destroy( This_Server, "Server going down (restarting).", NULL, false );
  88. else Client_Destroy( This_Server, "Server going down.", NULL, false );
  89. cnt = 0;
  90. c = My_Clients;
  91. while( c )
  92. {
  93. cnt++;
  94. next = (CLIENT *)c->next;
  95. free( c );
  96. c = next;
  97. }
  98. if( cnt ) Log( LOG_INFO, "Freed %d client structure%s.", cnt, cnt == 1 ? "" : "s" );
  99. } /* Client_Exit */
  100. GLOBAL CLIENT *
  101. Client_ThisServer( void )
  102. {
  103. return This_Server;
  104. } /* Client_ThisServer */
  105. /**
  106. * Initialize new local client; wrapper function for Init_New_Client().
  107. * @return New CLIENT structure.
  108. */
  109. GLOBAL CLIENT *
  110. Client_NewLocal(CONN_ID Idx, const char *Hostname, int Type, bool Idented)
  111. {
  112. return Init_New_Client(Idx, This_Server, NULL, Type, NULL, NULL,
  113. Hostname, NULL, 0, 0, NULL, Idented);
  114. } /* Client_NewLocal */
  115. /**
  116. * Initialize new remote server; wrapper function for Init_New_Client().
  117. * @return New CLIENT structure.
  118. */
  119. GLOBAL CLIENT *
  120. Client_NewRemoteServer(CLIENT *Introducer, const char *Hostname, CLIENT *TopServer,
  121. int Hops, int Token, const char *Info, bool Idented)
  122. {
  123. return Init_New_Client(NONE, Introducer, TopServer, CLIENT_SERVER,
  124. Hostname, NULL, Hostname, Info, Hops, Token, NULL, Idented);
  125. } /* Client_NewRemoteServer */
  126. /**
  127. * Initialize new remote client; wrapper function for Init_New_Client().
  128. * @return New CLIENT structure.
  129. */
  130. GLOBAL CLIENT *
  131. Client_NewRemoteUser(CLIENT *Introducer, const char *Nick, int Hops, const char *User,
  132. const char *Hostname, int Token, const char *Modes, const char *Info, bool Idented)
  133. {
  134. return Init_New_Client(NONE, Introducer, NULL, CLIENT_USER, Nick,
  135. User, Hostname, Info, Hops, Token, Modes, Idented);
  136. } /* Client_NewRemoteUser */
  137. /**
  138. * Initialize new client and set up the given parameters like client type,
  139. * user name, host name, introducing server etc. ...
  140. * @return New CLIENT structure.
  141. */
  142. static CLIENT *
  143. Init_New_Client(CONN_ID Idx, CLIENT *Introducer, CLIENT *TopServer,
  144. int Type, const char *ID, const char *User, const char *Hostname, const char *Info, int Hops,
  145. int Token, const char *Modes, bool Idented)
  146. {
  147. CLIENT *client;
  148. assert( Idx >= NONE );
  149. assert( Introducer != NULL );
  150. assert( Hostname != NULL );
  151. client = New_Client_Struct( );
  152. if( ! client ) return NULL;
  153. client->starttime = time(NULL);
  154. client->conn_id = Idx;
  155. client->introducer = Introducer;
  156. client->topserver = TopServer;
  157. client->type = Type;
  158. if( ID ) Client_SetID( client, ID );
  159. if( User ) Client_SetUser( client, User, Idented );
  160. if( Hostname ) Client_SetHostname( client, Hostname );
  161. if( Info ) Client_SetInfo( client, Info );
  162. client->hops = Hops;
  163. client->token = Token;
  164. if( Modes ) Client_SetModes( client, Modes );
  165. if( Type == CLIENT_SERVER ) Generate_MyToken( client );
  166. if( strchr( client->modes, 'a' ))
  167. strlcpy( client->away, DEFAULT_AWAY_MSG, sizeof( client->away ));
  168. client->next = (POINTER *)My_Clients;
  169. My_Clients = client;
  170. Adjust_Counters( client );
  171. return client;
  172. } /* Init_New_Client */
  173. GLOBAL void
  174. Client_Destroy( CLIENT *Client, const char *LogMsg, const char *FwdMsg, bool SendQuit )
  175. {
  176. /* remove a client */
  177. CLIENT *last, *c;
  178. char msg[LINE_LEN];
  179. const char *txt;
  180. assert( Client != NULL );
  181. if( LogMsg ) txt = LogMsg;
  182. else txt = FwdMsg;
  183. if( ! txt ) txt = "Reason unknown.";
  184. /* netsplit message */
  185. if( Client->type == CLIENT_SERVER ) {
  186. strlcpy(msg, This_Server->id, sizeof (msg));
  187. strlcat(msg, " ", sizeof (msg));
  188. strlcat(msg, Client->id, sizeof (msg));
  189. }
  190. last = NULL;
  191. c = My_Clients;
  192. while( c )
  193. {
  194. if(( Client->type == CLIENT_SERVER ) && ( c->introducer == Client ) && ( c != Client ))
  195. {
  196. /*
  197. * The client that is about to be removed is a server,
  198. * the client we are checking right now is a child of that
  199. * server and thus has to be removed, too.
  200. *
  201. * Call Client_Destroy() recursively with the server as the
  202. * new "object to be removed". This starts the cycle again, until
  203. * all servers that are linked via the original server have been
  204. * removed.
  205. */
  206. Client_Destroy( c, NULL, msg, false );
  207. last = NULL;
  208. c = My_Clients;
  209. continue;
  210. }
  211. if( c == Client )
  212. {
  213. /* found the client: remove it */
  214. if( last ) last->next = c->next;
  215. else My_Clients = (CLIENT *)c->next;
  216. if(c->type == CLIENT_USER || c->type == CLIENT_SERVICE)
  217. Destroy_UserOrService(c, txt, FwdMsg, SendQuit);
  218. else if( c->type == CLIENT_SERVER )
  219. {
  220. if( c != This_Server )
  221. {
  222. if( c->conn_id != NONE ) Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
  223. else Log( LOG_NOTICE|LOG_snotice, "Server \"%s\" unregistered: %s", c->id, txt );
  224. }
  225. /* inform other servers */
  226. if( ! NGIRCd_SignalQuit )
  227. {
  228. if( FwdMsg ) IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :%s", c->id, FwdMsg );
  229. else IRC_WriteStrServersPrefix( Client_NextHop( c ), c, "SQUIT %s :", c->id );
  230. }
  231. }
  232. else
  233. {
  234. if( c->conn_id != NONE )
  235. {
  236. if( c->id[0] ) Log( LOG_NOTICE, "Client \"%s\" unregistered (connection %d): %s", c->id, c->conn_id, txt );
  237. else Log( LOG_NOTICE, "Client unregistered (connection %d): %s", c->conn_id, txt );
  238. } else {
  239. Log(LOG_WARNING, "Unregistered unknown client \"%s\": %s",
  240. c->id[0] ? c->id : "(No Nick)", txt );
  241. }
  242. }
  243. free( c );
  244. break;
  245. }
  246. last = c;
  247. c = (CLIENT *)c->next;
  248. }
  249. } /* Client_Destroy */
  250. GLOBAL void
  251. Client_SetHostname( CLIENT *Client, const char *Hostname )
  252. {
  253. assert( Client != NULL );
  254. assert( Hostname != NULL );
  255. strlcpy( Client->host, Hostname, sizeof( Client->host ));
  256. } /* Client_SetHostname */
  257. GLOBAL void
  258. Client_SetID( CLIENT *Client, const char *ID )
  259. {
  260. assert( Client != NULL );
  261. assert( ID != NULL );
  262. strlcpy( Client->id, ID, sizeof( Client->id ));
  263. /* Hash */
  264. Client->hash = Hash( Client->id );
  265. } /* Client_SetID */
  266. GLOBAL void
  267. Client_SetUser( CLIENT *Client, const char *User, bool Idented )
  268. {
  269. /* set clients username */
  270. assert( Client != NULL );
  271. assert( User != NULL );
  272. if (Idented) {
  273. strlcpy(Client->user, User, sizeof(Client->user));
  274. } else {
  275. Client->user[0] = '~';
  276. strlcpy(Client->user + 1, User, sizeof(Client->user) - 1);
  277. }
  278. } /* Client_SetUser */
  279. GLOBAL void
  280. Client_SetInfo( CLIENT *Client, const char *Info )
  281. {
  282. /* set client hostname */
  283. assert( Client != NULL );
  284. assert( Info != NULL );
  285. strlcpy(Client->info, Info, sizeof(Client->info));
  286. } /* Client_SetInfo */
  287. GLOBAL void
  288. Client_SetModes( CLIENT *Client, const char *Modes )
  289. {
  290. assert( Client != NULL );
  291. assert( Modes != NULL );
  292. strlcpy(Client->modes, Modes, sizeof( Client->modes ));
  293. } /* Client_SetModes */
  294. GLOBAL void
  295. Client_SetFlags( CLIENT *Client, const char *Flags )
  296. {
  297. assert( Client != NULL );
  298. assert( Flags != NULL );
  299. strlcpy(Client->flags, Flags, sizeof(Client->flags));
  300. } /* Client_SetFlags */
  301. GLOBAL void
  302. Client_SetPassword( CLIENT *Client, const char *Pwd )
  303. {
  304. /* set password sent by client */
  305. assert( Client != NULL );
  306. assert( Pwd != NULL );
  307. strlcpy(Client->pwd, Pwd, sizeof(Client->pwd));
  308. } /* Client_SetPassword */
  309. GLOBAL void
  310. Client_SetAway( CLIENT *Client, const char *Txt )
  311. {
  312. /* Set AWAY reason of client */
  313. assert( Client != NULL );
  314. assert( Txt != NULL );
  315. strlcpy( Client->away, Txt, sizeof( Client->away ));
  316. LogDebug("%s \"%s\" is away: %s", Client_TypeText(Client),
  317. Client_Mask(Client), Txt);
  318. } /* Client_SetAway */
  319. GLOBAL void
  320. Client_SetType( CLIENT *Client, int Type )
  321. {
  322. assert( Client != NULL );
  323. Client->type = Type;
  324. if( Type == CLIENT_SERVER ) Generate_MyToken( Client );
  325. Adjust_Counters( Client );
  326. } /* Client_SetType */
  327. GLOBAL void
  328. Client_SetHops( CLIENT *Client, int Hops )
  329. {
  330. assert( Client != NULL );
  331. Client->hops = Hops;
  332. } /* Client_SetHops */
  333. GLOBAL void
  334. Client_SetToken( CLIENT *Client, int Token )
  335. {
  336. assert( Client != NULL );
  337. Client->token = Token;
  338. } /* Client_SetToken */
  339. GLOBAL void
  340. Client_SetIntroducer( CLIENT *Client, CLIENT *Introducer )
  341. {
  342. assert( Client != NULL );
  343. assert( Introducer != NULL );
  344. Client->introducer = Introducer;
  345. } /* Client_SetIntroducer */
  346. GLOBAL void
  347. Client_SetOperByMe( CLIENT *Client, bool OperByMe )
  348. {
  349. assert( Client != NULL );
  350. Client->oper_by_me = OperByMe;
  351. } /* Client_SetOperByMe */
  352. GLOBAL bool
  353. Client_ModeAdd( CLIENT *Client, char Mode )
  354. {
  355. /* Set Mode.
  356. * If Client already alread had Mode, return false.
  357. * If the Mode was newly set, return true.
  358. */
  359. char x[2];
  360. assert( Client != NULL );
  361. x[0] = Mode; x[1] = '\0';
  362. if (!strchr( Client->modes, x[0])) {
  363. strlcat( Client->modes, x, sizeof( Client->modes ));
  364. return true;
  365. }
  366. else return false;
  367. } /* Client_ModeAdd */
  368. GLOBAL bool
  369. Client_ModeDel( CLIENT *Client, char Mode )
  370. {
  371. /* Delete Mode.
  372. * If Mode was removed, return true.
  373. * If Client did not have Mode, return false.
  374. */
  375. char x[2], *p;
  376. assert( Client != NULL );
  377. x[0] = Mode; x[1] = '\0';
  378. p = strchr( Client->modes, x[0] );
  379. if( ! p ) return false;
  380. /* Client has Mode -> delete */
  381. while( *p )
  382. {
  383. *p = *(p + 1);
  384. p++;
  385. }
  386. return true;
  387. } /* Client_ModeDel */
  388. GLOBAL CLIENT *
  389. Client_Search( const char *Nick )
  390. {
  391. /* return Client-Structure that has the corresponding Nick.
  392. * If none is found, return NULL.
  393. */
  394. char search_id[CLIENT_ID_LEN], *ptr;
  395. CLIENT *c = NULL;
  396. UINT32 search_hash;
  397. assert( Nick != NULL );
  398. /* copy Nick and truncate hostmask if necessary */
  399. strlcpy( search_id, Nick, sizeof( search_id ));
  400. ptr = strchr( search_id, '!' );
  401. if( ptr ) *ptr = '\0';
  402. search_hash = Hash(search_id);
  403. c = My_Clients;
  404. while (c) {
  405. if (c->hash == search_hash && strcasecmp(c->id, search_id) == 0)
  406. return c;
  407. c = (CLIENT *)c->next;
  408. }
  409. return NULL;
  410. } /* Client_Search */
  411. GLOBAL CLIENT *
  412. Client_GetFromToken( CLIENT *Client, int Token )
  413. {
  414. /* Client-Struktur, die den entsprechenden Introducer (=Client)
  415. * und das gegebene Token hat, liefern. Wird keine gefunden,
  416. * so wird NULL geliefert. */
  417. CLIENT *c;
  418. assert( Client != NULL );
  419. assert( Token > 0 );
  420. c = My_Clients;
  421. while (c) {
  422. if ((c->type == CLIENT_SERVER) && (c->introducer == Client) &&
  423. (c->token == Token))
  424. return c;
  425. c = (CLIENT *)c->next;
  426. }
  427. return NULL;
  428. } /* Client_GetFromToken */
  429. GLOBAL int
  430. Client_Type( CLIENT *Client )
  431. {
  432. assert( Client != NULL );
  433. return Client->type;
  434. } /* Client_Type */
  435. GLOBAL CONN_ID
  436. Client_Conn( CLIENT *Client )
  437. {
  438. assert( Client != NULL );
  439. return Client->conn_id;
  440. } /* Client_Conn */
  441. GLOBAL char *
  442. Client_ID( CLIENT *Client )
  443. {
  444. assert( Client != NULL );
  445. #ifdef DEBUG
  446. if(Client->type == CLIENT_USER)
  447. assert(strlen(Client->id) < Conf_MaxNickLength);
  448. #endif
  449. if( Client->id[0] ) return Client->id;
  450. else return "*";
  451. } /* Client_ID */
  452. GLOBAL char *
  453. Client_Info( CLIENT *Client )
  454. {
  455. assert( Client != NULL );
  456. return Client->info;
  457. } /* Client_Info */
  458. GLOBAL char *
  459. Client_User( CLIENT *Client )
  460. {
  461. assert( Client != NULL );
  462. return Client->user[0] ? Client->user : "~";
  463. } /* Client_User */
  464. GLOBAL char *
  465. Client_Hostname( CLIENT *Client )
  466. {
  467. assert( Client != NULL );
  468. return Client->host;
  469. } /* Client_Hostname */
  470. GLOBAL char *
  471. Client_Password( CLIENT *Client )
  472. {
  473. assert( Client != NULL );
  474. return Client->pwd;
  475. } /* Client_Password */
  476. GLOBAL char *
  477. Client_Modes( CLIENT *Client )
  478. {
  479. assert( Client != NULL );
  480. return Client->modes;
  481. } /* Client_Modes */
  482. GLOBAL char *
  483. Client_Flags( CLIENT *Client )
  484. {
  485. assert( Client != NULL );
  486. return Client->flags;
  487. } /* Client_Flags */
  488. GLOBAL bool
  489. Client_OperByMe( CLIENT *Client )
  490. {
  491. assert( Client != NULL );
  492. return Client->oper_by_me;
  493. } /* Client_OperByMe */
  494. GLOBAL int
  495. Client_Hops( CLIENT *Client )
  496. {
  497. assert( Client != NULL );
  498. return Client->hops;
  499. } /* Client_Hops */
  500. GLOBAL int
  501. Client_Token( CLIENT *Client )
  502. {
  503. assert( Client != NULL );
  504. return Client->token;
  505. } /* Client_Token */
  506. GLOBAL int
  507. Client_MyToken( CLIENT *Client )
  508. {
  509. assert( Client != NULL );
  510. return Client->mytoken;
  511. } /* Client_MyToken */
  512. GLOBAL CLIENT *
  513. Client_NextHop( CLIENT *Client )
  514. {
  515. CLIENT *c;
  516. assert( Client != NULL );
  517. c = Client;
  518. while( c->introducer && ( c->introducer != c ) && ( c->introducer != This_Server ))
  519. c = c->introducer;
  520. return c;
  521. } /* Client_NextHop */
  522. /**
  523. * return Client-ID ("client!user@host"), this ID is needed for e.g.
  524. * prefixes. Returnes pointer to static buffer.
  525. */
  526. GLOBAL char *
  527. Client_Mask( CLIENT *Client )
  528. {
  529. static char GetID_Buffer[GETID_LEN];
  530. assert( Client != NULL );
  531. if( Client->type == CLIENT_SERVER ) return Client->id;
  532. snprintf(GetID_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user, Client->host);
  533. return GetID_Buffer;
  534. } /* Client_Mask */
  535. GLOBAL CLIENT *
  536. Client_Introducer( CLIENT *Client )
  537. {
  538. assert( Client != NULL );
  539. return Client->introducer;
  540. } /* Client_Introducer */
  541. GLOBAL CLIENT *
  542. Client_TopServer( CLIENT *Client )
  543. {
  544. assert( Client != NULL );
  545. return Client->topserver;
  546. } /* Client_TopServer */
  547. GLOBAL bool
  548. Client_HasMode( CLIENT *Client, char Mode )
  549. {
  550. assert( Client != NULL );
  551. return strchr( Client->modes, Mode ) != NULL;
  552. } /* Client_HasMode */
  553. GLOBAL char *
  554. Client_Away( CLIENT *Client )
  555. {
  556. assert( Client != NULL );
  557. return Client->away;
  558. } /* Client_Away */
  559. GLOBAL bool
  560. Client_CheckNick( CLIENT *Client, char *Nick )
  561. {
  562. assert( Client != NULL );
  563. assert( Nick != NULL );
  564. if (! Client_IsValidNick( Nick ))
  565. {
  566. IRC_WriteStrClient( Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID( Client ), Nick );
  567. return false;
  568. }
  569. /* Nick bereits vergeben? */
  570. if( Client_Search( Nick ))
  571. {
  572. /* den Nick gibt es bereits */
  573. IRC_WriteStrClient( Client, ERR_NICKNAMEINUSE_MSG, Client_ID( Client ), Nick );
  574. return false;
  575. }
  576. return true;
  577. } /* Client_CheckNick */
  578. GLOBAL bool
  579. Client_CheckID( CLIENT *Client, char *ID )
  580. {
  581. char str[COMMAND_LEN];
  582. CLIENT *c;
  583. assert( Client != NULL );
  584. assert( Client->conn_id > NONE );
  585. assert( ID != NULL );
  586. /* ID too long? */
  587. if (strlen(ID) > CLIENT_ID_LEN) {
  588. IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG, Client_ID(Client), ID);
  589. return false;
  590. }
  591. /* ID already in use? */
  592. c = My_Clients;
  593. while (c) {
  594. if (strcasecmp(c->id, ID) == 0) {
  595. snprintf(str, sizeof(str), "ID \"%s\" already registered", ID);
  596. if (c->conn_id != NONE)
  597. Log(LOG_ERR, "%s (on connection %d)!", str, c->conn_id);
  598. else
  599. Log(LOG_ERR, "%s (via network)!", str);
  600. Conn_Close(Client->conn_id, str, str, true);
  601. return false;
  602. }
  603. c = (CLIENT *)c->next;
  604. }
  605. return true;
  606. } /* Client_CheckID */
  607. GLOBAL CLIENT *
  608. Client_First( void )
  609. {
  610. return My_Clients;
  611. } /* Client_First */
  612. GLOBAL CLIENT *
  613. Client_Next( CLIENT *c )
  614. {
  615. assert( c != NULL );
  616. return (CLIENT *)c->next;
  617. } /* Client_Next */
  618. GLOBAL long
  619. Client_UserCount( void )
  620. {
  621. return Count( CLIENT_USER );
  622. } /* Client_UserCount */
  623. GLOBAL long
  624. Client_ServiceCount( void )
  625. {
  626. return Count( CLIENT_SERVICE );;
  627. } /* Client_ServiceCount */
  628. GLOBAL long
  629. Client_ServerCount( void )
  630. {
  631. return Count( CLIENT_SERVER );
  632. } /* Client_ServerCount */
  633. GLOBAL long
  634. Client_MyUserCount( void )
  635. {
  636. return MyCount( CLIENT_USER );
  637. } /* Client_MyUserCount */
  638. GLOBAL long
  639. Client_MyServiceCount( void )
  640. {
  641. return MyCount( CLIENT_SERVICE );
  642. } /* Client_MyServiceCount */
  643. GLOBAL unsigned long
  644. Client_MyServerCount( void )
  645. {
  646. CLIENT *c;
  647. unsigned long cnt = 0;
  648. c = My_Clients;
  649. while( c )
  650. {
  651. if(( c->type == CLIENT_SERVER ) && ( c->hops == 1 )) cnt++;
  652. c = (CLIENT *)c->next;
  653. }
  654. return cnt;
  655. } /* Client_MyServerCount */
  656. GLOBAL unsigned long
  657. Client_OperCount( void )
  658. {
  659. CLIENT *c;
  660. unsigned long cnt = 0;
  661. c = My_Clients;
  662. while( c )
  663. {
  664. if( c && ( c->type == CLIENT_USER ) && ( strchr( c->modes, 'o' ))) cnt++;
  665. c = (CLIENT *)c->next;
  666. }
  667. return cnt;
  668. } /* Client_OperCount */
  669. GLOBAL unsigned long
  670. Client_UnknownCount( void )
  671. {
  672. CLIENT *c;
  673. unsigned long cnt = 0;
  674. c = My_Clients;
  675. while( c )
  676. {
  677. if( c && ( c->type != CLIENT_USER ) && ( c->type != CLIENT_SERVICE ) && ( c->type != CLIENT_SERVER )) cnt++;
  678. c = (CLIENT *)c->next;
  679. }
  680. return cnt;
  681. } /* Client_UnknownCount */
  682. GLOBAL long
  683. Client_MaxUserCount( void )
  684. {
  685. return Max_Users;
  686. } /* Client_MaxUserCount */
  687. GLOBAL long
  688. Client_MyMaxUserCount( void )
  689. {
  690. return My_Max_Users;
  691. } /* Client_MyMaxUserCount */
  692. GLOBAL bool
  693. Client_IsValidNick( const char *Nick )
  694. {
  695. const char *ptr;
  696. static const char goodchars[] = ";0123456789-";
  697. assert( Nick != NULL );
  698. if( Nick[0] == '#' ) return false;
  699. if( strchr( goodchars, Nick[0] )) return false;
  700. if( strlen( Nick ) >= Conf_MaxNickLength) return false;
  701. ptr = Nick;
  702. while( *ptr )
  703. {
  704. if (( *ptr < 'A' ) && ( ! strchr( goodchars, *ptr ))) return false;
  705. if ( *ptr > '}' ) return false;
  706. ptr++;
  707. }
  708. return true;
  709. } /* Client_IsValidNick */
  710. /**
  711. * Return pointer to "My_Whowas" structure.
  712. */
  713. GLOBAL WHOWAS *
  714. Client_GetWhowas( void )
  715. {
  716. return My_Whowas;
  717. } /* Client_GetWhowas */
  718. /**
  719. * Return the index of the last used WHOWAS entry.
  720. */
  721. GLOBAL int
  722. Client_GetLastWhowasIndex( void )
  723. {
  724. return Last_Whowas;
  725. } /* Client_GetLastWhowasIndex */
  726. /**
  727. * Get the start time of this client.
  728. * The result is the start time in seconds since 1970-01-01, as reported
  729. * by the C function time(NULL).
  730. */
  731. GLOBAL time_t
  732. Client_StartTime(CLIENT *Client)
  733. {
  734. assert( Client != NULL );
  735. return Client->starttime;
  736. } /* Client_Uptime */
  737. static unsigned long
  738. Count( CLIENT_TYPE Type )
  739. {
  740. CLIENT *c;
  741. unsigned long cnt = 0;
  742. c = My_Clients;
  743. while( c )
  744. {
  745. if( c->type == Type ) cnt++;
  746. c = (CLIENT *)c->next;
  747. }
  748. return cnt;
  749. } /* Count */
  750. static unsigned long
  751. MyCount( CLIENT_TYPE Type )
  752. {
  753. CLIENT *c;
  754. unsigned long cnt = 0;
  755. c = My_Clients;
  756. while( c )
  757. {
  758. if(( c->introducer == This_Server ) && ( c->type == Type )) cnt++;
  759. c = (CLIENT *)c->next;
  760. }
  761. return cnt;
  762. } /* MyCount */
  763. static CLIENT *
  764. New_Client_Struct( void )
  765. {
  766. /* Neue CLIENT-Struktur pre-initialisieren */
  767. CLIENT *c;
  768. c = (CLIENT *)malloc( sizeof( CLIENT ));
  769. if( ! c )
  770. {
  771. Log( LOG_EMERG, "Can't allocate memory! [New_Client_Struct]" );
  772. return NULL;
  773. }
  774. memset( c, 0, sizeof ( CLIENT ));
  775. c->type = CLIENT_UNKNOWN;
  776. c->conn_id = NONE;
  777. c->oper_by_me = false;
  778. c->hops = -1;
  779. c->token = -1;
  780. c->mytoken = -1;
  781. return c;
  782. } /* New_Client */
  783. static void
  784. Generate_MyToken( CLIENT *Client )
  785. {
  786. CLIENT *c;
  787. int token;
  788. c = My_Clients;
  789. token = 2;
  790. while( c )
  791. {
  792. if( c->mytoken == token )
  793. {
  794. /* Das Token wurde bereits vergeben */
  795. token++;
  796. c = My_Clients;
  797. continue;
  798. }
  799. else c = (CLIENT *)c->next;
  800. }
  801. Client->mytoken = token;
  802. LogDebug("Assigned token %d to server \"%s\".", token, Client->id);
  803. } /* Generate_MyToken */
  804. static void
  805. Adjust_Counters( CLIENT *Client )
  806. {
  807. long count;
  808. assert( Client != NULL );
  809. if( Client->type != CLIENT_USER ) return;
  810. if( Client->conn_id != NONE )
  811. {
  812. /* Local connection */
  813. count = Client_MyUserCount( );
  814. if( count > My_Max_Users ) My_Max_Users = count;
  815. }
  816. count = Client_UserCount( );
  817. if( count > Max_Users ) Max_Users = count;
  818. } /* Adjust_Counters */
  819. /**
  820. * Register client in My_Whowas structure for further recall by WHOWAS.
  821. * Note: Only clients that have been connected at least 30 seconds will be
  822. * registered to prevent automated IRC bots to "destroy" a nice server
  823. * history database.
  824. */
  825. GLOBAL void
  826. Client_RegisterWhowas( CLIENT *Client )
  827. {
  828. int slot;
  829. time_t now;
  830. assert( Client != NULL );
  831. now = time(NULL);
  832. /* Don't register clients that were connected less than 30 seconds. */
  833. if( now - Client->starttime < 30 )
  834. return;
  835. slot = Last_Whowas + 1;
  836. if( slot >= MAX_WHOWAS || slot < 0 ) slot = 0;
  837. #ifdef DEBUG
  838. Log( LOG_DEBUG, "Saving WHOWAS information to slot %d ...", slot );
  839. #endif
  840. My_Whowas[slot].time = now;
  841. strlcpy( My_Whowas[slot].id, Client_ID( Client ),
  842. sizeof( My_Whowas[slot].id ));
  843. strlcpy( My_Whowas[slot].user, Client_User( Client ),
  844. sizeof( My_Whowas[slot].user ));
  845. strlcpy( My_Whowas[slot].host, Client_Hostname( Client ),
  846. sizeof( My_Whowas[slot].host ));
  847. strlcpy( My_Whowas[slot].info, Client_Info( Client ),
  848. sizeof( My_Whowas[slot].info ));
  849. strlcpy( My_Whowas[slot].server, Client_ID( Client_Introducer( Client )),
  850. sizeof( My_Whowas[slot].server ));
  851. Last_Whowas = slot;
  852. } /* Client_RegisterWhowas */
  853. GLOBAL char *
  854. Client_TypeText(CLIENT *Client)
  855. {
  856. assert(Client != NULL);
  857. switch (Client_Type(Client)) {
  858. case CLIENT_USER:
  859. return "User";
  860. break;
  861. case CLIENT_SERVICE:
  862. return "Service";
  863. break;
  864. case CLIENT_SERVER:
  865. return "Server";
  866. break;
  867. default:
  868. return "Client";
  869. }
  870. } /* Client_TypeText */
  871. /**
  872. * Destroy user or service client.
  873. */
  874. static void
  875. Destroy_UserOrService(CLIENT *Client, const char *Txt, const char *FwdMsg, bool SendQuit)
  876. {
  877. if(Client->conn_id != NONE) {
  878. /* Local (directly connected) client */
  879. Log(LOG_NOTICE,
  880. "%s \"%s\" unregistered (connection %d): %s",
  881. Client_TypeText(Client), Client_Mask(Client),
  882. Client->conn_id, Txt);
  883. if (SendQuit) {
  884. /* Inforam all the other servers */
  885. if (FwdMsg)
  886. IRC_WriteStrServersPrefix(NULL,
  887. Client, "QUIT :%s", FwdMsg );
  888. else
  889. IRC_WriteStrServersPrefix(NULL,
  890. Client, "QUIT :");
  891. }
  892. } else {
  893. /* Remote client */
  894. LogDebug("%s \"%s\" unregistered: %s",
  895. Client_TypeText(Client), Client_Mask(Client), Txt);
  896. if(SendQuit) {
  897. /* Inform all the other servers, but the ones in the
  898. * direction we got the QUIT from */
  899. if(FwdMsg)
  900. IRC_WriteStrServersPrefix(Client_NextHop(Client),
  901. Client, "QUIT :%s", FwdMsg );
  902. else
  903. IRC_WriteStrServersPrefix(Client_NextHop(Client),
  904. Client, "QUIT :" );
  905. }
  906. }
  907. /* Unregister client from channels */
  908. Channel_Quit(Client, FwdMsg ? FwdMsg : Client->id);
  909. /* Register client in My_Whowas structure */
  910. Client_RegisterWhowas(Client);
  911. } /* Destroy_UserOrService */
  912. /* -eof- */