1 |
/* Routines related to nickname colliding. |
2 |
* |
3 |
* IRC Services is copyright (c) 1996-2009 Andrew Church. |
4 |
* E-mail: <achurch@achurch.org> |
5 |
* Parts written by Andrew Kempe and others. |
6 |
* This program is free but copyrighted software; see the file GPL.txt for |
7 |
* details. |
8 |
*/ |
9 |
|
10 |
#include "services.h" |
11 |
#include "modules.h" |
12 |
#include "language.h" |
13 |
#include "timeout.h" |
14 |
|
15 |
#include "nickserv.h" |
16 |
#include "ns-local.h" |
17 |
|
18 |
/*************************************************************************/ |
19 |
|
20 |
static int cb_collide = -1; |
21 |
|
22 |
|
23 |
/* Structure used for collide/release/433 timeouts */ |
24 |
|
25 |
static struct my_timeout { |
26 |
struct my_timeout *next, *prev; |
27 |
NickInfo *ni; |
28 |
Timeout *to; |
29 |
int type; |
30 |
} *my_timeouts; |
31 |
|
32 |
|
33 |
static void timeout_collide(Timeout *t); |
34 |
static void timeout_release(Timeout *t); |
35 |
static void timeout_send_433(Timeout *t); |
36 |
|
37 |
/*************************************************************************/ |
38 |
/*************************************************************************/ |
39 |
|
40 |
/* Collide a nick. */ |
41 |
|
42 |
void collide_nick(NickInfo *ni, int from_timeout) |
43 |
{ |
44 |
if (!ni->user) |
45 |
return; |
46 |
if (!from_timeout) { |
47 |
rem_ns_timeout(ni, TO_COLLIDE, 1); |
48 |
rem_ns_timeout(ni, TO_SEND_433, 1); |
49 |
} |
50 |
if (call_callback_1(cb_collide, ni->user) > 0) |
51 |
return; |
52 |
if (NSForceNickChange) { |
53 |
char *guestnick = make_guest_nick(); |
54 |
notice_lang(s_NickServ, ni->user, FORCENICKCHANGE_NOW, guestnick); |
55 |
send_nickchange_remote(ni->nick, guestnick); |
56 |
ni->status |= NS_GUESTED; |
57 |
return; |
58 |
} else { |
59 |
notice_lang(s_NickServ, ni->user, DISCONNECT_NOW); |
60 |
kill_user(s_NickServ, ni->nick, "Nick kill enforced"); |
61 |
introduce_enforcer(ni); |
62 |
} |
63 |
} |
64 |
|
65 |
/*************************************************************************/ |
66 |
|
67 |
/* Introduce an enforcer for a given nick. */ |
68 |
|
69 |
void introduce_enforcer(NickInfo *ni) |
70 |
{ |
71 |
char realname[NICKMAX+16]; /*Long enough for s_NickServ + " Enforcement"*/ |
72 |
|
73 |
snprintf(realname, sizeof(realname), "%s Enforcement", s_NickServ); |
74 |
send_nick(ni->nick, NSEnforcerUser, NSEnforcerHost, ServerName, |
75 |
realname, enforcer_modes); |
76 |
ni->status |= NS_KILL_HELD; |
77 |
add_ns_timeout(ni, TO_RELEASE, NSReleaseTimeout); |
78 |
} |
79 |
|
80 |
/*************************************************************************/ |
81 |
|
82 |
/* Release hold on a nick. */ |
83 |
|
84 |
void release_nick(NickInfo *ni, int from_timeout) |
85 |
{ |
86 |
if (!from_timeout) |
87 |
rem_ns_timeout(ni, TO_RELEASE, 1); |
88 |
send_cmd(ni->nick, "QUIT"); |
89 |
ni->status &= ~NS_KILL_HELD; |
90 |
} |
91 |
|
92 |
/*************************************************************************/ |
93 |
|
94 |
/* Add a collide/release/433 timeout. */ |
95 |
|
96 |
void add_ns_timeout(NickInfo *ni, int type, time_t delay) |
97 |
{ |
98 |
Timeout *to; |
99 |
struct my_timeout *t; |
100 |
void (*timeout_routine)(Timeout *); |
101 |
|
102 |
if (!ni) { |
103 |
log("BUG: NULL NickInfo in add_ns_timeout (type=%d delay=%ld)", |
104 |
type, (long)delay); |
105 |
return; |
106 |
} |
107 |
if (type == TO_COLLIDE) |
108 |
timeout_routine = timeout_collide; |
109 |
else if (type == TO_RELEASE) |
110 |
timeout_routine = timeout_release; |
111 |
else if (type == TO_SEND_433) |
112 |
timeout_routine = timeout_send_433; |
113 |
else { |
114 |
module_log("BUG: unknown timeout type %d! ni=%p (%s), delay=%ld", |
115 |
type, ni, ni->nick, (long)delay); |
116 |
return; |
117 |
} |
118 |
to = add_timeout(delay, timeout_routine, 0); |
119 |
to->data = ni; |
120 |
t = smalloc(sizeof(*t)); |
121 |
LIST_INSERT(t, my_timeouts); |
122 |
t->ni = ni; |
123 |
t->to = to; |
124 |
t->type = type; |
125 |
ni->usecount++; /* make sure it isn't deleted when we're not looking */ |
126 |
} |
127 |
|
128 |
/*************************************************************************/ |
129 |
|
130 |
/* Remove a collide/release timeout from our private list. If del_to is |
131 |
* nonzero, also delete the associated timeout. If type == -1, delete |
132 |
* timeouts of all types. If ni == NULL, delete all timeouts of the given |
133 |
* type(s). |
134 |
*/ |
135 |
|
136 |
void rem_ns_timeout(NickInfo *ni, int type, int del_to) |
137 |
{ |
138 |
struct my_timeout *t, *t2; |
139 |
|
140 |
LIST_FOREACH_SAFE (t, my_timeouts, t2) { |
141 |
if ((!ni || t->ni == ni) && (type < 0 || t->type == type)) { |
142 |
LIST_REMOVE(t, my_timeouts); |
143 |
if (del_to) |
144 |
del_timeout(t->to); |
145 |
put_nickinfo(t->ni); /* cancel usecount++ above */ |
146 |
free(t); |
147 |
} |
148 |
} |
149 |
} |
150 |
|
151 |
/*************************************************************************/ |
152 |
/*************************************************************************/ |
153 |
|
154 |
/* Collide a nick on timeout. */ |
155 |
|
156 |
static void timeout_collide(Timeout *t) |
157 |
{ |
158 |
NickInfo *ni = t->data; |
159 |
int idented = 0; |
160 |
|
161 |
if (ni) { |
162 |
if (ni->nickgroup != 0) { |
163 |
NickGroupInfo *ngi = get_ngi(ni); |
164 |
idented = (ngi && (nick_identified(ni) || nick_ident_nomail(ni))); |
165 |
put_nickgroupinfo(ngi); |
166 |
} |
167 |
} else { |
168 |
log("BUG: NULL NickInfo in timeout_collide"); |
169 |
return; |
170 |
} |
171 |
/* If they identified or don't exist anymore, don't kill them. */ |
172 |
if (!(idented || !ni->user || ni->user->my_signon > t->settime)) { |
173 |
/* The RELEASE timeout will always add to the beginning of the |
174 |
* list, so we won't see it. Which is fine because it can't be |
175 |
* triggered yet anyway. */ |
176 |
collide_nick(ni, 1); |
177 |
} |
178 |
rem_ns_timeout(ni, TO_COLLIDE, 0); |
179 |
} |
180 |
|
181 |
/*************************************************************************/ |
182 |
|
183 |
/* Release a nick on timeout. */ |
184 |
|
185 |
static void timeout_release(Timeout *t) |
186 |
{ |
187 |
NickInfo *ni = t->data; |
188 |
|
189 |
if (!ni) { |
190 |
log("BUG: NULL NickInfo in timeout_release"); |
191 |
return; |
192 |
} |
193 |
release_nick(ni, 1); |
194 |
rem_ns_timeout(ni, TO_RELEASE, 0); |
195 |
} |
196 |
|
197 |
/*************************************************************************/ |
198 |
|
199 |
/* Send a 433 (nick in use) numeric to the given user. */ |
200 |
|
201 |
static void timeout_send_433(Timeout *t) |
202 |
{ |
203 |
NickInfo *ni = t->data; |
204 |
User *u; |
205 |
|
206 |
if (!ni) { |
207 |
log("BUG: NULL NickInfo in timeout_send_433"); |
208 |
return; |
209 |
} |
210 |
/* If they identified or don't exist anymore, don't send the 433. */ |
211 |
if (!((nick_identified(ni) || nick_ident_nomail(ni)) |
212 |
|| !(u = get_user(ni->nick)) |
213 |
|| u->my_signon > t->settime) |
214 |
) { |
215 |
if (ni->status & NS_VERBOTEN) { |
216 |
send_cmd(ServerName, "433 %s %s :Nickname may not be used", |
217 |
ni->nick, ni->nick); |
218 |
} else { |
219 |
send_cmd(ServerName, "433 %s %s :Nickname is registered to" |
220 |
" someone else", ni->nick, ni->nick); |
221 |
} |
222 |
} |
223 |
rem_ns_timeout(ni, TO_SEND_433, 0); |
224 |
} |
225 |
|
226 |
/*************************************************************************/ |
227 |
/*************************************************************************/ |
228 |
|
229 |
int init_collide(void) |
230 |
{ |
231 |
cb_collide = register_callback("collide"); |
232 |
if (cb_collide < 0) { |
233 |
module_log("collide: Unable to register callbacks"); |
234 |
exit_collide(); |
235 |
return 0; |
236 |
} |
237 |
return 1; |
238 |
} |
239 |
|
240 |
/*************************************************************************/ |
241 |
|
242 |
void exit_collide() |
243 |
{ |
244 |
rem_ns_timeout(NULL, -1, 1); |
245 |
unregister_callback(cb_collide); |
246 |
} |
247 |
|
248 |
/*************************************************************************/ |
249 |
|
250 |
/* |
251 |
* Local variables: |
252 |
* c-file-style: "stroustrup" |
253 |
* c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
254 |
* indent-tabs-mode: nil |
255 |
* End: |
256 |
* |
257 |
* vim: expandtab shiftwidth=4: |
258 |
*/ |