Initial import
[ratbox-ambernet.git] / modules / core / m_nick.c
blob5d49ad138ca8fc315eb50e9b43b3b604ea8ab0c2
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * m_nick.c: Sets a users nick.
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
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 2 of the License, or
12 * (at your option) any later version.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
24 * $Id: m_nick.c 23853 2007-04-22 14:09:34Z jilles $
27 #include "stdinc.h"
28 #include "client.h"
29 #include "hash.h"
30 #include "irc_string.h"
31 #include "ircd.h"
32 #include "numeric.h"
33 #include "s_conf.h"
34 #include "s_stats.h"
35 #include "s_user.h"
36 #include "hash.h"
37 #include "whowas.h"
38 #include "s_serv.h"
39 #include "send.h"
40 #include "channel.h"
41 #include "s_log.h"
42 #include "msg.h"
43 #include "parse.h"
44 #include "modules.h"
45 #include "common.h"
46 #include "packet.h"
47 #include "scache.h"
48 #include "s_newconf.h"
49 #include "monitor.h"
51 /* Give all UID nicks the same TS. This ensures nick TS is always the same on
52 * all servers for each nick-user pair, also if a user with a UID nick changes
53 * their nick but is collided again (the server detecting the collision will
54 * not propagate the nick change further). -- jilles
56 #define SAVE_NICKTS 100
58 static int mr_nick(struct Client *, struct Client *, int, const char **);
59 static int m_nick(struct Client *, struct Client *, int, const char **);
60 static int mc_nick(struct Client *, struct Client *, int, const char **);
61 static int ms_nick(struct Client *, struct Client *, int, const char **);
62 static int ms_uid(struct Client *, struct Client *, int, const char **);
63 static int ms_save(struct Client *, struct Client *, int, const char **);
64 static void save_user(struct Client *, struct Client *, struct Client *);
66 struct Message nick_msgtab = {
67 "NICK", 0, 0, 0, MFLG_SLOW,
68 {{mr_nick, 0}, {m_nick, 0}, {mc_nick, 3}, {ms_nick, 8}, mg_ignore, {m_nick, 0}}
70 struct Message uid_msgtab = {
71 "UID", 0, 0, 0, MFLG_SLOW,
72 {mg_ignore, mg_ignore, mg_ignore, {ms_uid, 9}, mg_ignore, mg_ignore}
74 struct Message save_msgtab = {
75 "SAVE", 0, 0, 0, MFLG_SLOW,
76 {mg_ignore, mg_ignore, mg_ignore, {ms_save, 3}, mg_ignore, mg_ignore}
79 mapi_clist_av1 nick_clist[] = { &nick_msgtab, &uid_msgtab, &save_msgtab, NULL };
80 DECLARE_MODULE_AV1(nick, NULL, NULL, nick_clist, NULL, NULL, "$Revision: 23853 $");
82 static int change_remote_nick(struct Client *, struct Client *, time_t, const char *, int);
84 static int clean_nick(const char *, int loc_client);
85 static int clean_username(const char *);
86 static int clean_host(const char *);
87 static int clean_uid(const char *uid);
89 static void set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick);
90 static void change_local_nick(struct Client *client_p, struct Client *source_p, char *nick, int);
91 static int register_client(struct Client *client_p, struct Client *server,
92 const char *nick, time_t newts, int parc, const char *parv[]);
94 static int perform_nick_collides(struct Client *, struct Client *,
95 struct Client *, int, const char **,
96 time_t, const char *, const char *);
97 static int perform_nickchange_collides(struct Client *, struct Client *,
98 struct Client *, int, const char **,
99 time_t, const char *);
101 /* mr_nick()
102 * parv[0] = sender prefix
103 * parv[1] = nickname
105 static int
106 mr_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
108 struct Client *target_p;
109 char nick[NICKLEN];
110 char *s;
112 if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~'))
114 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
115 me.name,
116 EmptyString(source_p->name) ? "*" : source_p->name);
117 return 0;
120 /* due to the scandinavian origins, (~ being uppercase of ^) and ~
121 * being disallowed as a nick char, we need to chop the first ~
122 * instead of just erroring.
124 if((s = strchr(parv[1], '~')))
125 *s = '\0';
127 /* copy the nick and terminate it */
128 strlcpy(nick, parv[1], sizeof(nick));
130 /* check the nickname is ok */
131 if(!clean_nick(nick, 1))
133 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
134 me.name, EmptyString(parv[0]) ? "*" : parv[0], parv[1]);
135 return 0;
138 /* check if the nick is resv'd */
139 if(find_nick_resv(nick))
141 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
142 me.name, EmptyString(source_p->name) ? "*" : source_p->name, nick);
143 return 0;
146 if(hash_find_nd(nick))
148 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
149 me.name,
150 EmptyString(source_p->name) ? "*" : source_p->name,
151 nick);
152 return 0;
155 if((target_p = find_client(nick)) == NULL)
156 set_initial_nick(client_p, source_p, nick);
157 else if(source_p == target_p)
158 strcpy(source_p->user->nick, nick);
159 else
160 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
162 return 0;
165 /* m_nick()
166 * parv[0] = sender prefix
167 * parv[1] = nickname
169 static int
170 m_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
172 struct Client *target_p;
173 char nick[NICKLEN];
174 char *s;
176 if(parc < 2 || EmptyString(parv[1]) || (parv[1][0] == '~'))
178 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
179 me.name, source_p->name);
180 return 0;
183 /* due to the scandinavian origins, (~ being uppercase of ^) and ~
184 * being disallowed as a nick char, we need to chop the first ~
185 * instead of just erroring.
187 if((s = strchr(parv[1], '~')))
188 *s = '\0';
190 /* mark end of grace period, to prevent nickflooding */
191 if(!IsFloodDone(source_p))
192 flood_endgrace(source_p);
194 /* terminate nick to NICKLEN, we dont want clean_nick() to error! */
195 strlcpy(nick, parv[1], sizeof(nick));
197 /* check the nickname is ok */
198 if(!clean_nick(nick, 1))
200 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
201 me.name, parv[0], nick);
202 return 0;
205 if(!IsExemptResv(source_p) && find_nick_resv(nick))
207 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
208 me.name, source_p->name, nick);
209 return 0;
212 if(hash_find_nd(nick))
214 sendto_one(source_p, form_str(ERR_UNAVAILRESOURCE),
215 me.name,
216 EmptyString(source_p->name) ? "*" : source_p->name,
217 nick);
218 return 0;
221 if((target_p = find_client(nick)))
223 /* If(target_p == source_p) the client is changing nicks between
224 * equivalent nicknames ie: [nick] -> {nick}
226 if(target_p == source_p)
228 /* check the nick isnt exactly the same */
229 if(strcmp(target_p->name, nick))
230 change_local_nick(client_p, source_p, nick, 1);
234 /* drop unregged client */
235 else if(IsUnknown(target_p))
237 exit_client(NULL, target_p, &me, "Overridden");
238 change_local_nick(client_p, source_p, nick, 1);
240 else
241 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, parv[0], nick);
243 return 0;
245 else
246 change_local_nick(client_p, source_p, nick, 1);
248 return 0;
251 /* ms_nick()
253 * server -> server nick change
254 * parv[0] = sender prefix
255 * parv[1] = nickname
256 * parv[2] = TS when nick change
258 * server introducing new nick
259 * parv[0] = sender prefix
260 * parv[1] = nickname
261 * parv[2] = hop count
262 * parv[3] = TS
263 * parv[4] = umode
264 * parv[5] = username
265 * parv[6] = hostname
266 * parv[7] = server
267 * parv[8] = ircname
269 static int
270 mc_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
272 struct Client *target_p;
273 time_t newts = 0;
275 /* if nicks erroneous, or too long, kill */
276 if(!clean_nick(parv[1], 0))
278 ServerStats->is_kill++;
279 sendto_realops_flags(UMODE_DEBUG, L_ALL,
280 "Bad Nick: %s From: %s(via %s)",
281 parv[1], source_p->servptr->name,
282 client_p->name);
283 sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
284 me.name, parv[1], me.name);
286 /* bad nick change, issue kill for the old nick to the rest
287 * of the network.
289 kill_client_serv_butone(client_p, source_p,
290 "%s (Bad Nickname)", me.name);
291 source_p->flags |= FLAGS_KILLED;
292 exit_client(client_p, source_p, &me, "Bad Nickname");
293 return 0;
296 newts = atol(parv[2]);
297 target_p = find_client(parv[1]);
299 /* if the nick doesnt exist, allow it and process like normal */
300 if(target_p == NULL)
302 change_remote_nick(client_p, source_p, newts, parv[1], 1);
304 else if(IsUnknown(target_p))
306 exit_client(NULL, target_p, &me, "Overridden");
307 change_remote_nick(client_p, source_p, newts, parv[1], 1);
309 else if(target_p == source_p)
311 /* client changing case of nick */
312 if(strcmp(target_p->name, parv[1]))
313 change_remote_nick(client_p, source_p, newts, parv[1], 1);
315 /* we've got a collision! */
316 else
317 perform_nickchange_collides(source_p, client_p, target_p,
318 parc, parv, newts, parv[1]);
320 return 0;
323 static int
324 ms_nick(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
326 struct Client *target_p;
327 time_t newts = 0;
329 if(parc != 9)
331 sendto_realops_flags(UMODE_ALL, L_ALL,
332 "Dropping server %s due to (invalid) command 'NICK' "
333 "with %d arguments (expecting 9)",
334 client_p->name, parc);
335 ilog(L_SERVER, "Excess parameters (%d) for command 'NICK' from %s.",
336 parc, client_p->name);
337 exit_client(client_p, client_p, client_p,
338 "Excess parameters to NICK command");
339 return 0;
342 /* if nicks empty, erroneous, or too long, kill */
343 if(!clean_nick(parv[1], 0))
345 ServerStats->is_kill++;
346 sendto_realops_flags(UMODE_DEBUG, L_ALL,
347 "Bad Nick: %s From: %s(via %s)",
348 parv[1], parv[7], client_p->name);
349 sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
350 me.name, parv[1], me.name);
351 return 0;
354 /* invalid username or host? */
355 if(!clean_username(parv[5]) || !clean_host(parv[6]))
357 ServerStats->is_kill++;
358 sendto_realops_flags(UMODE_DEBUG, L_ALL,
359 "Bad user@host: %s@%s From: %s(via %s)",
360 parv[5], parv[6], parv[7],
361 client_p->name);
362 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)",
363 me.name, parv[1], me.name);
364 return 0;
367 /* check the length of the clients gecos */
368 if(strlen(parv[8]) > REALLEN)
370 char *s = LOCAL_COPY(parv[8]);
371 /* why exactly do we care? --fl */
372 sendto_realops_flags(UMODE_ALL, L_ALL,
373 "Long realname from server %s for %s", parv[7],
374 parv[1]);
376 s[REALLEN] = '\0';
377 parv[8] = s;
380 newts = atol(parv[3]);
382 target_p = find_client(parv[1]);
384 /* if the nick doesnt exist, allow it and process like normal */
385 if(target_p == NULL)
387 register_client(client_p, NULL, parv[1], newts, parc, parv);
389 else if(IsUnknown(target_p))
391 exit_client(NULL, target_p, &me, "Overridden");
392 register_client(client_p, NULL, parv[1], newts, parc, parv);
394 else if(target_p == source_p)
396 /* client changing case of nick */
397 if(strcmp(target_p->name, parv[1]))
398 register_client(client_p, NULL, parv[1], newts, parc, parv);
400 /* we've got a collision! */
401 else
402 perform_nick_collides(source_p, client_p, target_p, parc, parv,
403 newts, parv[1], NULL);
405 return 0;
408 /* ms_uid()
409 * parv[1] - nickname
410 * parv[2] - hops
411 * parv[3] - TS
412 * parv[4] - umodes
413 * parv[5] - username
414 * parv[6] - hostname
415 * parv[7] - IP
416 * parv[8] - UID
417 * parv[9] - gecos
419 static int
420 ms_uid(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
422 struct Client *target_p;
423 time_t newts = 0;
425 newts = atol(parv[3]);
427 if(parc != 10)
429 sendto_realops_flags(UMODE_ALL, L_ALL,
430 "Dropping server %s due to (invalid) command 'UID' "
431 "with %d arguments (expecting 10)",
432 client_p->name, parc);
433 ilog(L_SERVER, "Excess parameters (%d) for command 'UID' from %s.",
434 parc, client_p->name);
435 exit_client(client_p, client_p, client_p,
436 "Excess parameters to UID command");
437 return 0;
440 /* if nicks erroneous, or too long, kill */
441 if(!clean_nick(parv[1], 0))
443 ServerStats->is_kill++;
444 sendto_realops_flags(UMODE_DEBUG, L_ALL,
445 "Bad Nick: %s From: %s(via %s)",
446 parv[1], source_p->name,
447 client_p->name);
448 sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
449 me.id, parv[8], me.name);
450 return 0;
453 if(!clean_username(parv[5]) || !clean_host(parv[6]))
455 ServerStats->is_kill++;
456 sendto_realops_flags(UMODE_DEBUG, L_ALL,
457 "Bad user@host: %s@%s From: %s(via %s)",
458 parv[5], parv[6], source_p->name,
459 client_p->name);
460 sendto_one(client_p, ":%s KILL %s :%s (Bad user@host)",
461 me.id, parv[8], me.name);
462 return 0;
465 if(!clean_uid(parv[8]))
467 ServerStats->is_kill++;
468 sendto_realops_flags(UMODE_DEBUG, L_ALL,
469 "Bad UID: %s From: %s(via %s)",
470 parv[8], source_p->name,
471 client_p->name);
472 sendto_one(client_p, ":%s KILL %s :%s (Bad UID)",
473 me.id, parv[8], me.name);
474 return 0;
477 /* check length of clients gecos */
478 if(strlen(parv[9]) > REALLEN)
480 char *s = LOCAL_COPY(parv[9]);
481 sendto_realops_flags(UMODE_ALL, L_ALL, "Long realname from server %s for %s",
482 parv[0], parv[1]);
483 s[REALLEN] = '\0';
484 parv[9] = s;
487 target_p = find_client(parv[1]);
489 if(target_p == NULL)
491 register_client(client_p, source_p, parv[1], newts, parc, parv);
493 else if(IsUnknown(target_p))
495 exit_client(NULL, target_p, &me, "Overridden");
496 register_client(client_p, source_p, parv[1], newts, parc, parv);
498 /* we've got a collision! */
499 else
500 perform_nick_collides(source_p, client_p, target_p, parc, parv,
501 newts, parv[1], parv[8]);
503 return 0;
506 /* ms_save()
507 * parv[1] - UID
508 * parv[2] - TS
510 static int
511 ms_save(struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
513 struct Client *target_p;
515 target_p = find_id(parv[1]);
516 if (target_p == NULL)
517 return 0;
518 if (!IsPerson(target_p))
519 sendto_realops_flags(UMODE_ALL, L_ALL,
520 "Ignored SAVE message for non-person %s from %s",
521 target_p->name, source_p->name);
522 else if (IsDigit(target_p->name[0]))
523 sendto_realops_flags(UMODE_DEBUG, L_ALL,
524 "Ignored noop SAVE message for %s from %s",
525 target_p->name, source_p->name);
526 else if (target_p->tsinfo == atol(parv[2]))
527 save_user(client_p, source_p, target_p);
528 else
529 sendto_realops_flags(UMODE_SKILL, L_ALL,
530 "Ignored SAVE message for %s from %s",
531 target_p->name, source_p->name);
532 return 0;
535 /* clean_nick()
537 * input - nickname to check
538 * output - 0 if erroneous, else 1
539 * side effects -
541 static int
542 clean_nick(const char *nick, int loc_client)
544 int len = 0;
546 /* nicks cant start with a digit or -, and must have a length */
547 if(*nick == '-' || *nick == '\0')
548 return 0;
550 if(loc_client && IsDigit(*nick))
551 return 0;
553 for (; *nick; nick++)
555 len++;
556 if(!IsNickChar(*nick))
557 return 0;
560 /* nicklen is +1 */
561 if(len >= NICKLEN)
562 return 0;
564 return 1;
567 /* clean_username()
569 * input - username to check
570 * output - 0 if erroneous, else 0
571 * side effects -
573 static int
574 clean_username(const char *username)
576 int len = 0;
578 for (; *username; username++)
580 len++;
582 if(!IsUserChar(*username))
583 return 0;
586 if(len > USERLEN)
587 return 0;
589 return 1;
592 /* clean_host()
594 * input - host to check
595 * output - 0 if erroneous, else 0
596 * side effects -
598 static int
599 clean_host(const char *host)
601 int len = 0;
603 for (; *host; host++)
605 len++;
607 if(!IsHostChar(*host))
608 return 0;
611 if(len > HOSTLEN)
612 return 0;
614 return 1;
617 static int
618 clean_uid(const char *uid)
620 int len = 1;
622 if(!IsDigit(*uid++))
623 return 0;
625 for(; *uid; uid++)
627 len++;
629 if(!IsIdChar(*uid))
630 return 0;
633 if(len != IDLEN-1)
634 return 0;
636 return 1;
639 static void
640 set_initial_nick(struct Client *client_p, struct Client *source_p, char *nick)
642 char buf[USERLEN + 1];
644 /* This had to be copied here to avoid problems.. */
645 source_p->tsinfo = CurrentTime;
646 if(!EmptyString(source_p->name))
647 del_from_client_hash(source_p->name, source_p);
648 else
650 make_user(source_p);
651 source_p->name = source_p->user->nick;
654 strcpy(source_p->user->nick, nick);
655 add_to_client_hash(nick, source_p);
657 /* fd_desc is long enough */
658 comm_note(client_p->localClient->fd, "Nick: %s", nick);
660 if(HasSentUser(source_p))
662 strlcpy(buf, source_p->username, sizeof(buf));
664 /* got user, heres nick. */
665 register_local_user(client_p, source_p, buf);
670 static void
671 change_local_nick(struct Client *client_p, struct Client *source_p, char *nick,
672 int dosend)
674 struct Client *target_p;
675 dlink_node *ptr, *next_ptr;
676 int samenick;
678 if (dosend)
680 if((source_p->localClient->last_nick_change + ConfigFileEntry.max_nick_time) < CurrentTime)
681 source_p->localClient->number_of_nick_changes = 0;
683 if(ConfigFileEntry.anti_nick_flood && !IsOper(source_p) &&
684 source_p->localClient->number_of_nick_changes > ConfigFileEntry.max_nick_changes)
686 sendto_one(source_p, form_str(ERR_NICKTOOFAST),
687 me.name, source_p->name, source_p->name,
688 nick, ConfigFileEntry.max_nick_time);
689 return;
692 source_p->localClient->last_nick_change = CurrentTime;
693 source_p->localClient->number_of_nick_changes++;
696 samenick = irccmp(source_p->name, nick) ? 0 : 1;
698 /* dont reset TS if theyre just changing case of nick */
699 if(!samenick)
701 /* force the TS to increase -- jilles */
702 if (source_p->tsinfo >= CurrentTime)
703 source_p->tsinfo++;
704 else
705 source_p->tsinfo = CurrentTime;
706 monitor_signoff(source_p);
707 /* we only do bancache for local users -- jilles */
708 if (source_p->user)
709 invalidate_bancache_user(source_p);
712 sendto_realops_flags(UMODE_NCHANGE, L_ALL,
713 "Nick change: From %s to %s [%s@%s]",
714 source_p->name, nick, source_p->username, source_p->host);
716 /* send the nick change to the users channels */
717 sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s",
718 source_p->name, source_p->username,
719 source_p->host, nick);
721 /* send the nick change to servers.. */
722 if(IsPerson(source_p))
724 add_history(source_p, 1);
726 if (dosend)
728 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
729 use_id(source_p), nick, (long) source_p->tsinfo);
730 sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
731 source_p->name, nick, (long) source_p->tsinfo);
735 /* Finally, add to hash */
736 del_from_client_hash(source_p->name, source_p);
737 strcpy(source_p->user->nick, nick);
738 add_to_client_hash(nick, source_p);
740 if(!samenick)
741 monitor_signon(source_p);
743 /* Make sure everyone that has this client on its accept list
744 * loses that reference.
746 /* we used to call del_all_accepts() here, but theres no real reason
747 * to clear a clients own list of accepted clients. So just remove
748 * them from everyone elses list --anfl
750 DLINK_FOREACH_SAFE(ptr, next_ptr, source_p->on_allow_list.head)
752 target_p = ptr->data;
754 dlinkFindDestroy(source_p, &target_p->localClient->allow_list);
755 dlinkDestroy(ptr, &source_p->on_allow_list);
758 /* fd_desc is long enough */
759 comm_note(client_p->localClient->fd, "Nick: %s", nick);
761 return;
765 * change_remote_nick()
767 static int
768 change_remote_nick(struct Client *client_p, struct Client *source_p,
769 time_t newts, const char *nick, int dosend)
771 struct nd_entry *nd;
772 int samenick = irccmp(source_p->name, nick) ? 0 : 1;
774 /* client changing their nick - dont reset ts if its same */
775 if(!samenick)
777 source_p->tsinfo = newts ? newts : CurrentTime;
778 monitor_signoff(source_p);
781 sendto_common_channels_local(source_p, ":%s!%s@%s NICK :%s",
782 source_p->name, source_p->username,
783 source_p->host, nick);
785 if(source_p->user)
787 add_history(source_p, 1);
788 if (dosend)
790 sendto_server(client_p, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
791 use_id(source_p), nick, (long) source_p->tsinfo);
792 sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
793 source_p->name, nick, (long) source_p->tsinfo);
797 del_from_client_hash(source_p->name, source_p);
799 /* invalidate nick delay when a remote client uses the nick.. */
800 if((nd = hash_find_nd(nick)))
801 free_nd_entry(nd);
803 strcpy(source_p->user->nick, nick);
804 add_to_client_hash(nick, source_p);
806 if(!samenick)
807 monitor_signon(source_p);
809 /* remove all accepts pointing to the client */
810 del_all_accepts(source_p);
812 return 0;
815 static int
816 perform_nick_collides(struct Client *source_p, struct Client *client_p,
817 struct Client *target_p, int parc, const char *parv[],
818 time_t newts, const char *nick, const char *uid)
820 int sameuser;
822 /* if we dont have a ts, or their TS's are the same, kill both */
823 if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
825 sendto_realops_flags(UMODE_ALL, L_ALL,
826 "Nick collision on %s(%s <- %s)(both killed)",
827 target_p->name, target_p->from->name, client_p->name);
829 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
830 form_str(ERR_NICKCOLLISION), target_p->name);
832 /* if the new client being introduced has a UID, we need to
833 * issue a KILL for it..
835 if(uid)
836 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
837 me.id, uid, me.name);
839 /* we then need to KILL the old client everywhere */
840 kill_client_serv_butone(NULL, target_p,
841 "%s (Nick collision (new))", me.name);
842 ServerStats->is_kill++;
844 target_p->flags |= FLAGS_KILLED;
845 exit_client(client_p, target_p, &me, "Nick collision (new)");
846 return 0;
848 /* the timestamps are different */
849 else
851 sameuser = (target_p->user) && !irccmp(target_p->username, parv[5])
852 && !irccmp(target_p->host, parv[6]);
854 if((sameuser && newts < target_p->tsinfo) ||
855 (!sameuser && newts > target_p->tsinfo))
857 /* if we have a UID, then we need to issue a KILL,
858 * otherwise we do nothing and hope that the other
859 * client will collide it..
861 if(uid)
862 sendto_one(client_p,
863 ":%s KILL %s :%s (Nick collision (new))",
864 me.id, uid, me.name);
865 return 0;
867 else
869 if(sameuser)
870 sendto_realops_flags(UMODE_ALL, L_ALL,
871 "Nick collision on %s(%s <- %s)(older killed)",
872 target_p->name, target_p->from->name,
873 client_p->name);
874 else
875 sendto_realops_flags(UMODE_ALL, L_ALL,
876 "Nick collision on %s(%s <- %s)(newer killed)",
877 target_p->name, target_p->from->name,
878 client_p->name);
880 ServerStats->is_kill++;
881 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
882 form_str(ERR_NICKCOLLISION), target_p->name);
884 /* now we just need to kill the existing client */
885 kill_client_serv_butone(client_p, target_p,
886 "%s (Nick collision (new))", me.name);
888 target_p->flags |= FLAGS_KILLED;
889 (void) exit_client(client_p, target_p, &me, "Nick collision");
891 register_client(client_p, parc == 10 ? source_p : NULL,
892 nick, newts, parc, parv);
894 return 0;
900 static int
901 perform_nickchange_collides(struct Client *source_p, struct Client *client_p,
902 struct Client *target_p, int parc,
903 const char *parv[], time_t newts, const char *nick)
905 int sameuser;
907 /* its a client changing nick and causing a collide */
908 if(!newts || !target_p->tsinfo || (newts == target_p->tsinfo) || !source_p->user)
910 sendto_realops_flags(UMODE_ALL, L_ALL,
911 "Nick change collision from %s to %s(%s <- %s)(both killed)",
912 source_p->name, target_p->name, target_p->from->name,
913 client_p->name);
915 ServerStats->is_kill++;
916 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
917 form_str(ERR_NICKCOLLISION), target_p->name);
919 kill_client_serv_butone(NULL, source_p, "%s (Nick change collision)", me.name);
921 ServerStats->is_kill++;
923 kill_client_serv_butone(NULL, target_p, "%s (Nick change collision)", me.name);
925 target_p->flags |= FLAGS_KILLED;
926 exit_client(NULL, target_p, &me, "Nick collision(new)");
927 source_p->flags |= FLAGS_KILLED;
928 exit_client(client_p, source_p, &me, "Nick collision(old)");
929 return 0;
931 else
933 sameuser = !irccmp(target_p->username, source_p->username) &&
934 !irccmp(target_p->host, source_p->host);
936 if((sameuser && newts < target_p->tsinfo) ||
937 (!sameuser && newts > target_p->tsinfo))
939 if(sameuser)
940 sendto_realops_flags(UMODE_ALL, L_ALL,
941 "Nick change collision from %s to %s(%s <- %s)(older killed)",
942 source_p->name, target_p->name,
943 target_p->from->name, client_p->name);
944 else
945 sendto_realops_flags(UMODE_ALL, L_ALL,
946 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
947 source_p->name, target_p->name,
948 target_p->from->name, client_p->name);
950 ServerStats->is_kill++;
952 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
953 form_str(ERR_NICKCOLLISION), target_p->name);
955 /* kill the client issuing the nickchange */
956 kill_client_serv_butone(client_p, source_p,
957 "%s (Nick change collision)", me.name);
959 source_p->flags |= FLAGS_KILLED;
961 if(sameuser)
962 exit_client(client_p, source_p, &me, "Nick collision(old)");
963 else
964 exit_client(client_p, source_p, &me, "Nick collision(new)");
965 return 0;
967 else
969 if(sameuser)
970 sendto_realops_flags(UMODE_ALL, L_ALL,
971 "Nick collision on %s(%s <- %s)(older killed)",
972 target_p->name, target_p->from->name,
973 client_p->name);
974 else
975 sendto_realops_flags(UMODE_ALL, L_ALL,
976 "Nick collision on %s(%s <- %s)(newer killed)",
977 target_p->name, target_p->from->name,
978 client_p->name);
980 sendto_one_numeric(target_p, ERR_NICKCOLLISION,
981 form_str(ERR_NICKCOLLISION), target_p->name);
983 /* kill the client who existed before hand */
984 kill_client_serv_butone(client_p, target_p,
985 "%s (Nick collision)", me.name);
987 ServerStats->is_kill++;
989 target_p->flags |= FLAGS_KILLED;
990 (void) exit_client(client_p, target_p, &me, "Nick collision");
994 change_remote_nick(client_p, source_p, newts, nick, 1);
996 return 0;
999 static int
1000 register_client(struct Client *client_p, struct Client *server,
1001 const char *nick, time_t newts, int parc, const char *parv[])
1003 struct Client *source_p;
1004 struct User *user;
1005 struct nd_entry *nd;
1006 const char *m;
1007 int flag;
1009 source_p = make_client(client_p);
1010 user = make_user(source_p);
1012 source_p->hopcount = atoi(parv[2]);
1013 source_p->tsinfo = newts;
1015 source_p->name = source_p->user->nick;
1016 strcpy(source_p->user->nick, nick);
1017 strlcpy(source_p->username, parv[5], sizeof(source_p->username));
1018 strlcpy(source_p->host, parv[6], sizeof(source_p->host));
1020 /* nothing must be done before this point that cant be cleaned up
1021 * just by doing a free_client(). --fl
1023 if(parc == 10)
1025 strlcpy(source_p->info, parv[9], sizeof(source_p->info));
1026 strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
1027 strlcpy(source_p->id, parv[8], sizeof(source_p->id));
1028 add_to_id_hash(source_p->id, source_p);
1030 else
1032 strlcpy(source_p->info, parv[8], sizeof(source_p->info));
1034 if((server = find_server(NULL, parv[7])) == NULL)
1036 sendto_realops_flags(UMODE_ALL, L_ALL,
1037 "Ghost killed: %s on invalid server %s",
1038 source_p->name, parv[7]);
1039 kill_client(client_p, source_p, "%s (Server doesn't exist)", me.name);
1040 free_user(source_p->user, source_p);
1041 free_client(source_p);
1042 return 0;
1047 dlinkAddTail(source_p, &source_p->node, &global_client_list);
1049 /* server is guaranteed to exist at this point */
1050 source_p->servptr = server;
1051 dlinkAdd(source_p, &source_p->lnode, &source_p->servptr->serv->users);
1053 /* remove any nd entries for this nick */
1054 if((nd = hash_find_nd(nick)))
1055 free_nd_entry(nd);
1057 add_to_client_hash(nick, source_p);
1058 add_to_hostname_hash(source_p->host, source_p);
1059 monitor_signon(source_p);
1061 m = &parv[4][1];
1062 while(*m)
1064 flag = user_modes_from_c_to_bitmask[(unsigned char) *m];
1066 #ifdef ENABLE_SERVICES
1067 if(flag & UMODE_SERVICE)
1069 int hit = 0;
1070 dlink_node *ptr;
1072 DLINK_FOREACH(ptr, service_list.head)
1074 if(!irccmp((const char *) ptr->data, source_p->servptr->name))
1076 hit++;
1077 break;
1081 if(!hit)
1083 m++;
1084 continue;
1087 #endif
1089 /* increment +i count if theyre invis */
1090 if(!(source_p->umodes & UMODE_INVISIBLE) &&
1091 (flag & UMODE_INVISIBLE))
1092 Count.invisi++;
1094 /* increment opered count if theyre opered */
1095 if(!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER))
1096 Count.oper++;
1098 source_p->umodes |= (flag & SEND_UMODES);
1099 m++;
1102 SetRemoteClient(source_p);
1104 if(++Count.total > Count.max_tot)
1105 Count.max_tot = Count.total;
1107 /* fake direction */
1108 if(source_p->servptr->from != source_p->from)
1110 struct Client *target_p = source_p->servptr->from;
1112 sendto_realops_flags(UMODE_DEBUG, L_ALL,
1113 "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
1114 client_p->name, source_p->name,
1115 source_p->username, source_p->host,
1116 source_p->servptr->name, target_p->name,
1117 target_p->from->name);
1118 kill_client(client_p, source_p,
1119 "%s (NICK from wrong direction (%s != %s))",
1120 me.name, source_p->servptr->name, target_p->from->name);
1121 source_p->flags |= FLAGS_KILLED;
1122 return exit_client(source_p, source_p, &me, "USER server wrong direction");
1125 return (introduce_client(client_p, source_p, user, nick));
1128 static void
1129 save_user(struct Client *client_p, struct Client *source_p,
1130 struct Client *target_p)
1132 if (!MyConnect(target_p) && (!has_id(target_p) || !IsCapable(target_p->from, CAP_SAVE)))
1134 /* This shouldn't happen */
1135 /* Note we only need SAVE support in this direction */
1136 sendto_realops_flags(UMODE_ALL, L_ALL,
1137 "Killed %s!%s@%s for nick collision detected by %s (%s does not support SAVE)",
1138 target_p->name, target_p->username, target_p->host, source_p->name, target_p->from->name);
1139 kill_client_serv_butone(NULL, target_p, "%s (Nick collision (no SAVE support))", me.name);
1140 ServerStats->is_kill++;
1142 target_p->flags |= FLAGS_KILLED;
1143 (void) exit_client(NULL, target_p, &me, "Nick collision (no SAVE support)");
1144 return;
1146 sendto_server(client_p, NULL, CAP_SAVE|CAP_TS6, NOCAPS, ":%s SAVE %s %ld",
1147 source_p->id, target_p->id, (long)target_p->tsinfo);
1148 sendto_server(client_p, NULL, CAP_TS6, CAP_SAVE, ":%s NICK %s :%ld",
1149 target_p->id, target_p->id, (long)SAVE_NICKTS);
1150 sendto_server(client_p, NULL, NOCAPS, CAP_TS6, ":%s NICK %s :%ld",
1151 target_p->name, target_p->id, (long)SAVE_NICKTS);
1152 if (!IsMe(client_p))
1153 sendto_realops_flags(UMODE_SKILL, L_ALL,
1154 "Received SAVE message for %s from %s",
1155 target_p->name, source_p->name);
1156 if (MyClient(target_p))
1158 sendto_one_numeric(target_p, RPL_SAVENICK,
1159 form_str(RPL_SAVENICK), target_p->id);
1160 change_local_nick(target_p, target_p, target_p->id, 0);
1161 target_p->tsinfo = SAVE_NICKTS;
1163 else
1164 change_remote_nick(target_p, target_p, SAVE_NICKTS, target_p->id, 0);