ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/services.C
Revision: 1.10
Committed: Sun Sep 16 18:54:45 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.9: +7 -2 lines
Log Message:
#defines to enum

File Contents

# User Rev Content
1 pippijn 1.1 /*
2     * services.C: Routines commonly used by various services.
3 pippijn 1.10 *
4     * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team
5     * Rights to this code are as documented in COPYING.
6     *
7     *
8     * Portions of this file were derived from sources bearing the following license:
9 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
10 pippijn 1.5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
11 pippijn 1.1 */
12    
13 pippijn 1.10 static char const rcsid[] = "$Id: services.C,v 1.9 2007-09-09 20:05:52 pippijn Exp $";
14 pippijn 1.5
15     #include <boost/foreach.hpp>
16 pippijn 1.1
17     #include "atheme.h"
18 pippijn 1.9 #include "servers.h"
19 pippijn 1.1 #include <account/myuser.h>
20     #include <account/mynick.h>
21     #include <account/mychan.h>
22     #include "pmodule.h"
23    
24 pippijn 1.5 unsigned authservice_loaded = 0;
25 pippijn 1.1 int use_myuser_access = 0;
26     int use_svsignore = 0;
27    
28     #define MAX_BUF 256
29    
30     /* ban wrapper for cmode, returns number of bans added (0 or 1) */
31     int
32     ban (user_t *sender, channel_t *c, user_t *user)
33     {
34     char mask[MAX_BUF];
35     char modemask[MAX_BUF];
36     chanban_t *cb;
37    
38     if (!c)
39     return 0;
40    
41     snprintf (mask, MAX_BUF, "*!*@%s", user->vhost);
42     mask[MAX_BUF - 1] = '\0';
43    
44     snprintf (modemask, MAX_BUF, "+b %s", mask);
45     modemask[MAX_BUF - 1] = '\0';
46    
47     cb = chanban_find (c, mask, 'b');
48    
49     if (cb != NULL)
50     return 0;
51    
52     chanban_add (c, mask, 'b');
53    
54 pippijn 1.5 phandler->mode_sts (sender->nick, c, modemask);
55 pippijn 1.1 return 1;
56     }
57    
58     /* returns number of modes removed -- jilles */
59     int
60     remove_banlike (user_t *source, channel_t *chan, int type, user_t *target)
61     {
62     char change[MAX_BUF];
63     int count = 0;
64     node_t *n, *tn;
65     chanban_t *cb;
66    
67     if (type == 0)
68     return 0;
69     if (source == NULL || chan == NULL || target == NULL)
70     return 0;
71    
72 pippijn 1.5 for (n = phandler->next_matching_ban (chan, target, type, chan->bans.head); n != NULL; n = phandler->next_matching_ban (chan, target, type, tn))
73 pippijn 1.1 {
74     tn = n->next;
75     cb = static_cast<chanban_t *> (n->data);
76    
77     snprintf (change, sizeof change, "-%c %s", cb->type, cb->mask);
78 pippijn 1.5 phandler->mode_sts (source->nick, chan, change);
79 pippijn 1.1 chanban_delete (cb);
80     count++;
81     }
82     return count;
83     }
84    
85     /* returns number of exceptions removed -- jilles */
86     int
87     remove_ban_exceptions (user_t *source, channel_t *chan, user_t *target)
88     {
89     return remove_banlike (source, chan, ircd->except_mchar, target);
90     }
91    
92     /* join a channel, creating it if necessary */
93     void
94 pippijn 1.5 join (char const * const chan, char const * const nick)
95 pippijn 1.1 {
96     channel_t *c;
97     user_t *u;
98     chanuser_t *cu;
99     bool isnew = false;
100     mychan_t *mc;
101 pippijn 1.8 metadata *md;
102 pippijn 1.1 time_t ts;
103    
104     u = user_find_named (nick);
105     if (!u)
106     return;
107     c = channel_find (chan);
108     if (c == NULL)
109     {
110 pippijn 1.7 mc = mychan_t::find (chan);
111 pippijn 1.1 if (chansvs.changets && mc != NULL)
112     {
113     /* Use the previous TS if known, registration
114     * time otherwise, but never ever create a channel
115     * with TS 0 -- jilles */
116     ts = mc->registered;
117     md = mc->find_metadata ("private:channelts");
118     if (md != NULL)
119     ts = atol (md->value);
120     if (ts == 0)
121     ts = NOW;
122     }
123     else
124     ts = NOW;
125     c = channel_add (chan, ts, me.me);
126     c->modes |= CMODE_NOEXT | CMODE_TOPIC;
127     if (mc != NULL)
128     check_modes (mc, false);
129     isnew = true;
130     }
131     else if ((cu = chanuser_find (c, u)))
132     {
133     slog (LG_DEBUG, "join(): i'm already in `%s'", c->name);
134     return;
135     }
136 pippijn 1.5 phandler->join_sts (c, u, isnew, channel_modes (c, true));
137 pippijn 1.1 cu = chanuser_add (c, CLIENT_NAME (u));
138     cu->modes |= CMODE_OP;
139     if (isnew)
140     {
141 pippijn 1.5 c->callback.add (c);
142 pippijn 1.1 if (config_options.chan != NULL && !irccasecmp (config_options.chan, c->name))
143     joinall (config_options.chan);
144     }
145     }
146    
147     /* part a channel */
148     void
149     part (char *chan, char *nick)
150     {
151     channel_t *c = channel_find (chan);
152     user_t *u = user_find_named (nick);
153    
154     if (!u || !c)
155     return;
156     if (!chanuser_find (c, u))
157     return;
158     if (me.connected)
159 pippijn 1.5 phandler->part_sts (c, u);
160 pippijn 1.1 chanuser_delete (c, u);
161     }
162    
163     void
164     services_init (void)
165     {
166     service_t *svs;
167    
168 pippijn 1.5 foreach (service_pair &sp, services)
169     {
170     svs = sp.second;
171     if (ircd->uses_uid && svs->me->uid[0] == '\0')
172     user_changeuid (svs->me, svs->uid);
173     else if (!ircd->uses_uid && svs->me->uid[0] != '\0')
174     user_changeuid (svs->me, NULL);
175     phandler->introduce_nick (svs->me);
176     }
177 pippijn 1.1 }
178    
179     void
180     joinall (char *name)
181     {
182     if (name == NULL)
183     return;
184    
185 pippijn 1.5 foreach (service_pair &sp, services)
186     join (name, sp.second->name);
187 pippijn 1.1 }
188    
189     void
190     partall (char *name)
191     {
192     service_t *svs;
193     mychan_t *mc;
194    
195     if (name == NULL)
196     return;
197 pippijn 1.7 mc = mychan_t::find (name);
198 pippijn 1.5 foreach (service_pair &sp, services)
199     {
200     svs = sp.second;
201     if (svs == chansvs.me && mc != NULL && config_options.join_chans)
202     continue;
203     /* Do not cache this channel_find(), the
204     * channel may disappear under our feet
205     * -- jilles */
206     if (chanuser_find (channel_find (name), svs->me))
207     part (name, svs->name);
208     }
209 pippijn 1.1 }
210    
211     /* reintroduce a service e.g. after it's been killed -- jilles */
212     void
213     reintroduce_user (user_t *u)
214     {
215     node_t *n;
216     channel_t *c;
217     service_t *svs;
218    
219     svs = find_service (u->nick);
220     if (svs == NULL)
221     {
222     slog (LG_DEBUG, "tried to reintroduce_user non-service %s", u->nick);
223     return;
224     }
225 pippijn 1.5 phandler->introduce_nick (u);
226 pippijn 1.1 LIST_FOREACH (n, u->channels.head)
227     {
228     c = ((chanuser_t *) n->data)->chan;
229     if (LIST_LENGTH (&c->members) > 1 || c->modes & ircd->perm_mode)
230 pippijn 1.5 phandler->join_sts (c, u, 0, channel_modes (c, true));
231 pippijn 1.1 else
232     {
233     /* channel will have been destroyed... */
234     /* XXX resend the bans instead of destroying them? */
235     chanban_clear (c);
236 pippijn 1.5 phandler->join_sts (c, u, 1, channel_modes (c, true));
237 pippijn 1.1 if (c->topic != NULL)
238 pippijn 1.5 phandler->topic_sts (c, c->topic_setter, c->topicts, 0, c->topic);
239 pippijn 1.1 }
240     }
241     }
242    
243     void
244 pippijn 1.5 verbose (mychan_t *mychan, char const * const fmt, ...)
245 pippijn 1.1 {
246     va_list ap;
247     char buf[BUFSIZE];
248    
249     if (mychan->chan == NULL)
250     return;
251    
252     va_start (ap, fmt);
253     vsnprintf (buf, BUFSIZE, fmt, ap);
254     va_end (ap);
255    
256     if ((MC_VERBOSE | MC_FORCEVERBOSE) & mychan->flags)
257     notice (chansvs.nick, mychan->name, "%s", buf);
258     else if (MC_VERBOSE_OPS & mychan->flags)
259 pippijn 1.5 phandler->wallchops (chansvs.me->me, mychan->chan, buf);
260 pippijn 1.1 }
261    
262     void
263 pippijn 1.5 snoop (char const * const fmt, ...)
264 pippijn 1.1 {
265     va_list ap;
266     char buf[BUFSIZE];
267    
268     if (!config_options.chan)
269     return;
270    
271     if (me.bursting)
272     return;
273    
274     if (!channel_find (config_options.chan))
275     return;
276    
277     va_start (ap, fmt);
278     vsnprintf (buf, BUFSIZE, fmt, ap);
279     va_end (ap);
280    
281 pippijn 1.5 phandler->privmsg (opersvs.nick, config_options.chan, "%s", buf);
282 pippijn 1.1 }
283    
284     /* protocol wrapper for nickchange/nick burst */
285     void
286     handle_nickchange (user_t *u)
287     {
288     mynick_t *mn;
289    
290     if (u == NULL)
291     return;
292    
293     if (runflags & RF_LIVE && log_debug_enabled ())
294     notice (globsvs.nick, u->nick, "Services are presently running in debug mode, attached to a console. You should take extra caution when utilizing your services passwords.");
295    
296     /* Only do the following checks if nicks are considered owned -- jilles */
297     if (nicksvs.me == NULL || nicksvs.no_nick_ownership)
298     return;
299    
300     /* They're logged in, don't send them spam -- jilles */
301     if (u->myuser)
302     u->flags |= UF_SEENINFO;
303    
304     /* Also don't send it if they came back from a split -- jilles */
305     if (!(u->server->flags & SF_EOB))
306     u->flags |= UF_SEENINFO;
307    
308 pippijn 1.9 if (!(mn = mynick_t::find (u->nick)))
309 pippijn 1.1 {
310     if (!nicksvs.spam)
311     return;
312    
313     if (!(u->flags & UF_SEENINFO))
314     {
315     notice (nicksvs.nick, u->nick, "Welcome to %s, %s! Here on %s, we provide services to enable the " "registration of nicknames and channels! For details, type \2/%s%s help\2 and \2/%s%s help\2.", me.netname, u->nick, me.netname, (ircd->uses_rcommand == false) ? "msg " : "", nicksvs.disp, (ircd->uses_rcommand == false) ? "msg " : "", chansvs.disp);
316    
317     u->flags |= UF_SEENINFO;
318     }
319    
320     return;
321     }
322    
323     if (u->myuser == mn->owner)
324     {
325     mn->lastseen = NOW;
326     return;
327     }
328    
329     /* OpenServices: is user on access list? -nenolod */
330 pippijn 1.6 if (mn->owner->access_verify (u))
331 pippijn 1.1 {
332     mn->lastseen = NOW;
333     return;
334     }
335    
336     notice (nicksvs.nick, u->nick, _("This nickname is registered. Please choose a different nickname, or identify via \2/%s%s identify <password>\2."), (ircd->uses_rcommand == false) ? "msg " : "", nicksvs.disp);
337 pippijn 1.5 mn->callback.enforce (mn, u);
338 pippijn 1.1 }
339    
340     /* User u is bursted as being logged in to login (if not NULL) or as
341     * being identified to their current nick (if login is NULL)
342     * Update the administration or log them out on ircd
343     * How to use this in protocol modules:
344     * 1. if login info is bursted in a command that always occurs, call
345     * this if the user is logged in, before handle_nickchange()
346     * 2. if it is bursted in a command that doesn't always occur, use
347     * netwide EOB as in the ratbox module; call this if the user is logged
348     * in; for all users, postpone handle_nickchange() until the user's
349     * server confirms EOB
350     * -- jilles
351     */
352     void
353     handle_burstlogin (user_t *u, char *login)
354     {
355     mynick_t *mn;
356     myuser_t *mu;
357    
358     if (login != NULL)
359     /* don't allow alias nicks here -- jilles */
360 pippijn 1.6 mu = myuser_t::find (login);
361 pippijn 1.1 else
362     {
363 pippijn 1.9 mn = mynick_t::find (u->nick);
364 pippijn 1.1 mu = mn != NULL ? mn->owner : NULL;
365     login = mu != NULL ? mu->name : u->nick;
366     }
367     if (mu == NULL)
368     {
369     /* account dropped during split...
370     * if we have an authentication service, log them out */
371     slog (LG_DEBUG, "handle_burstlogin(): got nonexistent login %s for user %s", login, u->nick);
372     if (authservice_loaded)
373     {
374     notice (nicksvs.nick ? nicksvs.nick : me.name, u->nick, _("Account %s dropped, forcing logout"), login);
375 pippijn 1.5 phandler->ircd_on_logout (u->nick, login, NULL);
376 pippijn 1.1 }
377     return;
378     }
379     if (u->myuser != NULL) /* already logged in, hmm */
380     return;
381     if (mu->flags & MU_NOBURSTLOGIN && authservice_loaded)
382     {
383     /* no splits for this account, this bursted login cannot
384     * be legit...
385     * if we have an authentication service, log them out */
386     slog (LG_INFO, "handle_burstlogin(): got illegit login %s for user %s", login, u->nick);
387     notice (nicksvs.nick ? nicksvs.nick : me.name, u->nick, _("Login to account %s seems invalid, forcing logout"), login);
388 pippijn 1.5 phandler->ircd_on_logout (u->nick, login, NULL);
389 pippijn 1.1 return;
390     }
391     u->myuser = mu;
392     mu->logins.insert (u);
393     slog (LG_DEBUG, "handle_burstlogin(): automatically identified %s as %s", u->nick, login);
394     }
395    
396     /* this could be done with more finesse, but hey! */
397     void
398 pippijn 1.5 notice (char const * const from, char const * const to, char const * const message, va_list ap)
399     {
400     char buf[BUFSIZE];
401     user_t *u;
402     channel_t *c;
403    
404     vsnprintf (buf, BUFSIZE, message, ap);
405    
406     if (config_options.use_privmsg)
407     phandler->privmsg (from, to, "%s", buf);
408     else
409     {
410     if (*to == '#')
411     {
412     c = channel_find (to);
413     if (c != NULL)
414     phandler->notice_channel_sts (user_find_named (from), c, buf);
415     }
416     else
417     {
418     u = user_find_named (to);
419     if (u != NULL)
420     phandler->notice_user_sts (user_find_named (from), u, buf);
421     }
422     }
423     }
424    
425     void
426     notice (char const * const from, char const * const to, char const * const message, ...)
427 pippijn 1.1 {
428     va_list args;
429     char buf[BUFSIZE];
430     user_t *u;
431     channel_t *c;
432    
433 pippijn 1.5 va_start (args, message);
434     vsnprintf (buf, BUFSIZE, message, args);
435 pippijn 1.1 va_end (args);
436    
437     if (config_options.use_privmsg)
438 pippijn 1.5 phandler->privmsg (from, to, "%s", buf);
439 pippijn 1.1 else
440     {
441     if (*to == '#')
442     {
443     c = channel_find (to);
444     if (c != NULL)
445 pippijn 1.5 phandler->notice_channel_sts (user_find_named (from), c, buf);
446 pippijn 1.1 }
447     else
448     {
449     u = user_find_named (to);
450     if (u != NULL)
451 pippijn 1.5 phandler->notice_user_sts (user_find_named (from), u, buf);
452 pippijn 1.1 }
453     }
454     }
455    
456     void
457 pippijn 1.7 command_fail (sourceinfo_t *si, fault::code code, char const * const fmt, ...)
458 pippijn 1.1 {
459     va_list args;
460     char buf[BUFSIZE];
461    
462     va_start (args, fmt);
463     vsnprintf (buf, sizeof buf, fmt, args);
464     va_end (args);
465    
466     if (si->su == NULL)
467     {
468     if (si->v != NULL && si->v->cmd_fail)
469     si->v->cmd_fail (si, code, buf);
470     return;
471     }
472    
473     if (config_options.use_privmsg)
474 pippijn 1.5 phandler->privmsg (si->service->name, si->su->nick, "%s", buf);
475 pippijn 1.1 else
476 pippijn 1.5 phandler->notice_user_sts (si->service->me, si->su, buf);
477 pippijn 1.1 }
478    
479     void
480 pippijn 1.5 command_success_nodata (sourceinfo_t *si, char const * const fmt, ...)
481 pippijn 1.1 {
482     va_list args;
483     char buf[BUFSIZE];
484    
485     va_start (args, fmt);
486     vsnprintf (buf, BUFSIZE, fmt, args);
487     va_end (args);
488    
489     if (si->su == NULL)
490     {
491     if (si->v != NULL && si->v->cmd_fail)
492     si->v->cmd_success_nodata (si, buf);
493     return;
494     }
495    
496     if (config_options.use_privmsg)
497 pippijn 1.5 phandler->privmsg (si->service->name, si->su->nick, "%s", buf);
498 pippijn 1.1 else
499 pippijn 1.5 phandler->notice_user_sts (si->service->me, si->su, buf);
500 pippijn 1.1 }
501    
502     void
503 pippijn 1.5 command_success_string (sourceinfo_t *si, char const * const result, char const * const fmt, ...)
504 pippijn 1.1 {
505     va_list args;
506     char buf[BUFSIZE];
507    
508     va_start (args, fmt);
509     vsnprintf (buf, BUFSIZE, fmt, args);
510     va_end (args);
511    
512     if (si->su == NULL)
513     {
514     if (si->v != NULL && si->v->cmd_fail)
515     si->v->cmd_success_string (si, result, buf);
516     return;
517     }
518    
519     if (config_options.use_privmsg)
520 pippijn 1.5 phandler->privmsg (si->service->name, si->su->nick, "%s", buf);
521 pippijn 1.1 else
522 pippijn 1.5 phandler->notice_user_sts (si->service->me, si->su, buf);
523 pippijn 1.1 }
524    
525     static void
526 pippijn 1.5 command_table_cb (char const * const line, void *data)
527 pippijn 1.1 {
528     command_success_nodata (static_cast<sourceinfo_t *> (data), "%s", line);
529     }
530    
531     void
532     command_success_table (sourceinfo_t *si, table_t * table)
533     {
534     table_render (table, command_table_cb, si);
535     }
536    
537 pippijn 1.5 char const * const
538 pippijn 1.1 get_source_name (sourceinfo_t *si)
539     {
540     static char result[NICKLEN + NICKLEN + 10];
541    
542     if (si->su != NULL)
543     {
544     if (si->smu && !irccasecmp (si->su->nick, si->smu->name))
545     snprintf (result, sizeof result, "%s", si->su->nick);
546     else
547     snprintf (result, sizeof result, "%s(%s)", si->su->nick, si->smu ? si->smu->name : "");
548     }
549     else if (si->s != NULL)
550     snprintf (result, sizeof result, "%s", si->s->name);
551     else
552     {
553     snprintf (result, sizeof result, "<%s>%s", si->v->description, si->smu ? si->smu->name : "");
554     }
555     return result;
556     }
557    
558 pippijn 1.5 char const * const
559 pippijn 1.1 get_source_mask (sourceinfo_t *si)
560     {
561     static char result[NICKLEN + USERLEN + HOSTLEN + 10];
562    
563     if (si->su != NULL)
564     {
565     snprintf (result, sizeof result, "%s!%s@%s", si->su->nick, si->su->user, si->su->vhost);
566     }
567     else if (si->s != NULL)
568     snprintf (result, sizeof result, "%s", si->s->name);
569     else
570     {
571     snprintf (result, sizeof result, "<%s>%s", si->v->description, si->smu ? si->smu->name : "");
572     }
573     return result;
574     }
575    
576 pippijn 1.5 char const * const
577 pippijn 1.1 get_oper_name (sourceinfo_t *si)
578     {
579     static char result[NICKLEN + USERLEN + HOSTLEN + NICKLEN + 10];
580    
581     if (si->su != NULL)
582     {
583     if (si->smu == NULL)
584     snprintf (result, sizeof result, "%s!%s@%s{%s}", si->su->nick, si->su->user, si->su->vhost, si->su->server->name);
585     else if (!irccasecmp (si->su->nick, si->smu->name))
586     snprintf (result, sizeof result, "%s", si->su->nick);
587     else
588     snprintf (result, sizeof result, "%s(%s)", si->su->nick, si->smu ? si->smu->name : "");
589     }
590     else if (si->s != NULL)
591     snprintf (result, sizeof result, "%s", si->s->name);
592     else
593     {
594     snprintf (result, sizeof result, "<%s>%s", si->v->description, si->smu ? si->smu->name : "");
595     }
596     return result;
597     }
598    
599     void
600 pippijn 1.5 wallops (char const * const fmt, ...)
601 pippijn 1.1 {
602     va_list args;
603     char buf[BUFSIZE];
604    
605     if (config_options.silent)
606     return;
607    
608     va_start (args, fmt);
609     vsnprintf (buf, BUFSIZE, fmt, args);
610     va_end (args);
611    
612     if (me.me != NULL && me.connected)
613 pippijn 1.5 phandler->wallops_sts (buf);
614 pippijn 1.1 else
615     slog (LG_ERROR, "wallops(): unable to send: %s", buf);
616     }
617    
618     void
619 pippijn 1.5 verbose_wallops (char const * const fmt, ...)
620 pippijn 1.1 {
621     va_list args;
622     char buf[BUFSIZE];
623    
624     if (config_options.silent || !config_options.verbose_wallops)
625     return;
626    
627     va_start (args, fmt);
628     vsnprintf (buf, BUFSIZE, fmt, args);
629     va_end (args);
630    
631     if (me.me != NULL && me.connected)
632 pippijn 1.5 phandler->wallops_sts (buf);
633 pippijn 1.1 else
634     slog (LG_ERROR, "verbose_wallops(): unable to send: %s", buf);
635     }