6686dc6f676d7764071c73e0b5253185771a1c5a
[ngircd-alex.git] / src / ngircd / irc-login.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4  *
5  * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6  * der GNU General Public License (GPL), wie von der Free Software Foundation
7  * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8  * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9  * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10  * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11  *
12  * $Id: irc-login.c,v 1.1 2002/02/27 23:26:21 alex Exp $
13  *
14  * irc-login.c: Anmeldung und Abmeldung im IRC
15  *
16  * $Log: irc-login.c,v $
17  * Revision 1.1  2002/02/27 23:26:21  alex
18  * - Modul aus irc.c bzw. irc.h ausgegliedert.
19  *
20  */
21
22
23 #include <portab.h>
24 #include "global.h"
25
26 #include <imp.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31
32 #include "ngircd.h"
33 #include "conf.h"
34 #include "irc.h"
35 #include "irc-write.h"
36 #include "log.h"
37 #include "messages.h"
38
39 #include <exp.h>
40 #include "irc-login.h"
41
42
43 LOCAL BOOLEAN Hello_User( CLIENT *Client );
44 LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason );
45
46
47 GLOBAL BOOLEAN IRC_PASS( CLIENT *Client, REQUEST *Req )
48 {
49         assert( Client != NULL );
50         assert( Req != NULL );
51
52         /* Fehler liefern, wenn kein lokaler Client */
53         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
54         
55         if(( Client_Type( Client ) == CLIENT_UNKNOWN ) && ( Req->argc == 1))
56         {
57                 /* noch nicht registrierte unbekannte Verbindung */
58                 Log( LOG_DEBUG, "Connection %d: got PASS command ...", Client_Conn( Client ));
59
60                 /* Passwort speichern */
61                 Client_SetPassword( Client, Req->argv[0] );
62
63                 Client_SetType( Client, CLIENT_GOTPASS );
64                 return CONNECTED;
65         }
66         else if((( Client_Type( Client ) == CLIENT_UNKNOWN ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER )) && (( Req->argc == 3 ) || ( Req->argc == 4 )))
67         {
68                 /* noch nicht registrierte Server-Verbindung */
69                 Log( LOG_DEBUG, "Connection %d: got PASS command (new server link) ...", Client_Conn( Client ));
70
71                 /* Passwort speichern */
72                 Client_SetPassword( Client, Req->argv[0] );
73
74                 Client_SetType( Client, CLIENT_GOTPASSSERVER );
75                 return CONNECTED;
76         }
77         else if(( Client_Type( Client ) == CLIENT_UNKNOWN  ) || ( Client_Type( Client ) == CLIENT_UNKNOWNSERVER ))
78         {
79                 /* Falsche Anzahl Parameter? */
80                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
81         }
82         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
83 } /* IRC_PASS */
84
85
86 GLOBAL BOOLEAN IRC_SERVER( CLIENT *Client, REQUEST *Req )
87 {
88         CHAR str[LINE_LEN], *ptr;
89         CLIENT *from, *c, *cl;
90         CL2CHAN *cl2chan;
91         INT max_hops, i;
92         CHANNEL *chan;
93         BOOLEAN ok;
94         
95         assert( Client != NULL );
96         assert( Req != NULL );
97
98         /* Fehler liefern, wenn kein lokaler Client */
99         if( Client_Conn( Client ) <= NONE ) return IRC_WriteStrClient( Client, ERR_UNKNOWNCOMMAND_MSG, Client_ID( Client ), Req->command );
100
101         if( Client_Type( Client ) == CLIENT_GOTPASSSERVER )
102         {
103                 /* Verbindung soll als Server-Server-Verbindung registriert werden */
104                 Log( LOG_DEBUG, "Connection %d: got SERVER command (new server link) ...", Client_Conn( Client ));
105
106                 /* Falsche Anzahl Parameter? */
107                 if(( Req->argc != 2 ) && ( Req->argc != 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
108
109                 /* Ist dieser Server bei uns konfiguriert? */
110                 for( i = 0; i < Conf_Server_Count; i++ ) if( strcasecmp( Req->argv[0], Conf_Server[i].name ) == 0 ) break;
111                 if( i >= Conf_Server_Count )
112                 {
113                         /* Server ist nicht konfiguriert! */
114                         Log( LOG_ERR, "Connection %d: Server \"%s\" not configured here!", Client_Conn( Client ), Req->argv[0] );
115                         Conn_Close( Client_Conn( Client ), NULL, "Server not configured here", TRUE );
116                         return DISCONNECTED;
117                 }
118                 if( strcmp( Client_Password( Client ), Conf_Server[i].pwd ) != 0 )
119                 {
120                         /* Falsches Passwort */
121                         Log( LOG_ERR, "Connection %d: Bad password for server \"%s\"!", Client_Conn( Client ), Req->argv[0] );
122                         Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
123                         return DISCONNECTED;
124                 }
125                 
126                 /* Ist ein Server mit dieser ID bereits registriert? */
127                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
128
129                 /* Server-Strukturen fuellen ;-) */
130                 Client_SetID( Client, Req->argv[0] );
131                 Client_SetHops( Client, 1 );
132                 Client_SetInfo( Client, Req->argv[Req->argc - 1] );
133                 
134                 /* Meldet sich der Server bei uns an? */
135                 if( Req->argc == 2 )
136                 {
137                         /* Unseren SERVER- und PASS-Befehl senden */
138                         ok = TRUE;
139                         if( ! IRC_WriteStrClient( Client, "PASS %s "PASSSERVERADD, Conf_Server[i].pwd )) ok = FALSE;
140                         else ok = IRC_WriteStrClient( Client, "SERVER %s 1 :%s", Conf_ServerName, Conf_ServerInfo );
141                         if( ! ok )
142                         {
143                                 Conn_Close( Client_Conn( Client ), "Unexpected server behavior!", NULL, FALSE );
144                                 return DISCONNECTED;
145                         }
146                         Client_SetIntroducer( Client, Client );
147                         Client_SetToken( Client, 1 );
148                 }
149                 else  Client_SetToken( Client, atoi( Req->argv[1] ));
150
151                 Log( LOG_NOTICE, "Server \"%s\" registered (connection %d, 1 hop - direct link).", Client_ID( Client ), Client_Conn( Client ));
152
153                 Client_SetType( Client, CLIENT_SERVER );
154
155                 /* maximalen Hop Count ermitteln */
156                 max_hops = 0;
157                 c = Client_First( );
158                 while( c )
159                 {
160                         if( Client_Hops( c ) > max_hops ) max_hops = Client_Hops( c );
161                         c = Client_Next( c );
162                 }
163                 
164                 /* Alle bisherigen Server dem neuen Server bekannt machen,
165                  * die bisherigen Server ueber den neuen informierenn */
166                 for( i = 0; i < ( max_hops + 1 ); i++ )
167                 {
168                         c = Client_First( );
169                         while( c )
170                         {
171                                 if(( Client_Type( c ) == CLIENT_SERVER ) && ( c != Client ) && ( c != Client_ThisServer( )) && ( Client_Hops( c ) == i ))
172                                 {
173                                         if( Client_Conn( c ) > NONE )
174                                         {
175                                                 /* Dem gefundenen Server gleich den neuen
176                                                  * Server bekannt machen */
177                                                 if( ! IRC_WriteStrClient( c, "SERVER %s %d %d :%s", Client_ID( Client ), Client_Hops( Client ) + 1, Client_MyToken( Client ), Client_Info( Client ))) return DISCONNECTED;
178                                         }
179                                         
180                                         /* Den neuen Server ueber den alten informieren */
181                                         if( ! IRC_WriteStrClientPrefix( Client, Client_Hops( c ) == 1 ? Client_ThisServer( ) : Client_Introducer( c ), "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ))) return DISCONNECTED;
182                                 }
183                                 c = Client_Next( c );
184                         }
185                 }
186
187                 /* alle User dem neuen Server bekannt machen */
188                 c = Client_First( );
189                 while( c )
190                 {
191                         if( Client_Type( c ) == CLIENT_USER )
192                         {
193                                 /* User an neuen Server melden */
194                                 if( ! IRC_WriteStrClient( Client, "NICK %s %d %s %s %d +%s :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_User( c ), Client_Hostname( c ), Client_MyToken( Client_Introducer( c )), Client_Modes( c ), Client_Info( c ))) return DISCONNECTED;
195                         }
196                         c = Client_Next( c );
197                 }
198
199                 /* Channels dem neuen Server bekannt machen */
200                 chan = Channel_First( );
201                 while( chan )
202                 {
203                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
204
205                         /* alle Member suchen */
206                         cl2chan = Channel_FirstMember( chan );
207                         while( cl2chan )
208                         {
209                                 cl = Channel_GetClient( cl2chan );
210                                 assert( cl != NULL );
211
212                                 /* Nick, ggf. mit Modes, anhaengen */
213                                 if( str[strlen( str ) - 1] != ':' ) strcat( str, "," );
214                                 if( strchr( Channel_UserModes( chan, cl ), 'v' )) strcat( str, "+" );
215                                 if( strchr( Channel_UserModes( chan, cl ), 'o' )) strcat( str, "@" );
216                                 strcat( str, Client_ID( cl ));
217
218                                 if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
219                                 {
220                                         /* Zeile senden */
221                                         if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
222                                         sprintf( str, "NJOIN %s :", Channel_Name( chan ));
223                                 }
224                                 
225                                 cl2chan = Channel_NextMember( chan, cl2chan );
226                         }
227
228                         /* noch Daten da? */
229                         if( str[strlen( str ) - 1] != ':')
230                         {
231                                 /* Ja; Also senden ... */
232                                 if( ! IRC_WriteStrClient( Client, str )) return DISCONNECTED;
233                         }
234
235                         /* naechsten Channel suchen */
236                         chan = Channel_Next( chan );
237                 }
238                 
239                 return CONNECTED;
240         }
241         else if( Client_Type( Client ) == CLIENT_SERVER )
242         {
243                 /* Neuer Server wird im Netz angekuendigt */
244
245                 /* Falsche Anzahl Parameter? */
246                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
247
248                 /* Ist ein Server mit dieser ID bereits registriert? */
249                 if( ! Client_CheckID( Client, Req->argv[0] )) return DISCONNECTED;
250
251                 /* Ueberfluessige Hostnamen aus Info-Text entfernen */
252                 ptr = strchr( Req->argv[3] + 2, '[' );
253                 if( ! ptr ) ptr = Req->argv[3];
254
255                 from = Client_GetFromID( Req->prefix );
256                 if( ! from )
257                 {
258                         /* Hm, Server, der diesen einfuehrt, ist nicht bekannt!? */
259                         Log( LOG_ALERT, "Unknown ID in prefix of SERVER: \"%s\"! (on connection %d)", Req->prefix, Client_Conn( Client ));
260                         Conn_Close( Client_Conn( Client ), NULL, "Unknown ID in prefix of SERVER", TRUE );
261                         return DISCONNECTED;
262                 }
263
264                 /* Neue Client-Struktur anlegen */
265                 c = Client_NewRemoteServer( Client, Req->argv[0], from, atoi( Req->argv[1] ), atoi( Req->argv[2] ), ptr, TRUE );
266                 if( ! c )
267                 {
268                         /* Neue Client-Struktur konnte nicht angelegt werden */
269                         Log( LOG_ALERT, "Can't create client structure for server! (on connection %d)", Client_Conn( Client ));
270                         Conn_Close( Client_Conn( Client ), NULL, "Can't allocate client structure for remote server", TRUE );
271                         return DISCONNECTED;
272                 }
273
274                 /* Log-Meldung zusammenbauen und ausgeben */
275                 if(( Client_Hops( c ) > 1 ) && ( Req->prefix[0] )) sprintf( str, "connected to %s, ", Client_ID( from ));
276                 else strcpy( str, "" );
277                 Log( LOG_NOTICE, "Server \"%s\" registered (via %s, %s%d hop%s).", Client_ID( c ), Client_ID( Client ), str, Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
278
279                 /* Andere Server informieren */
280                 IRC_WriteStrServersPrefix( Client, from, "SERVER %s %d %d :%s", Client_ID( c ), Client_Hops( c ) + 1, Client_MyToken( c ), Client_Info( c ));
281
282                 return CONNECTED;
283         }
284         else return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
285 } /* IRC_SERVER */
286
287
288 GLOBAL BOOLEAN IRC_NJOIN( CLIENT *Client, REQUEST *Req )
289 {
290         CHAR *channame, *ptr, modes[8];
291         BOOLEAN is_op, is_voiced;
292         CHANNEL *chan;
293         CLIENT *c;
294         
295         assert( Client != NULL );
296         assert( Req != NULL );
297
298         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTEREDSERVER_MSG, Client_ID( Client ));
299
300         /* Falsche Anzahl Parameter? */
301         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
302
303         channame = Req->argv[0];
304         ptr = strtok( Req->argv[1], "," );
305         while( ptr )
306         {
307                 is_op = is_voiced = FALSE;
308                 
309                 /* Prefixe abschneiden */
310                 while(( *ptr == '@' ) || ( *ptr == '+' ))
311                 {
312                         if( *ptr == '@' ) is_op = TRUE;
313                         if( *ptr == '+' ) is_voiced = TRUE;
314                         ptr++;
315                 }
316
317                 c = Client_GetFromID( ptr );
318                 if( c )
319                 {
320                         Channel_Join( c, channame );
321                         chan = Channel_Search( channame );
322                         assert( chan != NULL );
323                         
324                         if( is_op ) Channel_UserModeAdd( chan, c, 'o' );
325                         if( is_voiced ) Channel_UserModeAdd( chan, c, 'v' );
326
327                         /* im Channel bekannt machen */
328                         IRC_WriteStrChannelPrefix( Client, chan, c, FALSE, "JOIN :%s", channame );
329
330                         /* Channel-User-Modes setzen */
331                         strcpy( modes, Channel_UserModes( chan, c ));
332                         if( modes[0] )
333                         {
334                                 /* Modes im Channel bekannt machen */
335                                 IRC_WriteStrChannelPrefix( Client, chan, Client, FALSE, "MODE %s +%s %s", channame, modes, Client_ID( c ));
336                         }
337                 }
338                 else Log( LOG_ERR, "Got NJOIN for unknown nick \"%s\" for channel \"%s\"!", ptr, channame );
339                 
340                 /* naechsten Nick suchen */
341                 ptr = strtok( NULL, "," );
342         }
343
344         /* an andere Server weiterleiten */
345         IRC_WriteStrServersPrefix( Client, Client_ThisServer( ), "NJOIN %s :%s", Req->argv[0], Req->argv[1] );
346
347         return CONNECTED;
348 } /* IRC_NJOIN */
349
350
351 GLOBAL BOOLEAN IRC_NICK( CLIENT *Client, REQUEST *Req )
352 {
353         CLIENT *intr_c, *target, *c;
354         CHAR *modes;
355
356         assert( Client != NULL );
357         assert( Req != NULL );
358
359         /* Zumindest BitchX sendet NICK-USER in der falschen Reihenfolge. */
360 #ifndef STRICT_RFC
361         if( Client_Type( Client ) == CLIENT_UNKNOWN || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTUSER || Client_Type( Client ) == CLIENT_USER || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
362 #else
363         if( Client_Type( Client ) == CLIENT_UNKNOWN || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_USER || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
364 #endif
365         {
366                 /* User-Registrierung bzw. Nick-Aenderung */
367
368                 /* Falsche Anzahl Parameter? */
369                 if( Req->argc != 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
370
371                 /* "Ziel-Client" ermitteln */
372                 if( Client_Type( Client ) == CLIENT_SERVER )
373                 {
374                         target = Client_GetFromID( Req->prefix );
375                         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
376                 }
377                 else
378                 {
379                         /* Ist der Client "restricted"? */
380                         if( Client_HasMode( Client, 'r' )) return IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
381                         target = Client;
382                 }
383
384 #ifndef STRICT_RFC
385                 /* Wenn der Client zu seinem eigenen Nick wechseln will, so machen
386                  * wir nichts. So macht es das Original und mind. Snak hat probleme,
387                  * wenn wir es nicht so machen. Ob es so okay ist? Hm ... */
388                 if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 ) return CONNECTED;
389 #endif
390                 
391                 /* pruefen, ob Nick bereits vergeben. Speziallfall: der Client
392                  * will nur die Gross- und Kleinschreibung aendern. Das darf
393                  * er natuerlich machen :-) */
394                 if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 )
395                 {
396                         if( ! Client_CheckNick( target, Req->argv[0] )) return CONNECTED;
397                 }
398
399                 /* Nick-Aenderung: allen mitteilen! */
400                 
401                 if( Client_Type( Client ) == CLIENT_USER ) IRC_WriteStrClientPrefix( Client, Client, "NICK :%s", Req->argv[0] );
402                 IRC_WriteStrServersPrefix( Client, target, "NICK :%s", Req->argv[0] );
403                 IRC_WriteStrRelatedPrefix( target, target, FALSE, "NICK :%s", Req->argv[0] );
404
405                 if(( Client_Type( target ) != CLIENT_USER ) && ( Client_Type( target ) != CLIENT_SERVER ))
406                 {
407                         /* Neuer Client */
408                         Log( LOG_DEBUG, "Connection %d: got valid NICK command ...", Client_Conn( Client ));
409
410                         /* Client-Nick registrieren */
411                         Client_SetID( target, Req->argv[0] );
412
413                         /* schon ein USER da? Dann registrieren! */
414                         if( Client_Type( Client ) == CLIENT_GOTUSER ) return Hello_User( Client );
415                         else Client_SetType( Client, CLIENT_GOTNICK );
416                 }
417                 else
418                 {
419                         /* Nick-Aenderung */
420                         Log( LOG_INFO, "User \"%s\" changed nick: \"%s\" -> \"%s\".", Client_Mask( target ), Client_ID( target ), Req->argv[0] );
421
422                         /* neuen Client-Nick speichern */
423                         Client_SetID( target, Req->argv[0] );
424                 }
425
426                 return CONNECTED;
427         }
428         else if( Client_Type( Client ) == CLIENT_SERVER )
429         {
430                 /* Server fuehrt neuen Client ein */
431
432                 /* Falsche Anzahl Parameter? */
433                 if( Req->argc != 7 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
434
435                 /* Nick ueberpruefen */
436                 c = Client_GetFromID( Req->argv[0] );
437                 if( c )
438                 {
439                         /* Der neue Nick ist auf diesem Server bereits registriert:
440                          * sowohl der neue, als auch der alte Client muessen nun
441                          * disconnectiert werden. */
442                         Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
443                         Kill_Nick( Req->argv[0], "Nick collision" );
444                         return CONNECTED;
445                 }
446
447                 /* Server, zu dem der Client connectiert ist, suchen */
448                 intr_c = Client_GetFromToken( Client, atoi( Req->argv[4] ));
449                 if( ! intr_c )
450                 {
451                         Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
452                         Kill_Nick( Req->argv[0], "Unknown server" );
453                         return CONNECTED;
454                 }
455
456                 /* Neue Client-Struktur anlegen */
457                 c = Client_NewRemoteUser( intr_c, Req->argv[0], atoi( Req->argv[1] ), Req->argv[2], Req->argv[3], atoi( Req->argv[4] ), Req->argv[5] + 1, Req->argv[6], TRUE );
458                 if( ! c )
459                 {
460                         /* Eine neue Client-Struktur konnte nicht angelegt werden.
461                          * Der Client muss disconnectiert werden, damit der Netz-
462                          * status konsistent bleibt. */
463                         Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client ));
464                         Kill_Nick( Req->argv[0], "Server error" );
465                         return CONNECTED;
466                 }
467
468                 modes = Client_Modes( c );
469                 if( *modes ) Log( LOG_DEBUG, "User \"%s\" (+%s) registered (via %s, on %s, %d hop%s).", Client_Mask( c ), modes, Client_ID( Client ), Client_ID( intr_c ), Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
470                 else Log( LOG_DEBUG, "User \"%s\" registered (via %s, on %s, %d hop%s).", Client_Mask( c ), Client_ID( Client ), Client_ID( intr_c ), Client_Hops( c ), Client_Hops( c ) > 1 ? "s": "" );
471
472                 /* Andere Server, ausser dem Introducer, informieren */
473                 IRC_WriteStrServersPrefix( Client, Client, "NICK %s %d %s %s %d %s :%s", Req->argv[0], atoi( Req->argv[1] ) + 1, Req->argv[2], Req->argv[3], Client_MyToken( intr_c ), Req->argv[5], Req->argv[6] );
474
475                 return CONNECTED;
476         }
477         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
478 } /* IRC_NICK */
479
480
481 GLOBAL BOOLEAN IRC_USER( CLIENT *Client, REQUEST *Req )
482 {
483         assert( Client != NULL );
484         assert( Req != NULL );
485
486 #ifndef STRICT_RFC
487         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS || Client_Type( Client ) == CLIENT_UNKNOWN )
488 #else
489         if( Client_Type( Client ) == CLIENT_GOTNICK || Client_Type( Client ) == CLIENT_GOTPASS )
490 #endif
491         {
492                 /* Falsche Anzahl Parameter? */
493                 if( Req->argc != 4 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
494
495                 Client_SetUser( Client, Req->argv[0], FALSE );
496                 Client_SetInfo( Client, Req->argv[3] );
497
498                 Log( LOG_DEBUG, "Connection %d: got valid USER command ...", Client_Conn( Client ));
499                 if( Client_Type( Client ) == CLIENT_GOTNICK ) return Hello_User( Client );
500                 else Client_SetType( Client, CLIENT_GOTUSER );
501                 return CONNECTED;
502         }
503         else if( Client_Type( Client ) == CLIENT_USER || Client_Type( Client ) == CLIENT_SERVER || Client_Type( Client ) == CLIENT_SERVICE )
504         {
505                 return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
506         }
507         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
508 } /* IRC_USER */
509
510
511 GLOBAL BOOLEAN IRC_QUIT( CLIENT *Client, REQUEST *Req )
512 {
513         CLIENT *target;
514         
515         assert( Client != NULL );
516         assert( Req != NULL );
517
518         if(( Client_Type( Client ) == CLIENT_USER ) || ( Client_Type( Client ) == CLIENT_SERVICE ))
519         {
520                 /* User / Service */
521                 
522                 /* Falsche Anzahl Parameter? */
523                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
524
525                 if( Req->argc == 0 ) Conn_Close( Client_Conn( Client ), "Got QUIT command.", NULL, TRUE );
526                 else Conn_Close( Client_Conn( Client ), "Got QUIT command.", Req->argv[0], TRUE );
527                 
528                 return DISCONNECTED;
529         }
530         else if ( Client_Type( Client ) == CLIENT_SERVER )
531         {
532                 /* Server */
533
534                 /* Falsche Anzahl Parameter? */
535                 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
536
537                 target = Client_Search( Req->prefix );
538                 if( ! target )
539                 {
540                         Log( LOG_ERR, "Got QUIT from %s for unknown client!?", Client_ID( Client ));
541                         return CONNECTED;
542                 }
543
544                 if( Req->argc == 0 ) Client_Destroy( target, "Got QUIT command.", NULL );
545                 else Client_Destroy( target, "Got QUIT command.", Req->argv[0] );
546
547                 return CONNECTED;
548         }
549         else return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
550 } /* IRC_QUIT */
551
552
553 GLOBAL BOOLEAN IRC_SQUIT( CLIENT *Client, REQUEST *Req )
554 {
555         CLIENT *target;
556         CHAR msg[LINE_LEN + 64];
557         
558         assert( Client != NULL );
559         assert( Req != NULL );
560
561         /* SQUIT ist nur fuer Server erlaubt */
562         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
563
564         /* Falsche Anzahl Parameter? */
565         if( Req->argc != 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
566
567         Log( LOG_DEBUG, "Got SQUIT from %s for \"%s\": \"%s\" ...", Client_ID( Client ), Req->argv[0], Req->argv[1] );
568         
569         /* SQUIT an alle Server weiterleiten */
570         IRC_WriteStrServers( Client, "SQUIT %s :%s", Req->argv[0], Req->argv[1] );
571
572         target = Client_GetFromID( Req->argv[0] );
573         if( ! target )
574         {
575                 Log( LOG_ERR, "Got SQUIT from %s for unknown server \"%s\"!?", Client_ID( Client ), Req->argv[0] );
576                 return CONNECTED;
577         }
578
579         if( Req->argv[1][0] )
580         {
581                 if( strlen( Req->argv[1] ) > LINE_LEN ) Req->argv[1][LINE_LEN] = '\0';
582                 sprintf( msg, "%s (SQUIT from %s).", Req->argv[1], Client_ID( Client ));
583         }
584         else sprintf( msg, "Got SQUIT from %s.", Client_ID( Client ));
585
586         if( Client_Conn( target ) > NONE )
587         {
588                 /* dieser Server hat die Connection */
589                 if( Req->argv[1][0] ) Conn_Close( Client_Conn( target ), msg, Req->argv[1], TRUE );
590                 else Conn_Close( Client_Conn( target ), msg, NULL, TRUE );
591                 return DISCONNECTED;
592         }
593         else
594         {
595                 /* Verbindung hielt anderer Server */
596                 Client_Destroy( target, msg, Req->argv[1] );
597                 return CONNECTED;
598         }
599 } /* IRC_SQUIT */
600
601
602 GLOBAL BOOLEAN IRC_PING( CLIENT *Client, REQUEST *Req )
603 {
604         CLIENT *target, *from;
605
606         assert( Client != NULL );
607         assert( Req != NULL );
608
609         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
610
611         /* Falsche Anzahl Parameter? */
612         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
613         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
614
615         if( Req->argc == 2 )
616         {
617                 /* es wurde ein Ziel-Client angegeben */
618                 target = Client_GetFromID( Req->argv[1] );
619                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
620                 if( target != Client_ThisServer( ))
621                 {
622                         /* ok, forwarden */
623                         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
624                         else from = Client;
625                         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
626                         return IRC_WriteStrClientPrefix( target, from, "PING %s :%s", Client_ID( from ), Req->argv[1] );
627                 }
628         }
629
630         Log( LOG_DEBUG, "Connection %d: got PING, sending PONG ...", Client_Conn( Client ));
631         return IRC_WriteStrClient( Client, "PONG %s :%s", Client_ID( Client_ThisServer( )), Client_ID( Client ));
632 } /* IRC_PING */
633
634
635 GLOBAL BOOLEAN IRC_PONG( CLIENT *Client, REQUEST *Req )
636 {
637         CLIENT *target, *from;
638
639         assert( Client != NULL );
640         assert( Req != NULL );
641
642         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
643
644         /* Falsche Anzahl Parameter? */
645         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NOORIGIN_MSG, Client_ID( Client ));
646         if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
647
648         /* forwarden? */
649         if( Req->argc == 2 )
650         {
651                 target = Client_GetFromID( Req->argv[1] );
652                 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
653                 if( target != Client_ThisServer( ))
654                 {
655                         /* ok, forwarden */
656                         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_GetFromID( Req->prefix );
657                         else from = Client;
658                         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
659                         return IRC_WriteStrClientPrefix( target, from, "PONG %s :%s", Client_ID( from ), Req->argv[1] );
660                 }
661         }
662
663         /* Der Connection-Timestamp wurde schon beim Lesen aus dem Socket
664                 * aktualisiert, daher muss das hier nicht mehr gemacht werden. */
665
666         if( Client_Conn( Client ) > NONE ) Log( LOG_DEBUG, "Connection %d: received PONG. Lag: %ld seconds.", Client_Conn( Client ), time( NULL ) - Conn_LastPing( Client_Conn( Client )));
667         else Log( LOG_DEBUG, "Connection %d: received PONG.", Client_Conn( Client ));
668
669         return CONNECTED;
670 } /* IRC_PONG */
671
672
673 LOCAL BOOLEAN Hello_User( CLIENT *Client )
674 {
675         assert( Client != NULL );
676
677         /* Passwort ueberpruefen */
678         if( strcmp( Client_Password( Client ), Conf_ServerPwd ) != 0 )
679         {
680                 /* Falsches Passwort */
681                 Log( LOG_ERR, "User \"%s\" rejected (connection %d): Bad password!", Client_Mask( Client ), Client_Conn( Client ));
682                 Conn_Close( Client_Conn( Client ), NULL, "Bad password", TRUE );
683                 return DISCONNECTED;
684         }
685
686         Log( LOG_NOTICE, "User \"%s\" registered (connection %d).", Client_Mask( Client ), Client_Conn( Client ));
687
688         /* Andere Server informieren */
689         IRC_WriteStrServers( NULL, "NICK %s 1 %s %s 1 +%s :%s", Client_ID( Client ), Client_User( Client ), Client_Hostname( Client ), Client_Modes( Client ), Client_Info( Client ));
690
691         if( ! IRC_WriteStrClient( Client, RPL_WELCOME_MSG, Client_ID( Client ), Client_Mask( Client ))) return FALSE;
692         if( ! IRC_WriteStrClient( Client, RPL_YOURHOST_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
693         if( ! IRC_WriteStrClient( Client, RPL_CREATED_MSG, Client_ID( Client ), NGIRCd_StartStr )) return FALSE;
694         if( ! IRC_WriteStrClient( Client, RPL_MYINFO_MSG, Client_ID( Client ), Client_ID( Client_ThisServer( )))) return FALSE;
695
696         Client_SetType( Client, CLIENT_USER );
697
698         if( ! IRC_Send_LUSERS( Client )) return DISCONNECTED;
699         if( ! IRC_Show_MOTD( Client )) return DISCONNECTED;
700
701         return CONNECTED;
702 } /* Hello_User */
703
704
705 LOCAL VOID Kill_Nick( CHAR *Nick, CHAR *Reason )
706 {
707         CLIENT *c;
708
709         assert( Nick != NULL );
710         assert( Reason != NULL );
711
712         Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s", Nick, Reason );
713
714         /* andere Server benachrichtigen */
715         IRC_WriteStrServers( NULL, "KILL %s :%s", Nick, Reason );
716
717         /* Ggf. einen eigenen Client toeten */
718         c = Client_GetFromID( Nick );
719         if( c && ( Client_Conn( c ) != NONE )) Conn_Close( Client_Conn( c ), NULL, Reason, TRUE );
720 } /* Kill_Nick */
721
722
723 /* -eof- */