]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/lists.c
Fixed handling of already existent entries in invite and ban lists:
[ngircd-alex.git] / src / ngircd / lists.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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  * Management of IRC lists: ban, invite, ...
12  */
13
14
15 #include "portab.h"
16
17 static char UNUSED id[] = "$Id: lists.c,v 1.14 2004/04/09 21:41:52 alex Exp $";
18
19 #include "imp.h"
20 #include <assert.h>
21
22 #include "defines.h"
23 #include "conn.h"
24 #include "client.h"
25 #include "channel.h"
26 #include "log.h"
27 #include "match.h"
28 #include "messages.h"
29 #include "irc-write.h"
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <strings.h>
34
35 #include "exp.h"
36 #include "lists.h"
37
38
39 #define MASK_LEN 2*CLIENT_HOST_LEN
40
41
42 typedef struct _C2C
43 {
44         struct _C2C *next;
45         CHAR mask[MASK_LEN];
46         CHANNEL *channel;
47         BOOLEAN onlyonce;
48 } C2C;
49
50
51 LOCAL C2C *My_Invites, *My_Bans;
52
53
54 LOCAL C2C *New_C2C PARAMS(( CHAR *Mask, CHANNEL *Chan, BOOLEAN OnlyOnce ));
55
56 LOCAL BOOLEAN Check_List PARAMS(( C2C **Cl2Chan, CLIENT *Client, CHANNEL *Chan ));
57 LOCAL BOOLEAN Already_Registered PARAMS(( C2C *Cl2Chan, CHAR *Mask, CHANNEL *Chan ));
58
59
60
61 GLOBAL VOID
62 Lists_Init( VOID )
63 {
64         /* Modul initialisieren */
65
66         My_Invites = My_Bans = NULL;
67 } /* Lists_Init */
68
69
70 GLOBAL VOID
71 Lists_Exit( VOID )
72 {
73         /* Modul abmelden */
74
75         C2C *c2c, *next;
76
77         /* Invite-Lists freigeben */
78         c2c = My_Invites;
79         while( c2c )
80         {
81                 next = c2c->next;
82                 free( c2c );
83                 c2c = next;
84         }
85
86         /* Ban-Lists freigeben */
87         c2c = My_Bans;
88         while( c2c )
89         {
90                 next = c2c->next;
91                 free( c2c );
92                 c2c = next;
93         }
94 } /* Lists_Exit */
95
96
97 GLOBAL BOOLEAN
98 Lists_CheckInvited( CLIENT *Client, CHANNEL *Chan )
99 {
100         return Check_List( &My_Invites, Client, Chan );
101 } /* Lists_CheckInvited */
102
103
104 GLOBAL BOOLEAN
105 Lists_AddInvited( CHAR *Mask, CHANNEL *Chan, BOOLEAN OnlyOnce )
106 {
107         C2C *c2c;
108
109         assert( Mask != NULL );
110         assert( Chan != NULL );
111
112         if( Already_Registered( My_Invites, Mask, Chan )) return TRUE;
113         
114         c2c = New_C2C( Mask, Chan, OnlyOnce );
115         if( ! c2c )
116         {
117                 Log( LOG_ERR, "Can't add new invite list entry!" );
118                 return FALSE;
119         }
120
121         /* verketten */
122         c2c->next = My_Invites;
123         My_Invites = c2c;
124
125         Log( LOG_DEBUG, "Added \"%s\" to invite list for \"%s\".", Mask, Channel_Name( Chan ));
126         return TRUE;
127 } /* Lists_AddInvited */
128
129
130 GLOBAL VOID
131 Lists_DelInvited( CHAR *Mask, CHANNEL *Chan )
132 {
133         C2C *c2c, *last, *next;
134
135         assert( Mask != NULL );
136         assert( Chan != NULL );
137
138         last = NULL;
139         c2c = My_Invites;
140         while( c2c )
141         {
142                 next = c2c->next;
143                 if(( c2c->channel == Chan ) && ( strcasecmp( c2c->mask, Mask ) == 0 ))
144                 {
145                         /* dieser Eintrag muss geloescht werden */
146                         Log( LOG_DEBUG, "Deleted \"%s\" from invite list for \"%s\"." , c2c->mask, Channel_Name( Chan ));
147                         if( last ) last->next = next;
148                         else My_Invites = next;
149                         free( c2c );
150                 }
151                 else last = c2c;
152                 c2c = next;
153         }
154 } /* Lists_DelInvited */
155
156
157 GLOBAL BOOLEAN
158 Lists_ShowInvites( CLIENT *Client, CHANNEL *Channel )
159 {
160         C2C *c2c;
161
162         assert( Client != NULL );
163         assert( Channel != NULL );
164
165         c2c = My_Invites;
166         while( c2c )
167         {
168                 if( c2c->channel == Channel )
169                 {
170                         /* Eintrag fuer Channel gefunden; ausgeben: */
171                         if( ! IRC_WriteStrClient( Client, RPL_INVITELIST_MSG, Client_ID( Client ), Channel_Name( Channel ), c2c->mask )) return DISCONNECTED;
172                 }
173                 c2c = c2c->next;
174         }
175         return IRC_WriteStrClient( Client, RPL_ENDOFINVITELIST_MSG, Client_ID( Client ), Channel_Name( Channel ));
176 } /* Lists_ShowInvites */
177
178
179 GLOBAL BOOLEAN
180 Lists_CheckBanned( CLIENT *Client, CHANNEL *Chan )
181 {
182         return Check_List( &My_Bans, Client, Chan );
183 } /* Lists_CheckBanned */
184
185
186 GLOBAL BOOLEAN
187 Lists_AddBanned( CHAR *Mask, CHANNEL *Chan )
188 {
189         C2C *c2c;
190
191         assert( Mask != NULL );
192         assert( Chan != NULL );
193
194         if( Already_Registered( My_Bans, Mask, Chan )) return TRUE;
195
196         c2c = New_C2C( Mask, Chan, FALSE );
197         if( ! c2c )
198         {
199                 Log( LOG_ERR, "Can't add new ban list entry!" );
200                 return FALSE;
201         }
202
203         /* verketten */
204         c2c->next = My_Bans;
205         My_Bans = c2c;
206
207         Log( LOG_DEBUG, "Added \"%s\" to ban list for \"%s\".", Mask, Channel_Name( Chan ));
208         return TRUE;
209 } /* Lists_AddBanned */
210
211
212 GLOBAL VOID
213 Lists_DelBanned( CHAR *Mask, CHANNEL *Chan )
214 {
215         C2C *c2c, *last, *next;
216
217         assert( Mask != NULL );
218         assert( Chan != NULL );
219
220         last = NULL;
221         c2c = My_Bans;
222         while( c2c )
223         {
224                 next = c2c->next;
225                 if(( c2c->channel == Chan ) && ( strcasecmp( c2c->mask, Mask ) == 0 ))
226                 {
227                         /* dieser Eintrag muss geloescht werden */
228                         Log( LOG_DEBUG, "Deleted \"%s\" from ban list for \"%s\"." , c2c->mask, Channel_Name( Chan ));
229                         if( last ) last->next = next;
230                         else My_Bans = next;
231                         free( c2c );
232                 }
233                 else last = c2c;
234                 c2c = next;
235         }
236 } /* Lists_DelBanned */
237
238
239 GLOBAL BOOLEAN
240 Lists_ShowBans( CLIENT *Client, CHANNEL *Channel )
241 {
242         C2C *c2c;
243
244         assert( Client != NULL );
245         assert( Channel != NULL );
246
247         c2c = My_Bans;
248         while( c2c )
249         {
250                 if( c2c->channel == Channel )
251                 {
252                         /* Eintrag fuer Channel gefunden; ausgeben: */
253                         if( ! IRC_WriteStrClient( Client, RPL_BANLIST_MSG, Client_ID( Client ), Channel_Name( Channel ), c2c->mask )) return DISCONNECTED;
254                 }
255                 c2c = c2c->next;
256         }
257         return IRC_WriteStrClient( Client, RPL_ENDOFBANLIST_MSG, Client_ID( Client ), Channel_Name( Channel ));
258 } /* Lists_ShowBans */
259
260
261 GLOBAL VOID
262 Lists_DeleteChannel( CHANNEL *Chan )
263 {
264         /* Channel wurde geloescht, Invite- und Ban-Lists aufraeumen */
265
266         C2C *c2c, *last, *next;
267
268         /* Invite-List */
269         last = NULL;
270         c2c = My_Invites;
271         while( c2c )
272         {
273                 next = c2c->next;
274                 if( c2c->channel == Chan )
275                 {
276                         /* dieser Eintrag muss geloescht werden */
277                         Log( LOG_DEBUG, "Deleted \"%s\" from invite list for \"%s\"." , c2c->mask, Channel_Name( Chan ));
278                         if( last ) last->next = next;
279                         else My_Invites = next;
280                         free( c2c );
281                 }
282                 else last = c2c;
283                 c2c = next;
284         }
285
286         /* Ban-List */
287         last = NULL;
288         c2c = My_Bans;
289         while( c2c )
290         {
291                 next = c2c->next;
292                 if( c2c->channel == Chan )
293                 {
294                         /* dieser Eintrag muss geloescht werden */
295                         Log( LOG_DEBUG, "Deleted \"%s\" from ban list for \"%s\"." , c2c->mask, Channel_Name( Chan ));
296                         if( last ) last->next = next;
297                         else My_Bans = next;
298                         free( c2c );
299                 }
300                 else last = c2c;
301                 c2c = next;
302         }
303 } /* Lists_DeleteChannel */
304
305
306 GLOBAL CHAR *
307 Lists_MakeMask( CHAR *Pattern )
308 {
309         /* Hier wird aus einem "beliebigen" Pattern eine gueltige IRC-Mask erzeugt.
310          * Diese ist aber nur bis zum naechsten Aufruf von Lists_MakeMask() gueltig,
311          * da ein einziger globaler Puffer verwendet wird. ->Umkopieren!*/
312
313         STATIC CHAR TheMask[MASK_LEN];
314         CHAR *excl, *at;
315
316         assert( Pattern != NULL );
317
318         excl = strchr( Pattern, '!' );
319         at = strchr( Pattern, '@' );
320
321         if(( at ) && ( at < excl )) excl = NULL;
322
323         if(( ! at ) && ( ! excl ))
324         {
325                 /* weder ! noch @ vorhanden: als Nick annehmen */
326                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - 5 );
327                 strlcat( TheMask, "!*@*", sizeof( TheMask ));
328                 return TheMask;
329         }
330
331         if(( ! at ) && ( excl ))
332         {
333                 /* Domain fehlt */
334                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - 3 );
335                 strlcat( TheMask, "@*", sizeof( TheMask ));
336                 return TheMask;
337         }
338
339         if(( at ) && ( ! excl ))
340         {
341                 /* User fehlt */
342                 *at = '\0'; at++;
343                 strlcpy( TheMask, Pattern, sizeof( TheMask ) - strlen( at ) - 4 );
344                 strlcat( TheMask, "!*@", sizeof( TheMask ));
345                 strlcat( TheMask, at, sizeof( TheMask ));
346                 return TheMask;
347         }
348
349         /* alle Teile vorhanden */
350         strlcpy( TheMask, Pattern, sizeof( TheMask ));
351         return TheMask;
352 } /* Lists_MakeMask */
353
354
355 LOCAL C2C *
356 New_C2C( CHAR *Mask, CHANNEL *Chan, BOOLEAN OnlyOnce )
357 {
358         C2C *c2c;
359         
360         assert( Mask != NULL );
361         assert( Chan != NULL );
362
363         /* Speicher fuer Eintrag anfordern */
364         c2c = (C2C *)malloc( sizeof( C2C ));
365         if( ! c2c )
366         {
367                 Log( LOG_EMERG, "Can't allocate memory! [New_C2C]" );
368                 return NULL;
369         }
370
371         strlcpy( c2c->mask, Mask, sizeof( c2c->mask ));
372         c2c->channel = Chan;
373         c2c->onlyonce = OnlyOnce;
374
375         return c2c;
376 } /* New_C2C */
377
378
379 LOCAL BOOLEAN
380 Check_List( C2C **Cl2Chan, CLIENT *Client, CHANNEL *Chan )
381 {
382         C2C *c2c, *last;
383
384         assert( Cl2Chan != NULL );
385         assert( Client != NULL );
386         assert( Chan != NULL );
387
388         c2c = *Cl2Chan;
389         last = NULL;
390
391         while( c2c )
392         {
393                 if( c2c->channel == Chan )
394                 {
395                         /* Ok, richtiger Channel. Passt die Maske? */
396                         if( Match( c2c->mask, Client_Mask( Client )))
397                         {
398                                 /* Treffer! */
399                                 if( c2c->onlyonce )
400                                 {
401                                         /* Eintrag loeschen */
402                                         Log( LOG_DEBUG, "Deleted \"%s\" from %s list for \"%s\".", c2c->mask, *Cl2Chan == My_Invites ? "invite" : "ban", Channel_Name( Chan ));
403                                         if( last ) last->next = c2c->next;
404                                         else *Cl2Chan = c2c->next;
405                                         free( c2c );
406                                 }
407                                 return TRUE;
408                         }
409                 }
410                 last = c2c;
411                 c2c = c2c->next;
412         }
413
414         return FALSE;
415 } /* Check_List */
416
417
418 LOCAL BOOLEAN
419 Already_Registered( C2C *List, CHAR *Mask, CHANNEL *Chan )
420 {
421         C2C *c2c;
422
423         c2c = List;
424         while( c2c )
425         {
426                 if(( c2c->channel == Chan ) && ( strcasecmp( c2c->mask, Mask ) == 0 )) return TRUE;
427                 c2c = c2c->next;
428         }
429         return FALSE;
430 } /* Already_Registered */
431
432
433 /* -eof- */