Anope IRC Services  Version 1.8
process.c
Go to the documentation of this file.
1 /* Main processing code for Services.
2  *
3  * (C) 2003-2014 Anope Team
4  * Contact us at team@anope.org
5  *
6  * Please read COPYING and README for further details.
7  *
8  * Based on the original code of Epona by Lara.
9  * Based on the original code of Services by Andy Church.
10  *
11  *
12  */
13 
14 #include "services.h"
15 #include "messages.h"
16 #include "modules.h"
17 
18 /*************************************************************************/
19 
20 /* Use ignore code? */
21 int allow_ignore = 1;
22 
23 /* Masks to ignore. */
25 
26 /*************************************************************************/
27 
33 void add_ignore(const char *nick, time_t delta)
34 {
35  IgnoreData *ign;
36  char tmp[BUFSIZE];
37  char *mask, *user, *host;
38  User *u;
39  time_t now;
40 
41  if (!nick)
42  return;
43  now = time(NULL);
44 
45  /* If it s an existing user, we ignore the hostmask. */
46  if ((u = finduser(nick))) {
47  snprintf(tmp, sizeof(tmp), "*!*@%s", u->host);
48  mask = sstrdup(tmp);
49 
50  /* Determine whether we get a nick or a mask. */
51  } else if ((host = strchr(nick, '@'))) {
52  /* Check whether we have a nick too.. */
53  if ((user = strchr(nick, '!'))) {
54  /* this should never happen */
55  if (user > host)
56  return;
57  mask = sstrdup(nick);
58  } else {
59  /* We have user@host. Add nick wildcard. */
60  snprintf(tmp, sizeof(tmp), "*!%s", nick);
61  mask = sstrdup(tmp);
62  }
63  /* We only got a nick.. */
64  } else {
65  snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
66  mask = sstrdup(tmp);
67  }
68 
69  /* Check if we already got an identical entry. */
70  for (ign = ignore; ign; ign = ign->next)
71  if (stricmp(ign->mask, mask) == 0)
72  break;
73 
74  /* Found one.. */
75  if (ign) {
76  if (delta == 0)
77  ign->time = 0;
78  else if (ign->time < now + delta)
79  ign->time = now + delta;
80 
81  free(mask);
82  /* Create new entry.. */
83  } else {
84  ign = scalloc(sizeof(*ign), 1);
85  ign->mask = mask;
86  ign->time = (delta == 0 ? 0 : now + delta);
87  ign->prev = NULL;
88  ign->next = ignore;
89  if (ignore)
90  ignore->prev = ign;
91  ignore = ign;
92  if (debug)
93  alog("debug: Added new ignore entry for %s", mask);
94  }
95 }
96 
97 /*************************************************************************/
98 
106 IgnoreData *get_ignore(const char *nick)
107 {
108  IgnoreData *ign;
109  char tmp[BUFSIZE];
110  char *user, *host;
111  time_t now;
112  User *u;
113 
114  if (!nick)
115  return NULL;
116 
117  /* User has disabled the IGNORE system */
118  if (!allow_ignore)
119  return NULL;
120 
121  now = time(NULL);
122  u = finduser(nick);
123 
124  /* If we find a real user, match his mask against the ignorelist. */
125  if (u) {
126  /* Opers are not ignored, even if a matching entry may be present. */
127  if (is_oper(u))
128  return NULL;
129  for (ign = ignore; ign; ign = ign->next)
130  if (match_usermask_full(ign->mask, u, true))
131  break;
132  } else {
133  /* We didn't get a user.. generate a valid mask. */
134  if ((host = strchr(nick, '@'))) {
135  if ((user = strchr(nick, '!'))) {
136  /* this should never happen */
137  if (user > host)
138  return NULL;
139  snprintf(tmp, sizeof(tmp), "%s", nick);
140  } else {
141  /* We have user@host. Add nick wildcard. */
142  snprintf(tmp, sizeof(tmp), "*!%s", nick);
143  }
144 
145  /* We only got a nick.. */
146  } else
147  snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
148  for (ign = ignore; ign; ign = ign->next)
149  if (match_wild_nocase(ign->mask, tmp))
150  break;
151  }
152 
153  /* Check whether the entry has timed out */
154  if (ign && ign->time != 0 && ign->time <= now) {
155  if (debug)
156  alog("debug: Expiring ignore entry %s", ign->mask);
157  if (ign->prev)
158  ign->prev->next = ign->next;
159  else if (ignore == ign)
160  ignore = ign->next;
161  if (ign->next)
162  ign->next->prev = ign->prev;
163  free(ign->mask);
164  free(ign);
165  ign = NULL;
166  }
167  if (ign && debug)
168  alog("debug: Found ignore entry (%s) for %s", ign->mask, nick);
169  return ign;
170 }
171 
172 /*************************************************************************/
173 
179 int delete_ignore(const char *nick)
180 {
181  IgnoreData *ign;
182  char tmp[BUFSIZE];
183  char *user, *host;
184  User *u;
185 
186  if (!nick)
187  return 0;
188 
189  /* If it s an existing user, we ignore the hostmask. */
190  if ((u = finduser(nick))) {
191  snprintf(tmp, sizeof(tmp), "*!*@%s", u->host);
192 
193  /* Determine whether we get a nick or a mask. */
194  } else if ((host = strchr(nick, '@'))) {
195  /* Check whether we have a nick too.. */
196  if ((user = strchr(nick, '!'))) {
197  /* this should never happen */
198  if (user > host)
199  return 0;
200  snprintf(tmp, sizeof(tmp), "%s", nick);
201  } else {
202  /* We have user@host. Add nick wildcard. */
203  snprintf(tmp, sizeof(tmp), "*!%s", nick);
204  }
205 
206  /* We only got a nick.. */
207  } else
208  snprintf(tmp, sizeof(tmp), "%s!*@*", nick);
209 
210  for (ign = ignore; ign; ign = ign->next)
211  if (stricmp(ign->mask, tmp) == 0)
212  break;
213 
214  /* No matching ignore found. */
215  if (!ign)
216  return 0;
217 
218  if (debug)
219  alog("Deleting ignore entry %s", ign->mask);
220 
221  /* Delete the entry and all references to it. */
222  if (ign->prev)
223  ign->prev->next = ign->next;
224  else if (ignore == ign)
225  ignore = ign->next;
226  if (ign->next)
227  ign->next->prev = ign->prev;
228  free(ign->mask);
229  free(ign);
230  ign = NULL;
231 
232  return 1;
233 }
234 
235 /*************************************************************************/
236 
242 {
243  IgnoreData *ign, *next;
244  int i = 0;
245 
246  if (!ignore)
247  return 0;
248 
249  for (ign = ignore; ign; ign = next) {
250  next = ign->next;
251  if (debug)
252  alog("Deleting ignore entry %s", ign->mask);
253  free(ign->mask);
254  free(ign);
255  i++;
256  }
257  ignore = NULL;
258  return i;
259 }
260 
261 /*************************************************************************/
262 
263 /* split_buf: Split a buffer into arguments and store the arguments in an
264  * argument vector pointed to by argv (which will be malloc'd
265  * as necessary); return the argument count. If colon_special
266  * is non-zero, then treat a parameter with a leading ':' as
267  * the last parameter of the line, per the IRC RFC. Destroys
268  * the buffer by side effect.
269  */
270 int split_buf(char *buf, char ***argv, int colon_special)
271 {
272  int argvsize = 8;
273  int argc;
274  char *s;
275 
276  *argv = scalloc(sizeof(char *) * argvsize, 1);
277  argc = 0;
278  while (*buf) {
279  if (argc == argvsize) {
280  argvsize += 8;
281  *argv = srealloc(*argv, sizeof(char *) * argvsize);
282  }
283  if (*buf == ':') {
284  (*argv)[argc++] = buf + 1;
285  buf = "";
286  } else {
287  s = strpbrk(buf, " ");
288  if (s) {
289  *s++ = 0;
290  while (*s == ' ')
291  s++;
292  } else {
293  s = buf + strlen(buf);
294  }
295  (*argv)[argc++] = buf;
296  buf = s;
297  }
298  }
299  return argc;
300 }
301 
302 /*************************************************************************/
303 
304 /* process: Main processing routine. Takes the string in inbuf (global
305  * variable) and does something appropriate with it. */
306 
307 void process()
308 {
309  int retVal = 0;
310  Message *current = NULL;
311  char source[64];
312  char cmd[64];
313  char buf[4096]; /* Most need only 512, InspIRCd 2.0 is seriously oversized though.. */
314  char *s;
315  int ac; /* Parameters for the command */
316  char **av;
317  Message *m;
318 
319  /* zero out the buffers before we do much else */
320  *buf = '\0';
321  *source = '\0';
322  *cmd = '\0';
323 
324  /* If debugging, log the buffer */
325  if (debug) {
326  alog("debug: Received: %s", inbuf);
327  }
328 
329  /* First make a copy of the buffer so we have the original in case we
330  * crash - in that case, we want to know what we crashed on. */
331  strscpy(buf, inbuf, sizeof(buf));
332 
333  doCleanBuffer((char *) buf);
334 
335  /* Split the buffer into pieces. */
336  if (*buf == ':') {
337  s = strpbrk(buf, " ");
338  if (!s)
339  return;
340  *s = 0;
341  while (isspace(*++s));
342  strscpy(source, buf + 1, sizeof(source));
343  memmove(buf, s, strlen(s) + 1);
344  } else {
345  *source = 0;
346  }
347  if (!*buf)
348  return;
349  s = strpbrk(buf, " ");
350  if (s) {
351  *s = 0;
352  while (isspace(*++s));
353  } else
354  s = buf + strlen(buf);
355  strscpy(cmd, buf, sizeof(cmd));
356  ac = split_buf(s, &av, 1);
357  if (protocoldebug) {
358  protocol_debug(source, cmd, ac, av);
359  }
360  if (mod_current_buffer) {
361  free(mod_current_buffer);
362  }
363  /* fix to moduleGetLastBuffer() bug 296 */
364  /* old logic was that since its meant for PRIVMSG that we would get
365  the NICK as AV[0] and the rest would be in av[1], however on Bahamut
366  based systems when you do /cs it assumes we will translate the command
367  to the NICK and thus AV[0] is the message. The new logic is to check
368  av[0] to see if its a service nick if so assign mod_current_buffer the
369  value from AV[1] else just assign av[0] - TSL */
370  /* First check if the ircd proto module overrides this -GD */
371  /* fix to moduleGetLastBuffer() bug 476:
372  fixed in part by adding {} to nickIsServices()
373  however if you have a pseudo they could not use moduleGetLastBuffer()
374  cause they are not part of nickIsServices, even those the ac count is 2
375  that was ignored and only the first param was passed on which is fine for
376  Bahmut ircd aliases but not for pseudo clients on. So additional logic is
377  that if the ac is greater then 1 copy av[1] else copy av[0]
378  I also changed from if statments, cause attempting to access a array member
379  that is not set can lead to odd things - TSL (3/12/06) */
380  if (!anope_set_mod_current_buffer(ac, av)) {
381  if (ac >= 1) {
382  if (nickIsServices(av[0], 1)) {
384  (ac > 1 ? sstrdup(av[1]) : sstrdup(av[0]));
385  } else {
387  (ac > 1 ? sstrdup(av[1]) : sstrdup(av[0]));
388  }
389  } else {
390  mod_current_buffer = NULL;
391  }
392  }
393  /* Do something with the message. */
394  m = find_message(cmd);
395  if (m) {
396  if (m->func) {
399  retVal = m->func(source, ac, av);
401  mod_current_module = NULL;
402  if (retVal == MOD_CONT) {
403  current = m->next;
404  while (current && current->func && retVal == MOD_CONT) {
407  retVal = current->func(source, ac, av);
409  mod_current_module = NULL;
410  current = current->next;
411  }
412  }
413  }
414  } else {
415  if (debug)
416  alog("debug: unknown message from server (%s)", inbuf);
417  }
418 
419  /* Load/unload modules if needed */
421 
422  /* Free argument list we created */
423  free(av);
424 }
425 
426 /*************************************************************************/
E int is_oper(User *user)
Definition: users.c:937
E void doCleanBuffer(char *str)
Definition: misc.c:800
char * mod_name
Definition: modules.h:215
void process()
Definition: process.c:307
E int match_wild_nocase(const char *pattern, const char *str)
Definition: misc.c:268
E int snprintf(char *buf, size_t size, const char *fmt,...)
Definition: compat.c:37
static Channel * current
Definition: channels.c:427
MDE char * mod_current_buffer
Definition: modules.c:54
struct ignore_data * prev
Definition: services.h:1058
E int stricmp(const char *s1, const char *s2)
Definition: compat.c:58
int(* func)(char *source, int ac, char **av)
Definition: modules.h:213
int split_buf(char *buf, char ***argv, int colon_special)
Definition: process.c:270
Message * find_message(const char *name)
Definition: messages.c:456
char * host
Definition: services.h:878
E char * strscpy(char *d, const char *s, size_t len)
Definition: db-merger.c:1886
time_t time
Definition: services.h:1060
struct ignore_data * next
Definition: services.h:1058
E int anope_set_mod_current_buffer(int ac, char **av)
Definition: ircd.c:120
E char * sstrdup(const char *s)
Definition: memory.c:105
E void * scalloc(long elsize, long els)
Definition: memory.c:55
E char inbuf[BUFSIZE]
Definition: extern.h:793
IgnoreData * ignore
Definition: process.c:24
MDE void handleModuleOperationQueue(void)
Definition: modules.c:2840
MDE Module * findModule(char *name)
Definition: modules.c:473
E int nickIsServices(char *nick, int bot)
Definition: misc.c:857
E User * finduser(const char *nick)
Definition: users.c:323
E int protocoldebug
Definition: extern.h:783
char * mask
Definition: services.h:1059
E void alog(const char *fmt,...) FORMAT(printf
int clear_ignores()
Definition: process.c:241
#define MOD_CONT
Definition: modules.h:54
int delete_ignore(const char *nick)
Definition: process.c:179
E int debug
Definition: extern.h:775
E void protocol_debug(char *source, char *cmd, int argc, char **argv)
Definition: misc.c:773
MDE Module * mod_current_module
Definition: modules.c:52
E void * srealloc(void *oldptr, long newsize)
Definition: memory.c:80
E int match_usermask_full(const char *mask, User *user, boolean full)
Definition: users.c:1029
IgnoreData * get_ignore(const char *nick)
Definition: process.c:106
void add_ignore(const char *nick, time_t delta)
Definition: process.c:33
int allow_ignore
Definition: process.c:21
MDE char * mod_current_module_name
Definition: modules.c:53
#define BUFSIZE
Definition: config.h:47
Message * next
Definition: modules.h:216