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
24 * $Id: m_nick.c 3418 2007-04-22 11:22:10Z jilles $
30 #include "irc_string.h"
48 #include "s_newconf.h"
51 static int mr_nick(struct Client
*, struct Client
*, int, const char **);
52 static int m_nick(struct Client
*, struct Client
*, int, const char **);
53 static int mc_nick(struct Client
*, struct Client
*, int, const char **);
54 static int ms_nick(struct Client
*, struct Client
*, int, const char **);
55 static int ms_uid(struct Client
*, struct Client
*, int, const char **);
56 static int ms_euid(struct Client
*, struct Client
*, int, const char **);
57 static int ms_save(struct Client
*, struct Client
*, int, const char **);
58 static int can_save(struct Client
*);
59 static void save_user(struct Client
*, struct Client
*, struct Client
*);
61 struct Message nick_msgtab
= {
62 "NICK", 0, 0, 0, MFLG_SLOW
,
63 {{mr_nick
, 0}, {m_nick
, 0}, {mc_nick
, 3}, {ms_nick
, 8}, mg_ignore
, {m_nick
, 0}}
65 struct Message uid_msgtab
= {
66 "UID", 0, 0, 0, MFLG_SLOW
,
67 {mg_ignore
, mg_ignore
, mg_ignore
, {ms_uid
, 9}, mg_ignore
, mg_ignore
}
69 struct Message euid_msgtab
= {
70 "EUID", 0, 0, 0, MFLG_SLOW
,
71 {mg_ignore
, mg_ignore
, mg_ignore
, {ms_euid
, 12}, mg_ignore
, mg_ignore
}
73 struct Message save_msgtab
= {
74 "SAVE", 0, 0, 0, MFLG_SLOW
,
75 {mg_ignore
, mg_ignore
, mg_ignore
, {ms_save
, 3}, mg_ignore
, mg_ignore
}
78 mapi_clist_av1 nick_clist
[] = { &nick_msgtab
, &uid_msgtab
, &euid_msgtab
,
81 DECLARE_MODULE_AV1(nick
, NULL
, NULL
, nick_clist
, NULL
, NULL
, "$Revision: 3418 $");
83 static int change_remote_nick(struct Client
*, struct Client
*, time_t,
86 static int clean_nick(const char *, int loc_client
);
87 static int clean_username(const char *);
88 static int clean_host(const char *);
89 static int clean_uid(const char *uid
);
91 static void set_initial_nick(struct Client
*client_p
, struct Client
*source_p
, char *nick
);
92 static void change_local_nick(struct Client
*client_p
, struct Client
*source_p
, char *nick
, int);
93 static int register_client(struct Client
*client_p
, struct Client
*server
,
94 const char *nick
, time_t newts
, int parc
, const char *parv
[]);
96 static int perform_nick_collides(struct Client
*, struct Client
*,
97 struct Client
*, int, const char **,
98 time_t, const char *, const char *);
99 static int perform_nickchange_collides(struct Client
*, struct Client
*,
100 struct Client
*, int, const char **, time_t, const char *);
103 * parv[0] = sender prefix
107 mr_nick(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
109 struct Client
*target_p
;
113 if (strlen(client_p
->id
) == 3)
115 exit_client(client_p
, client_p
, client_p
, "Mixing client and server protocol");
119 if(parc
< 2 || EmptyString(parv
[1]) || (parv
[1][0] == '~'))
121 sendto_one(source_p
, form_str(ERR_NONICKNAMEGIVEN
),
122 me
.name
, EmptyString(source_p
->name
) ? "*" : source_p
->name
);
126 /* due to the scandinavian origins, (~ being uppercase of ^) and ~
127 * being disallowed as a nick char, we need to chop the first ~
128 * instead of just erroring.
130 if((s
= strchr(parv
[1], '~')))
133 /* copy the nick and terminate it */
134 strlcpy(nick
, parv
[1], sizeof(nick
));
136 /* check the nickname is ok */
137 if(!clean_nick(nick
, 1))
139 sendto_one(source_p
, form_str(ERR_ERRONEUSNICKNAME
),
140 me
.name
, EmptyString(parv
[0]) ? "*" : parv
[0], parv
[1]);
144 /* check if the nick is resv'd */
145 if(find_nick_resv(nick
))
147 sendto_one(source_p
, form_str(ERR_ERRONEUSNICKNAME
),
148 me
.name
, EmptyString(source_p
->name
) ? "*" : source_p
->name
, nick
);
152 if(hash_find_nd(nick
))
154 sendto_one(source_p
, form_str(ERR_UNAVAILRESOURCE
),
155 me
.name
, EmptyString(source_p
->name
) ? "*" : source_p
->name
, nick
);
159 if((target_p
= find_named_client(nick
)) == NULL
)
160 set_initial_nick(client_p
, source_p
, nick
);
161 else if(source_p
== target_p
)
162 strcpy(source_p
->name
, nick
);
164 sendto_one(source_p
, form_str(ERR_NICKNAMEINUSE
), me
.name
, "*", nick
);
170 * parv[0] = sender prefix
174 m_nick(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
176 struct Client
*target_p
;
180 if(parc
< 2 || EmptyString(parv
[1]) || (parv
[1][0] == '~'))
182 sendto_one(source_p
, form_str(ERR_NONICKNAMEGIVEN
), me
.name
, source_p
->name
);
186 /* due to the scandinavian origins, (~ being uppercase of ^) and ~
187 * being disallowed as a nick char, we need to chop the first ~
188 * instead of just erroring.
190 if((s
= strchr(parv
[1], '~')))
193 /* mark end of grace period, to prevent nickflooding */
194 if(!IsFloodDone(source_p
))
195 flood_endgrace(source_p
);
197 /* terminate nick to NICKLEN, we dont want clean_nick() to error! */
198 strlcpy(nick
, parv
[1], sizeof(nick
));
200 /* check the nickname is ok */
201 if(!clean_nick(nick
, 1))
203 sendto_one(source_p
, form_str(ERR_ERRONEUSNICKNAME
), me
.name
, parv
[0], nick
);
207 if(!IsExemptResv(source_p
) && find_nick_resv(nick
))
209 sendto_one(source_p
, form_str(ERR_ERRONEUSNICKNAME
), me
.name
, source_p
->name
, nick
);
213 if(hash_find_nd(nick
))
215 sendto_one(source_p
, form_str(ERR_UNAVAILRESOURCE
),
216 me
.name
, EmptyString(source_p
->name
) ? "*" : source_p
->name
, nick
);
220 if((target_p
= find_named_client(nick
)))
222 /* If(target_p == source_p) the client is changing nicks between
223 * equivalent nicknames ie: [nick] -> {nick}
225 if(target_p
== source_p
)
227 /* check the nick isnt exactly the same */
228 if(strcmp(target_p
->name
, nick
))
229 change_local_nick(client_p
, source_p
, nick
, 1);
233 /* drop unregged client */
234 else if(IsUnknown(target_p
))
236 exit_client(NULL
, target_p
, &me
, "Overridden");
237 change_local_nick(client_p
, source_p
, nick
, 1);
240 sendto_one(source_p
, form_str(ERR_NICKNAMEINUSE
), me
.name
, parv
[0], nick
);
245 change_local_nick(client_p
, source_p
, nick
, 1);
252 * server -> server nick change
253 * parv[0] = sender prefix
255 * parv[2] = TS when nick change
257 * server introducing new nick
258 * parv[0] = sender prefix
260 * parv[2] = hop count
269 mc_nick(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
271 struct Client
*target_p
;
274 /* if nicks erroneous, or too long, kill */
275 if(!clean_nick(parv
[1], 0))
277 ServerStats
->is_kill
++;
278 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
279 "Bad Nick: %s From: %s(via %s)",
280 parv
[1], source_p
->user
->server
, client_p
->name
);
281 sendto_one(client_p
, ":%s KILL %s :%s (Bad Nickname)", me
.name
, parv
[1], me
.name
);
283 /* bad nick change, issue kill for the old nick to the rest
286 kill_client_serv_butone(client_p
, source_p
, "%s (Bad Nickname)", me
.name
);
287 source_p
->flags
|= FLAGS_KILLED
;
288 exit_client(client_p
, source_p
, &me
, "Bad Nickname");
292 newts
= atol(parv
[2]);
293 target_p
= find_named_client(parv
[1]);
295 /* if the nick doesnt exist, allow it and process like normal */
298 change_remote_nick(client_p
, source_p
, newts
, parv
[1], 1);
300 else if(IsUnknown(target_p
))
302 exit_client(NULL
, target_p
, &me
, "Overridden");
303 change_remote_nick(client_p
, source_p
, newts
, parv
[1], 1);
305 else if(target_p
== source_p
)
307 /* client changing case of nick */
308 if(strcmp(target_p
->name
, parv
[1]))
309 change_remote_nick(client_p
, source_p
, newts
, parv
[1], 1);
311 /* we've got a collision! */
313 perform_nickchange_collides(source_p
, client_p
, target_p
,
314 parc
, parv
, newts
, parv
[1]);
320 ms_nick(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
322 struct Client
*target_p
;
327 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
328 "Dropping server %s due to (invalid) command 'NICK' "
329 "with %d arguments (expecting 9)", client_p
->name
, parc
);
330 ilog(L_SERVER
, "Excess parameters (%d) for command 'NICK' from %s.",
331 parc
, client_p
->name
);
332 exit_client(client_p
, client_p
, client_p
, "Excess parameters to NICK command");
336 /* if nicks empty, erroneous, or too long, kill */
337 if(!clean_nick(parv
[1], 0))
339 ServerStats
->is_kill
++;
340 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
341 "Bad Nick: %s From: %s(via %s)",
342 parv
[1], parv
[7], client_p
->name
);
343 sendto_one(client_p
, ":%s KILL %s :%s (Bad Nickname)", me
.name
, parv
[1], me
.name
);
347 /* invalid username or host? */
348 if(!clean_username(parv
[5]) || !clean_host(parv
[6]))
350 ServerStats
->is_kill
++;
351 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
352 "Bad user@host: %s@%s From: %s(via %s)",
353 parv
[5], parv
[6], parv
[7], client_p
->name
);
354 sendto_one(client_p
, ":%s KILL %s :%s (Bad user@host)", me
.name
, parv
[1], me
.name
);
358 /* check the length of the clients gecos */
359 if(strlen(parv
[8]) > REALLEN
)
361 char *s
= LOCAL_COPY(parv
[8]);
362 /* why exactly do we care? --fl */
363 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
364 "Long realname from server %s for %s", parv
[7], parv
[1]);
370 newts
= atol(parv
[3]);
372 target_p
= find_named_client(parv
[1]);
374 /* if the nick doesnt exist, allow it and process like normal */
377 register_client(client_p
, NULL
, parv
[1], newts
, parc
, parv
);
379 else if(IsUnknown(target_p
))
381 exit_client(NULL
, target_p
, &me
, "Overridden");
382 register_client(client_p
, NULL
, parv
[1], newts
, parc
, parv
);
384 else if(target_p
== source_p
)
386 /* client changing case of nick */
387 if(strcmp(target_p
->name
, parv
[1]))
388 register_client(client_p
, NULL
, parv
[1], newts
, parc
, parv
);
390 /* we've got a collision! */
392 perform_nick_collides(source_p
, client_p
, target_p
, parc
, parv
,
393 newts
, parv
[1], NULL
);
410 ms_uid(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
412 struct Client
*target_p
;
415 newts
= atol(parv
[3]);
419 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
420 "Dropping server %s due to (invalid) command 'UID' "
421 "with %d arguments (expecting 10)", client_p
->name
, parc
);
422 ilog(L_SERVER
, "Excess parameters (%d) for command 'UID' from %s.",
423 parc
, client_p
->name
);
424 exit_client(client_p
, client_p
, client_p
, "Excess parameters to UID command");
428 /* if nicks erroneous, or too long, kill */
429 if(!clean_nick(parv
[1], 0))
431 ServerStats
->is_kill
++;
432 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
433 "Bad Nick: %s From: %s(via %s)",
434 parv
[1], source_p
->name
, client_p
->name
);
435 sendto_one(client_p
, ":%s KILL %s :%s (Bad Nickname)", me
.id
, parv
[8], me
.name
);
439 if(!clean_username(parv
[5]) || !clean_host(parv
[6]))
441 ServerStats
->is_kill
++;
442 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
443 "Bad user@host: %s@%s From: %s(via %s)",
444 parv
[5], parv
[6], source_p
->name
, client_p
->name
);
445 sendto_one(client_p
, ":%s KILL %s :%s (Bad user@host)", me
.id
, parv
[8], me
.name
);
449 if(!clean_uid(parv
[8]))
451 ServerStats
->is_kill
++;
452 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
453 "Bad UID: %s From: %s(via %s)",
454 parv
[8], source_p
->name
, client_p
->name
);
455 sendto_one(client_p
, ":%s KILL %s :%s (Bad UID)", me
.id
, parv
[8], me
.name
);
459 /* check length of clients gecos */
460 if(strlen(parv
[9]) > REALLEN
)
462 char *s
= LOCAL_COPY(parv
[9]);
463 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Long realname from server %s for %s",
469 target_p
= find_named_client(parv
[1]);
473 register_client(client_p
, source_p
, parv
[1], newts
, parc
, parv
);
475 else if(IsUnknown(target_p
))
477 exit_client(NULL
, target_p
, &me
, "Overridden");
478 register_client(client_p
, source_p
, parv
[1], newts
, parc
, parv
);
480 /* we've got a collision! */
482 perform_nick_collides(source_p
, client_p
, target_p
, parc
, parv
,
483 newts
, parv
[1], parv
[8]);
502 ms_euid(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
504 struct Client
*target_p
;
507 newts
= atol(parv
[3]);
511 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
512 "Dropping server %s due to (invalid) command 'EUID' "
513 "with %d arguments (expecting 12)", client_p
->name
, parc
);
514 ilog(L_SERVER
, "Excess parameters (%d) for command 'EUID' from %s.",
515 parc
, client_p
->name
);
516 exit_client(client_p
, client_p
, client_p
, "Excess parameters to EUID command");
520 /* if nicks erroneous, or too long, kill */
521 if(!clean_nick(parv
[1], 0))
523 ServerStats
->is_kill
++;
524 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
525 "Bad Nick: %s From: %s(via %s)",
526 parv
[1], source_p
->name
, client_p
->name
);
527 sendto_one(client_p
, ":%s KILL %s :%s (Bad Nickname)", me
.id
, parv
[8], me
.name
);
531 if(!clean_username(parv
[5]) || !clean_host(parv
[6]))
533 ServerStats
->is_kill
++;
534 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
535 "Bad user@host: %s@%s From: %s(via %s)",
536 parv
[5], parv
[6], source_p
->name
, client_p
->name
);
537 sendto_one(client_p
, ":%s KILL %s :%s (Bad user@host)", me
.id
, parv
[8], me
.name
);
541 if(!clean_uid(parv
[8]))
543 ServerStats
->is_kill
++;
544 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
545 "Bad UID: %s From: %s(via %s)",
546 parv
[8], source_p
->name
, client_p
->name
);
547 sendto_one(client_p
, ":%s KILL %s :%s (Bad UID)", me
.id
, parv
[8], me
.name
);
551 if(strcmp(parv
[9], "*") && !clean_host(parv
[9]))
553 ServerStats
->is_kill
++;
554 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
555 "Bad realhost: %s From: %s(via %s)",
556 parv
[9], source_p
->name
, client_p
->name
);
557 sendto_one(client_p
, ":%s KILL %s :%s (Bad user@host)", me
.id
, parv
[8], me
.name
);
561 /* check length of clients gecos */
562 if(strlen(parv
[11]) > REALLEN
)
564 char *s
= LOCAL_COPY(parv
[11]);
565 sendto_realops_snomask(SNO_GENERAL
, L_ALL
, "Long realname from server %s for %s",
571 target_p
= find_named_client(parv
[1]);
575 register_client(client_p
, source_p
, parv
[1], newts
, parc
, parv
);
577 else if(IsUnknown(target_p
))
579 exit_client(NULL
, target_p
, &me
, "Overridden");
580 register_client(client_p
, source_p
, parv
[1], newts
, parc
, parv
);
582 /* we've got a collision! */
584 perform_nick_collides(source_p
, client_p
, target_p
, parc
, parv
,
585 newts
, parv
[1], parv
[8]);
595 ms_save(struct Client
*client_p
, struct Client
*source_p
, int parc
, const char *parv
[])
597 struct Client
*target_p
;
599 target_p
= find_id(parv
[1]);
600 if (target_p
== NULL
)
602 if (!IsPerson(target_p
))
603 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
604 "Ignored SAVE message for non-person %s from %s",
605 target_p
->name
, source_p
->name
);
606 else if (IsDigit(target_p
->name
[0]))
607 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
608 "Ignored noop SAVE message for %s from %s",
609 target_p
->name
, source_p
->name
);
610 else if (target_p
->tsinfo
== atol(parv
[2]))
611 save_user(client_p
, source_p
, target_p
);
613 sendto_realops_snomask(SNO_SKILL
, L_ALL
,
614 "Ignored SAVE message for %s from %s",
615 target_p
->name
, source_p
->name
);
621 * input - nickname to check
622 * output - 0 if erroneous, else 1
626 clean_nick(const char *nick
, int loc_client
)
630 /* nicks cant start with a digit or -, and must have a length */
631 if(*nick
== '-' || *nick
== '\0')
634 if(loc_client
&& IsDigit(*nick
))
640 if(!IsNickChar(*nick
))
653 * input - username to check
654 * output - 0 if erroneous, else 0
658 clean_username(const char *username
)
662 for(; *username
; username
++)
666 if(!IsUserChar(*username
))
678 * input - host to check
679 * output - 0 if erroneous, else 0
683 clean_host(const char *host
)
691 if(!IsHostChar(*host
))
702 clean_uid(const char *uid
)
724 set_initial_nick(struct Client
*client_p
, struct Client
*source_p
, char *nick
)
726 char buf
[USERLEN
+ 1];
728 /* This had to be copied here to avoid problems.. */
729 source_p
->tsinfo
= CurrentTime
;
730 if(source_p
->name
[0])
731 del_from_client_hash(source_p
->name
, source_p
);
733 strcpy(source_p
->name
, nick
);
734 add_to_client_hash(nick
, source_p
);
736 /* fd_desc is long enough */
737 comm_note(client_p
->localClient
->fd
, "Nick: %s", nick
);
739 if(source_p
->flags
& FLAGS_SENTUSER
)
741 strlcpy(buf
, source_p
->username
, sizeof(buf
));
743 /* got user, heres nick. */
744 register_local_user(client_p
, source_p
, buf
);
750 change_local_nick(struct Client
*client_p
, struct Client
*source_p
,
751 char *nick
, int dosend
)
753 struct Client
*target_p
;
754 dlink_node
*ptr
, *next_ptr
;
755 struct Channel
*chptr
;
760 chptr
= find_bannickchange_channel(source_p
);
763 sendto_one_numeric(source_p
, ERR_BANNICKCHANGE
,
764 form_str(ERR_BANNICKCHANGE
),
765 nick
, chptr
->chname
);
768 if((source_p
->localClient
->last_nick_change
+ ConfigFileEntry
.max_nick_time
) < CurrentTime
)
769 source_p
->localClient
->number_of_nick_changes
= 0;
771 source_p
->localClient
->last_nick_change
= CurrentTime
;
772 source_p
->localClient
->number_of_nick_changes
++;
774 if(ConfigFileEntry
.anti_nick_flood
&& !IsOper(source_p
) &&
775 source_p
->localClient
->number_of_nick_changes
> ConfigFileEntry
.max_nick_changes
)
777 sendto_one(source_p
, form_str(ERR_NICKTOOFAST
),
778 me
.name
, source_p
->name
, source_p
->name
,
779 nick
, ConfigFileEntry
.max_nick_time
);
784 samenick
= irccmp(source_p
->name
, nick
) ? 0 : 1;
786 /* dont reset TS if theyre just changing case of nick */
789 /* force the TS to increase -- jilles */
790 if (source_p
->tsinfo
>= CurrentTime
)
793 source_p
->tsinfo
= CurrentTime
;
794 monitor_signoff(source_p
);
795 /* we only do bancache for local users -- jilles */
797 invalidate_bancache_user(source_p
);
800 sendto_realops_snomask(SNO_NCHANGE
, L_ALL
,
801 "Nick change: From %s to %s [%s@%s]",
802 source_p
->name
, nick
, source_p
->username
, source_p
->host
);
804 /* send the nick change to the users channels */
805 sendto_common_channels_local(source_p
, ":%s!%s@%s NICK :%s",
806 source_p
->name
, source_p
->username
, source_p
->host
, nick
);
808 /* send the nick change to servers.. */
811 add_history(source_p
, 1);
815 sendto_server(client_p
, NULL
, CAP_TS6
, NOCAPS
, ":%s NICK %s :%ld",
816 use_id(source_p
), nick
, (long) source_p
->tsinfo
);
817 sendto_server(client_p
, NULL
, NOCAPS
, CAP_TS6
, ":%s NICK %s :%ld",
818 source_p
->name
, nick
, (long) source_p
->tsinfo
);
822 /* Finally, add to hash */
823 del_from_client_hash(source_p
->name
, source_p
);
824 strcpy(source_p
->name
, nick
);
825 add_to_client_hash(nick
, source_p
);
828 monitor_signon(source_p
);
830 /* Make sure everyone that has this client on its accept list
831 * loses that reference.
833 /* we used to call del_all_accepts() here, but theres no real reason
834 * to clear a clients own list of accepted clients. So just remove
835 * them from everyone elses list --anfl
837 DLINK_FOREACH_SAFE(ptr
, next_ptr
, source_p
->on_allow_list
.head
)
839 target_p
= ptr
->data
;
841 dlinkFindDestroy(source_p
, &target_p
->localClient
->allow_list
);
842 dlinkDestroy(ptr
, &source_p
->on_allow_list
);
845 /* fd_desc is long enough */
846 comm_note(client_p
->localClient
->fd
, "Nick: %s", nick
);
852 * change_remote_nick()
855 change_remote_nick(struct Client
*client_p
, struct Client
*source_p
,
856 time_t newts
, const char *nick
, int dosend
)
859 int samenick
= irccmp(source_p
->name
, nick
) ? 0 : 1;
861 /* client changing their nick - dont reset ts if its same */
864 source_p
->tsinfo
= newts
? newts
: CurrentTime
;
865 monitor_signoff(source_p
);
868 sendto_common_channels_local(source_p
, ":%s!%s@%s NICK :%s",
869 source_p
->name
, source_p
->username
, source_p
->host
, nick
);
873 add_history(source_p
, 1);
876 sendto_server(client_p
, NULL
, CAP_TS6
, NOCAPS
, ":%s NICK %s :%ld",
877 use_id(source_p
), nick
, (long) source_p
->tsinfo
);
878 sendto_server(client_p
, NULL
, NOCAPS
, CAP_TS6
, ":%s NICK %s :%ld",
879 source_p
->name
, nick
, (long) source_p
->tsinfo
);
883 del_from_client_hash(source_p
->name
, source_p
);
885 /* invalidate nick delay when a remote client uses the nick.. */
886 if((nd
= hash_find_nd(nick
)))
889 strcpy(source_p
->name
, nick
);
890 add_to_client_hash(nick
, source_p
);
893 monitor_signon(source_p
);
895 /* remove all accepts pointing to the client */
896 del_all_accepts(source_p
);
902 perform_nick_collides(struct Client
*source_p
, struct Client
*client_p
,
903 struct Client
*target_p
, int parc
, const char *parv
[],
904 time_t newts
, const char *nick
, const char *uid
)
910 use_save
= ConfigFileEntry
.collision_fnc
&& can_save(target_p
) &&
911 uid
!= NULL
&& can_save(source_p
);
912 action
= use_save
? "saved" : "killed";
914 /* if we dont have a ts, or their TS's are the same, kill both */
915 if(!newts
|| !target_p
->tsinfo
|| (newts
== target_p
->tsinfo
))
917 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
918 "Nick collision on %s(%s <- %s)(both %s)",
919 target_p
->name
, target_p
->from
->name
, client_p
->name
, action
);
923 save_user(&me
, &me
, target_p
);
924 ServerStats
->is_save
++;
925 sendto_one(client_p
, ":%s SAVE %s %ld", me
.id
,
927 register_client(client_p
, source_p
,
928 uid
, newts
, parc
, parv
);
932 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
933 form_str(ERR_NICKCOLLISION
), target_p
->name
);
935 /* if the new client being introduced has a UID, we need to
936 * issue a KILL for it..
939 sendto_one(client_p
, ":%s KILL %s :%s (Nick collision (new))",
940 me
.id
, uid
, me
.name
);
942 /* we then need to KILL the old client everywhere */
943 kill_client_serv_butone(NULL
, target_p
, "%s (Nick collision (new))", me
.name
);
944 ServerStats
->is_kill
++;
946 target_p
->flags
|= FLAGS_KILLED
;
947 exit_client(client_p
, target_p
, &me
, "Nick collision (new)");
951 /* the timestamps are different */
954 sameuser
= (target_p
->user
) && !irccmp(target_p
->username
, parv
[5])
955 && !irccmp(target_p
->host
, parv
[6]);
957 if((sameuser
&& newts
< target_p
->tsinfo
) ||
958 (!sameuser
&& newts
> target_p
->tsinfo
))
960 /* if we have a UID, then we need to issue a KILL,
961 * otherwise we do nothing and hope that the other
962 * client will collide it..
966 sendto_one(client_p
, ":%s SAVE %s %ld", me
.id
,
968 register_client(client_p
, source_p
,
969 uid
, newts
, parc
, parv
);
973 ":%s KILL %s :%s (Nick collision (new))",
974 me
.id
, uid
, me
.name
);
980 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
981 "Nick collision on %s(%s <- %s)(older %s)",
982 target_p
->name
, target_p
->from
->name
,
983 client_p
->name
, action
);
985 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
986 "Nick collision on %s(%s <- %s)(newer %s)",
987 target_p
->name
, target_p
->from
->name
,
988 client_p
->name
, action
);
992 ServerStats
->is_save
++;
993 save_user(&me
, &me
, target_p
);
997 ServerStats
->is_kill
++;
998 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
999 form_str(ERR_NICKCOLLISION
), target_p
->name
);
1001 /* now we just need to kill the existing client */
1002 kill_client_serv_butone(client_p
, target_p
,
1003 "%s (Nick collision (new))", me
.name
);
1005 target_p
->flags
|= FLAGS_KILLED
;
1006 (void) exit_client(client_p
, target_p
, &me
, "Nick collision");
1009 register_client(client_p
, parc
>= 10 ? source_p
: NULL
,
1010 nick
, newts
, parc
, parv
);
1019 perform_nickchange_collides(struct Client
*source_p
, struct Client
*client_p
,
1020 struct Client
*target_p
, int parc
,
1021 const char *parv
[], time_t newts
, const char *nick
)
1027 use_save
= ConfigFileEntry
.collision_fnc
&& can_save(target_p
) &&
1029 action
= use_save
? "saved" : "killed";
1031 /* its a client changing nick and causing a collide */
1032 if(!newts
|| !target_p
->tsinfo
|| (newts
== target_p
->tsinfo
) || !source_p
->user
)
1034 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1035 "Nick change collision from %s to %s(%s <- %s)(both %s)",
1036 source_p
->name
, target_p
->name
, target_p
->from
->name
,
1037 client_p
->name
, action
);
1041 ServerStats
->is_save
+= 2;
1042 save_user(&me
, &me
, target_p
);
1043 sendto_one(client_p
, ":%s SAVE %s %ld", me
.id
,
1044 source_p
->id
, (long)newts
);
1045 /* don't send a redundant nick change */
1046 if (!IsDigit(source_p
->name
[0]))
1047 change_remote_nick(client_p
, source_p
, CurrentTime
, source_p
->id
, 1);
1051 ServerStats
->is_kill
++;
1052 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
1053 form_str(ERR_NICKCOLLISION
), target_p
->name
);
1055 kill_client_serv_butone(NULL
, source_p
, "%s (Nick change collision)", me
.name
);
1057 ServerStats
->is_kill
++;
1059 kill_client_serv_butone(NULL
, target_p
, "%s (Nick change collision)", me
.name
);
1061 target_p
->flags
|= FLAGS_KILLED
;
1062 exit_client(NULL
, target_p
, &me
, "Nick collision(new)");
1063 source_p
->flags
|= FLAGS_KILLED
;
1064 exit_client(client_p
, source_p
, &me
, "Nick collision(old)");
1070 sameuser
= !irccmp(target_p
->username
, source_p
->username
) &&
1071 !irccmp(target_p
->host
, source_p
->host
);
1073 if((sameuser
&& newts
< target_p
->tsinfo
) ||
1074 (!sameuser
&& newts
> target_p
->tsinfo
))
1077 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1078 "Nick change collision from %s to %s(%s <- %s)(older %s)",
1079 source_p
->name
, target_p
->name
,
1080 target_p
->from
->name
, client_p
->name
, action
);
1082 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1083 "Nick change collision from %s to %s(%s <- %s)(newer %s)",
1084 source_p
->name
, target_p
->name
,
1085 target_p
->from
->name
, client_p
->name
, action
);
1089 ServerStats
->is_save
++;
1090 /* can't broadcast a SAVE because the
1091 * nickchange has happened at client_p
1092 * but not in other directions -- jilles */
1093 sendto_one(client_p
, ":%s SAVE %s %ld", me
.id
,
1094 source_p
->id
, (long)newts
);
1095 /* same CurrentTime as in save_user() */
1096 /* send a :<id> NICK <id> <ts> (!) */
1097 if (!IsDigit(source_p
->name
[0]))
1098 change_remote_nick(client_p
, source_p
, CurrentTime
, source_p
->id
, 1);
1102 ServerStats
->is_kill
++;
1104 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
1105 form_str(ERR_NICKCOLLISION
), target_p
->name
);
1107 /* kill the client issuing the nickchange */
1108 kill_client_serv_butone(client_p
, source_p
,
1109 "%s (Nick change collision)", me
.name
);
1111 source_p
->flags
|= FLAGS_KILLED
;
1114 exit_client(client_p
, source_p
, &me
, "Nick collision(old)");
1116 exit_client(client_p
, source_p
, &me
, "Nick collision(new)");
1123 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1124 "Nick collision on %s(%s <- %s)(older %s)",
1125 target_p
->name
, target_p
->from
->name
,
1126 client_p
->name
, action
);
1128 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1129 "Nick collision on %s(%s <- %s)(newer %s)",
1130 target_p
->name
, target_p
->from
->name
,
1131 client_p
->name
, action
);
1135 ServerStats
->is_save
++;
1136 save_user(&me
, &me
, target_p
);
1140 sendto_one_numeric(target_p
, ERR_NICKCOLLISION
,
1141 form_str(ERR_NICKCOLLISION
), target_p
->name
);
1143 /* kill the client who existed before hand */
1144 kill_client_serv_butone(client_p
, target_p
, "%s (Nick collision)", me
.name
);
1146 ServerStats
->is_kill
++;
1148 target_p
->flags
|= FLAGS_KILLED
;
1149 (void) exit_client(client_p
, target_p
, &me
, "Nick collision");
1154 change_remote_nick(client_p
, source_p
, newts
, nick
, 1);
1160 register_client(struct Client
*client_p
, struct Client
*server
,
1161 const char *nick
, time_t newts
, int parc
, const char *parv
[])
1163 struct Client
*source_p
;
1165 struct nd_entry
*nd
;
1169 source_p
= make_client(client_p
);
1170 user
= make_user(source_p
);
1171 dlinkAddTail(source_p
, &source_p
->node
, &global_client_list
);
1173 source_p
->hopcount
= atoi(parv
[2]);
1174 source_p
->tsinfo
= newts
;
1176 strcpy(source_p
->name
, nick
);
1177 strlcpy(source_p
->username
, parv
[5], sizeof(source_p
->username
));
1178 strlcpy(source_p
->host
, parv
[6], sizeof(source_p
->host
));
1179 strlcpy(source_p
->orighost
, source_p
->host
, sizeof(source_p
->orighost
));
1183 user
->server
= find_or_add(server
->name
);
1184 strlcpy(source_p
->info
, parv
[11], sizeof(source_p
->info
));
1185 strlcpy(source_p
->sockhost
, parv
[7], sizeof(source_p
->sockhost
));
1186 strlcpy(source_p
->id
, parv
[8], sizeof(source_p
->id
));
1187 add_to_id_hash(source_p
->id
, source_p
);
1188 if (strcmp(parv
[9], "*"))
1190 strlcpy(source_p
->orighost
, parv
[9], sizeof(source_p
->orighost
));
1191 if (irccmp(source_p
->host
, source_p
->orighost
))
1192 SetDynSpoof(source_p
);
1194 if (strcmp(parv
[10], "*"))
1195 strlcpy(source_p
->user
->suser
, parv
[10], sizeof(source_p
->user
->suser
));
1199 user
->server
= find_or_add(server
->name
);
1200 strlcpy(source_p
->info
, parv
[9], sizeof(source_p
->info
));
1201 strlcpy(source_p
->sockhost
, parv
[7], sizeof(source_p
->sockhost
));
1202 strlcpy(source_p
->id
, parv
[8], sizeof(source_p
->id
));
1203 add_to_id_hash(source_p
->id
, source_p
);
1207 user
->server
= find_or_add(parv
[7]);
1208 strlcpy(source_p
->info
, parv
[8], sizeof(source_p
->info
));
1211 /* remove any nd entries for this nick */
1212 if((nd
= hash_find_nd(nick
)))
1215 add_to_client_hash(nick
, source_p
);
1216 add_to_hostname_hash(source_p
->host
, source_p
);
1217 monitor_signon(source_p
);
1222 flag
= user_modes
[(unsigned char) *m
];
1224 if(flag
& UMODE_SERVICE
)
1229 DLINK_FOREACH(ptr
, service_list
.head
)
1231 if(!irccmp((const char *) ptr
->data
, user
->server
))
1245 /* increment +i count if theyre invis */
1246 if(!(source_p
->umodes
& UMODE_INVISIBLE
) && (flag
& UMODE_INVISIBLE
))
1249 /* increment opered count if theyre opered */
1250 if(!(source_p
->umodes
& UMODE_OPER
) && (flag
& UMODE_OPER
))
1253 source_p
->umodes
|= flag
;
1257 if(IsOper(source_p
) && !IsService(source_p
))
1258 dlinkAddAlloc(source_p
, &oper_list
);
1260 SetRemoteClient(source_p
);
1262 if(++Count
.total
> Count
.max_tot
)
1263 Count
.max_tot
= Count
.total
;
1267 if((source_p
->servptr
= find_server(NULL
, user
->server
)) == NULL
)
1269 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1270 "Ghost killed: %s on invalid server %s",
1271 source_p
->name
, user
->server
);
1272 kill_client(client_p
, source_p
, "%s (Server doesn't exist)", me
.name
);
1273 source_p
->flags
|= FLAGS_KILLED
;
1274 return exit_client(NULL
, source_p
, &me
, "Ghosted Client");
1278 source_p
->servptr
= server
;
1280 dlinkAdd(source_p
, &source_p
->lnode
, &source_p
->servptr
->serv
->users
);
1282 /* fake direction */
1283 if(source_p
->servptr
->from
!= source_p
->from
)
1285 struct Client
*target_p
= source_p
->servptr
->from
;
1287 sendto_realops_snomask(SNO_DEBUG
, L_ALL
,
1288 "Bad User [%s] :%s USER %s@%s %s, != %s[%s]",
1289 client_p
->name
, source_p
->name
,
1290 source_p
->username
, source_p
->host
,
1291 user
->server
, target_p
->name
, target_p
->from
->name
);
1292 kill_client(client_p
, source_p
,
1293 "%s (NICK from wrong direction (%s != %s))",
1294 me
.name
, user
->server
, target_p
->from
->name
);
1295 source_p
->flags
|= FLAGS_KILLED
;
1296 return exit_client(source_p
, source_p
, &me
, "USER server wrong direction");
1299 call_hook(h_new_remote_user
, source_p
);
1301 return (introduce_client(client_p
, source_p
, user
, nick
, parc
== 12));
1304 /* Check if we can do SAVE. target_p can be a client to save or a
1305 * server introducing a client -- jilles */
1307 can_save(struct Client
*target_p
)
1309 struct Client
*serv_p
;
1311 if (MyClient(target_p
))
1313 if (!has_id(target_p
))
1315 serv_p
= IsServer(target_p
) ? target_p
: target_p
->servptr
;
1316 while (serv_p
!= NULL
&& serv_p
!= &me
)
1318 if (!(serv_p
->serv
->caps
& CAP_SAVE
))
1320 serv_p
= serv_p
->servptr
;
1322 return serv_p
== &me
;
1326 save_user(struct Client
*client_p
, struct Client
*source_p
,
1327 struct Client
*target_p
)
1329 if (!MyConnect(target_p
) && (!has_id(target_p
) || !IsCapable(target_p
->from
, CAP_SAVE
)))
1331 /* This shouldn't happen */
1332 /* Note we only need SAVE support in this direction */
1333 sendto_realops_snomask(SNO_GENERAL
, L_ALL
,
1334 "Killed %s!%s@%s for nick collision detected by %s (%s does not support SAVE)",
1335 target_p
->name
, target_p
->username
, target_p
->host
, source_p
->name
, target_p
->from
->name
);
1336 kill_client_serv_butone(NULL
, target_p
, "%s (Nick collision (no SAVE support))", me
.name
);
1337 ServerStats
->is_kill
++;
1339 target_p
->flags
|= FLAGS_KILLED
;
1340 (void) exit_client(NULL
, target_p
, &me
, "Nick collision (no SAVE support)");
1343 sendto_server(client_p
, NULL
, CAP_SAVE
|CAP_TS6
, NOCAPS
, ":%s SAVE %s %ld",
1344 source_p
->id
, target_p
->id
, (long)target_p
->tsinfo
);
1345 sendto_server(client_p
, NULL
, CAP_TS6
, CAP_SAVE
, ":%s NICK %s :%ld",
1346 target_p
->id
, target_p
->id
, (long)CurrentTime
);
1347 sendto_server(client_p
, NULL
, NOCAPS
, CAP_TS6
, ":%s NICK %s :%ld",
1348 target_p
->name
, target_p
->id
, (long)CurrentTime
);
1349 if (!IsMe(client_p
))
1350 sendto_realops_snomask(SNO_SKILL
, L_ALL
,
1351 "Received SAVE message for %s from %s",
1352 target_p
->name
, source_p
->name
);
1353 if (MyClient(target_p
))
1355 sendto_one_numeric(target_p
, RPL_SAVENICK
,
1356 form_str(RPL_SAVENICK
), target_p
->id
);
1357 change_local_nick(target_p
, target_p
, target_p
->id
, 0);
1361 /* XXX the uid nick gets garbage TS; shouldn't matter though */
1362 change_remote_nick(target_p
, target_p
, CurrentTime
, target_p
->id
, 0);