]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-login.c
New connection option CONN_RFC1459.
[ngircd-alex.git] / src / ngircd / irc-login.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  * Login and logout
12  */
13
14
15 #include "portab.h"
16
17 #include "imp.h"
18 #include <assert.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <strings.h>
23
24 #include "ngircd.h"
25 #include "resolve.h"
26 #include "conn-func.h"
27 #include "conf.h"
28 #include "client.h"
29 #include "channel.h"
30 #include "log.h"
31 #include "messages.h"
32 #include "parse.h"
33 #include "irc.h"
34 #include "irc-info.h"
35 #include "irc-write.h"
36
37 #include "exp.h"
38 #include "irc-login.h"
39
40
41 static bool Hello_User PARAMS(( CLIENT *Client ));
42 static void Kill_Nick PARAMS(( char *Nick, char *Reason ));
43
44
45 /**
46  * Handler for the IRC command "PASS".
47  * See RFC 2813 section 4.1.1, and RFC 2812 section 3.1.1.
48  */
49 GLOBAL bool
50 IRC_PASS( CLIENT *Client, REQUEST *Req )
51 {
52         char *type, *orig_flags;
53         int protohigh, protolow;
54
55         assert( Client != NULL );
56         assert( Req != NULL );
57
58         /* Return an error if this is not a local client */
59         if (Client_Conn(Client) <= NONE)
60                 return IRC_WriteStrClient(Client, ERR_UNKNOWNCOMMAND_MSG,
61                                           Client_ID(Client), Req->command);
62
63         if (Client_Type(Client) == CLIENT_UNKNOWN && Req->argc == 1) {
64                 /* Not yet registered "unknown" connection, PASS with one
65                  * argument: either a regular client, service, or server
66                  * using the old RFC 1459 section 4.1.1 syntax. */
67                 LogDebug("Connection %d: got PASS command ...",
68                          Client_Conn(Client));
69         } else if ((Client_Type(Client) == CLIENT_UNKNOWN ||
70                     Client_Type(Client) == CLIENT_UNKNOWNSERVER) &&
71                    (Req->argc == 3 || Req->argc == 4)) {
72                 /* Not yet registered "unknown" connection or outgoing server
73                  * link, PASS with three or four argument: server using the
74                  * RFC 2813 section 4.1.1 syntax. */
75                 LogDebug("Connection %d: got PASS command (new server link) ...",
76                          Client_Conn(Client));
77         } else if (Client_Type(Client) == CLIENT_UNKNOWN ||
78                    Client_Type(Client) == CLIENT_UNKNOWNSERVER) {
79                 /* Unregistered connection, but wrong number of arguments: */
80                 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
81                                           Client_ID(Client), Req->command);
82         } else {
83                 /* Registered connection, PASS command is not allowed! */
84                 return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
85                                           Client_ID(Client));
86         }
87
88         Client_SetPassword(Client, Req->argv[0]);
89         Client_SetType(Client, CLIENT_GOTPASS);
90
91         /* Protocol version */
92         if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) {
93                 int c2, c4;
94
95                 c2 = Req->argv[1][2];
96                 c4 = Req->argv[1][4];
97
98                 Req->argv[1][4] = '\0';
99                 protolow = atoi(&Req->argv[1][2]);
100                 Req->argv[1][2] = '\0';
101                 protohigh = atoi(Req->argv[1]);
102
103                 Req->argv[1][2] = c2;
104                 Req->argv[1][4] = c4;
105         } else
106                 protohigh = protolow = 0;
107
108         /* Protocol type, see doc/Protocol.txt */
109         if (Req->argc >= 2 && strlen(Req->argv[1]) > 4)
110                 type = &Req->argv[1][4];
111         else
112                 type = NULL;
113
114         /* Protocol flags/options */
115         if (Req->argc >= 4)
116                 orig_flags = Req->argv[3];
117         else
118                 orig_flags = "";
119
120         /* Implementation, version and IRC+ flags */
121         if (Req->argc >= 3) {
122                 char *impl, *ptr, *serverver, *flags;
123
124                 impl = Req->argv[2];
125                 ptr = strchr(impl, '|');
126                 if (ptr)
127                         *ptr = '\0';
128
129                 if (type && strcmp(type, PROTOIRCPLUS) == 0) {
130                         /* The peer seems to be a server which supports the
131                          * IRC+ protocol (see doc/Protocol.txt). */
132                         serverver = ptr + 1;
133                         flags = strchr(serverver, ':');
134                         if (flags) {
135                                 *flags = '\0';
136                                 flags++;
137                         } else
138                                 flags = "";
139                         Log(LOG_INFO,
140                             "Peer announces itself as %s-%s using protocol %d.%d/IRC+ (flags: \"%s\").",
141                             impl, serverver, protohigh, protolow, flags);
142                 } else {
143                         /* The peer seems to be a server supporting the
144                          * "original" IRC protocol (RFC 2813). */
145                         serverver = "";
146                         if (strchr(orig_flags, 'Z'))
147                                 flags = "Z";
148                         else
149                                 flags = "";
150                         Log(LOG_INFO,
151                             "Peer announces itself as \"%s\" using protocol %d.%d (flags: \"%s\").",
152                             impl, protohigh, protolow, flags);
153                 }
154                 Client_SetFlags(Client, flags);
155         }
156
157         return CONNECTED;
158 } /* IRC_PASS */
159
160
161 /**
162  * IRC "NICK" command.
163  * This function implements the IRC command "NICK" which is used to register
164  * with the server, to change already registered nicknames and to introduce
165  * new users which are connected to other servers.
166  */
167 GLOBAL bool
168 IRC_NICK( CLIENT *Client, REQUEST *Req )
169 {
170         CLIENT *intr_c, *target, *c;
171         CONN_ID conn;
172         char *nick, *user, *hostname, *modes, *info;
173         int token, hops;
174
175         assert( Client != NULL );
176         assert( Req != NULL );
177
178 #ifndef STRICT_RFC
179         /* Some IRC clients, for example BitchX, send the NICK and USER
180          * commands in the wrong order ... */
181         if( Client_Type( Client ) == CLIENT_UNKNOWN
182             || Client_Type( Client ) == CLIENT_GOTPASS
183             || Client_Type( Client ) == CLIENT_GOTNICK
184             || Client_Type( Client ) == CLIENT_GOTUSER
185             || Client_Type( Client ) == CLIENT_USER
186             || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
187 #else
188         if( Client_Type( Client ) == CLIENT_UNKNOWN
189             || Client_Type( Client ) == CLIENT_GOTPASS
190             || Client_Type( Client ) == CLIENT_GOTNICK
191             || Client_Type( Client ) == CLIENT_USER
192             || ( Client_Type( Client ) == CLIENT_SERVER && Req->argc == 1 ))
193 #endif
194         {
195                 /* User registration or change of nickname */
196
197                 /* Wrong number of arguments? */
198                 if( Req->argc != 1 )
199                         return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG,
200                                                    Client_ID( Client ),
201                                                    Req->command );
202
203                 /* Search "target" client */
204                 if( Client_Type( Client ) == CLIENT_SERVER )
205                 {
206                         target = Client_Search( Req->prefix );
207                         if( ! target )
208                                 return IRC_WriteStrClient( Client,
209                                                            ERR_NOSUCHNICK_MSG,
210                                                            Client_ID( Client ),
211                                                            Req->argv[0] );
212                 }
213                 else
214                 {
215                         /* Is this a restricted client? */
216                         if( Client_HasMode( Client, 'r' ))
217                                 return IRC_WriteStrClient( Client,
218                                                            ERR_RESTRICTED_MSG,
219                                                            Client_ID( Client ));
220
221                         target = Client;
222                 }
223
224 #ifndef STRICT_RFC
225                 /* If the clients tries to change to its own nickname we won't
226                  * do anything. This is how the original ircd behaves and some
227                  * clients (for example Snak) expect it to be like this.
228                  * But I doubt that this is "really the right thing" ... */
229                 if( strcmp( Client_ID( target ), Req->argv[0] ) == 0 )
230                         return CONNECTED;
231 #endif
232
233                 /* Check that the new nickname is available. Special case:
234                  * the client only changes from/to upper to lower case. */
235                 if( strcasecmp( Client_ID( target ), Req->argv[0] ) != 0 )
236                 {
237                         if( ! Client_CheckNick( target, Req->argv[0] ))
238                                 return CONNECTED;
239                 }
240
241                 if(( Client_Type( target ) != CLIENT_USER )
242                    && ( Client_Type( target ) != CLIENT_SERVER ))
243                 {
244                         /* New client */
245                         Log( LOG_DEBUG, "Connection %d: got valid NICK command ...", 
246                              Client_Conn( Client ));
247
248                         /* Register new nickname of this client */
249                         Client_SetID( target, Req->argv[0] );
250
251                         /* If we received a valid USER command already then
252                          * register the new client! */
253                         if( Client_Type( Client ) == CLIENT_GOTUSER )
254                                 return Hello_User( Client );
255                         else
256                                 Client_SetType( Client, CLIENT_GOTNICK );
257                 }
258                 else
259                 {
260                         /* Nickname change */
261                         if (Client_Conn(target) > NONE) {
262                                 /* Local client */
263                                 Log(LOG_INFO,
264                                     "User \"%s\" changed nick (connection %d): \"%s\" -> \"%s\".",
265                                     Client_Mask(target), Client_Conn(target),
266                                     Client_ID(target), Req->argv[0]);
267                                 Conn_UpdateIdle(Client_Conn(target));
268                         }
269                         else
270                         {
271                                 /* Remote client */
272                                 Log( LOG_DEBUG,
273                                      "User \"%s\" changed nick: \"%s\" -> \"%s\".",
274                                      Client_Mask( target ), Client_ID( target ),
275                                      Req->argv[0] );
276                         }
277
278                         /* Inform all users and servers (which have to know)
279                          * of this nickname change */
280                         if( Client_Type( Client ) == CLIENT_USER )
281                                 IRC_WriteStrClientPrefix( Client, Client,
282                                                           "NICK :%s",
283                                                           Req->argv[0] );
284                         IRC_WriteStrServersPrefix( Client, target,
285                                                    "NICK :%s", Req->argv[0] );
286                         IRC_WriteStrRelatedPrefix( target, target, false,
287                                                    "NICK :%s", Req->argv[0] );
288
289                         /* Register old nickname for WHOWAS queries */
290                         Client_RegisterWhowas( target );
291
292                         /* Save new nickname */
293                         Client_SetID( target, Req->argv[0] );
294
295                         IRC_SetPenalty( target, 2 );
296                 }
297
298                 return CONNECTED;
299         } else if(Client_Type(Client) == CLIENT_SERVER ||
300                   Client_Type(Client) == CLIENT_SERVICE) {
301                 /* Server or service introduces new client */
302
303                 /* Bad number of parameters? */
304                 if (Req->argc != 2 && Req->argc != 7)
305                         return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
306                                                   Client_ID(Client), Req->command);
307
308                 if (Req->argc >= 7) {
309                         /* RFC 2813 compatible syntax */
310                         nick = Req->argv[0];
311                         hops = atoi(Req->argv[1]);
312                         user = Req->argv[2];
313                         hostname = Req->argv[3];
314                         token = atoi(Req->argv[4]);
315                         modes = Req->argv[5] + 1;
316                         info = Req->argv[6];
317                 } else {
318                         /* RFC 1459 compatible syntax */
319                         nick = Req->argv[0];
320                         hops = 1;
321                         user = Req->argv[0];
322                         hostname = Client_ID(Client);
323                         token = atoi(Req->argv[1]);
324                         modes = "";
325                         info = Req->argv[0];
326
327                         conn = Client_Conn(Client);
328                         if (conn != NONE &&
329                             !(Conn_Options(conn) & CONN_RFC1459)) {
330                                 Log(LOG_INFO,
331                                     "Switching connection %d (\"%s\") to RFC 1459 compatibility mode.",
332                                     conn, Client_ID(Client));
333                                 Conn_SetOption(conn, CONN_RFC1459);
334                         }
335                 }
336
337                 /* Nick ueberpruefen */
338                 c = Client_Search(nick);
339                 if(c) {
340                         /* Der neue Nick ist auf diesem Server bereits registriert:
341                          * sowohl der neue, als auch der alte Client muessen nun
342                          * disconnectiert werden. */
343                         Log( LOG_ERR, "Server %s introduces already registered nick \"%s\"!", Client_ID( Client ), Req->argv[0] );
344                         Kill_Nick( Req->argv[0], "Nick collision" );
345                         return CONNECTED;
346                 }
347
348                 /* Server, zu dem der Client connectiert ist, suchen */
349                 intr_c = Client_GetFromToken(Client, token);
350                 if( ! intr_c )
351                 {
352                         Log( LOG_ERR, "Server %s introduces nick \"%s\" on unknown server!?", Client_ID( Client ), Req->argv[0] );
353                         Kill_Nick( Req->argv[0], "Unknown server" );
354                         return CONNECTED;
355                 }
356
357                 /* Neue Client-Struktur anlegen */
358                 c = Client_NewRemoteUser(intr_c, nick, hops, user, hostname,
359                                          token, modes, info, true);
360                 if( ! c )
361                 {
362                         /* Eine neue Client-Struktur konnte nicht angelegt werden.
363                          * Der Client muss disconnectiert werden, damit der Netz-
364                          * status konsistent bleibt. */
365                         Log( LOG_ALERT, "Can't create client structure! (on connection %d)", Client_Conn( Client ));
366                         Kill_Nick( Req->argv[0], "Server error" );
367                         return CONNECTED;
368                 }
369
370                 modes = Client_Modes( c );
371                 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": "" );
372                 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": "" );
373
374                 /* Andere Server, ausser dem Introducer, informieren */
375                 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] );
376
377                 return CONNECTED;
378         }
379         else return IRC_WriteStrClient( Client, ERR_ALREADYREGISTRED_MSG, Client_ID( Client ));
380 } /* IRC_NICK */
381
382
383 /**
384  * Handler for the IRC command "USER".
385  */
386 GLOBAL bool
387 IRC_USER(CLIENT * Client, REQUEST * Req)
388 {
389         CLIENT *c;
390 #ifdef IDENTAUTH
391         char *ptr;
392 #endif
393
394         assert(Client != NULL);
395         assert(Req != NULL);
396
397         if (Client_Type(Client) == CLIENT_GOTNICK ||
398 #ifndef STRICT_RFC
399             Client_Type(Client) == CLIENT_UNKNOWN ||
400 #endif
401             Client_Type(Client) == CLIENT_GOTPASS)
402         {
403                 /* New connection */
404                 if (Req->argc != 4)
405                         return IRC_WriteStrClient(Client,
406                                                   ERR_NEEDMOREPARAMS_MSG,
407                                                   Client_ID(Client),
408                                                   Req->command);
409
410                 /* User name */
411 #ifdef IDENTAUTH
412                 ptr = Client_User(Client);
413                 if (!ptr || !*ptr || *ptr == '~')
414                         Client_SetUser(Client, Req->argv[0], false);
415 #else
416                 Client_SetUser(Client, Req->argv[0], false);
417 #endif
418
419                 /* "Real name" or user info text: Don't set it to the empty
420                  * string, the original ircd can't deal with such "real names"
421                  * (e. g. "USER user * * :") ... */
422                 if (*Req->argv[3])
423                         Client_SetInfo(Client, Req->argv[3]);
424                 else
425                         Client_SetInfo(Client, "-");
426
427                 LogDebug("Connection %d: got valid USER command ...",
428                     Client_Conn(Client));
429                 if (Client_Type(Client) == CLIENT_GOTNICK)
430                         return Hello_User(Client);
431                 else
432                         Client_SetType(Client, CLIENT_GOTUSER);
433                 return CONNECTED;
434
435         } else if (Client_Type(Client) == CLIENT_SERVER ||
436                    Client_Type(Client) == CLIENT_SERVICE) {
437                 /* Server/service updating an user */
438                 if (Req->argc != 4)
439                         return IRC_WriteStrClient(Client,
440                                                   ERR_NEEDMOREPARAMS_MSG,
441                                                   Client_ID(Client),
442                                                   Req->command);
443                 c = Client_Search(Req->prefix);
444                 if (!c)
445                         return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
446                                                   Client_ID(Client),
447                                                   Req->prefix);
448
449                 Client_SetUser(c, Req->argv[0], true);
450                 Client_SetHostname(c, Req->argv[1]);
451                 Client_SetInfo(c, Req->argv[3]);
452
453                 LogDebug("Connection %d: got valid USER command for \"%s\".",
454                          Client_Conn(Client), Client_Mask(c));
455                 return CONNECTED;
456         } else if (Client_Type(Client) == CLIENT_USER) {
457                 /* Already registered connection */
458                 return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
459                                           Client_ID(Client));
460         } else {
461                 /* Unexpected/invalid connection state? */
462                 return IRC_WriteStrClient(Client, ERR_NOTREGISTERED_MSG,
463                                           Client_ID(Client));
464         }
465 } /* IRC_USER */
466
467
468 /**
469  * Service registration.
470  * ngIRCd does not support services at the moment, so this function is a
471  * dummy that returns ERR_ERRONEUSNICKNAME on each call.
472  */
473 GLOBAL bool
474 IRC_SERVICE(CLIENT *Client, REQUEST *Req)
475 {
476         assert(Client != NULL);
477         assert(Req != NULL);
478
479         if (Client_Type(Client) != CLIENT_GOTPASS)
480                 return IRC_WriteStrClient(Client, ERR_ALREADYREGISTRED_MSG,
481                                           Client_ID(Client));
482
483         if (Req->argc != 6)
484                 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
485                                           Client_ID(Client), Req->command);
486
487         return IRC_WriteStrClient(Client, ERR_ERRONEUSNICKNAME_MSG,
488                                   Client_ID(Client), Req->argv[0]);
489 } /* IRC_SERVICE */
490
491
492 GLOBAL bool
493 IRC_QUIT( CLIENT *Client, REQUEST *Req )
494 {
495         CLIENT *target;
496         char quitmsg[LINE_LEN];
497
498         assert( Client != NULL );
499         assert( Req != NULL );
500
501         /* Wrong number of arguments? */
502         if( Req->argc > 1 )
503                 return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
504
505         if (Req->argc == 1)
506                 strlcpy(quitmsg, Req->argv[0], sizeof quitmsg);
507
508         if ( Client_Type( Client ) == CLIENT_SERVER )
509         {
510                 /* Server */
511                 target = Client_Search( Req->prefix );
512                 if( ! target )
513                 {
514                         /* Den Client kennen wir nicht (mehr), also nichts zu tun. */
515                         Log( LOG_WARNING, "Got QUIT from %s for unknown client!?", Client_ID( Client ));
516                         return CONNECTED;
517                 }
518
519                 Client_Destroy( target, "Got QUIT command.", Req->argc == 1 ? quitmsg : NULL, true);
520
521                 return CONNECTED;
522         }
523         else
524         {
525                 if (Req->argc == 1 && quitmsg[0] != '\"') {
526                         /* " " to avoid confusion */
527                         strlcpy(quitmsg, "\"", sizeof quitmsg);
528                         strlcat(quitmsg, Req->argv[0], sizeof quitmsg-1);
529                         strlcat(quitmsg, "\"", sizeof quitmsg );
530                 }
531
532                 /* User, Service, oder noch nicht registriert */
533                 Conn_Close( Client_Conn( Client ), "Got QUIT command.", Req->argc == 1 ? quitmsg : NULL, true);
534
535                 return DISCONNECTED;
536         }
537 } /* IRC_QUIT */
538
539
540 GLOBAL bool
541 IRC_PING(CLIENT *Client, REQUEST *Req)
542 {
543         CLIENT *target, *from;
544
545         assert(Client != NULL);
546         assert(Req != NULL);
547
548         /* Wrong number of arguments? */
549         if (Req->argc < 1)
550                 return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
551                                           Client_ID(Client));
552 #ifdef STRICT_RFC
553         /* Don't ignore additional arguments when in "strict" mode */
554         if (Req->argc > 2)
555                  return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
556                                            Client_ID(Client), Req->command);
557 #endif
558
559         if (Req->argc > 1) {
560                 /* A target has been specified ... */
561                 target = Client_Search(Req->argv[1]);
562
563                 if (!target || Client_Type(target) != CLIENT_SERVER)
564                         return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
565                                         Client_ID(Client), Req->argv[1]);
566
567                 if (target != Client_ThisServer()) {
568                         /* Ok, we have to forward the PING */
569                         if (Client_Type(Client) == CLIENT_SERVER)
570                                 from = Client_Search(Req->prefix);
571                         else
572                                 from = Client;
573                         if (!from)
574                                 return IRC_WriteStrClient(Client,
575                                                 ERR_NOSUCHSERVER_MSG,
576                                                 Client_ID(Client), Req->prefix);
577
578                         return IRC_WriteStrClientPrefix(target, from,
579                                         "PING %s :%s", Req->argv[0],
580                                         Req->argv[1] );
581                 }
582         }
583
584         if (Client_Type(Client) == CLIENT_SERVER) {
585                 if (Req->prefix)
586                         from = Client_Search(Req->prefix);
587                 else
588                         from = Client;
589         } else
590                 from = Client_ThisServer();
591         if (!from)
592                 return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
593                                         Client_ID(Client), Req->prefix);
594
595         Log(LOG_DEBUG, "Connection %d: got PING, sending PONG ...",
596             Client_Conn(Client));
597
598 #ifdef STRICT_RFC
599         return IRC_WriteStrClient(Client, "PONG %s :%s",
600                 Client_ID(from), Client_ID(Client));
601 #else
602         /* Some clients depend on the argument being returned in the PONG
603          * reply (not mentioned in any RFC, though) */
604         return IRC_WriteStrClient(Client, "PONG %s :%s",
605                 Client_ID(from), Req->argv[0]);
606 #endif
607 } /* IRC_PING */
608
609
610 GLOBAL bool
611 IRC_PONG(CLIENT *Client, REQUEST *Req)
612 {
613         CLIENT *target, *from;
614         char *s;
615
616         assert(Client != NULL);
617         assert(Req != NULL);
618
619         /* Wrong number of arguments? */
620         if (Req->argc < 1)
621                 return IRC_WriteStrClient(Client, ERR_NOORIGIN_MSG,
622                                           Client_ID(Client));
623         if (Req->argc > 2)
624                 return IRC_WriteStrClient(Client, ERR_NEEDMOREPARAMS_MSG,
625                                           Client_ID(Client), Req->command);
626
627         /* Forward? */
628         if (Req->argc == 2 && Client_Type(Client) == CLIENT_SERVER) {
629                 target = Client_Search(Req->argv[0]);
630                 if (!target)
631                         return IRC_WriteStrClient(Client, ERR_NOSUCHSERVER_MSG,
632                                         Client_ID(Client), Req->argv[0]);
633
634                 from = Client_Search(Req->prefix);
635
636                 if (target != Client_ThisServer() && target != from) {
637                         /* Ok, we have to forward the message. */
638                         if (!from)
639                                 return IRC_WriteStrClient(Client,
640                                                 ERR_NOSUCHSERVER_MSG,
641                                                 Client_ID(Client), Req->prefix);
642
643                         if (Client_Type(Client_NextHop(target)) != CLIENT_SERVER)
644                                 s = Client_ID(from);
645                         else
646                                 s = Req->argv[0];
647                         return IRC_WriteStrClientPrefix(target, from,
648                                  "PONG %s :%s", s, Req->argv[1]);
649                 }
650         }
651
652         /* The connection timestamp has already been updated when the data has
653          * been read from so socket, so we don't need to update it here. */
654
655         if (Client_Conn(Client) > NONE)
656                 Log(LOG_DEBUG,
657                         "Connection %d: received PONG. Lag: %ld seconds.",
658                         Client_Conn(Client),
659                         time(NULL) - Conn_LastPing(Client_Conn(Client)));
660         else
661                  Log(LOG_DEBUG,
662                         "Connection %d: received PONG.", Client_Conn(Client));
663
664         return CONNECTED;
665 } /* IRC_PONG */
666
667
668 static bool
669 Hello_User(CLIENT * Client)
670 {
671         assert(Client != NULL);
672
673         /* Check password ... */
674         if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
675                 /* Bad password! */
676                 Log(LOG_ERR,
677                     "User \"%s\" rejected (connection %d): Bad password!",
678                     Client_Mask(Client), Client_Conn(Client));
679                 Conn_Close(Client_Conn(Client), NULL, "Bad password", true);
680                 return DISCONNECTED;
681         }
682
683         Log(LOG_NOTICE, "User \"%s\" registered (connection %d).",
684             Client_Mask(Client), Client_Conn(Client));
685
686         /* Inform other servers */
687         IRC_WriteStrServers(NULL, "NICK %s 1 %s %s 1 +%s :%s",
688                             Client_ID(Client), Client_User(Client),
689                             Client_Hostname(Client), Client_Modes(Client),
690                             Client_Info(Client));
691
692         if (!IRC_WriteStrClient
693             (Client, RPL_WELCOME_MSG, Client_ID(Client), Client_Mask(Client)))
694                 return false;
695         if (!IRC_WriteStrClient
696             (Client, RPL_YOURHOST_MSG, Client_ID(Client),
697              Client_ID(Client_ThisServer()), PACKAGE_VERSION, TARGET_CPU,
698              TARGET_VENDOR, TARGET_OS))
699                 return false;
700         if (!IRC_WriteStrClient
701             (Client, RPL_CREATED_MSG, Client_ID(Client), NGIRCd_StartStr))
702                 return false;
703         if (!IRC_WriteStrClient
704             (Client, RPL_MYINFO_MSG, Client_ID(Client),
705              Client_ID(Client_ThisServer()), PACKAGE_VERSION, USERMODES,
706              CHANMODES))
707                 return false;
708
709         /* Features supported by this server (005 numeric, ISUPPORT),
710          * see <http://www.irc.org/tech_docs/005.html> for details. */
711         if (!IRC_Send_ISUPPORT(Client))
712                 return DISCONNECTED;
713
714         Client_SetType(Client, CLIENT_USER);
715
716         if (!IRC_Send_LUSERS(Client))
717                 return DISCONNECTED;
718         if (!IRC_Show_MOTD(Client))
719                 return DISCONNECTED;
720
721         /* Suspend the client for a second ... */
722         IRC_SetPenalty(Client, 1);
723
724         return CONNECTED;
725 } /* Hello_User */
726
727
728 static void
729 Kill_Nick( char *Nick, char *Reason )
730 {
731         REQUEST r;
732
733         assert( Nick != NULL );
734         assert( Reason != NULL );
735
736         r.prefix = (char *)Client_ThisServer( );
737         r.argv[0] = Nick;
738         r.argv[1] = Reason;
739         r.argc = 2;
740
741         Log( LOG_ERR, "User(s) with nick \"%s\" will be disconnected: %s", Nick, Reason );
742         IRC_KILL( Client_ThisServer( ), &r );
743 } /* Kill_Nick */
744
745
746 /* -eof- */