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