- fixed broken handling of modes received from other servers.
[ngircd-alex.git] / src / ngircd / irc-mode.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  * IRC commands for mode changes (MODE, AWAY, ...)
12  */
13
14
15 #include "portab.h"
16
17 static char UNUSED id[] = "$Id: irc-mode.c,v 1.22 2002/12/16 10:52:53 alex Exp $";
18
19 #include "imp.h"
20 #include <assert.h>
21 #include <string.h>
22
23 #include "conn.h"
24 #include "client.h"
25 #include "channel.h"
26 #include "defines.h"
27 #include "irc-write.h"
28 #include "lists.h"
29 #include "log.h"
30 #include "parse.h"
31 #include "messages.h"
32 #include "resolve.h"
33 #include "conf.h"
34
35 #include "exp.h"
36 #include "irc-mode.h"
37
38
39 LOCAL BOOLEAN Client_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ));
40 LOCAL BOOLEAN Channel_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ));
41
42 LOCAL BOOLEAN Add_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
43 LOCAL BOOLEAN Add_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
44
45 LOCAL BOOLEAN Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
46 LOCAL BOOLEAN Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
47
48 LOCAL BOOLEAN Send_ListChange PARAMS(( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask ));
49
50
51 GLOBAL BOOLEAN
52 IRC_MODE( CLIENT *Client, REQUEST *Req )
53 {
54         CLIENT *cl, *origin;
55         CHANNEL *chan;
56
57         assert( Client != NULL );
58         assert( Req != NULL );
59
60         /* No parameters? */
61         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
62
63         /* Origin for answers */
64         if( Client_Type( Client ) == CLIENT_SERVER )
65         {
66                 origin = Client_Search( Req->prefix );
67                 if( ! origin ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
68         }
69         else origin = Client;
70         
71         /* Channel or user mode? */
72         cl = chan = NULL;
73         if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
74         if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
75
76         if( cl ) return Client_Mode( Client, Req, origin, cl );
77         if( chan ) return Channel_Mode( Client, Req, origin, chan );
78
79         /* No target found! */
80         return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
81 } /* IRC_MODE */
82
83
84 LOCAL BOOLEAN
85 Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
86 {
87         /* Handle client mode requests */
88
89         CHAR the_modes[COMMAND_LEN], x[2], *mode_ptr;
90         BOOLEAN ok, set;
91         INT mode_arg;
92
93         /* Is the client allowed to request or change the modes? */
94         if( Client_Type( Client ) == CLIENT_USER )
95         {
96                 /* Users are only allowed to manipulate their own modes! */
97                 if( Target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
98         }
99
100         /* Mode request: let's answer it :-) */
101         if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_UMODEIS_MSG, Client_ID( Origin ), Client_Modes( Target ));
102
103         mode_arg = 1;
104         mode_ptr = Req->argv[mode_arg];
105
106         /* Initial state: set or unset modes? */
107         if( *mode_ptr == '+' ) set = TRUE;
108         else if( *mode_ptr == '-' ) set = FALSE;
109         else return IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Origin ));
110
111         /* Prepare reply string */
112         if( set ) strcpy( the_modes, "+" );
113         else strcpy( the_modes, "-" );
114
115         x[1] = '\0';
116         ok = CONNECTED;
117         while( mode_ptr )
118         {
119                 mode_ptr++;
120                 if( ! *mode_ptr )
121                 {
122                         /* Try next argument if there's any */
123                         mode_arg++;
124                         if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
125                         else break;
126                 }
127                 
128                 switch( *mode_ptr )
129                 {
130                         case '+':
131                         case '-':
132                                 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
133                                 {
134                                         /* Action modifier ("+"/"-") must be changed ... */
135                                         if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
136                                         {
137                                                 /* Adjust last action modifier in result */
138                                                 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
139                                         }
140                                         else
141                                         {
142                                                 /* Append modifier character to result string */
143                                                 x[0] = *mode_ptr; strcat( the_modes, x );
144                                         }
145                                         if( *mode_ptr == '+' ) set = TRUE;
146                                         else set = FALSE;
147                                 }
148                                 continue;
149                 }
150                 
151                 /* Validate modes */
152                 x[0] = '\0';
153                 switch( *mode_ptr )
154                 {
155                         case 'i':
156                                 /* Invisible */
157                                 x[0] = 'i';
158                                 break;
159                         case 'o':
160                                 /* IRC operator (only unsetable!) */
161                                 if( ! set )
162                                 {
163                                         Client_SetOperByMe( Target, FALSE );
164                                         x[0] = 'o';
165                                 }
166                                 else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
167                                 break;
168                         case 'r':
169                                 /* Restricted (only setable) */
170                                 if( set ) x[0] = 'r';
171                                 else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
172                                 break;
173                         case 's':
174                                 /* Server messages */
175                                 x[0] = 's';
176                                 break;
177                         default:
178                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ));
179                                 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
180                                 x[0] = '\0';
181                 }
182                 if( ! ok ) break;
183
184                 /* Is there a valid mode change? */
185                 if( ! x[0] ) continue;
186
187                 if( set )
188                 {
189                         /* Set mode */
190                         if( Client_ModeAdd( Target, x[0] )) strcat( the_modes, x );
191
192                 }
193                 else
194                 {
195                         /* Unset mode */
196                         if( Client_ModeDel( Target, x[0] )) strcat( the_modes, x );
197                 }               
198         }
199
200         /* Are there changed modes? */
201         if( the_modes[1] )
202         {
203                 /* Remoce needless action modifier characters */
204                 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
205
206                 if( Client_Type( Client ) == CLIENT_SERVER )
207                 {
208                         /* Forward modes to other servers */
209                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
210                 }
211                 else
212                 {
213                         /* Send reply to client and inform other servers */
214                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s", Client_ID( Target ), the_modes );
215                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
216                 }
217                 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( Target ), Client_Modes( Target ));
218         }
219                 
220         return ok;
221 } /* Client_Mode */
222
223
224 LOCAL BOOLEAN
225 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
226 {
227         /* Handle channel and channel-user modes */
228
229         CHAR the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], *mode_ptr;
230         BOOLEAN ok, set, modeok, skiponce;
231         INT mode_arg, arg_arg;
232         CLIENT *client;
233
234         /* Mode request: let's answer it :-) */
235         if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_CHANNELMODEIS_MSG, Client_ID( Origin ), Channel_Name( Channel ), Channel_Modes( Channel ));
236
237         /* Is the user allowed to change modes? */
238         if( Client_Type( Client ) == CLIENT_USER )
239         {
240                 if( strchr( Channel_UserModes( Channel, Origin ), 'o' )) modeok = TRUE;
241                 else modeok = FALSE;
242                 if( Conf_OperCanMode )
243                 {
244                         /* auch IRC-Operatoren duerfen MODE verwenden */
245                         if( Client_OperByMe( Origin )) modeok = TRUE;
246                 }
247         }
248         else modeok = TRUE;
249
250         mode_arg = 1;
251         mode_ptr = Req->argv[mode_arg];
252         if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
253         else arg_arg = -1;
254
255         /* Initial state: set or unset modes? */
256         skiponce = FALSE;
257         if( *mode_ptr == '-' ) set = FALSE;
258         else if( *mode_ptr == '+' ) set = TRUE;
259         else set = skiponce = TRUE;
260
261         /* Prepare reply string */
262         if( set ) strcpy( the_modes, "+" );
263         else strcpy( the_modes, "-" );
264         strcpy( the_args, " " );
265
266         x[1] = '\0';
267         ok = CONNECTED;
268         while( mode_ptr )
269         {
270                 if( ! skiponce ) mode_ptr++;
271                 if( ! *mode_ptr )
272                 {
273                         /* Try next argument if there's any */
274                         if( arg_arg > mode_arg ) mode_arg = arg_arg;
275                         else mode_arg++;
276                         if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
277                         else break;
278                         if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
279                         else arg_arg = -1;
280                 }
281                 skiponce = FALSE;
282
283                 switch( *mode_ptr )
284                 {
285                         case '+':
286                         case '-':
287                                 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
288                                 {
289                                         /* Action modifier ("+"/"-") must be changed ... */
290                                         if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
291                                         {
292                                                 /* Adjust last action modifier in result */
293                                                 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
294                                         }
295                                         else
296                                         {
297                                                 /* Append modifier character to result string */
298                                                 x[0] = *mode_ptr; strcat( the_modes, x );
299                                         }
300                                         if( *mode_ptr == '+' ) set = TRUE;
301                                         else set = FALSE;
302                                 }
303                                 continue;
304                 }
305
306                 /* Are there arguments left? */
307                 if( arg_arg >= Req->argc ) arg_arg = -1;
308
309                 /* Validate modes */
310                 x[0] = '\0';
311                 client = NULL;
312                 switch( *mode_ptr )
313                 {
314                         /* Channel modes */
315                         case 'i':
316                                 /* Invite-Only */
317                                 if( modeok ) x[0] = 'i';
318                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
319                                 break;
320                         case 'm':
321                                 /* Moderated */
322                                 if( modeok ) x[0] = 'm';
323                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
324                                 break;
325                         case 'n':
326                                 /* kein Schreiben in den Channel von aussen */
327                                 if( modeok ) x[0] = 'n';
328                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
329                                 break;
330                         case 't':
331                                 /* Topic Lock */
332                                 if( modeok ) x[0] = 't';
333                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
334                                 break;
335                         case 'P':
336                                 /* Persistent channel */
337                                 if( modeok )
338                                 {
339                                         if( set && ( ! Client_OperByMe( Client )))
340                                         {
341                                                 /* Only IRC operators are allowed to set P mode */
342                                                 ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
343                                         }
344                                         else x[0] = 'P';
345                                 }
346                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
347                                 break;
348
349                         /* Channel user modes */
350                         case 'o':
351                                 /* Channel operator */
352                         case 'v':
353                                 /* Voice */
354                                 if( arg_arg > mode_arg )
355                                 {
356                                         if( modeok )
357                                         {
358                                                 client = Client_Search( Req->argv[arg_arg] );
359                                                 if( client ) x[0] = *mode_ptr;
360                                                 else ok = IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[arg_arg] );
361                                         }
362                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
363                                         Req->argv[arg_arg][0] = '\0';
364                                         arg_arg++;
365                                 }
366                                 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
367                                 break;
368
369                         /* Channel lists */
370                         case 'I':
371                                 /* Invite lists */
372                                 if( arg_arg > mode_arg )
373                                 {
374                                         /* modify list */
375                                         if( modeok )
376                                         {
377                                                 if( set ) Add_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
378                                                 else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
379                                         }
380                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
381                                         Req->argv[arg_arg][0] = '\0';
382                                         arg_arg++;
383                                 }
384                                 else Lists_ShowInvites( Origin, Channel );
385                                 break;
386                         case 'b':
387                                 /* Ban lists */
388                                 if( arg_arg > mode_arg )
389                                 {
390                                         /* modify list */
391                                         if( modeok )
392                                         {
393                                                 if( set ) Add_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
394                                                 else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
395                                         }
396                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
397                                         Req->argv[arg_arg][0] = '\0';
398                                         arg_arg++;
399                                 }
400                                 else Lists_ShowBans( Origin, Channel );
401                                 break;
402
403                         default:
404                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
405                                 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
406                                 x[0] = '\0';
407                 }
408                 if( ! ok ) break;
409
410                 /* Is there a valid mode change? */
411                 if( ! x[0] ) continue;
412
413                 if( set )
414                 {
415                         /* Set mode */
416                         if( client )
417                         {
418                                 /* Channel-User-Mode */
419                                 if( Channel_UserModeAdd( Channel, client, x[0] ))
420                                 {
421                                         strcat( the_args, Client_ID( client ));
422                                         strcat( the_args, " " ); strcat( the_modes, x );
423                                         Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
424                                 }
425                         }
426                         else
427                         {
428                                 /* Channel-Mode */
429                                 if( Channel_ModeAdd( Channel, x[0] ))
430                                 {
431                                         strcat( the_modes, x );
432                                         Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
433                                 }
434                         }
435                 }
436                 else
437                 {
438                         /* Unset mode */
439                         if( client )
440                         {
441                                 /* Channel-User-Mode */
442                                 if( Channel_UserModeDel( Channel, client, x[0] ))
443                                 {
444                                         strcat( the_args, Client_ID( client ));
445                                         strcat( the_args, " " ); strcat( the_modes, x );
446                                         Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
447                                 }
448                         }
449                         else
450                         {
451                                 /* Channel-Mode */
452                                 if( Channel_ModeDel( Channel, x[0] ))
453                                 {
454                                         strcat( the_modes, x );
455                                         Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
456                                 }
457                         }
458                 }               
459         }
460
461         /* Are there changed modes? */
462         if( the_modes[1] )
463         {
464                 /* Clean up mode string */
465                 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
466
467                 /* Clean up argument string if there are none */
468                 if( ! the_args[1] ) the_args[0] = '\0';
469
470                 if( Client_Type( Client ) == CLIENT_SERVER )
471                 {
472                         /* Forward mode changes to channel users and other servers */
473                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
474                         IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
475                 }
476                 else
477                 {
478                         /* Send reply to client and inform other servers and channel users */
479                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
480                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
481                         IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
482                 }
483         }
484
485         return CONNECTED;
486 } /* Channel_Mode */
487
488
489 GLOBAL BOOLEAN
490 IRC_AWAY( CLIENT *Client, REQUEST *Req )
491 {
492         assert( Client != NULL );
493         assert( Req != NULL );
494
495         /* Falsche Anzahl Parameter? */
496         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
497
498         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
499         {
500                 /* AWAY setzen */
501                 Client_SetAway( Client, Req->argv[0] );
502                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
503                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
504         }
505         else
506         {
507                 /* AWAY loeschen */
508                 Client_SetAway( Client, NULL );
509                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
510                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
511         }
512 } /* IRC_AWAY */
513
514
515 LOCAL BOOLEAN
516 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
517 {
518         CHAR *mask;
519
520         assert( Client != NULL );
521         assert( Channel != NULL );
522         assert( Pattern != NULL );
523
524         mask = Lists_MakeMask( Pattern );
525
526         if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
527         return Send_ListChange( "+I", Prefix, Client, Channel, mask );
528 } /* Add_Invite */
529
530
531 LOCAL BOOLEAN
532 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
533 {
534         CHAR *mask;
535
536         assert( Client != NULL );
537         assert( Channel != NULL );
538         assert( Pattern != NULL );
539
540         mask = Lists_MakeMask( Pattern );
541
542         if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
543         return Send_ListChange( "+b", Prefix, Client, Channel, mask );
544 } /* Add_Ban */
545
546
547 LOCAL BOOLEAN
548 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
549 {
550         CHAR *mask;
551
552         assert( Client != NULL );
553         assert( Channel != NULL );
554         assert( Pattern != NULL );
555
556         mask = Lists_MakeMask( Pattern );
557         Lists_DelInvited( mask, Channel );
558         return Send_ListChange( "-I", Prefix, Client, Channel, mask );
559 } /* Del_Invite */
560
561
562 LOCAL BOOLEAN
563 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
564 {
565         CHAR *mask;
566
567         assert( Client != NULL );
568         assert( Channel != NULL );
569         assert( Pattern != NULL );
570
571         mask = Lists_MakeMask( Pattern );
572         Lists_DelBanned( mask, Channel );
573         return Send_ListChange( "-b", Prefix, Client, Channel, mask );
574 } /* Del_Ban */
575
576
577 LOCAL BOOLEAN
578 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
579 {
580         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
581
582         BOOLEAN ok;
583
584         if( Client_Type( Client ) == CLIENT_USER )
585         {
586                 /* Bestaetigung an Client */
587                 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
588         }
589         else ok = TRUE;
590
591         /* an andere Server */
592         IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
593
594         /* und lokale User im Channel */
595         IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
596         
597         return ok;
598 } /* Send_ListChange */
599
600
601 /* -eof- */