1 /* $Id: automode.c 448 2010-08-22 09:20:48Z tsaviran $
2 * -------------------------------------------------------
3 * Copyright (C) 2002-2006 Tommi Saviranta <wnd@iki.fi>
4 * -------------------------------------------------------
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif /* ifdef HAVE_CONFIG_H */
21
22 #ifdef AUTOMODE
23
24 #include "automode.h"
25 #include "common.h"
26 #include "llist.h"
27 #include "perm.h"
28 #include "irc.h"
29 #include "miau.h"
30 /* vsnprintf */
31 #include "tools.h"
32
33 #include <string.h>
34
35 #if HAVE_STRINGS_H
36 #include <strings.h>
37 #endif
38
39
40
41 permlist_type automodelist;
42
43
44
45 static inline void
automode_drop(automode_type * line,llist_node * node,llist_list * list)46 automode_drop(automode_type *line, llist_node *node, llist_list *list)
47 {
48 xfree(line->nick);
49 xfree(node->data);
50 llist_delete(node, list);
51 } /* static inline void automode_drop(automode_type *line, llist_node *node,
52 llist_list *list) */
53
54
55
56 /*
57 * Process mode queues.
58 */
59 void
automode_do(void)60 automode_do(void)
61 {
62 channel_type *channel;
63 char modes[4];
64 char *nicks;
65 size_t size;
66
67 size = 1;
68 nicks = (char *) xmalloc(size);
69
70 LLIST_WALK_H(active_channels.head, channel_type *);
71 channel = data;
72
73 if (channel->oper == 1) {
74 int count;
75 size_t nlen, tlen;
76
77 nicks[0] = '\0'; /* clear nicks */
78 tlen = 1;
79 memset(modes, 0, sizeof(modes)); /* clear modes */
80 count = 0;
81
82 /* Commit three modes at a time. */
83 LLIST_WALK_H(channel->mode_queue.head, automode_type *);
84 modes[count] = data->mode;
85 /* paranoid */
86 nlen = strlen(data->nick);
87 tlen += nlen + 1;
88 if (tlen > size) {
89 size = tlen;
90 nicks = (char *) xrealloc(nicks, size);
91 }
92 strcat(nicks, " ");
93 strncat(nicks, data->nick, nlen);
94 count++;
95 if (count == 3) {
96 irc_write_head(&c_server,
97 "MODE %s +%s%s",
98 channel->name,
99 modes,
100 nicks);
101 /* clear nicks and modes */
102 nicks[0] = '\0';
103 memset(modes, 0, 4);
104 count = 0;
105 tlen = 1;
106 }
107 LLIST_WALK_F; /* walk queue */
108
109 /* Commit remaining modes. */
110 if (count > 0) {
111 irc_write_head(&c_server,
112 "MODE %s +%s%s",
113 channel->name,
114 modes,
115 nicks);
116 }
117
118 /* Clear mode-queue as there are all now processed. */
119 automode_clear(&data->mode_queue);
120 } /* if (channel->oper == 1) */
121 LLIST_WALK_F; /* walk channels */
122
123 xfree(nicks);
124 } /* void automode_do(void) */
125
126
127
128 /*
129 * Add nick to be auto-opped.
130 */
131 void
automode_queue(const char * nick,const char * hostname,channel_type * channel)132 automode_queue(const char *nick, const char *hostname, channel_type *channel)
133 {
134 automode_type *modeact;
135 char *mask;
136 size_t msize;
137
138 char modes[] = "ov";
139 int mode_c;
140
141 /* termination and validity guaranteed */
142 msize = strlen(nick) + strlen(hostname) + strlen(channel->name) + 5;
143 mask = (char *) xmalloc(msize);
144
145 for (mode_c = 0; mode_c < 2; mode_c++) { /* strlen(ov) - 1 */
146 /* generate mask and see if any automode should take place */
147 snprintf(mask, msize, "%c:%s!%s/%s",
148 modes[mode_c], nick, hostname,
149 channel->name);
150 mask[msize - 1] = '\0';
151 if (is_perm(&automodelist, mask) && automode_lookup(nick,
152 channel, modes[mode_c]) == NULL) {
153 modeact = (automode_type *)
154 xmalloc(sizeof(automode_type));
155 modeact->nick = xstrdup(nick);
156 modeact->mode = modes[mode_c];
157 llist_add_tail(llist_create(modeact),
158 &channel->mode_queue);
159 status.automodes++;
160 }
161 }
162
163 xfree(mask);
164 } /* void automode_queue(const char *, const char *, channel_type *) */
165
166
167
168 void
automode_clear(llist_list * queue)169 automode_clear(llist_list *queue)
170 {
171 LLIST_WALK_H(queue->head, automode_type *);
172 automode_drop(data, node, queue);
173 status.automodes--;
174 LLIST_WALK_F;
175 } /* void automode_clear(llist_list *queue) */
176
177
178
179 /*
180 * Drop automode action from automode -queue.
181 *
182 * If mode == NULL, don't care about mode.
183 * If channel == NULL, don't care about channel.
184 */
185 void
automode_drop_nick(const char * nick,const char mode)186 automode_drop_nick(const char *nick, const char mode)
187 {
188 LLIST_WALK_H(active_channels.head, channel_type *);
189 automode_drop_channel(data, nick, mode);
190 LLIST_WALK_F;
191 } /* void automode_drop_nick(const char *, const char) */
192
193
194
195 void
automode_drop_channel(channel_type * channel,const char * nick,const char mode)196 automode_drop_channel(channel_type *channel, const char *nick, const char mode)
197 {
198 int nick_ok, mode_ok;
199 LLIST_WALK_H(channel->mode_queue.head, automode_type *);
200 nick_ok = (nick == NULL) || (nick != NULL
201 && xstrcasecmp(nick, data->nick) == 0);
202 mode_ok = (mode == '\0') || (mode == data->mode);
203 if (nick_ok == 1 && mode_ok == 1) {
204 automode_drop(data, node, &channel->mode_queue);
205 }
206 LLIST_WALK_F;
207 } /* void automode_drop_channel(channel_type *, const char *, const char) */
208
209
210
211 /*
212 * Look up for an auto-op action in queue.
213 *
214 * Returns pointer to automode_type if found, otherwise NULL:
215 */
216 llist_node *
automode_lookup(const char * nick,channel_type * channel,const char mode)217 automode_lookup(const char *nick, channel_type *channel, const char mode)
218 {
219 llist_node *ptr;
220 automode_type *modeact;
221
222 for (ptr = channel->mode_queue.head; ptr != NULL; ptr = ptr->next) {
223 modeact = (automode_type *) ptr->data;
224 if (xstrcasecmp(nick, modeact->nick) == 0
225 && modeact->mode == mode) {
226 return ptr;
227 }
228 }
229
230 return NULL;
231 } /* llist_nost *automode_lookup(channel_type *, const char *, const char) */
232
233
234
235 #endif /* ifdef AUTOMODE */
236