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