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