ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/branches/8.2.x/modules/core/m_nick.c
Revision: 32
Committed: Sun Oct 2 20:41:23 2005 UTC (18 years, 5 months ago) by knight
Content type: text/x-csrc
Original Path: ircd-hybrid/modules/core/m_nick.c
File size: 27182 byte(s)
Log Message:
- svn:keywords

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_nick.c: Sets a users nick.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "handlers.h"
27 #include "client.h"
28 #include "hash.h"
29 #include "fdlist.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 "whowas.h"
37 #include "s_serv.h"
38 #include "send.h"
39 #include "list.h"
40 #include "channel.h"
41 #include "s_log.h"
42 #include "resv.h"
43 #include "msg.h"
44 #include "parse.h"
45 #include "modules.h"
46 #include "common.h"
47 #include "packet.h"
48
49 static void m_nick(struct Client *, struct Client *, int, char **);
50 static void mr_nick(struct Client *, struct Client *, int, char **);
51 static void ms_nick(struct Client *, struct Client *, int, char **);
52 static void ms_uid(struct Client *, struct Client *, int, char **);
53
54 static void nick_from_server(struct Client *, struct Client *, int, char **,
55 time_t, char *, char *);
56 static void client_from_server(struct Client *, struct Client *, int, char **,
57 time_t, char *, char *);
58 static int check_clean_nick(struct Client *client_p, struct Client *source_p,
59 char *nick, char *newnick,
60 struct Client *server_p);
61 static int check_clean_user(struct Client *client_p, char *nick, char *user,
62 struct Client *server_p);
63 static int check_clean_host(struct Client *client_p, char *nick, char *host,
64 struct Client *server_p);
65
66 static int clean_nick_name(char *, int);
67 static int clean_user_name(char *);
68 static int clean_host_name(char *);
69 static void perform_nick_collides(struct Client *, struct Client *, struct Client *,
70 int, char **, time_t, char *, char *, char *);
71 struct Message nick_msgtab = {
72 "NICK", 0, 0, 1, 0, MFLG_SLOW, 0,
73 {mr_nick, m_nick, ms_nick, m_ignore, m_nick, m_ignore}
74 };
75
76 struct Message uid_msgtab = {
77 "UID", 0, 0, 10, 0, MFLG_SLOW, 0,
78 {m_ignore, m_ignore, ms_uid, m_ignore, m_ignore, m_ignore}
79 };
80
81 #ifndef STATIC_MODULES
82 void
83 _modinit(void)
84 {
85 mod_add_cmd(&nick_msgtab);
86 mod_add_cmd(&uid_msgtab);
87 }
88
89 void
90 _moddeinit(void)
91 {
92 mod_del_cmd(&nick_msgtab);
93 mod_del_cmd(&uid_msgtab);
94 }
95
96 const char *_version = "$Revision$";
97 #endif
98
99 /* mr_nick()
100 *
101 * parv[0] = sender prefix
102 * parv[1] = nickname
103 */
104 static void
105 mr_nick(struct Client *client_p, struct Client *source_p,
106 int parc, char *parv[])
107 {
108 struct Client *target_p, *uclient_p;
109 char nick[NICKLEN];
110 char *s;
111 dlink_node *ptr;
112
113 if (parc < 2 || EmptyString(parv[1]))
114 {
115 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
116 me.name, EmptyString(parv[0]) ? "*" : parv[0]);
117 return;
118 }
119
120 /* Terminate the nick at the first ~ */
121 /* XXX - Is this still needed?? */
122 if ((s = strchr(parv[1], '~')) != NULL)
123 *s = '\0';
124
125 /* copy the nick and terminate it */
126 strlcpy(nick, parv[1], sizeof(nick));
127
128 /* check the nickname is ok */
129 if (!clean_nick_name(nick, 1))
130 {
131 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
132 me.name, EmptyString(parv[0]) ? "*" : parv[0], parv[1]);
133 return;
134 }
135
136 /* check if the nick is resv'd */
137 if (find_matching_name_conf(NRESV_TYPE, nick, NULL, NULL, 0) &&
138 !IsExemptResv(source_p))
139 {
140 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
141 me.name, EmptyString(parv[0]) ? "*" : parv[0], nick);
142 return;
143 }
144
145 if ((target_p = find_client(nick)) == NULL)
146 {
147 if (!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
148 {
149 /* We don't know anyone called nick, but our hub might */
150 DLINK_FOREACH(ptr, unknown_list.head)
151 {
152 uclient_p = ptr->data;
153
154 if (!strcmp(nick, uclient_p->llname))
155 {
156
157 /* We're already waiting for a reply about this nick
158 * for someone else. */
159
160 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
161 return;
162 }
163 }
164
165 /* Set their llname so we can find them later */
166 strcpy(source_p->llname, nick);
167
168 /* Ask the hub about their requested name */
169 sendto_one(uplink, ":%s NBURST %s %s !%s", me.name, nick,
170 nick, nick);
171
172 /* wait for LLNICK */
173 return;
174 }
175 else
176 {
177 set_initial_nick(client_p, source_p, nick);
178 return;
179 }
180 }
181 else if (source_p == target_p)
182 {
183 strcpy(source_p->name, nick);
184 return;
185 }
186 else
187 {
188 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name, "*", nick);
189 }
190 }
191
192 /* m_nick()
193 *
194 * parv[0] = sender prefix
195 * parv[1] = nickname
196 */
197 static void
198 m_nick(struct Client *client_p, struct Client *source_p,
199 int parc, char *parv[])
200 {
201 char nick[NICKLEN];
202 struct Client *target_p;
203
204 if (parc < 2 || EmptyString(parv[1]))
205 {
206 sendto_one(source_p, form_str(ERR_NONICKNAMEGIVEN),
207 me.name, parv[0]);
208 return;
209 }
210
211 /* mark end of grace period, to prevent nickflooding */
212 if (!IsFloodDone(source_p))
213 flood_endgrace(source_p);
214
215 /* terminate nick to NICKLEN */
216 strlcpy(nick, parv[1], sizeof(nick));
217
218 /* check the nickname is ok */
219 if (!clean_nick_name(nick, 1))
220 {
221 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
222 me.name, parv[0], nick);
223 return;
224 }
225
226 if (find_matching_name_conf(NRESV_TYPE, nick,
227 NULL, NULL, 0) && !IsExemptResv(source_p) &&
228 !(IsOper(source_p) && ConfigFileEntry.oper_pass_resv))
229 {
230 sendto_one(source_p, form_str(ERR_ERRONEUSNICKNAME),
231 me.name, parv[0], nick);
232 return;
233 }
234
235 if ((target_p = find_client(nick)))
236 {
237 /* If(target_p == source_p) the client is changing nicks between
238 * equivalent nicknames ie: [nick] -> {nick}
239 */
240
241 if (target_p == source_p)
242 {
243 /* check the nick isnt exactly the same */
244 if (!strcmp(target_p->name, nick))
245 return; /* client is doing :old NICK old ignore it. */
246
247 change_local_nick(client_p, source_p, nick);
248 return;
249 }
250
251 /* if the client that has the nick isn't registered yet (nick but no
252 * user) then drop the unregged client
253 */
254 if (IsUnknown(target_p))
255 {
256 /* the old code had an if(MyConnect(target_p)) here.. but I cant see
257 * how that can happen, m_nick() is local only --fl_
258 */
259 exit_client(target_p, &me, "Overridden");
260 change_local_nick(client_p, source_p, nick);
261 return;
262 }
263 else
264 {
265 sendto_one(source_p, form_str(ERR_NICKNAMEINUSE), me.name,
266 parv[0], nick);
267 return;
268 }
269 }
270 else
271 {
272 if (!ServerInfo.hub && uplink && IsCapable(uplink, CAP_LL))
273 {
274 /* The uplink might know someone by this name already. */
275 sendto_one(uplink, ":%s NBURST %s %s %s",
276 ID_or_name(&me, uplink), nick,
277 nick, source_p->name);
278 return;
279 }
280 else
281 {
282 change_local_nick(client_p,source_p,nick);
283 return;
284 }
285 }
286 }
287
288 /*
289 * ms_nick()
290 *
291 * server -> server nick change
292 * parv[0] = sender prefix
293 * parv[1] = nickname
294 * parv[2] = TS when nick change
295 *
296 * server introducing new nick
297 * parv[0] = sender prefix
298 * parv[1] = nickname
299 * parv[2] = hop count
300 * parv[3] = TS
301 * parv[4] = umode
302 * parv[5] = username
303 * parv[6] = hostname
304 * parv[7] = server
305 * parv[8] = ircname
306 */
307 static void
308 ms_nick(struct Client *client_p, struct Client *source_p,
309 int parc, char *parv[])
310 {
311 struct Client* target_p;
312 char nick[NICKLEN];
313 char ngecos[REALLEN + 1];
314 time_t newts = 0;
315 char *nnick = parv[1];
316 char *nhop = parv[2];
317 char *nts = parv[3];
318 char *nusername = parv[5];
319 char *nhost = parv[6];
320 char *nserver = parv[7];
321
322 if (parc < 2 || EmptyString(nnick))
323 return;
324
325 /* fix the lengths */
326 strlcpy(nick, nnick, sizeof(nick));
327
328 if (parc == 9)
329 {
330 struct Client *server_p = find_server(nserver);
331
332 strlcpy(ngecos, parv[8], sizeof(ngecos));
333
334 if (server_p == NULL)
335 {
336 sendto_realops_flags(UMODE_ALL, L_ALL,
337 "Invalid server %s from %s for NICK %s",
338 nserver, source_p->name, nick);
339 sendto_one(client_p, ":%s KILL %s :%s (Server doesn't exist!)",
340 me.name, nick, me.name);
341 return;
342 }
343
344 if (check_clean_nick(client_p, source_p, nick, nnick, server_p) ||
345 check_clean_user(client_p, nick, nusername, server_p) ||
346 check_clean_host(client_p, nick, nhost, server_p))
347 return;
348
349 /* check the length of the clients gecos */
350 if (strlen(parv[8]) > REALLEN)
351 sendto_realops_flags(UMODE_ALL, L_ALL,
352 "Long realname from server %s for %s",
353 nserver, nnick);
354
355 if (IsServer(source_p))
356 newts = atol(nts);
357 }
358 else if (parc == 3)
359 {
360 if (IsServer(source_p))
361 /* Server's cant change nicks.. */
362 return;
363
364 if (check_clean_nick(client_p, source_p, nick, nnick,
365 source_p->servptr))
366 return;
367
368 /*
369 * Yes, this is right. HOP field is the TS field for parc = 3
370 */
371 newts = atol(nhop);
372 }
373
374 /* if the nick doesnt exist, allow it and process like normal */
375 if (!(target_p = find_client(nick)))
376 {
377 nick_from_server(client_p, source_p, parc, parv, newts, nick, ngecos);
378 return;
379 }
380
381 /* we're not living in the past anymore, an unknown client is local only. */
382 if (IsUnknown(target_p))
383 {
384 exit_client(target_p, &me, "Overridden");
385 nick_from_server(client_p, source_p, parc, parv, newts, nick, ngecos);
386 return;
387 }
388
389 if (target_p == source_p)
390 {
391 if (strcmp(target_p->name, nick))
392 {
393 /* client changing case of nick */
394 nick_from_server(client_p, source_p, parc, parv, newts, nick, ngecos);
395 return;
396 }
397 else
398 /* client not changing nicks at all */
399 return;
400 }
401
402 perform_nick_collides(source_p, client_p, target_p,
403 parc, parv, newts, nick, ngecos, NULL);
404 }
405
406 /* ms_uid()
407 *
408 * parv[0] = sender prefix
409 * parv[1] = nickname
410 * parv[2] = hop count
411 * parv[3] = TS
412 * parv[4] = umode
413 * parv[5] = username
414 * parv[6] = hostname
415 * parv[7] = ip
416 * parv[8] = uid
417 * parv[9] = ircname (gecos)
418 */
419 static void
420 ms_uid(struct Client *client_p, struct Client *source_p,
421 int parc, char *parv[])
422 {
423 struct Client *target_p;
424 char nick[NICKLEN];
425 char ugecos[REALLEN + 1];
426 time_t newts = 0;
427 char *unick = parv[1];
428 char *uts = parv[3];
429 char *uname = parv[5];
430 char *uhost = parv[6];
431 char *uid = parv[8];
432
433 if (EmptyString(unick))
434 return;
435
436 /* Fix the lengths */
437 strlcpy(nick, parv[1], sizeof(nick));
438 strlcpy(ugecos, parv[9], sizeof(ugecos));
439
440 if (check_clean_nick(client_p, source_p, nick, unick, source_p) ||
441 check_clean_user(client_p, nick, uname, source_p) ||
442 check_clean_host(client_p, nick, uhost, source_p))
443 return;
444
445 if (strlen(parv[9]) > REALLEN)
446 sendto_realops_flags(UMODE_ALL, L_ALL, "Long realname from server %s for %s",
447 parv[0], parv[1]);
448
449 newts = atol(uts);
450
451 /* if there is an ID collision, kill our client, and kill theirs.
452 * this may generate 401's, but it ensures that both clients always
453 * go, even if the other server refuses to do the right thing.
454 */
455 if ((target_p = hash_find_id(uid)) != NULL)
456 {
457 sendto_realops_flags(UMODE_ALL, L_ALL,
458 "ID collision on %s(%s <- %s)(both killed)",
459 target_p->name, target_p->from->name,
460 client_p->name);
461
462 if (ServerInfo.hub && IsCapable(client_p, CAP_LL))
463 add_lazylinkclient(client_p, source_p);
464
465 kill_client_ll_serv_butone(NULL, target_p, "%s (ID collision)",
466 me.name);
467
468 ServerStats->is_kill++;
469
470 SetKilled(target_p);
471 exit_client(target_p, &me, "ID Collision");
472 return;
473 }
474
475 if ((target_p = find_client(unick)) == NULL)
476 client_from_server(client_p, source_p, parc, parv, newts, nick, ugecos);
477 else if (IsUnknown(target_p))
478 {
479 exit_client(target_p, &me, "Overridden");
480 client_from_server(client_p, source_p, parc, parv, newts, nick, ugecos);
481 }
482 else
483 perform_nick_collides(source_p, client_p, target_p,
484 parc, parv, newts, nick, ugecos, uid);
485 }
486
487 /* check_clean_nick()
488 *
489 * input - pointer to source
490 * -
491 * - nickname
492 * - truncated nickname
493 * - origin of client
494 * - pointer to server nick is coming from
495 * output - none
496 * side effects - if nickname is erroneous, or a different length to
497 * truncated nickname, return 1
498 */
499 static int
500 check_clean_nick(struct Client *client_p, struct Client *source_p,
501 char *nick, char *newnick, struct Client *server_p)
502 {
503 /* the old code did some wacky stuff here, if the nick is invalid, kill it
504 * and dont bother messing at all
505 */
506 if (!clean_nick_name(nick, 0) || strcmp(nick, newnick))
507 {
508 ServerStats->is_kill++;
509 sendto_realops_flags(UMODE_DEBUG, L_ALL,
510 "Bad Nick: %s From: %s(via %s)",
511 nick, server_p->name, client_p->name);
512
513 sendto_one(client_p, ":%s KILL %s :%s (Bad Nickname)",
514 me.name, newnick, me.name);
515
516 /* bad nick change */
517 if (source_p != client_p)
518 {
519 kill_client_ll_serv_butone(client_p, source_p,
520 "%s (Bad Nickname)",
521 me.name);
522 SetKilled(source_p);
523 exit_client(source_p, &me, "Bad Nickname");
524 }
525
526 return (1);
527 }
528
529 return (0);
530 }
531
532 /* check_clean_user()
533 *
534 * input - pointer to client sending data
535 * - nickname
536 * - username to check
537 * - origin of NICK
538 * output - none
539 * side effects - if username is erroneous, return 1
540 */
541 static int
542 check_clean_user(struct Client *client_p, char *nick,
543 char *user, struct Client *server_p)
544 {
545 if (strlen(user) > USERLEN)
546 {
547 ServerStats->is_kill++;
548 sendto_realops_flags(UMODE_DEBUG, L_ALL,
549 "Long Username: %s Nickname: %s From: %s(via %s)",
550 user, nick, server_p->name, client_p->name);
551
552 sendto_one(client_p, ":%s KILL %s :%s (Bad Username)",
553 me.name, nick, me.name);
554
555 return (1);
556 }
557
558 if (!clean_user_name(user))
559 sendto_realops_flags(UMODE_DEBUG, L_ALL,
560 "Bad Username: %s Nickname: %s From: %s(via %s)",
561 user, nick, server_p->name, client_p->name);
562
563 return (0);
564 }
565
566 /* check_clean_host()
567 *
568 * input - pointer to client sending us data
569 * - nickname
570 * - hostname to check
571 * - source name
572 * output - none
573 * side effects - if hostname is erroneous, return 1
574 */
575 static int
576 check_clean_host(struct Client *client_p, char *nick,
577 char *host, struct Client *server_p)
578 {
579 if (strlen(host) > HOSTLEN)
580 {
581 ServerStats->is_kill++;
582 sendto_realops_flags(UMODE_DEBUG, L_ALL,
583 "Long Hostname: %s Nickname: %s From: %s(via %s)",
584 host, nick, server_p->name, client_p->name);
585
586 sendto_one(client_p, ":%s KILL %s :%s (Bad Hostname)",
587 me.name, nick, me.name);
588
589 return (1);
590 }
591
592 if (!clean_host_name(host))
593 sendto_realops_flags(UMODE_DEBUG, L_ALL,
594 "Bad Hostname: %s Nickname: %s From: %s(via %s)",
595 host, nick, server_p->name, client_p->name);
596
597 return (0);
598 }
599
600 /* clean_nick_name()
601 *
602 * input - nickname
603 * - whether it's a local nick (1) or remote (0)
604 * output - none
605 * side effects - walks through the nickname, returning 0 if erroneous
606 */
607 static int
608 clean_nick_name(char *nick, int local)
609 {
610 assert(nick);
611 if (nick == NULL)
612 return (0);
613
614 /* nicks cant start with a digit or - or be 0 length */
615 /* This closer duplicates behaviour of hybrid-6 */
616
617 if (*nick == '-' || (IsDigit(*nick) && local) || *nick == '\0')
618 return (0);
619
620 for(; *nick; nick++)
621 {
622 if (!IsNickChar(*nick))
623 return (0);
624 }
625
626 return (1);
627 }
628
629 /* clean_user_name()
630 *
631 * input - username
632 * output - none
633 * side effects - walks through the username, returning 0 if erroneous
634 */
635 static int
636 clean_user_name(char *user)
637 {
638 assert(user);
639 if (user == NULL)
640 return 0;
641
642 for(; *user; user++)
643 {
644 if (!IsUserChar(*user))
645 return 0;
646 }
647
648 return 1;
649 }
650
651 /* clean_host_name()
652 * input - hostname
653 * output - none
654 * side effects - walks through the hostname, returning 0 if erroneous
655 */
656 static int
657 clean_host_name(char *host)
658 {
659 assert(host);
660 if (host == NULL)
661 return 0;
662 for(; *host; host++)
663 {
664 if (!IsHostChar(*host))
665 return 0;
666 }
667
668 return 1;
669 }
670
671 /*
672 * nick_from_server()
673 */
674 static void
675 nick_from_server(struct Client *client_p, struct Client *source_p, int parc,
676 char *parv[], time_t newts, char *nick, char *ngecos)
677 {
678 if (IsServer(source_p))
679 {
680 /* A server introducing a new client, change source */
681 source_p = make_client(client_p);
682 dlinkAdd(source_p, &source_p->node, &global_client_list);
683
684 /* We don't need to introduce leafs clients back to them! */
685 if (ServerInfo.hub && IsCapable(client_p, CAP_LL))
686 add_lazylinkclient(client_p, source_p);
687
688 if (parc > 2)
689 source_p->hopcount = atoi(parv[2]);
690 if (newts)
691 source_p->tsinfo = newts;
692 else
693 {
694 newts = source_p->tsinfo = CurrentTime;
695 ts_warn("Remote nick %s (%s) introduced without a TS", nick, parv[0]);
696 }
697
698 /* copy the nick in place */
699 strcpy(source_p->name, nick);
700 hash_add_client(source_p);
701
702 if (parc > 8)
703 {
704 unsigned int flag;
705 char *m;
706
707 /* parse usermodes */
708 m = &parv[4][1];
709
710 while (*m)
711 {
712 flag = user_modes[(unsigned char)*m];
713 if (!(source_p->umodes & UMODE_INVISIBLE) && (flag & UMODE_INVISIBLE))
714 Count.invisi++;
715 if (!(source_p->umodes & UMODE_OPER) && (flag & UMODE_OPER))
716 Count.oper++;
717
718 source_p->umodes |= flag & SEND_UMODES;
719 m++;
720 }
721
722 register_remote_user(client_p, source_p, parv[5], parv[6],
723 parv[7], ngecos);
724 }
725
726 }
727 else if (source_p->name[0])
728 {
729 /* client changing their nick */
730 if (irccmp(parv[0], nick))
731 source_p->tsinfo = newts ? newts : CurrentTime;
732
733 sendto_common_channels_local(source_p, 1, ":%s!%s@%s NICK :%s",
734 source_p->name,source_p->username,
735 source_p->host, nick);
736
737 add_history(source_p,1);
738 sendto_server(client_p, source_p, NULL, CAP_TS6, NOCAPS, NOFLAGS,
739 ":%s NICK %s :%lu",
740 ID(source_p), nick, (unsigned long)source_p->tsinfo);
741 sendto_server(client_p, source_p, NULL, NOCAPS, CAP_TS6, NOFLAGS,
742 ":%s NICK %s :%lu",
743 parv[0], nick, (unsigned long)source_p->tsinfo);
744 }
745
746 /* set the new nick name */
747 if (source_p->name[0])
748 hash_del_client(source_p);
749
750 strcpy(source_p->name, nick);
751 hash_add_client(source_p);
752 }
753
754 /*
755 * client_from_server()
756 */
757 static void
758 client_from_server(struct Client *client_p, struct Client *source_p, int parc,
759 char *parv[], time_t newts, char *nick, char *ugecos)
760 {
761 char *m;
762 unsigned int flag;
763 const char *servername = source_p->name;
764
765 source_p = make_client(client_p);
766 dlinkAdd(source_p, &source_p->node, &global_client_list);
767
768 /* We don't need to introduce leafs clients back to them! */
769 if (ServerInfo.hub && IsCapable(client_p, CAP_LL))
770 add_lazylinkclient(client_p, source_p);
771
772 source_p->hopcount = atoi(parv[2]);
773 source_p->tsinfo = newts;
774
775 /* copy the nick in place */
776 strcpy(source_p->name, nick);
777 strlcpy(source_p->id, parv[8], sizeof(source_p->id));
778 strlcpy(source_p->sockhost, parv[7], sizeof(source_p->sockhost));
779
780 hash_add_client(source_p);
781 hash_add_id(source_p);
782
783 /* parse usermodes */
784 m = &parv[4][1];
785 while (*m)
786 {
787 flag = user_modes[(unsigned char)*m];
788 if (flag & UMODE_INVISIBLE)
789 Count.invisi++;
790 if (flag & UMODE_OPER)
791 Count.oper++;
792
793 source_p->umodes |= flag & SEND_UMODES;
794 m++;
795 }
796
797 register_remote_user(client_p, source_p, parv[5], parv[6],
798 servername, ugecos);
799 }
800
801 static void
802 perform_nick_collides(struct Client *source_p, struct Client *client_p,
803 struct Client *target_p, int parc, char *parv[],
804 time_t newts, char *nick, char *gecos, char *uid)
805 {
806 int sameuser;
807
808 /* server introducing new nick */
809 if (IsServer(source_p))
810 {
811 /* if we dont have a ts, or their TS's are the same, kill both */
812 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
813 {
814 sendto_realops_flags(UMODE_ALL, L_ALL,
815 "Nick collision on %s(%s <- %s)(both killed)",
816 target_p->name, target_p->from->name,
817 client_p->name);
818
819 if (ServerInfo.hub && IsCapable(client_p,CAP_LL))
820 add_lazylinkclient(client_p, target_p);
821
822 /* if we have a UID, issue a kill for it */
823 if (uid)
824 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
825 me.id, uid, me.name);
826
827 kill_client_ll_serv_butone(NULL, target_p,
828 "%s (Nick collision (new))",
829 me.name);
830 ServerStats->is_kill++;
831 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
832 me.name, target_p->name, target_p->name);
833
834 SetKilled(target_p);
835 exit_client(target_p, &me, "Nick collision (new)");
836 return;
837 }
838 /* the timestamps are different */
839 else
840 {
841 sameuser = !irccmp(target_p->username, parv[5]) &&
842 !irccmp(target_p->host, parv[6]);
843
844 /* if the users are the same (loaded a client on a different server)
845 * and the new users ts is older, or the users are different and the
846 * new users ts is newer, ignore the new client and let it do the kill
847 */
848 if ((sameuser && newts < target_p->tsinfo) ||
849 (!sameuser && newts > target_p->tsinfo))
850 {
851 if (uid)
852 sendto_one(client_p, ":%s KILL %s :%s (Nick collision (new))",
853 me.id, uid, me.name);
854
855 client_burst_if_needed(client_p, target_p);
856 return;
857 }
858 else
859 {
860 if (sameuser)
861 sendto_realops_flags(UMODE_ALL, L_ALL,
862 "Nick collision on %s(%s <- %s)(older killed)",
863 target_p->name, target_p->from->name,
864 client_p->name);
865 else
866 sendto_realops_flags(UMODE_ALL, L_ALL,
867 "Nick collision on %s(%s <- %s)(newer killed)",
868 target_p->name, target_p->from->name,
869 client_p->name);
870
871 ServerStats->is_kill++;
872 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
873 me.name, target_p->name, target_p->name);
874
875 /* if it came from a LL server, itd have been source_p,
876 * so we dont need to mark target_p as known
877 */
878 kill_client_ll_serv_butone(source_p, target_p,
879 "%s (Nick collision (new))",
880 me.name);
881
882 SetKilled(target_p);
883 exit_client(target_p, &me, "Nick collision");
884
885 if (parc == 9)
886 nick_from_server(client_p, source_p, parc, parv, newts, nick, gecos);
887 else if (parc == 10)
888 client_from_server(client_p, source_p, parc, parv, newts, nick, gecos);
889
890 return;
891 }
892 }
893 }
894
895 /* its a client changing nick and causing a collide */
896 if (!newts || !target_p->tsinfo || (newts == target_p->tsinfo))
897 {
898 sendto_realops_flags(UMODE_ALL, L_ALL,
899 "Nick change collision from %s to %s(%s <- %s)(both killed)",
900 source_p->name, target_p->name, target_p->from->name,
901 client_p->name);
902
903 ServerStats->is_kill++;
904 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
905 me.name, target_p->name, target_p->name);
906
907 /* if we got the message from a LL, it knows about source_p */
908 kill_client_ll_serv_butone(NULL, source_p,
909 "%s (Nick change collision)",
910 me.name);
911
912 ServerStats->is_kill++;
913 /* If we got the message from a LL, ensure it gets the kill */
914 if (ServerInfo.hub && IsCapable(client_p,CAP_LL))
915 add_lazylinkclient(client_p, target_p);
916
917 kill_client_ll_serv_butone(NULL, target_p,
918 "%s (Nick change collision)",
919 me.name);
920
921 SetKilled(target_p);
922 exit_client(target_p, &me, "Nick collision (new)");
923 SetKilled(source_p);
924 exit_client(source_p, &me, "Nick collision (old)");
925 return;
926 }
927 else
928 {
929 sameuser = !irccmp(target_p->username, source_p->username) &&
930 !irccmp(target_p->host, source_p->host);
931
932 if ((sameuser && newts < target_p->tsinfo) ||
933 (!sameuser && newts > target_p->tsinfo))
934 {
935 if (sameuser)
936 sendto_realops_flags(UMODE_ALL, L_ALL,
937 "Nick change collision from %s to %s(%s <- %s)(older killed)",
938 source_p->name, target_p->name, target_p->from->name,
939 client_p->name);
940 else
941 sendto_realops_flags(UMODE_ALL, L_ALL,
942 "Nick change collision from %s to %s(%s <- %s)(newer killed)",
943 source_p->name, target_p->name, target_p->from->name,
944 client_p->name);
945
946 ServerStats->is_kill++;
947
948 /* this won't go back to the incoming link, so LL doesnt matter */
949 kill_client_ll_serv_butone(client_p, source_p,
950 "%s (Nick change collision)",
951 me.name);
952
953 SetKilled(source_p);
954
955 if (sameuser)
956 exit_client(source_p, &me, "Nick collision (old)");
957 else
958 exit_client(source_p, &me, "Nick collision (new)");
959 return;
960 }
961 else
962 {
963 if (sameuser)
964 sendto_realops_flags(UMODE_ALL, L_ALL,
965 "Nick collision on %s(%s <- %s)(older killed)",
966 target_p->name, target_p->from->name,
967 client_p->name);
968 else
969 sendto_realops_flags(UMODE_ALL, L_ALL,
970 "Nick collision on %s(%s <- %s)(newer killed)",
971 target_p->name, target_p->from->name,
972 client_p->name);
973
974 kill_client_ll_serv_butone(source_p, target_p,
975 "%s (Nick collision)",
976 me.name);
977
978 ServerStats->is_kill++;
979 sendto_one(target_p, form_str(ERR_NICKCOLLISION),
980 me.name, target_p->name, target_p->name);
981
982 SetKilled(target_p);
983 exit_client(target_p, &me, "Nick collision");
984 }
985 }
986
987 /* we should only ever call nick_from_server() here, as
988 * this is a client changing nick, not a new client
989 */
990 nick_from_server(client_p, source_p, parc, parv, newts, nick, gecos);
991 }

Properties

Name Value
svn:eol-style native
svn:keywords Revision