ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/contrib/ircd_alis.C
Revision: 1.3
Committed: Tue Aug 28 17:08:09 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.2: +22 -44 lines
Log Message:
- changed name
- updated the example config to the new system
- added more documentation
- enhanced documentation generators
- added a link to the pdf to the website
- added an RSS feed generator
- transitioned hooks to c++ callbacks
- did various merges with upstream along the way
- added const where appropriate
- removed the old block allocator
- fixed most memory leaks
- transitioned some dictionaries to std::map
- transitioned some lists to std::vector
- made some free functions members where appropriate
- renamed string to dynstr and added a static string ststr
- use NOW instead of time (NULL) if possible
- completely reworked database backends, crypto handlers and protocol handlers
  to use an object factory
- removed the old module system. ermyth does not do any dynamic loading anymore
- fixed most of the build system
- reworked how protocol commands work

File Contents

# User Rev Content
1 pippijn 1.1 /*
2 pippijn 1.3 * Copyright © 2005-2007 William Pitcock, et al.
3 pippijn 1.2 * The rights to this code are as documented under doc/pod/license.pod.
4 pippijn 1.1 *
5 pippijn 1.3 * Copyright © 2003-2007 Lee Hardy <leeh@leeh.co.uk>
6     * Copyright © 2003-2007 ircd-ratbox development team
7 pippijn 1.1 *
8     * ALIS, based on the ratbox-services implementation.
9     *
10 pippijn 1.3 * $Id: ircd_alis.C,v 1.2 2007-07-21 01:29:08 pippijn Exp $
11 pippijn 1.1 */
12    
13     #include "atheme.h"
14 pippijn 1.3 #include <ermyth/module.h>
15    
16     static char const rcsid[] = "$Id$";
17 pippijn 1.1
18 pippijn 1.3 REGISTER_MODULE ("alis", false, "William Pitcock <nenolod -at- nenolod.net>");
19 pippijn 1.1
20     #define ALIS_MAX_PARC 10
21     #define ALIS_MAX_MATCH 60
22    
23     #define DIR_UNSET 0
24     #define DIR_SET 1
25     #define DIR_EQUAL 2
26    
27     service_t *alis;
28     cmdvec alis_cmdtree;
29    
30     static void alis_cmd_list (sourceinfo_t *si, int parc, char *parv[]);
31     static void alis_cmd_help (sourceinfo_t *si, int parc, char *parv[]);
32     static void alis_handler (sourceinfo_t *si, int parc, char *parv[]);
33    
34 pippijn 1.3 command_t const alis_list = { "LIST", "Lists channels matching given parameters.", AC_NONE, ALIS_MAX_PARC, alis_cmd_list };
35     command_t const alis_help = { "HELP", "Displays contextual help information.", AC_NONE, 1, alis_cmd_help };
36 pippijn 1.1
37     struct alis_query
38     {
39     char const *mask;
40     char *topic;
41     int min;
42     int max;
43     int show_mode;
44     int show_topicwho;
45     unsigned int mode;
46     int mode_dir;
47     int mode_key;
48     int mode_limit;
49     int skip;
50     };
51    
52 pippijn 1.3 bool
53     _modinit (module *m)
54 pippijn 1.1 {
55     alis = add_service ("ALIS", "alis", me.name, "Channel Directory", alis_handler, alis_cmdtree);
56    
57 pippijn 1.3 alis_cmdtree << alis_list;
58     alis_cmdtree << alis_help;
59    
60     return true;
61 pippijn 1.1 }
62    
63     void
64     _moddeinit ()
65     {
66 pippijn 1.3 alis_cmdtree >> alis_list;
67     alis_cmdtree >> alis_help;
68 pippijn 1.1
69     del_service (alis);
70     }
71    
72     static int
73 pippijn 1.3 alis_parse_mode (char const * const txt, int *key, int *limit)
74 pippijn 1.1 {
75     int mode = 0;
76 pippijn 1.3 char const *text = txt;
77 pippijn 1.1
78     if (!text)
79     return 0;
80    
81     while (*text)
82     {
83     switch (*text)
84     {
85     case 'l':
86     *limit = 1;
87     break;
88     case 'k':
89     *key = 1;
90     break;
91     default:
92     mode |= mode_to_flag (*text);
93     break;
94     }
95    
96     text++;
97     }
98    
99     return mode;
100     }
101    
102     static int
103     parse_alis (sourceinfo_t *si, int parc, char *parv[], struct alis_query *query)
104     {
105     int i = 0;
106     char *opt = NULL, *arg = NULL;
107    
108     while ((opt = parv[i++]))
109     {
110     if (!strcasecmp (opt, "-min"))
111     {
112     if ((arg = parv[i++]) == NULL || (query->min = atoi (arg)) < 1)
113     {
114     command_fail (si, fault_badparams, "Invalid -min option");
115     return 0;
116     }
117     }
118     else if (!strcasecmp (opt, "-max"))
119     {
120     if ((arg = parv[i++]) == NULL || (query->max = atoi (arg)) < 1)
121     {
122     command_fail (si, fault_badparams, "Invalid -max option");
123     return 0;
124     }
125     }
126     else if (!strcasecmp (opt, "-skip"))
127     {
128     if ((arg = parv[i++]) == NULL || (query->skip = atoi (arg)) < 1)
129     {
130     command_fail (si, fault_badparams, "Invalid -skip option");
131     return 0;
132     }
133     }
134     else if (!strcasecmp (opt, "-topic"))
135     {
136     query->topic = strtok (NULL, " ");
137     }
138     else if (!strcasecmp (opt, "-show"))
139     {
140     arg = parv[i++];
141    
142     if (arg == NULL)
143     {
144     command_fail (si, fault_badparams, "Invalid -show option");
145     return 0;
146     }
147    
148     if (arg[0] == 'm')
149     {
150     query->show_mode = 1;
151    
152     if (arg[1] == 't')
153     query->show_topicwho = 1;
154     }
155     else if (arg[0] == 't')
156     {
157     query->show_topicwho = 1;
158    
159     if (arg[1] == 'm')
160     query->show_mode = 1;
161     }
162     }
163     else if (!strcasecmp (opt, "-mode"))
164     {
165     arg = parv[i++];
166    
167     if (arg == NULL)
168     {
169     command_fail (si, fault_badparams, "Invalid -mode option");
170     return 0;
171     }
172    
173     switch (*arg)
174     {
175     case '+':
176     query->mode_dir = DIR_SET;
177     break;
178     case '-':
179     query->mode_dir = DIR_UNSET;
180     break;
181     case '=':
182     query->mode_dir = DIR_EQUAL;
183     break;
184     default:
185     command_fail (si, fault_badparams, "Invalid -mode option");
186     return 0;
187     }
188    
189     query->mode = alis_parse_mode (arg + 1, &query->mode_key, &query->mode_limit);
190    
191     if (query->mode == 0)
192     {
193     command_fail (si, fault_badparams, "Invalid -mode option");
194     return 0;
195     }
196     }
197     else
198     {
199     command_fail (si, fault_badparams, "Invalid option %s", opt);
200     return 0;
201     }
202     }
203    
204     return 1;
205     }
206    
207     static void
208     print_channel (sourceinfo_t *si, channel_t *c, struct alis_query *query)
209     {
210     int show_topicwho = query->show_topicwho;
211     int show_topic = 1;
212     char modestr[MAXEXTMODES + 60];
213     int i, j;
214    
215     /* cant show a topicwho, when a channel has no topic. */
216     if (!c->topic)
217     {
218     show_topicwho = 0;
219     show_topic = 0;
220     }
221     if (query->show_mode)
222     {
223     j = 0;
224     modestr[j++] = '+';
225     for (i = 0; i < MAXEXTMODES; i++)
226     if (c->extmodes[i] != NULL)
227     modestr[j++] = ignore_mode_list[i].mode;
228     if (c->limit != 0)
229     modestr[j++] = 'l';
230     if (c->key != NULL)
231     modestr[j++] = 'k';
232     modestr[j] = '\0';
233     strlcat (modestr, flags_to_string (c->modes), sizeof modestr);
234     }
235    
236     if (query->show_mode && show_topicwho && show_topic)
237     command_success_nodata (si, "%-50s %-8s %3ld :%s (%s)", c->name, modestr, LIST_LENGTH (&c->members), c->topic, c->topic_setter);
238     else if (query->show_mode)
239     command_success_nodata (si, "%-50s %-8s %3ld :%s", c->name, modestr, LIST_LENGTH (&c->members), c->topic);
240     else if (show_topicwho && show_topic)
241     command_success_nodata (si, "%-50s %3ld :%s (%s)", c->name, LIST_LENGTH (&c->members), c->topic, c->topic_setter);
242     else if (show_topic)
243     command_success_nodata (si, "%-50s %3ld :%s", c->name, LIST_LENGTH (&c->members), c->topic);
244     else
245     command_success_nodata (si, "%-50s %3ld", c->name, LIST_LENGTH (&c->members));
246     }
247    
248     static int
249     show_channel (channel_t *c, struct alis_query *query)
250     {
251     /* skip +s channels */
252     if (c->modes & CMODE_SEC)
253     return 0;
254    
255     if ((int) LIST_LENGTH (&c->members) < query->min || (query->max && (int) LIST_LENGTH (&c->members) > query->max))
256     return 0;
257    
258     if (query->mode)
259     {
260     if (query->mode_dir == DIR_SET)
261     {
262     if (((c->modes & query->mode) == 0) || (query->mode_key && c->key[0] == '\0') || (query->mode_limit && !c->limit))
263     return 0;
264     }
265     else if (query->mode_dir == DIR_UNSET)
266     {
267     if ((c->modes & query->mode) || (query->mode_key && c->key[0] != '\0') || (query->mode_limit && c->limit))
268     return 0;
269     }
270     else if (query->mode_dir == DIR_EQUAL)
271     {
272     if ((c->modes != query->mode) || (query->mode_key && c->key[0] == '\0') || (query->mode_limit && !c->limit))
273     return 0;
274     }
275     }
276    
277     if (match (query->mask, c->name))
278     return 0;
279    
280     if (query->topic != NULL && match (query->topic, c->topic))
281     return 0;
282    
283     if (query->skip)
284     {
285     query->skip--;
286     return 0;
287     }
288    
289     return 1;
290     }
291    
292     static void
293     alis_cmd_list (sourceinfo_t *si, int parc, char *parv[])
294     {
295     channel_t *c;
296     struct alis_query query;
297     dictionary_iteration_state_t state;
298     int maxmatch = ALIS_MAX_MATCH;
299    
300     memset (&query, 0, sizeof (struct alis_query));
301    
302     query.mask = parc >= 1 ? parv[0] : "*";
303     if (!parse_alis (si, parc - 1, parv + 1, &query))
304     return;
305    
306     logcommand (si, CMDLOG_GET, "LIST %s", query.mask);
307    
308     command_success_nodata (si, "Returning maximum of %d channel names matching '\2%s\2'", ALIS_MAX_MATCH, query.mask);
309    
310     /* hunting for one channel.. */
311     if (strchr (query.mask, '*') == NULL && strchr (query.mask, '?') == NULL)
312     {
313     if ((c = channel_find (query.mask)) != NULL)
314     {
315     if (!(c->modes & CMODE_SEC))
316     print_channel (si, c, &query);
317     }
318    
319     command_success_nodata (si, "End of output");
320     return;
321     }
322    
323     DICTIONARY_FOREACH (c, channel_t, &state, chanlist)
324     {
325     /* matches, so show it */
326     if (show_channel (c, &query))
327     {
328     print_channel (si, c, &query);
329    
330     if (--maxmatch == 0)
331     {
332     command_success_nodata (si, "Maximum channel output reached");
333     break;
334     }
335     }
336     }
337    
338     command_success_nodata (si, "End of output");
339     return;
340     }
341    
342     static void
343     alis_cmd_help (sourceinfo_t *si, int parc, char *parv[])
344     {
345 pippijn 1.3 command_help (si, alis_cmdtree);
346 pippijn 1.1 }
347    
348     static void
349     alis_handler (sourceinfo_t *si, int parc, char *parv[])
350     {
351     char orig[BUFSIZE];
352     char *cmd;
353     char *text;
354    
355     /* this should never happen */
356     if (parv[0][0] == '&')
357     {
358     slog (LG_ERROR, "services(): got parv with local channel: %s", parv[0]);
359     return;
360     }
361    
362     /* make a copy of the original for debugging */
363     strlcpy (orig, parv[parc - 1], BUFSIZE);
364    
365     /* lets go through this to get the command */
366     cmd = strtok (parv[parc - 1], " ");
367     text = strtok (NULL, "");
368    
369     if (!cmd)
370     return;
371     if (*cmd == '\001')
372     {
373     handle_ctcp_common (si, cmd, text);
374     return;
375     }
376    
377     /* take the command through the hash table */
378 pippijn 1.3 command_exec_split (alis, si, cmd, text, alis_cmdtree);
379 pippijn 1.1 }