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