]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/lists.c
d3efb1f7386e746ecbad05979b9b84cf6a92b8ed
[ngircd-alex.git] / src / ngircd / lists.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
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  * Please read the file COPYING, README and AUTHORS for more information.
10  */
11
12 #include "portab.h"
13
14 /**
15  * @file
16  * Management of IRC lists: ban, invite, etc.
17  */
18
19 #include <assert.h>
20
21 #include "defines.h"
22 #include "conn.h"
23 #include "channel.h"
24 #include "log.h"
25 #include "match.h"
26 #include "messages.h"
27 #include "irc-write.h"
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32
33 #include "lists.h"
34
35 struct list_elem {
36         struct list_elem *next; /** pointer to next list element */
37         char mask[MASK_LEN];    /** IRC mask */
38         char *reason;           /** Optional "reason" text */
39         time_t valid_until;     /** 0: unlimited; 1: once; t(>1): until t */
40 };
41
42 /**
43  * Get IRC mask stored in list element.
44  *
45  * @param list_elem List element.
46  * @return Pointer to IRC mask
47  */
48 GLOBAL const char *
49 Lists_GetMask(const struct list_elem *e)
50 {
51         assert(e != NULL);
52         return e->mask;
53 }
54
55 /**
56  * Get optional "reason" text stored in list element.
57  *
58  * @param list_elem List element.
59  * @return Pointer to "reason" text or empty string ("").
60  */
61 GLOBAL const char *
62 Lists_GetReason(const struct list_elem *e)
63 {
64         assert(e != NULL);
65         return e->reason ? e->reason : "";
66 }
67
68 /**
69  * Get "validity" value stored in list element.
70  *
71  * @param list_elem List element.
72  * @return Validity: 0=unlimited, 1=once, >1 until this time stamp.
73  */
74 GLOBAL time_t
75 Lists_GetValidity(const struct list_elem *e)
76 {
77         assert(e != NULL);
78         return e->valid_until;
79 }
80
81 /**
82  * Get first list element of a list.
83  *
84  * @param h List head.
85  * @return Pointer to first list element.
86  */
87 GLOBAL struct list_elem*
88 Lists_GetFirst(const struct list_head *h)
89 {
90         assert(h != NULL);
91         return h->first;
92 }
93
94 /**
95  * Get next list element of a list.
96  *
97  * @param e Current list element.
98  * @return Pointer to next list element.
99  */
100 GLOBAL struct list_elem*
101 Lists_GetNext(const struct list_elem *e)
102 {
103         assert(e != NULL);
104         return e->next;
105 }
106
107 /**
108  * Add a new mask to a list.
109  *
110  * @param h List head.
111  * @param Mask The IRC mask to add to the list.
112  * @param ValidUntil 0: unlimited, 1: only once, t>1: until given time_t.
113  * @param Reason Reason string or NULL, if no reason should be saved.
114  * @return true on success, false otherwise.
115  */
116 bool
117 Lists_Add(struct list_head *h, const char *Mask, time_t ValidUntil,
118           const char *Reason)
119 {
120         struct list_elem *e, *newelem;
121
122         assert(h != NULL);
123         assert(Mask != NULL);
124
125         e = Lists_CheckDupeMask(h, Mask);
126         if (e) {
127                 e->valid_until = ValidUntil;
128                 if (Reason) {
129                         if (e->reason)
130                                 free(e->reason);
131                         e->reason = strdup(Reason);
132                 }
133                 return true;
134         }
135
136         e = Lists_GetFirst(h);
137
138         newelem = malloc(sizeof(struct list_elem));
139         if (!newelem) {
140                 Log(LOG_EMERG,
141                     "Can't allocate memory for new list entry!");
142                 return false;
143         }
144
145         strlcpy(newelem->mask, Mask, sizeof(newelem->mask));
146         if (Reason) {
147                 newelem->reason = strdup(Reason);
148                 if (!newelem->reason)
149                         Log(LOG_EMERG,
150                             "Can't allocate memory for new list reason text!");
151         }
152         else
153                 newelem->reason = NULL;
154         newelem->valid_until = ValidUntil;
155         newelem->next = e;
156         h->first = newelem;
157
158         return true;
159 }
160
161 /**
162  * Delete a list element from a list.
163  *
164  * @param h List head.
165  * @param p Pointer to previous list element or NULL, if there is none.
166  * @param victim List element to delete.
167  */
168 static void
169 Lists_Unlink(struct list_head *h, struct list_elem *p, struct list_elem *victim)
170 {
171         assert(victim != NULL);
172         assert(h != NULL);
173
174         if (p)
175                 p->next = victim->next;
176         else
177                 h->first = victim->next;
178
179         if (victim->reason)
180                 free(victim->reason);
181
182         free(victim);
183 }
184
185 /**
186  * Delete a given IRC mask from a list.
187  *
188  * @param h List head.
189  * @param Mask IRC mask to delete from the list.
190  */
191 GLOBAL void
192 Lists_Del(struct list_head *h, const char *Mask)
193 {
194         struct list_elem *e, *last, *victim;
195
196         assert(h != NULL);
197         assert(Mask != NULL);
198
199         last = NULL;
200         e = Lists_GetFirst(h);
201         while (e) {
202                 if (strcasecmp(e->mask, Mask) == 0) {
203                         LogDebug("Deleted \"%s\" from list", e->mask);
204                         victim = e;
205                         e = victim->next;
206                         Lists_Unlink(h, last, victim);
207                         continue;
208                 }
209                 last = e;
210                 e = e->next;
211         }
212 }
213
214 /**
215  * Free a complete list.
216  *
217  * @param head List head.
218  */
219 GLOBAL void
220 Lists_Free(struct list_head *head)
221 {
222         struct list_elem *e, *victim;
223
224         assert(head != NULL);
225
226         e = head->first;
227         head->first = NULL;
228         while (e) {
229                 LogDebug("Deleted \"%s\" from list" , e->mask);
230                 victim = e;
231                 e = e->next;
232                 if (victim->reason)
233                         free(victim->reason);
234                 free(victim);
235         }
236 }
237
238 /**
239  * Check if an IRC mask is already contained in a list.
240  *
241  * @param h List head.
242  * @param Mask IRC mask to test.
243  * @return true if mask is already stored in the list, false otherwise.
244  */
245 GLOBAL struct list_elem *
246 Lists_CheckDupeMask(const struct list_head *h, const char *Mask )
247 {
248         struct list_elem *e;
249         e = h->first;
250         while (e) {
251                 if (strcasecmp(e->mask, Mask) == 0)
252                         return e;
253                 e = e->next;
254         }
255         return NULL;
256 }
257
258 /**
259  * Generate a valid IRC mask from "any" string given.
260  *
261  * @param Pattern Source string to generate an IRC mask for.
262  * @param mask    Buffer to store the mask.
263  * @param len     Size of the buffer.
264  */
265 GLOBAL void
266 Lists_MakeMask(const char *Pattern, char *mask, size_t len)
267 {
268         char *excl, *at;
269
270         assert(Pattern != NULL);
271
272         excl = strchr(Pattern, '!');
273         at = strchr(Pattern, '@');
274
275         if (at && at < excl)
276                 excl = NULL;
277
278         if (!at && !excl) {
279                 /* Neither "!" nor "@" found: use string as nickname */
280                 strlcpy(mask, Pattern, len - 5);
281                 strlcat(mask, "!*@*", len);
282         } else if (!at && excl) {
283                 /* Domain part is missing */
284                 strlcpy(mask, Pattern, len - 3);
285                 strlcat(mask, "@*", len);
286         } else if (at && !excl) {
287                 /* User name is missing */
288                 *at = '\0'; at++;
289                 strlcpy(mask, Pattern, len - 5);
290                 strlcat(mask, "!*@", len);
291                 strlcat(mask, at, len);
292         } else {
293                 /* All parts (nick, user and domain name) are given */
294                 strlcpy(mask, Pattern, len);
295         }
296 } /* Lists_MakeMask */
297
298 /**
299  * Check if a client is listed in a list.
300  *
301  * @param h List head.
302  * @param Client Client to check.
303  * @return true if client is listed, false if not.
304  */
305 bool
306 Lists_Check(struct list_head *h, CLIENT *Client)
307 {
308         return Lists_CheckReason(h, Client, NULL, 0);
309 }
310
311 /**
312  * Check if a client is listed in a list and store the reason.
313  *
314  * @param h      List head.
315  * @param Client Client to check.
316  * @param reason Buffer to store the reason.
317  * @param len    Size of the buffer if reason should be saved.
318  * @return true if client is listed, false if not.
319  */
320 bool
321 Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
322 {
323         struct list_elem *e, *last, *next;
324
325         assert(h != NULL);
326
327         e = h->first;
328         last = NULL;
329
330         while (e) {
331                 next = e->next;
332                 if (Match(e->mask, Client_MaskCloaked(Client))) {
333                         if (len && e->reason)
334                                 strlcpy(reason, e->reason, len);
335                         if (e->valid_until == 1) {
336                                 /* Entry is valid only once, delete it */
337                                 LogDebug("Deleted \"%s\" from list (used).",
338                                          e->mask);
339                                 Lists_Unlink(h, last, e);
340                         }
341                         return true;
342                 }
343                 last = e;
344                 e = next;
345         }
346
347         return false;
348 }
349
350 /**
351  * Check list and purge expired entries.
352  *
353  * @param h List head.
354  */
355 GLOBAL void
356 Lists_Expire(struct list_head *h, const char *ListName)
357 {
358         struct list_elem *e, *last, *next;
359         time_t now;
360
361         assert(h != NULL);
362
363         e = h->first;
364         last = NULL;
365         now = time(NULL);
366
367         while (e) {
368                 next = e->next;
369                 if (e->valid_until > 1 && e->valid_until < now) {
370                         /* Entry is expired, delete it */
371                         if (e->reason)
372                                 Log(LOG_INFO,
373                                     "Deleted \"%s\" (\"%s\") from %s list (expired).",
374                                     e->mask, e->reason, ListName);
375                         else
376                                 Log(LOG_INFO,
377                                     "Deleted \"%s\" from %s list (expired).",
378                                     e->mask, ListName);
379                         Lists_Unlink(h, last, e);
380                         e = next;
381                         continue;
382                 }
383                 last = e;
384                 e = next;
385         }
386 }
387
388 /**
389  * Return the number of entries of a list.
390  *
391  * @param h List head.
392  * @return Number of items.
393  */
394 GLOBAL unsigned long
395 Lists_Count(struct list_head *h)
396 {
397         struct list_elem *e;
398         unsigned long count = 0;
399
400         assert(h != NULL);
401
402         e = h->first;
403         while (e) {
404                 count++;
405                 e = e->next;
406         }
407         return count;
408 }
409
410 /* -eof- */