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