ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/src/services.C
Revision: 1.9
Committed: Sun Sep 9 20:05:52 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.8: +4 -3 lines
Log Message:
- changed configurations to the c++ stdlib
- more #defines to enum
- removed getopt.h and link.h from the system as they were unused
- reworked logstreams
- added an itoa with old syntax
- made klines objects
- moved some global variables into appropriate classes
- fixed boost.foreach's compiler workaround #if's
- allow other files to add exceptions with ADD_EXCEPTION
- changed mynick_t to c++ object
- moved servers.h out of atheme.h
- corrected PING from inspircd 1.2

File Contents

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