Author: Isomer <isomer@coders.net>
[ircu2.10.12-pk.git] / ircd / m_nick.c
1 /*
2  * IRC - Internet Relay Chat, ircd/m_nick.c
3  * Copyright (C) 1990 Jarkko Oikarinen and
4  *                    University of Oulu, Computing Center
5  *
6  * See file AUTHORS in IRC package for additional names of
7  * the programmers.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 1, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  * $Id$
24  */
25
26 /*
27  * m_functions execute protocol messages on this server:
28  *
29  *    cptr    is always NON-NULL, pointing to a *LOCAL* client
30  *            structure (with an open socket connected!). This
31  *            identifies the physical socket where the message
32  *            originated (or which caused the m_function to be
33  *            executed--some m_functions may call others...).
34  *
35  *    sptr    is the source of the message, defined by the
36  *            prefix part of the message if present. If not
37  *            or prefix not found, then sptr==cptr.
38  *
39  *            (!IsServer(cptr)) => (cptr == sptr), because
40  *            prefixes are taken *only* from servers...
41  *
42  *            (IsServer(cptr))
43  *                    (sptr == cptr) => the message didn't
44  *                    have the prefix.
45  *
46  *                    (sptr != cptr && IsServer(sptr) means
47  *                    the prefix specified servername. (?)
48  *
49  *                    (sptr != cptr && !IsServer(sptr) means
50  *                    that message originated from a remote
51  *                    user (not local).
52  *
53  *            combining
54  *
55  *            (!IsServer(sptr)) means that, sptr can safely
56  *            taken as defining the target structure of the
57  *            message in this server.
58  *
59  *    *Always* true (if 'parse' and others are working correct):
60  *
61  *    1)      sptr->from == cptr  (note: cptr->from == cptr)
62  *
63  *    2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64  *            *cannot* be a local connection, unless it's
65  *            actually cptr!). [MyConnect(x) should probably
66  *            be defined as (x == x->from) --msa ]
67  *
68  *    parc    number of variable parameter strings (if zero,
69  *            parv is allowed to be NULL)
70  *
71  *    parv    a NULL terminated list of parameter pointers,
72  *
73  *                    parv[0], sender (prefix string), if not present
74  *                            this points to an empty string.
75  *                    parv[1]...parv[parc-1]
76  *                            pointers to additional parameters
77  *                    parv[parc] == NULL, *always*
78  *
79  *            note:   it is guaranteed that parv[0]..parv[parc-1] are all
80  *                    non-NULL pointers.
81  */
82 #if 0
83 /*
84  * No need to include handlers.h here the signatures must match
85  * and we don't need to force a rebuild of all the handlers everytime
86  * we add a new one to the list. --Bleep
87  */
88 #include "handlers.h"
89 #endif /* 0 */
90 #include "IPcheck.h"
91 #include "client.h"
92 #include "hash.h"
93 #include "ircd.h"
94 #include "ircd_chattr.h"
95 #include "ircd_reply.h"
96 #include "ircd_string.h"
97 #include "msg.h"
98 #include "numeric.h"
99 #include "numnicks.h"
100 #include "s_debug.h"
101 #include "s_misc.h"
102 #include "s_user.h"
103 #include "send.h"
104
105 #include <assert.h>
106 #include <stdlib.h>
107 #include <string.h>
108
109 /*
110  * m_nick - message handler for local clients
111  * parv[0] = sender prefix
112  * parv[1] = nickname
113  */
114 int m_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
115 {
116   struct Client* acptr;
117   char           nick[NICKLEN + 2];
118   char*          arg;
119   char*          s;
120   const char*    client_name;
121
122   assert(0 != cptr);
123   assert(cptr == sptr);
124
125   /*
126    * parv[0] will be empty for clients connecting for the first time
127    */
128   client_name = (*sptr->name) ? sptr->name : "*";
129
130   if (parc < 2) {
131     send_reply(sptr, ERR_NONICKNAMEGIVEN);
132     return 0;
133   }
134   /*
135    * Don't let them send make us send back a really long string of
136    * garbage
137    */
138   arg = parv[1];
139   if (strlen(arg) > NICKLEN)
140     arg[NICKLEN] = '\0';
141
142   if ((s = strchr(arg, '~')))
143     *s = '\0';
144
145   strcpy(nick, arg);
146
147   /*
148    * If do_nick_name() returns a null name OR if the server sent a nick
149    * name and do_nick_name() changed it in some way (due to rules of nick
150    * creation) then reject it. If from a server and we reject it,
151    * and KILL it. -avalon 4/4/92
152    */
153   if (0 == do_nick_name(nick)) {
154     send_reply(sptr, ERR_ERRONEUSNICKNAME, arg);
155     return 0;
156   }
157
158   /* 
159    * Check if this is a LOCAL user trying to use a reserved (Juped)
160    * nick, if so tell him that it's a nick in use...
161    */
162   if (isNickJuped(nick)) {
163     send_reply(sptr, ERR_NICKNAMEINUSE, nick);
164     return 0;                        /* NICK message ignored */
165   }
166
167   if (!(acptr = FindClient(nick))) {
168     /*
169      * No collisions, all clear...
170      */
171     return set_nick_name(cptr, sptr, nick, parc, parv);
172   }
173   if (IsServer(acptr)) {
174     send_reply(sptr, ERR_NICKNAMEINUSE, nick);
175     return 0;                        /* NICK message ignored */
176   }
177   /*
178    * If acptr == sptr, then we have a client doing a nick
179    * change between *equivalent* nicknames as far as server
180    * is concerned (user is changing the case of his/her
181    * nickname or somesuch)
182    */
183   if (acptr == sptr) {
184     /*
185      * If acptr == sptr, then we have a client doing a nick
186      * change between *equivalent* nicknames as far as server
187      * is concerned (user is changing the case of his/her
188      * nickname or somesuch)
189      */
190     if (0 != strcmp(acptr->name, nick)) {
191       /*
192        * Allows change of case in his/her nick
193        */
194       return set_nick_name(cptr, sptr, nick, parc, parv);
195     }
196     /*
197      * This is just ':old NICK old' type thing.
198      * Just forget the whole thing here. There is
199      * no point forwarding it to anywhere,
200      * especially since servers prior to this
201      * version would treat it as nick collision.
202      */
203     return 0;
204   }
205   /*
206    * Note: From this point forward it can be assumed that
207    * acptr != sptr (point to different client structures).
208    */
209   assert(acptr != sptr);
210   /*
211    * If the older one is "non-person", the new entry is just
212    * allowed to overwrite it. Just silently drop non-person,
213    * and proceed with the nick. This should take care of the
214    * "dormant nick" way of generating collisions...
215    *
216    * XXX - hmmm can this happen after one is registered?
217    */
218   if (IsUnknown(acptr) && MyConnect(acptr)) {
219     ++ServerStats->is_ref;
220     exit_client(cptr, acptr, &me, "Overridden by other sign on");
221     return set_nick_name(cptr, sptr, nick, parc, parv);
222   }
223   /*
224    * NICK is coming from local client connection. Just
225    * send error reply and ignore the command.
226    */
227   send_reply(sptr, ERR_NICKNAMEINUSE, nick);
228   return 0;                        /* NICK message ignored */
229 }
230
231
232 /*
233  * ms_nick - server message handler for nicks
234  * parv[0] = sender prefix
235  * parv[1] = nickname
236  *
237  * If from server, source is client:
238  *   parv[2] = timestamp
239  *
240  * Source is server:
241  *   parv[2] = hopcount
242  *   parv[3] = timestamp
243  *   parv[4] = username
244  *   parv[5] = hostname
245  *   parv[6] = umode (optional)
246  *   parv[parc-4] = %<lastmod>:<mask>   <- Only if matching GLINE
247  *   parv[parc-3] = IP#                 <- Only Protocol >= 10
248  *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
249  *   parv[parc-1] = info
250  *   parv[0] = server
251  */
252 int ms_nick(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
253 {
254   struct Client* acptr;
255   char           nick[NICKLEN + 2];
256   time_t         lastnick = 0;
257   int            differ = 1;
258
259   assert(0 != cptr);
260   assert(0 != sptr);
261   assert(IsServer(cptr));
262
263   if ((IsServer(sptr) && parc < 8) || parc < 3) {
264     sendto_opmask_butone(0, SNO_OLDSNO, "bad NICK param count for %s from %C",
265                          parv[1], cptr);
266     return need_more_params(sptr, "NICK");
267   }
268
269   ircd_strncpy(nick, parv[1], NICKLEN);
270   nick[NICKLEN] = '\0';
271
272   if (!IsBurstOrBurstAck(sptr)) {
273      if (IsServer(sptr)) {
274        lastnick = atoi(parv[3]);
275        if (lastnick > OLDEST_TS) 
276          sptr->serv->lag = TStime() - lastnick;
277      }
278      else {
279        lastnick = atoi(parv[2]); 
280        if (lastnick > OLDEST_TS)
281          sptr->user->server->serv->lag = TStime() - lastnick;
282      }
283   }
284   /*
285    * If do_nick_name() returns a null name OR if the server sent a nick
286    * name and do_nick_name() changed it in some way (due to rules of nick
287    * creation) then reject it. If from a server and we reject it,
288    * and KILL it. -avalon 4/4/92
289    */
290   if (0 == do_nick_name(nick) || 0 != strcmp(nick, parv[1])) {
291     send_reply(sptr, ERR_ERRONEUSNICKNAME, parv[1]);
292
293     ++ServerStats->is_kill;
294     sendto_opmask_butone(0, SNO_OLDSNO, "Bad Nick: %s From: %s %C", parv[1],
295                          parv[0], cptr);
296     sendcmdto_one(&me, CMD_KILL, cptr, "%s :%s (%s <- %s[%s])",
297                   IsServer(sptr) ? parv[parc - 2] : parv[0], me.name, parv[1],
298                   nick, cptr->name);
299     if (!IsServer(sptr)) {
300       /*
301        * bad nick _change_
302        */
303       sendcmdto_serv_butone(&me, CMD_KILL, 0, "%s :%s (%s <- %s!%s@%s)",
304                             parv[0], me.name, cptr->name, parv[0],
305                             sptr->user ? sptr->username : "",
306                             sptr->user ? sptr->user->server->name :
307                             cptr->name);
308     }
309     return 0;
310   }
311   /*
312    * Check against nick name collisions.
313    *
314    * Put this 'if' here so that the nesting goes nicely on the screen :)
315    * We check against server name list before determining if the nickname
316    * is present in the nicklist (due to the way the below for loop is
317    * constructed). -avalon
318    */
319    
320   acptr = FindClient(nick);
321   if (!acptr) {
322     /*
323      * No collisions, all clear...
324      */
325     return set_nick_name(cptr, sptr, nick, parc, parv);
326   }
327   assert(0 != acptr);
328
329   if (IsServer(acptr)) {
330     /*
331      * We have a nickname trying to use the same name as
332      * a server. Send out a nick collision KILL to remove
333      * the nickname. As long as only a KILL is sent out,
334      * there is no danger of the server being disconnected.
335      * Ultimate way to jupiter a nick ? >;-). -avalon
336      */
337     sendto_opmask_butone(0, SNO_OLDSNO, "Nick collision on %C(%C <- %C)", sptr,
338                          acptr->from, cptr);
339     ++ServerStats->is_kill;
340
341     sendcmdto_one(&me, CMD_KILL, cptr, "%C :%s (%s <- %s)", sptr, me.name,
342                   acptr->from->name, cptr->name);
343
344     sptr->flags |= FLAGS_KILLED;
345     /*
346      * if sptr is a server it is exited here, nothing else to do
347      */
348     return exit_client(cptr, sptr, &me, "Nick/Server collision");
349   }
350
351   /*
352    * If acptr == sptr, then we have a client doing a nick
353    * change between *equivalent* nicknames as far as server
354    * is concerned (user is changing the case of his/her
355    * nickname or somesuch)
356    */
357   if (acptr == sptr) {
358     if (strcmp(acptr->name, nick) != 0)
359       /*
360        * Allows change of case in his/her nick
361        */
362       return set_nick_name(cptr, sptr, nick, parc, parv);
363     else
364       /*
365        * This is just ':old NICK old' type thing.
366        * Just forget the whole thing here. There is
367        * no point forwarding it to anywhere,
368        * especially since servers prior to this
369        * version would treat it as nick collision.
370        */
371       return 0;                        /* NICK Message ignored */
372   }
373
374   /*
375    * Note: From this point forward it can be assumed that
376    * acptr != sptr (point to different client structures).
377    */
378   assert(acptr != sptr);
379   /*
380    * If the older one is "non-person", the new entry is just
381    * allowed to overwrite it. Just silently drop non-person,
382    * and proceed with the nick. This should take care of the
383    * "dormant nick" way of generating collisions...
384    */
385   if (IsUnknown(acptr) && MyConnect(acptr)) {
386     ++ServerStats->is_ref;
387     exit_client(cptr, acptr, &me, "Overridden by other sign on");
388     return set_nick_name(cptr, sptr, nick, parc, parv);
389   }
390   /*
391    * Decide, we really have a nick collision and deal with it
392    */
393   /*
394    * NICK was coming from a server connection.
395    * This means we have a race condition (two users signing on
396    * at the same time), or two net fragments reconnecting with the same nick.
397    * The latter can happen because two different users connected
398    * or because one and the same user switched server during a net break.
399    * If the TimeStamps are equal, we kill both (or only 'new'
400    * if it was a ":server NICK new ...").
401    * Otherwise we kill the youngest when user@host differ,
402    * or the oldest when they are the same.
403    * We treat user and ~user as different, because if it wasn't
404    * a faked ~user the AUTH wouldn't have added the '~'.
405    * --Run
406    *
407    */
408   if (IsServer(sptr)) {
409     /*
410      * A new NICK being introduced by a neighbouring
411      * server (e.g. message type ":server NICK new ..." received)
412      *
413      * compare IP address and username
414      */
415     differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
416               (0 != ircd_strcmp(acptr->user->username, parv[4]));
417     sendto_opmask_butone(0, SNO_OLDSNO, "Nick collision on %C (%C %Tu <- "
418                          "%C %Tu (%s user@host))", acptr, acptr->from,
419                          acptr->lastnick, cptr, lastnick,
420                          differ ? "Different" : "Same");
421   }
422   else {
423     /*
424      * A NICK change has collided (e.g. message type ":old NICK new").
425      *
426      * compare IP address and username
427      */
428     differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
429               (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
430     sendto_opmask_butone(0, SNO_OLDSNO, "Nick change collision from %C to "
431                          "%C (%C %Tu <- %C %Tu)", sptr, acptr, acptr->from,
432                          acptr->lastnick, cptr, lastnick);
433   }
434   /*
435    * Now remove (kill) the nick on our side if it is the youngest.
436    * If no timestamp was received, we ignore the incoming nick
437    * (and expect a KILL for our legit nick soon ):
438    * When the timestamps are equal we kill both nicks. --Run
439    * acptr->from != cptr should *always* be true (?).
440    *
441    * This exits the client sending the NICK message
442    */
443   if (acptr->from != cptr) {
444     if ((differ && lastnick >= acptr->lastnick) || (!differ && lastnick <= acptr->lastnick)) {
445       if (!IsServer(sptr)) {
446         ++ServerStats->is_kill;
447         sendcmdto_serv_butone(&me, CMD_KILL, sptr, "%C :%s (%s <- %s (Nick "
448                               "collision))", sptr, me.name, acptr->from->name,
449                               cptr->name);
450         assert(!MyConnect(sptr));
451 #if 0
452         /*
453          * XXX - impossible
454          */
455         if (MyConnect(sptr))
456           sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost 2)", /* XXX DEAD */
457                      NumServ(&me), NumNick(sptr), me.name);
458 #endif
459         sptr->flags |= FLAGS_KILLED;
460         exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
461         /*
462          * we have killed sptr off, zero out it's pointer so if it's used
463          * again we'll know about it --Bleep
464          */
465         sptr = 0;
466       }
467       if (lastnick != acptr->lastnick)
468         return 0;                /* Ignore the NICK */
469     }
470     send_reply(acptr, ERR_NICKCOLLISION, nick);
471   }
472
473   ++ServerStats->is_kill;
474   acptr->flags |= FLAGS_KILLED;
475   /*
476    * This exits the client we had before getting the NICK message
477    */
478   if (differ) {
479     sendcmdto_serv_butone(&me, CMD_KILL, acptr, "%C :%s (%s <- %s (older "
480                           "nick overruled))", acptr, me.name,
481                           acptr->from->name, cptr->name);
482     if (MyConnect(acptr))
483       sendcmdto_one(acptr, CMD_QUIT, cptr, ":Local kill by %s (Ghost)",
484                     me.name);
485     exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
486   }
487   else {
488     sendcmdto_serv_butone(&me, CMD_KILL, acptr, "%C :%s (%s <- %s (nick "
489                           "collision from same user@host))", acptr, me.name,
490                           acptr->from->name, cptr->name);
491     if (MyConnect(acptr))
492       sendcmdto_one(acptr, CMD_QUIT, cptr, ":Local kill by %s (Ghost: ",
493                     "switched servers too fast)", me.name);
494     exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
495   }
496   if (lastnick == acptr->lastnick)
497     return 0;
498
499   assert(0 != sptr);
500   return set_nick_name(cptr, sptr, nick, parc, parv);
501 }
502
503 #if 0
504 /*
505  * m_nick
506  *
507  * parv[0] = sender prefix
508  * parv[1] = nickname
509  *
510  * If from server, source is client:
511  *   parv[2] = timestamp
512  *
513  * Source is server:
514  *   parv[2] = hopcount
515  *   parv[3] = timestamp
516  *   parv[4] = username
517  *   parv[5] = hostname
518  *   parv[6] = umode (optional)
519  *   parv[parc-3] = IP#                 <- Only Protocol >= 10
520  *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
521  *   parv[parc-1] = info
522  *   parv[0] = server
523  */
524 int m_nick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
525 {
526   struct Client* acptr;
527   char           nick[NICKLEN + 2];
528   char*          s;
529   time_t         lastnick = 0;
530   int            differ = 1;
531
532   if (parc < 2) {
533     sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]); /* XXX DEAD */
534     return 0;
535   }
536   else if ((IsServer(sptr) && parc < 8) || (IsServer(cptr) && parc < 3))
537   {
538     need_more_params(sptr, "NICK");
539     sendto_ops("bad NICK param count for %s from %s", parv[1], cptr->name); /* XXX DEAD */
540     return 0;
541   }
542   if (MyConnect(sptr) && (s = strchr(parv[1], '~')))
543     *s = '\0';
544   ircd_strncpy(nick, parv[1], NICKLEN);
545   nick[NICKLEN] = '\0';
546   if (IsServer(cptr)) {
547     if (IsServer(sptr)) {
548       lastnick = atoi(parv[3]);
549       if (lastnick > OLDEST_TS) 
550         sptr->serv->lag = TStime() - lastnick;
551     } else {
552       lastnick = atoi(parv[2]); 
553       if (lastnick > OLDEST_TS)
554        sptr->user->server->serv->lag = TStime() - lastnick;
555     }
556   }
557   /*
558    * If do_nick_name() returns a null name OR if the server sent a nick
559    * name and do_nick_name() changed it in some way (due to rules of nick
560    * creation) then reject it. If from a server and we reject it,
561    * and KILL it. -avalon 4/4/92
562    */
563   if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
564   {
565     sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]); /* XXX DEAD */
566
567     if (IsServer(cptr))
568     {
569       ServerStats->is_kill++;
570       sendto_ops("Bad Nick: %s From: %s %s", /* XXX DEAD */
571           parv[1], parv[0], cptr->name);
572       sendto_one(cptr, "%s " TOK_KILL " %s :%s (%s <- %s[%s])", /* XXX DEAD */
573             NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
574             parv[1], nick, cptr->name);
575       if (!IsServer(sptr))        /* bad nick _change_ */
576       {
577         sendto_highprot_butone(&me, 10, "%s " TOK_KILL " %s :%s (%s <- %s!%s@%s)", /* XXX DEAD */
578             NumServ(&me), parv[0], me.name, cptr->name,
579             parv[0], sptr->user ? sptr->username : "",
580             sptr->user ? sptr->user->server->name : cptr->name);
581       }
582     }
583     return 0;
584   }
585
586   /* 
587    * Check if this is a LOCAL user trying to use a reserved (Juped)
588    * nick, if so tell him that it's a nick in use...
589    */
590   if ((!IsServer(cptr)) && isNickJuped(nick))
591   {
592     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, /* XXX DEAD */
593         /* parv[0] is empty when connecting */
594         EmptyString(parv[0]) ? "*" : parv[0], nick);
595     return 0;                        /* NICK message ignored */
596   }
597
598   /*
599    * Check against nick name collisions.
600    *
601    * Put this 'if' here so that the nesting goes nicely on the screen :)
602    * We check against server name list before determining if the nickname
603    * is present in the nicklist (due to the way the below for loop is
604    * constructed). -avalon
605    */
606    
607   acptr = FindServer(nick);
608   
609   if (acptr) { /* There is a nick collision with a server */
610     if (MyConnect(sptr))
611     {
612       /* Local user trying to use a nick thats a server
613        * Return an error message and ignore the command
614        */
615       sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, /* XXX DEAD */
616           EmptyString(parv[0]) ? "*" : parv[0], nick);
617       return 0;                        /* NICK message ignored */
618     }
619     
620     /*
621      * We have a nickname trying to use the same name as
622      * a server. Send out a nick collision KILL to remove
623      * the nickname. As long as only a KILL is sent out,
624      * there is no danger of the server being disconnected.
625      * Ultimate way to jupiter a nick ? >;-). -avalon
626      */
627     sendto_ops("Nick collision on %s(%s <- %s)", /* XXX DEAD */
628                sptr->name, acptr->from->name, cptr->name);
629     ServerStats->is_kill++;
630     sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s <- %s)", /* XXX DEAD */
631                NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
632                cptr->name);
633     sptr->flags |= FLAGS_KILLED;
634     return exit_client(cptr, sptr, &me, "Nick/Server collision");
635   }
636   
637   acptr = FindClient(nick);
638
639   /* No collisions?  Set the nick name and we're done */
640   if (!acptr)
641     return set_nick_name(cptr, sptr, nick, parc, parv);
642   /*
643    * If acptr == sptr, then we have a client doing a nick
644    * change between *equivalent* nicknames as far as server
645    * is concerned (user is changing the case of his/her
646    * nickname or somesuch)
647    */
648   if (acptr == sptr)
649   {
650     if (strcmp(acptr->name, nick) != 0)
651       /*
652        * Allows change of case in his/her nick
653        */
654       return set_nick_name(cptr, sptr, nick, parc, parv);
655     else
656       /*
657        * This is just ':old NICK old' type thing.
658        * Just forget the whole thing here. There is
659        * no point forwarding it to anywhere,
660        * especially since servers prior to this
661        * version would treat it as nick collision.
662        */
663       return 0;                        /* NICK Message ignored */
664   }
665
666   /*
667    * Note: From this point forward it can be assumed that
668    * acptr != sptr (point to different client structures).
669    */
670   /*
671    * If the older one is "non-person", the new entry is just
672    * allowed to overwrite it. Just silently drop non-person,
673    * and proceed with the nick. This should take care of the
674    * "dormant nick" way of generating collisions...
675    */
676   if (IsUnknown(acptr) && MyConnect(acptr))
677   {
678     ++ServerStats->is_ref;
679     exit_client(cptr, acptr, &me, "Overridden by other sign on");
680     return set_nick_name(cptr, sptr, nick, parc, parv);
681   }
682   /*
683    * Decide, we really have a nick collision and deal with it
684    */
685   if (!IsServer(cptr))
686   {
687     /*
688      * NICK is coming from local client connection. Just
689      * send error reply and ignore the command.
690      */
691     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, /* XXX DEAD */
692         /* parv[0] is empty when connecting */
693         EmptyString(parv[0]) ? "*" : parv[0], nick);
694     return 0;                        /* NICK message ignored */
695   }
696   /*
697    * NICK was coming from a server connection.
698    * This means we have a race condition (two users signing on
699    * at the same time), or two net fragments reconnecting with the same nick.
700    * The latter can happen because two different users connected
701    * or because one and the same user switched server during a net break.
702    * If the TimeStamps are equal, we kill both (or only 'new'
703    * if it was a ":server NICK new ...").
704    * Otherwise we kill the youngest when user@host differ,
705    * or the oldest when they are the same.
706    * We treat user and ~user as different, because if it wasn't
707    * a faked ~user the AUTH wouldn't have added the '~'.
708    * --Run
709    *
710    */
711   if (IsServer(sptr))
712   {
713     /*
714      * A new NICK being introduced by a neighbouring
715      * server (e.g. message type ":server NICK new ..." received)
716      */
717     differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
718             (0 != ircd_strcmp(acptr->user->username, parv[4]));
719     sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT /* XXX DEAD */
720                " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
721                cptr->name, lastnick, differ ? "Different" : "Same");
722   }
723   else
724   {
725     /*
726      * A NICK change has collided (e.g. message type ":old NICK new").
727      */
728     lastnick = atoi(parv[2]);
729     differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
730             (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
731     sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s " /* XXX DEAD */
732                TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
733                acptr->lastnick, cptr->name, lastnick);
734   }
735   /*
736    * Now remove (kill) the nick on our side if it is the youngest.
737    * If no timestamp was received, we ignore the incoming nick
738    * (and expect a KILL for our legit nick soon ):
739    * When the timestamps are equal we kill both nicks. --Run
740    * acptr->from != cptr should *always* be true (?).
741    */
742   if (acptr->from != cptr)
743   {
744     if ((differ && lastnick >= acptr->lastnick) ||
745         (!differ && lastnick <= acptr->lastnick))
746     {
747       if (!IsServer(sptr))
748       {
749         ServerStats->is_kill++;
750         sendto_highprot_butone(cptr, 10,        /* Kill old from outgoing servers */ /* XXX DEAD */
751                                "%s " TOK_KILL " %s%s :%s (%s <- %s (Nick collision))",
752                                NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
753                                cptr->name);
754         if (MyConnect(sptr) && IsServer(cptr) && Protocol(cptr) > 9)
755           sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost2)", /* XXX DEAD */
756                      NumServ(&me), NumNick(sptr), me.name);
757         sptr->flags |= FLAGS_KILLED;
758         exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
759       }
760       if (lastnick != acptr->lastnick)
761         return 0;                /* Ignore the NICK */
762     }
763     sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick); /* XXX DEAD */
764   }
765   ServerStats->is_kill++;
766   acptr->flags |= FLAGS_KILLED;
767   if (differ)
768   {
769     sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */ /* XXX DEAD */
770                            "%s " TOK_KILL " %s%s :%s (%s <- %s (older nick overruled))",
771                            NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
772                            cptr->name);
773     if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
774       sendto_one(cptr, "%s%s " TOK_QUIT " :Local kill by %s (Ghost)", /* XXX DEAD */
775           NumNick(acptr), me.name);
776     exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
777   }
778   else
779   {
780     sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */ /* XXX DEAD */
781                            "%s " TOK_KILL " %s%s :%s (%s <- %s (nick collision from same user@host))",
782                            NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
783                            cptr->name);
784     if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
785       sendto_one(cptr, /* XXX DEAD */
786           "%s%s " TOK_QUIT " :Local kill by %s (Ghost: switched servers too fast)",
787           NumNick(acptr), me.name);
788     exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
789   }
790   if (lastnick == acptr->lastnick)
791     return 0;
792
793   return set_nick_name(cptr, sptr, nick, parc, parv);
794 }
795
796 #endif /* 0 */