]> jfr.im git - solanum.git/blame - modules/m_services.c
extensions: add AV2 description strings to a few modules
[solanum.git] / modules / m_services.c
CommitLineData
212380e3
AC
1/* modules/m_services.c
2 * Copyright (C) 2005 Lee Hardy <lee -at- leeh.co.uk>
3 * Copyright (C) 2005 ircd-ratbox development team
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * 1.Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * 2.Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3.The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
21 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
25 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
26 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
212380e3
AC
28 */
29
30#include "stdinc.h"
31
212380e3
AC
32#include "send.h"
33#include "channel.h"
34#include "client.h"
35#include "common.h"
36#include "config.h"
37#include "ircd.h"
38#include "numeric.h"
212380e3
AC
39#include "s_conf.h"
40#include "s_newconf.h"
41#include "s_serv.h"
42#include "hash.h"
43#include "msg.h"
44#include "parse.h"
45#include "modules.h"
212380e3
AC
46#include "whowas.h"
47#include "monitor.h"
0b904d91 48#include "supported.h"
212380e3 49
c46a4ecd
KB
50static int _modinit(void);
51static void _moddeinit(void);
52
53static void mark_services(void);
54static void unmark_services(void);
55
428ca87b
AC
56static int me_su(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
57static int me_login(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
58static int me_rsfnc(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
59static int me_nickdelay(struct MsgBuf *, struct Client *, struct Client *, int, const char **);
212380e3
AC
60
61static void h_svc_server_introduced(hook_data_client *);
62static void h_svc_whois(hook_data_client *);
63static void h_svc_stats(hook_data_int *);
c46a4ecd
KB
64static void h_svc_conf_read_start(void *);
65static void h_svc_conf_read_end(void *);
212380e3
AC
66
67struct Message su_msgtab = {
7baa37a9 68 "SU", 0, 0, 0, 0,
212380e3
AC
69 {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_su, 2}, mg_ignore}
70};
71struct Message login_msgtab = {
7baa37a9 72 "LOGIN", 0, 0, 0, 0,
212380e3
AC
73 {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_login, 2}, mg_ignore}
74};
75struct Message rsfnc_msgtab = {
7baa37a9 76 "RSFNC", 0, 0, 0, 0,
212380e3
AC
77 {mg_ignore, mg_ignore, mg_ignore, mg_ignore, {me_rsfnc, 4}, mg_ignore}
78};
79struct Message nickdelay_msgtab = {
7baa37a9 80 "NICKDELAY", 0, 0, 0, 0,
212380e3
AC
81 {mg_unreg, mg_ignore, mg_ignore, mg_ignore, {me_nickdelay, 3}, mg_ignore}
82};
83
55abcbb2 84mapi_clist_av1 services_clist[] = {
212380e3
AC
85 &su_msgtab, &login_msgtab, &rsfnc_msgtab, &nickdelay_msgtab, NULL
86};
87mapi_hfn_list_av1 services_hfnlist[] = {
88 { "doing_stats", (hookfn) h_svc_stats },
89 { "doing_whois", (hookfn) h_svc_whois },
90 { "doing_whois_global", (hookfn) h_svc_whois },
91 { "server_introduced", (hookfn) h_svc_server_introduced },
c46a4ecd
KB
92 { "conf_read_start", (hookfn) h_svc_conf_read_start },
93 { "conf_read_end", (hookfn) h_svc_conf_read_end },
212380e3
AC
94 { NULL, NULL }
95};
96
105a4985 97DECLARE_MODULE_AV2(services, _modinit, _moddeinit, services_clist, NULL, services_hfnlist, NULL, NULL, NULL);
c46a4ecd
KB
98
99static int
100_modinit(void)
101{
102 mark_services();
0b904d91 103 add_isupport("FNC", isupport_string, "");
8a4b8377 104 return 0;
c46a4ecd
KB
105}
106
107static void
108_moddeinit(void)
109{
0b904d91 110 delete_isupport("FNC");
c46a4ecd
KB
111 unmark_services();
112}
212380e3
AC
113
114static int
428ca87b 115me_su(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
116 int parc, const char *parv[])
117{
118 struct Client *target_p;
119
120 if(!(source_p->flags & FLAGS_SERVICE))
ec57fe67
KB
121 {
122 sendto_realops_snomask(SNO_GENERAL, L_ALL,
123 "Non-service server %s attempting to execute services-only command SU", source_p->name);
212380e3 124 return 0;
ec57fe67 125 }
212380e3
AC
126
127 if((target_p = find_client(parv[1])) == NULL)
128 return 0;
129
130 if(!target_p->user)
131 return 0;
132
133 if(EmptyString(parv[2]))
134 target_p->user->suser[0] = '\0';
135 else
f427c8b0 136 rb_strlcpy(target_p->user->suser, parv[2], sizeof(target_p->user->suser));
212380e3 137
583f064f 138 sendto_common_channels_local_butone(target_p, CLICAP_ACCOUNT_NOTIFY, NOCAPS, ":%s!%s@%s ACCOUNT %s",
7a7f86d3
AC
139 target_p->name, target_p->username, target_p->host,
140 EmptyString(target_p->user->suser) ? "*" : target_p->user->suser);
141
212380e3
AC
142 invalidate_bancache_user(target_p);
143
144 return 0;
145}
146
147static int
428ca87b 148me_login(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
149 int parc, const char *parv[])
150{
151 if(!IsPerson(source_p))
152 return 0;
153
f427c8b0 154 rb_strlcpy(source_p->user->suser, parv[1], sizeof(source_p->user->suser));
212380e3
AC
155 return 0;
156}
157
212380e3 158static int
428ca87b 159me_rsfnc(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p,
212380e3
AC
160 int parc, const char *parv[])
161{
162 struct Client *target_p;
163 struct Client *exist_p;
164 time_t newts, curts;
75d60088 165 char note[NICKLEN + 10];
212380e3
AC
166
167 if(!(source_p->flags & FLAGS_SERVICE))
ec57fe67
KB
168 {
169 sendto_realops_snomask(SNO_GENERAL, L_ALL,
170 "Non-service server %s attempting to execute services-only command RSFNC", source_p->name);
212380e3 171 return 0;
ec57fe67 172 }
212380e3
AC
173
174 if((target_p = find_person(parv[1])) == NULL)
175 return 0;
176
177 if(!MyClient(target_p))
178 return 0;
179
2d28539c 180 if(!clean_nick(parv[2], 0) || IsDigit(parv[2][0]))
212380e3
AC
181 return 0;
182
183 curts = atol(parv[4]);
184
185 /* if tsinfo is different from what it was when services issued the
186 * RSFNC, then we ignore it. This can happen when a client changes
187 * nicknames before the RSFNC arrives.. --anfl
188 */
189 if(target_p->tsinfo != curts)
190 return 0;
191
192 if((exist_p = find_named_client(parv[2])))
193 {
194 char buf[BUFSIZE];
195
196 /* this would be one hell of a race condition to trigger
55abcbb2 197 * this one given the tsinfo check above, but its here for
212380e3
AC
198 * safety --anfl
199 */
200 if(target_p == exist_p)
03510227 201 goto doit;
212380e3
AC
202
203 if(MyClient(exist_p))
204 sendto_one(exist_p, ":%s KILL %s :(Nickname regained by services)",
205 me.name, exist_p->name);
206
207 exist_p->flags |= FLAGS_KILLED;
208 /* Do not send kills to servers for unknowns -- jilles */
209 if(IsClient(exist_p))
45ed8835 210 {
212380e3
AC
211 kill_client_serv_butone(NULL, exist_p, "%s (Nickname regained by services)",
212 me.name);
45ed8835
JT
213 sendto_realops_snomask(SNO_SKILL, L_ALL,
214 "Nick collision due to services forced nick change on %s",
215 parv[2]);
216 }
212380e3 217
5203cba5 218 snprintf(buf, sizeof(buf), "Killed (%s (Nickname regained by services))",
212380e3
AC
219 me.name);
220 exit_client(NULL, exist_p, &me, buf);
221 }
222
03510227 223doit:
212380e3
AC
224 newts = atol(parv[3]);
225
226 /* timestamp is older than 15mins, ignore it */
e3354945
VY
227 if(newts < (rb_current_time() - 900))
228 newts = rb_current_time() - 900;
212380e3
AC
229
230 target_p->tsinfo = newts;
231
232 monitor_signoff(target_p);
233
234 invalidate_bancache_user(target_p);
235
236 sendto_realops_snomask(SNO_NCHANGE, L_ALL,
237 "Nick change: From %s to %s [%s@%s]",
238 target_p->name, parv[2], target_p->username,
239 target_p->host);
240
583f064f 241 sendto_common_channels_local(target_p, NOCAPS, NOCAPS, ":%s!%s@%s NICK :%s",
212380e3
AC
242 target_p->name, target_p->username,
243 target_p->host, parv[2]);
244
b47f8a4f 245 whowas_add_history(target_p, 1);
212380e3
AC
246 sendto_server(NULL, NULL, CAP_TS6, NOCAPS, ":%s NICK %s :%ld",
247 use_id(target_p), parv[2], (long) target_p->tsinfo);
212380e3
AC
248
249 del_from_client_hash(target_p->name, target_p);
e2606551 250 rb_strlcpy(target_p->name, parv[2], NICKLEN);
212380e3
AC
251 add_to_client_hash(target_p->name, target_p);
252
253 monitor_signon(target_p);
254
255 del_all_accepts(target_p);
256
5203cba5 257 snprintf(note, NICKLEN + 10, "Nick: %s", target_p->name);
75d60088 258 rb_note(target_p->localClient->F, note);
212380e3
AC
259 return 0;
260}
261
262/*
263** me_nickdelay
212380e3
AC
264** parv[1] = duration in seconds (0 to remove)
265** parv[2] = nick
266*/
267static int
428ca87b 268me_nickdelay(struct MsgBuf *msgbuf_p, struct Client *client_p, struct Client *source_p, int parc, const char *parv[])
212380e3
AC
269{
270 int duration;
271 struct nd_entry *nd;
272
273 if(!(source_p->flags & FLAGS_SERVICE))
ec57fe67
KB
274 {
275 sendto_realops_snomask(SNO_GENERAL, L_ALL,
276 "Non-service server %s attempting to execute services-only command NICKDELAY", source_p->name);
212380e3 277 return 0;
ec57fe67 278 }
212380e3
AC
279
280 duration = atoi(parv[1]);
281 if (duration <= 0)
282 {
a4bf26dd 283 nd = rb_dictionary_retrieve(nd_dict, parv[2]);
212380e3
AC
284 if (nd != NULL)
285 free_nd_entry(nd);
286 }
287 else
288 {
289 if (duration > 86400)
290 duration = 86400;
291 add_nd_entry(parv[2]);
a4bf26dd 292 nd = rb_dictionary_retrieve(nd_dict, parv[2]);
212380e3 293 if (nd != NULL)
e3354945 294 nd->expire = rb_current_time() + duration;
212380e3
AC
295 }
296
297 return 0;
298}
299
300static void
301h_svc_server_introduced(hook_data_client *hdata)
302{
5b96d9a6 303 rb_dlink_node *ptr;
212380e3 304
5b96d9a6 305 RB_DLINK_FOREACH(ptr, service_list.head)
212380e3
AC
306 {
307 if(!irccmp((const char *) ptr->data, hdata->target->name))
308 {
309 hdata->target->flags |= FLAGS_SERVICE;
310 return;
311 }
312 }
313}
314
315static void
316h_svc_whois(hook_data_client *data)
317{
318 char *p = data->target->user->suser;
319 if(!EmptyString(p))
320 {
321 /* Try to strip off any leading digits as this may be used to
322 * store both an ID number and an account name in one field.
323 * If only digits are present, leave as is.
324 */
325 while(IsDigit(*p))
326 p++;
327 if(*p == '\0')
328 p = data->target->user->suser;
329
5b383ce0
JT
330 sendto_one_numeric(data->client, RPL_WHOISLOGGEDIN,
331 form_str(RPL_WHOISLOGGEDIN),
212380e3
AC
332 data->target->name, p);
333 }
334}
335
336static void
337h_svc_stats(hook_data_int *data)
338{
339 char statchar = (char) data->arg2;
5b96d9a6 340 rb_dlink_node *ptr;
212380e3
AC
341
342 if (statchar == 'U' && IsOper(data->client))
343 {
5b96d9a6 344 RB_DLINK_FOREACH(ptr, service_list.head)
212380e3
AC
345 {
346 sendto_one_numeric(data->client, RPL_STATSULINE,
347 form_str(RPL_STATSULINE),
0cce01d3 348 (const char *)ptr->data, "*", "*", "s");
212380e3
AC
349 }
350 }
351}
c46a4ecd
KB
352
353static void
354h_svc_conf_read_start(void *dummy)
355{
356 unmark_services();
357}
358
359static void
360unmark_services(void)
361{
362 struct Client *target_p;
363 rb_dlink_node *ptr;
364
365 RB_DLINK_FOREACH(ptr, global_serv_list.head)
366 {
367 target_p = ptr->data;
368
369 target_p->flags &= ~FLAGS_SERVICE;
370 }
371}
372
373static void
374h_svc_conf_read_end(void *dummy)
375{
376 mark_services();
377}
378
379static void
380mark_services(void)
381{
382 struct Client *target_p;
383 rb_dlink_node *ptr;
384
385 RB_DLINK_FOREACH(ptr, service_list.head)
386 {
387 target_p = find_server(NULL, (const char *)ptr->data);
388
389 if (target_p)
390 target_p->flags |= FLAGS_SERVICE;
391 }
392}