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