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     sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, client_name);
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     sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, client_name, 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     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, 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     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, 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     IPcheck_connect_fail(acptr->ip);
221     exit_client(cptr, acptr, &me, "Overridden by other sign on");
222     return set_nick_name(cptr, sptr, nick, parc, parv);
223   }
224   /*
225    * NICK is coming from local client connection. Just
226    * send error reply and ignore the command.
227    */
228   sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name, client_name, nick);
229   return 0;                        /* NICK message ignored */
230 }
231
232
233 /*
234  * ms_nick - server message handler for nicks
235  * parv[0] = sender prefix
236  * parv[1] = nickname
237  *
238  * If from server, source is client:
239  *   parv[2] = timestamp
240  *
241  * Source is server:
242  *   parv[2] = hopcount
243  *   parv[3] = timestamp
244  *   parv[4] = username
245  *   parv[5] = hostname
246  *   parv[6] = umode (optional)
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_ops("bad NICK param count for %s from %s", parv[1], cptr->name);
265     return need_more_params(sptr, "NICK");
266   }
267
268   ircd_strncpy(nick, parv[1], NICKLEN);
269   nick[NICKLEN] = '\0';
270
271   if (!IsBurstOrBurstAck(sptr)) {
272      if (IsServer(sptr)) {
273        lastnick = atoi(parv[3]);
274        if (lastnick > OLDEST_TS) 
275          sptr->serv->lag = TStime() - lastnick;
276      }
277      else {
278        lastnick = atoi(parv[2]); 
279        if (lastnick > OLDEST_TS)
280          sptr->user->server->serv->lag = TStime() - lastnick;
281      }
282   }
283   /*
284    * If do_nick_name() returns a null name OR if the server sent a nick
285    * name and do_nick_name() changed it in some way (due to rules of nick
286    * creation) then reject it. If from a server and we reject it,
287    * and KILL it. -avalon 4/4/92
288    */
289   if (0 == do_nick_name(nick) || 0 != strcmp(nick, parv[1])) {
290     sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]);
291
292     ++ServerStats->is_kill;
293     sendto_ops("Bad Nick: %s From: %s %s", parv[1], parv[0], cptr->name);
294     sendto_one(cptr, "%s " TOK_KILL " %s :%s (%s <- %s[%s])",
295                NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
296                parv[1], nick, cptr->name);
297     if (!IsServer(sptr)) {
298       /*
299        * bad nick _change_
300        */
301       sendto_highprot_butone(&me, 10, "%s " TOK_KILL " %s :%s (%s <- %s!%s@%s)",
302                              NumServ(&me), parv[0], me.name, cptr->name,
303                              parv[0], sptr->user ? sptr->username : "",
304                              sptr->user ? sptr->user->server->name : cptr->name);
305     }
306     return 0;
307   }
308   /*
309    * Check against nick name collisions.
310    *
311    * Put this 'if' here so that the nesting goes nicely on the screen :)
312    * We check against server name list before determining if the nickname
313    * is present in the nicklist (due to the way the below for loop is
314    * constructed). -avalon
315    */
316   if (!(acptr = FindClient(nick))) {
317     /*
318      * No collisions, all clear...
319      */
320     return set_nick_name(cptr, sptr, nick, parc, parv);
321   }
322   assert(0 != acptr);
323
324   if (IsServer(acptr)) {
325     /*
326      * We have a nickname trying to use the same name as
327      * a server. Send out a nick collision KILL to remove
328      * the nickname. As long as only a KILL is sent out,
329      * there is no danger of the server being disconnected.
330      * Ultimate way to jupiter a nick ? >;-). -avalon
331      */
332     sendto_ops("Nick collision on %s(%s <- %s)", sptr->name, acptr->from->name, cptr->name);
333     ++ServerStats->is_kill;
334
335     sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s <- %s)",
336                NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
337                cptr->name);
338
339     sptr->flags |= FLAGS_KILLED;
340     /*
341      * if sptr is a server it is exited here, nothing else to do
342      */
343     return exit_client(cptr, sptr, &me, "Nick/Server collision");
344   }
345
346   /*
347    * If acptr == sptr, then we have a client doing a nick
348    * change between *equivalent* nicknames as far as server
349    * is concerned (user is changing the case of his/her
350    * nickname or somesuch)
351    */
352   if (acptr == sptr) {
353     if (strcmp(acptr->name, nick) != 0)
354       /*
355        * Allows change of case in his/her nick
356        */
357       return set_nick_name(cptr, sptr, nick, parc, parv);
358     else
359       /*
360        * This is just ':old NICK old' type thing.
361        * Just forget the whole thing here. There is
362        * no point forwarding it to anywhere,
363        * especially since servers prior to this
364        * version would treat it as nick collision.
365        */
366       return 0;                        /* NICK Message ignored */
367   }
368
369   /*
370    * Note: From this point forward it can be assumed that
371    * acptr != sptr (point to different client structures).
372    */
373   assert(acptr != sptr);
374   /*
375    * If the older one is "non-person", the new entry is just
376    * allowed to overwrite it. Just silently drop non-person,
377    * and proceed with the nick. This should take care of the
378    * "dormant nick" way of generating collisions...
379    */
380   if (IsUnknown(acptr) && MyConnect(acptr)) {
381     ++ServerStats->is_ref;
382     IPcheck_connect_fail(acptr->ip);
383     exit_client(cptr, acptr, &me, "Overridden by other sign on");
384     return set_nick_name(cptr, sptr, nick, parc, parv);
385   }
386   /*
387    * Decide, we really have a nick collision and deal with it
388    */
389   /*
390    * NICK was coming from a server connection.
391    * This means we have a race condition (two users signing on
392    * at the same time), or two net fragments reconnecting with the same nick.
393    * The latter can happen because two different users connected
394    * or because one and the same user switched server during a net break.
395    * If the TimeStamps are equal, we kill both (or only 'new'
396    * if it was a ":server NICK new ...").
397    * Otherwise we kill the youngest when user@host differ,
398    * or the oldest when they are the same.
399    * We treat user and ~user as different, because if it wasn't
400    * a faked ~user the AUTH wouldn't have added the '~'.
401    * --Run
402    *
403    */
404   if (IsServer(sptr)) {
405     /*
406      * A new NICK being introduced by a neighbouring
407      * server (e.g. message type ":server NICK new ..." received)
408      *
409      * compare IP address and username
410      */
411     differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
412               (0 != ircd_strcmp(acptr->user->username, parv[4]));
413     sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT
414                " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
415                cptr->name, lastnick, differ ? "Different" : "Same");
416   }
417   else {
418     /*
419      * A NICK change has collided (e.g. message type ":old NICK new").
420      *
421      * compare IP address and username
422      */
423     differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
424               (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
425     sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s "
426                TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
427                acptr->lastnick, cptr->name, lastnick);
428   }
429   /*
430    * Now remove (kill) the nick on our side if it is the youngest.
431    * If no timestamp was received, we ignore the incoming nick
432    * (and expect a KILL for our legit nick soon ):
433    * When the timestamps are equal we kill both nicks. --Run
434    * acptr->from != cptr should *always* be true (?).
435    *
436    * This exits the client sending the NICK message
437    */
438   if (acptr->from != cptr) {
439     if ((differ && lastnick >= acptr->lastnick) || (!differ && lastnick <= acptr->lastnick)) {
440       if (!IsServer(sptr)) {
441         ++ServerStats->is_kill;
442         sendto_highprot_butone(&me, 10,        /* Kill old from outgoing servers */
443                               "%s " TOK_KILL " %s%s :%s (%s <- %s (Nick collision))",
444                               NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
445                               cptr->name);
446         assert(!MyConnect(sptr));
447 #if 0
448         /*
449          * XXX - impossible
450          */
451         if (MyConnect(sptr))
452           sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost 2)",
453                      NumServ(&me), NumNick(sptr), me.name);
454 #endif
455         sptr->flags |= FLAGS_KILLED;
456         exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
457         /*
458          * we have killed sptr off, zero out it's pointer so if it's used
459          * again we'll know about it --Bleep
460          */
461         sptr = 0;
462       }
463       if (lastnick != acptr->lastnick)
464         return 0;                /* Ignore the NICK */
465     }
466     sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick);
467   }
468
469   ++ServerStats->is_kill;
470   acptr->flags |= FLAGS_KILLED;
471   /*
472    * This exits the client we had before getting the NICK message
473    */
474   if (differ) {
475     sendto_highprot_butone(&me, 10,        /* Kill our old from outgoing servers */
476                            "%s " TOK_KILL " %s%s :%s (%s <- %s (older nick overruled))",
477                            NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
478                            cptr->name);
479     if (MyConnect(acptr))
480       sendto_one(cptr, "%s%s " TOK_QUIT " :Local kill by %s (Ghost)",
481                  NumNick(acptr), me.name);
482     exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
483   }
484   else {
485     sendto_highprot_butone(&me, 10,        /* Kill our old from outgoing servers */
486                           "%s " TOK_KILL " %s%s :%s (%s <- %s (nick collision from same user@host))",
487                           NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
488                           cptr->name);
489     if (MyConnect(acptr))
490       sendto_one(cptr,
491                  "%s%s " TOK_QUIT " :Local kill by %s (Ghost: switched servers too fast)",
492                   NumNick(acptr), me.name);
493     exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
494   }
495   if (lastnick == acptr->lastnick)
496     return 0;
497
498   assert(0 != sptr);
499   return set_nick_name(cptr, sptr, nick, parc, parv);
500 }
501
502 #if 0
503 /*
504  * m_nick
505  *
506  * parv[0] = sender prefix
507  * parv[1] = nickname
508  *
509  * If from server, source is client:
510  *   parv[2] = timestamp
511  *
512  * Source is server:
513  *   parv[2] = hopcount
514  *   parv[3] = timestamp
515  *   parv[4] = username
516  *   parv[5] = hostname
517  *   parv[6] = umode (optional)
518  *   parv[parc-3] = IP#                 <- Only Protocol >= 10
519  *   parv[parc-2] = YXX, numeric nick   <- Only Protocol >= 10
520  *   parv[parc-1] = info
521  *   parv[0] = server
522  */
523 int m_nick(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
524 {
525   struct Client* acptr;
526   char           nick[NICKLEN + 2];
527   char*          s;
528   time_t         lastnick = 0;
529   int            differ = 1;
530
531   if (parc < 2) {
532     sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN), me.name, parv[0]);
533     return 0;
534   }
535   else if ((IsServer(sptr) && parc < 8) || (IsServer(cptr) && parc < 3))
536   {
537     need_more_params(sptr, "NICK");
538     sendto_ops("bad NICK param count for %s from %s", parv[1], cptr->name);
539     return 0;
540   }
541   if (MyConnect(sptr) && (s = strchr(parv[1], '~')))
542     *s = '\0';
543   ircd_strncpy(nick, parv[1], NICKLEN);
544   nick[NICKLEN] = '\0';
545   if (IsServer(cptr)) {
546     if (IsServer(sptr)) {
547       lastnick = atoi(parv[3]);
548       if (lastnick > OLDEST_TS) 
549         sptr->serv->lag = TStime() - lastnick;
550     } else {
551       lastnick = atoi(parv[2]); 
552       if (lastnick > OLDEST_TS)
553        sptr->user->server->serv->lag = TStime() - lastnick;
554     }
555   }
556   /*
557    * If do_nick_name() returns a null name OR if the server sent a nick
558    * name and do_nick_name() changed it in some way (due to rules of nick
559    * creation) then reject it. If from a server and we reject it,
560    * and KILL it. -avalon 4/4/92
561    */
562   if (do_nick_name(nick) == 0 || (IsServer(cptr) && strcmp(nick, parv[1])))
563   {
564     sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME), me.name, parv[0], parv[1]);
565
566     if (IsServer(cptr))
567     {
568       ServerStats->is_kill++;
569       sendto_ops("Bad Nick: %s From: %s %s",
570           parv[1], parv[0], cptr->name);
571       sendto_one(cptr, "%s " TOK_KILL " %s :%s (%s <- %s[%s])",
572             NumServ(&me), IsServer(sptr) ? parv[parc - 2] : parv[0], me.name,
573             parv[1], nick, cptr->name);
574       if (!IsServer(sptr))        /* bad nick _change_ */
575       {
576         sendto_highprot_butone(&me, 10, "%s " TOK_KILL " %s :%s (%s <- %s!%s@%s)",
577             NumServ(&me), parv[0], me.name, cptr->name,
578             parv[0], sptr->user ? sptr->username : "",
579             sptr->user ? sptr->user->server->name : cptr->name);
580       }
581     }
582     return 0;
583   }
584
585   /* 
586    * Check if this is a LOCAL user trying to use a reserved (Juped)
587    * nick, if so tell him that it's a nick in use...
588    */
589   if ((!IsServer(cptr)) && isNickJuped(nick))
590   {
591     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
592         /* parv[0] is empty when connecting */
593         EmptyString(parv[0]) ? "*" : parv[0], nick);
594     return 0;                        /* NICK message ignored */
595   }
596
597   /*
598    * Check against nick name collisions.
599    *
600    * Put this 'if' here so that the nesting goes nicely on the screen :)
601    * We check against server name list before determining if the nickname
602    * is present in the nicklist (due to the way the below for loop is
603    * constructed). -avalon
604    */
605   if ((acptr = FindServer(nick))) {
606     if (MyConnect(sptr))
607     {
608       sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
609           EmptyString(parv[0]) ? "*" : parv[0], nick);
610       return 0;                        /* NICK message ignored */
611     }
612     /*
613      * We have a nickname trying to use the same name as
614      * a server. Send out a nick collision KILL to remove
615      * the nickname. As long as only a KILL is sent out,
616      * there is no danger of the server being disconnected.
617      * Ultimate way to jupiter a nick ? >;-). -avalon
618      */
619     sendto_ops("Nick collision on %s(%s <- %s)",
620                sptr->name, acptr->from->name, cptr->name);
621     ServerStats->is_kill++;
622     sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (%s <- %s)",
623                NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
624                cptr->name);
625     sptr->flags |= FLAGS_KILLED;
626     return exit_client(cptr, sptr, &me, "Nick/Server collision");
627   }
628
629   if (!(acptr = FindClient(nick)))
630     return set_nick_name(cptr, sptr, nick, parc, parv);  /* No collisions, all clear... */
631   /*
632    * If acptr == sptr, then we have a client doing a nick
633    * change between *equivalent* nicknames as far as server
634    * is concerned (user is changing the case of his/her
635    * nickname or somesuch)
636    */
637   if (acptr == sptr)
638   {
639     if (strcmp(acptr->name, nick) != 0)
640       /*
641        * Allows change of case in his/her nick
642        */
643       return set_nick_name(cptr, sptr, nick, parc, parv);
644     else
645       /*
646        * This is just ':old NICK old' type thing.
647        * Just forget the whole thing here. There is
648        * no point forwarding it to anywhere,
649        * especially since servers prior to this
650        * version would treat it as nick collision.
651        */
652       return 0;                        /* NICK Message ignored */
653   }
654
655   /*
656    * Note: From this point forward it can be assumed that
657    * acptr != sptr (point to different client structures).
658    */
659   /*
660    * If the older one is "non-person", the new entry is just
661    * allowed to overwrite it. Just silently drop non-person,
662    * and proceed with the nick. This should take care of the
663    * "dormant nick" way of generating collisions...
664    */
665   if (IsUnknown(acptr) && MyConnect(acptr))
666   {
667     ++ServerStats->is_ref;
668     IPcheck_connect_fail(acptr->ip);
669     exit_client(cptr, acptr, &me, "Overridden by other sign on");
670     return set_nick_name(cptr, sptr, nick, parc, parv);
671   }
672   /*
673    * Decide, we really have a nick collision and deal with it
674    */
675   if (!IsServer(cptr))
676   {
677     /*
678      * NICK is coming from local client connection. Just
679      * send error reply and ignore the command.
680      */
681     sendto_one(sptr, err_str(ERR_NICKNAMEINUSE), me.name,
682         /* parv[0] is empty when connecting */
683         EmptyString(parv[0]) ? "*" : parv[0], nick);
684     return 0;                        /* NICK message ignored */
685   }
686   /*
687    * NICK was coming from a server connection.
688    * This means we have a race condition (two users signing on
689    * at the same time), or two net fragments reconnecting with the same nick.
690    * The latter can happen because two different users connected
691    * or because one and the same user switched server during a net break.
692    * If the TimeStamps are equal, we kill both (or only 'new'
693    * if it was a ":server NICK new ...").
694    * Otherwise we kill the youngest when user@host differ,
695    * or the oldest when they are the same.
696    * We treat user and ~user as different, because if it wasn't
697    * a faked ~user the AUTH wouldn't have added the '~'.
698    * --Run
699    *
700    */
701   if (IsServer(sptr))
702   {
703     /*
704      * A new NICK being introduced by a neighbouring
705      * server (e.g. message type ":server NICK new ..." received)
706      */
707     differ =  (acptr->ip.s_addr != htonl(base64toint(parv[parc - 3]))) ||
708             (0 != ircd_strcmp(acptr->user->username, parv[4]));
709     sendto_ops("Nick collision on %s (%s " TIME_T_FMT " <- %s " TIME_T_FMT
710                " (%s user@host))", acptr->name, acptr->from->name, acptr->lastnick,
711                cptr->name, lastnick, differ ? "Different" : "Same");
712   }
713   else
714   {
715     /*
716      * A NICK change has collided (e.g. message type ":old NICK new").
717      */
718     lastnick = atoi(parv[2]);
719     differ =  (acptr->ip.s_addr != sptr->ip.s_addr) ||
720             (0 != ircd_strcmp(acptr->user->username, sptr->user->username));              
721     sendto_ops("Nick change collision from %s to %s (%s " TIME_T_FMT " <- %s "
722                TIME_T_FMT ")", sptr->name, acptr->name, acptr->from->name,
723                acptr->lastnick, cptr->name, lastnick);
724   }
725   /*
726    * Now remove (kill) the nick on our side if it is the youngest.
727    * If no timestamp was received, we ignore the incoming nick
728    * (and expect a KILL for our legit nick soon ):
729    * When the timestamps are equal we kill both nicks. --Run
730    * acptr->from != cptr should *always* be true (?).
731    */
732   if (acptr->from != cptr)
733   {
734     if ((differ && lastnick >= acptr->lastnick) ||
735         (!differ && lastnick <= acptr->lastnick))
736     {
737       if (!IsServer(sptr))
738       {
739         ServerStats->is_kill++;
740         sendto_highprot_butone(cptr, 10,        /* Kill old from outgoing servers */
741                                "%s " TOK_KILL " %s%s :%s (%s <- %s (Nick collision))",
742                                NumServ(&me), NumNick(sptr), me.name, acptr->from->name,
743                                cptr->name);
744         if (MyConnect(sptr) && IsServer(cptr) && Protocol(cptr) > 9)
745           sendto_one(cptr, "%s " TOK_KILL " %s%s :%s (Ghost2)",
746                      NumServ(&me), NumNick(sptr), me.name);
747         sptr->flags |= FLAGS_KILLED;
748         exit_client(cptr, sptr, &me, "Nick collision (you're a ghost)");
749       }
750       if (lastnick != acptr->lastnick)
751         return 0;                /* Ignore the NICK */
752     }
753     sendto_one(acptr, err_str(ERR_NICKCOLLISION), me.name, acptr->name, nick);
754   }
755   ServerStats->is_kill++;
756   acptr->flags |= FLAGS_KILLED;
757   if (differ)
758   {
759     sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
760                            "%s " TOK_KILL " %s%s :%s (%s <- %s (older nick overruled))",
761                            NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
762                            cptr->name);
763     if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
764       sendto_one(cptr, "%s%s " TOK_QUIT " :Local kill by %s (Ghost)",
765           NumNick(acptr), me.name);
766     exit_client(cptr, acptr, &me, "Nick collision (older nick overruled)");
767   }
768   else
769   {
770     sendto_highprot_butone(cptr, 10,        /* Kill our old from outgoing servers */
771                            "%s " TOK_KILL " %s%s :%s (%s <- %s (nick collision from same user@host))",
772                            NumServ(&me), NumNick(acptr), me.name, acptr->from->name,
773                            cptr->name);
774     if (MyConnect(acptr) && IsServer(cptr) && Protocol(cptr) > 9)
775       sendto_one(cptr,
776           "%s%s " TOK_QUIT " :Local kill by %s (Ghost: switched servers too fast)",
777           NumNick(acptr), me.name);
778     exit_client(cptr, acptr, &me, "Nick collision (You collided yourself)");
779   }
780   if (lastnick == acptr->lastnick)
781     return 0;
782
783   return set_nick_name(cptr, sptr, nick, parc, parv);
784 }
785
786 #endif /* 0 */