]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/lists.c
9a10ac7dab9f50995b3107b0f1b136cae92f9c44
[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 "imp.h"
20 #include <assert.h>
21
22 #include "defines.h"
23 #include "conn.h"
24 #include "channel.h"
25 #include "log.h"
26 #include "match.h"
27 #include "messages.h"
28 #include "irc-write.h"
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33
34 #include "exp.h"
35 #include "lists.h"
36
37 #define MASK_LEN        (2*CLIENT_HOST_LEN)
38
39 struct list_elem {
40         struct list_elem *next;
41         char mask[MASK_LEN];
42         char *reason;
43         time_t valid_until;     /** 0: unlimited; 1: once; t(>1): until t */
44 };
45
46
47 GLOBAL const char *
48 Lists_GetMask(const struct list_elem *e)
49 {
50         return e->mask;
51 }
52
53 GLOBAL const char *
54 Lists_GetReason(const struct list_elem *e)
55 {
56         assert(e != NULL);
57         return e->reason;
58 }
59
60 GLOBAL time_t
61 Lists_GetValidity(const struct list_elem *e)
62 {
63         assert(e != NULL);
64         return e->valid_until;
65 }
66
67 GLOBAL struct list_elem*
68 Lists_GetFirst(const struct list_head *h)
69 {
70         return h->first;
71 }
72
73
74 GLOBAL struct list_elem*
75 Lists_GetNext(const struct list_elem *e)
76 {
77         return e->next;
78 }
79
80 /**
81  * Add a new mask to a list.
82  *
83  * @param header List head.
84  * @param Mask The IRC mask to add to the list.
85  * @param ValidUntil 0: unlimited, 1: only once, t>1: until given time_t.
86  * @param Reason Reason string or NULL, if no reason should be saved.
87  * @return true on success, false otherwise.
88  */
89 bool
90 Lists_Add(struct list_head *header, const char *Mask, time_t ValidUntil,
91           const char *Reason)
92 {
93         struct list_elem *e, *newelem;
94
95         assert( header != NULL );
96         assert( Mask != NULL );
97
98         if (Lists_CheckDupeMask(header, Mask )) return true;
99
100         e = Lists_GetFirst(header);
101
102         newelem = malloc(sizeof(struct list_elem));
103         if( ! newelem ) {
104                 Log( LOG_EMERG, "Can't allocate memory for new Ban/Invite entry!" );
105                 return false;
106         }
107
108         strlcpy(newelem->mask, Mask, sizeof(newelem->mask));
109         if (Reason) {
110                 newelem->reason = malloc(strlen(Reason) + 1);
111                 if (newelem->reason)
112                         strlcpy(newelem->reason, Reason, strlen(Reason) + 1);
113                 else
114                         Log(LOG_EMERG,
115                             "Can't allocate memory for new list reason text!");
116         }
117         else
118                 newelem->reason = NULL;
119         newelem->valid_until = ValidUntil;
120         newelem->next = e;
121         header->first = newelem;
122
123         return true;
124 }
125
126
127 static void
128 Lists_Unlink(struct list_head *header, struct list_elem *p, struct list_elem *victim)
129 {
130         assert(victim != NULL);
131         assert(header != NULL);
132
133         if (p) p->next = victim->next;
134         else header->first = victim->next;
135
136         if (victim->reason)
137                 free(victim->reason);
138         free(victim);
139 }
140
141
142 GLOBAL void
143 Lists_Del(struct list_head *header, const char *Mask)
144 {
145         struct list_elem *e, *last, *victim;
146
147         assert( header != NULL );
148         assert( Mask != NULL );
149
150         last = NULL;
151         e = Lists_GetFirst(header);
152         while( e ) {
153                 if(strcasecmp( e->mask, Mask ) == 0 ) {
154                         LogDebug("Deleted \"%s\" from list", e->mask);
155                         victim = e;
156                         e = victim->next;
157                         Lists_Unlink(header, last, victim);
158                         continue;
159                 }
160                 last = e;
161                 e = e->next;
162         }
163 }
164
165
166 GLOBAL void
167 Lists_Free(struct list_head *head)
168 {
169         struct list_elem *e, *victim;
170
171         assert(head != NULL);
172
173         e = head->first;
174         head->first = NULL;
175         while (e) {
176                 LogDebug("Deleted \"%s\" from invite list" , e->mask);
177                 victim = e;
178                 e = e->next;
179                 if (victim->reason)
180                         free(victim->reason);
181                 free(victim);
182         }
183 }
184
185
186 GLOBAL bool
187 Lists_CheckDupeMask(const struct list_head *h, const char *Mask )
188 {
189         struct list_elem *e;
190         e = h->first;
191         while (e) {
192                 if (strcasecmp( e->mask, Mask ) == 0 )
193                         return true;
194                 e = e->next;
195         }
196         return false;
197 }
198
199
200 GLOBAL const char *
201 Lists_MakeMask(const char *Pattern)
202 {
203         /* This function generats a valid IRC mask of "any" string. This
204          * mask is only valid until the next call to Lists_MakeMask(),
205          * because a single global buffer is used. You have to copy the
206          * generated mask to some sane location yourself! */
207
208         static char TheMask[MASK_LEN];
209         char *excl, *at;
210
211         assert( Pattern != NULL );
212
213         excl = strchr( Pattern, '!' );
214         at = strchr( Pattern, '@' );
215
216         if(( at ) && ( at < excl )) excl = NULL;
217
218         if(( ! at ) && ( ! excl ))
219         {
220                 /* Neither "!" nor "@" found: use string as nick name */
221                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - 5 );
222                 strlcat( TheMask, "!*@*", sizeof( TheMask ));
223                 return TheMask;
224         }
225
226         if(( ! at ) && ( excl ))
227         {
228                 /* Domain part is missing */
229                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - 3 );
230                 strlcat( TheMask, "@*", sizeof( TheMask ));
231                 return TheMask;
232         }
233
234         if(( at ) && ( ! excl ))
235         {
236                 /* User name is missing */
237                 *at = '\0'; at++;
238                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - 5 );
239                 strlcat( TheMask, "!*@", sizeof( TheMask ));
240                 strlcat( TheMask, at, sizeof( TheMask ));
241                 return TheMask;
242         }
243
244         /* All parts (nick, user and domain name) are given */
245         strlcpy( TheMask, Pattern, sizeof( TheMask ));
246         return TheMask;
247 } /* Lists_MakeMask */
248
249
250 bool
251 Lists_Check( struct list_head *header, CLIENT *Client)
252 {
253         struct list_elem *e, *last, *next;
254
255         assert( header != NULL );
256
257         e = header->first;
258         last = NULL;
259
260         while (e) {
261                 next = e->next;
262                 if (e->valid_until > 1 && e->valid_until < time(NULL)) {
263                         /* Entry is expired, delete it */
264                         LogDebug("Deleted \"%s\" from list (expired).",
265                                  e->mask);
266                         Lists_Unlink(header, last, e);
267                         e = next;
268                         continue;
269                 }
270                 if (Match(e->mask, Client_Mask(Client))) {
271                         if (e->valid_until == 1 ) {
272                                 /* Entry is valid only once, delete it */
273                                 LogDebug("Deleted \"%s\" from list (used).",
274                                          e->mask);
275                                 Lists_Unlink(header, last, e);
276                         }
277                         return true;
278                 }
279                 last = e;
280                 e = next;
281         }
282
283         return false;
284 }
285
286 /* -eof- */