]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-mode.c
- new (and much more flexible!) MODE parser
[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.20 2002/12/15 15:51:24 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                 x[0] = '\0';
152                 if( Client_Type( Client ) == CLIENT_SERVER )
153                 {
154                         /* MODE request was received from a server:
155                          * therefore don't validate but trust it! */
156                         x[0] = *mode_ptr;
157                 }
158                 else
159                 {
160                         /* Validate modes */
161                         switch( *mode_ptr )
162                         {
163                                 case 'i':
164                                         /* Invisible */
165                                         x[0] = 'i';
166                                         break;
167                                 case 'o':
168                                         /* IRC operator (only unsetable!) */
169                                         if( ! set )
170                                         {
171                                                 Client_SetOperByMe( Target, FALSE );
172                                                 x[0] = 'o';
173                                         }
174                                         else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
175                                         break;
176                                 case 'r':
177                                         /* Restricted (only setable) */
178                                         if( set ) x[0] = 'r';
179                                         else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
180                                         break;
181                                 case 's':
182                                         /* Server messages */
183                                         x[0] = 's';
184                                         break;
185                                 default:
186                                         Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ));
187                                         ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
188                                         x[0] = '\0';
189                         }
190                 }
191                 if( ! ok ) break;
192
193                 /* Is there a valid mode change? */
194                 if( ! x[0] ) continue;
195
196                 if( set )
197                 {
198                         /* Set mode */
199                         if( Client_ModeAdd( Target, x[0] )) strcat( the_modes, x );
200
201                 }
202                 else
203                 {
204                         /* Unset mode */
205                         if( Client_ModeDel( Target, x[0] )) strcat( the_modes, x );
206                 }               
207         }
208
209         /* Are there changed modes? */
210         if( the_modes[1] )
211         {
212                 /* Remoce needless action modifier characters */
213                 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
214
215                 if( Client_Type( Client ) == CLIENT_SERVER )
216                 {
217                         /* Forward modes to other servers */
218                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
219                 }
220                 else
221                 {
222                         /* Send reply to client and inform other servers */
223                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s", Client_ID( Target ), the_modes );
224                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
225                 }
226                 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( Target ), Client_Modes( Target ));
227         }
228                 
229         return ok;
230 } /* Client_Mode */
231
232
233 LOCAL BOOLEAN
234 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
235 {
236         /* Handle channel and channel-user modes */
237
238         CHAR the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], *mode_ptr;
239         BOOLEAN ok, set, modeok, skiponce;
240         INT mode_arg, arg_arg;
241         CLIENT *client;
242
243         /* Mode request: let's answer it :-) */
244         if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_CHANNELMODEIS_MSG, Client_ID( Origin ), Channel_Name( Channel ), Channel_Modes( Channel ));
245
246         /* Is the user allowed to change modes? */
247         if( Client_Type( Client ) == CLIENT_USER )
248         {
249                 if( strchr( Channel_UserModes( Channel, Origin ), 'o' )) modeok = TRUE;
250                 else modeok = FALSE;
251                 if( Conf_OperCanMode )
252                 {
253                         /* auch IRC-Operatoren duerfen MODE verwenden */
254                         if( Client_OperByMe( Origin )) modeok = TRUE;
255                 }
256         }
257         else modeok = TRUE;
258
259         mode_arg = 1;
260         mode_ptr = Req->argv[mode_arg];
261         if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
262         else arg_arg = -1;
263
264         /* Initial state: set or unset modes? */
265         skiponce = FALSE;
266         if( *mode_ptr == '-' ) set = FALSE;
267         else if( *mode_ptr == '+' ) set = TRUE;
268         else set = skiponce = TRUE;
269
270         /* Prepare reply string */
271         if( set ) strcpy( the_modes, "+" );
272         else strcpy( the_modes, "-" );
273         strcpy( the_args, " " );
274
275         x[1] = '\0';
276         ok = CONNECTED;
277         while( mode_ptr )
278         {
279                 if( ! skiponce ) mode_ptr++;
280                 if( ! *mode_ptr )
281                 {
282                         /* Try next argument if there's any */
283                         if( arg_arg > mode_arg ) mode_arg = arg_arg;
284                         else mode_arg++;
285                         if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
286                         else break;
287                         if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
288                         else arg_arg = -1;
289                 }
290                 skiponce = FALSE;
291
292                 switch( *mode_ptr )
293                 {
294                         case '+':
295                         case '-':
296                                 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
297                                 {
298                                         /* Action modifier ("+"/"-") must be changed ... */
299                                         if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
300                                         {
301                                                 /* Adjust last action modifier in result */
302                                                 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
303                                         }
304                                         else
305                                         {
306                                                 /* Append modifier character to result string */
307                                                 x[0] = *mode_ptr; strcat( the_modes, x );
308                                         }
309                                         if( *mode_ptr == '+' ) set = TRUE;
310                                         else set = FALSE;
311                                 }
312                                 continue;
313                 }
314
315                 /* Are there arguments left? */
316                 if( arg_arg >= Req->argc ) arg_arg = -1;
317
318                 x[0] = '\0';
319                 client = NULL;
320                 if( Client_Type( Client ) == CLIENT_SERVER )
321                 {
322                         /* MODE request was received from a server:
323                          * therefore don't validate but trust it! */
324                         x[0] = *mode_ptr;
325                 }
326                 else
327                 {
328                         /* Validate modes */
329                         switch( *mode_ptr )
330                         {
331                                 /* Channel modes */
332                                 case 'i':
333                                         /* Invite-Only */
334                                         if( modeok ) x[0] = 'i';
335                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
336                                         break;
337                                 case 'm':
338                                         /* Moderated */
339                                         if( modeok ) x[0] = 'm';
340                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
341                                         break;
342                                 case 'n':
343                                         /* kein Schreiben in den Channel von aussen */
344                                         if( modeok ) x[0] = 'n';
345                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
346                                         break;
347                                 case 't':
348                                         /* Topic Lock */
349                                         if( modeok ) x[0] = 't';
350                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
351                                         break;
352                                 case 'P':
353                                         /* Persistent channel */
354                                         if( modeok )
355                                         {
356                                                 if( set && ( ! Client_OperByMe( Client )))
357                                                 {
358                                                         /* Only IRC operators are allowed to set P mode */
359                                                         ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
360                                                 }
361                                                 else x[0] = 'P';
362                                         }
363                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
364                                         break;
365
366                                 /* Channel user modes */
367                                 case 'o':
368                                         /* Channel operator */
369                                 case 'v':
370                                         /* Voice */
371                                         if( arg_arg > mode_arg )
372                                         {
373                                                 if( modeok )
374                                                 {
375                                                         client = Client_Search( Req->argv[arg_arg] );
376                                                         if( client ) x[0] = *mode_ptr;
377                                                         else ok = IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[arg_arg] );
378                                                 }
379                                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
380                                                 arg_arg++;
381                                         }
382                                         else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
383                                         break;
384
385                                 /* Channel lists */
386                                 case 'I':
387                                         /* Invite lists */
388                                         if( arg_arg > mode_arg )
389                                         {
390                                                 /* modify list */
391                                                 if( modeok )
392                                                 {
393                                                         if( set ) Add_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
394                                                         else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
395                                                 }
396                                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
397                                                 arg_arg++;
398                                         }
399                                         else Lists_ShowInvites( Origin, Channel );
400                                         break;
401                                 case 'b':
402                                         /* Ban lists */
403                                         if( arg_arg > mode_arg )
404                                         {
405                                                 /* modify list */
406                                                 if( modeok )
407                                                 {
408                                                         if( set ) Add_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
409                                                         else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
410                                                 }
411                                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
412                                                 arg_arg++;
413                                         }
414                                         else Lists_ShowBans( Origin, Channel );
415                                         break;
416
417                                 default:
418                                         Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
419                                         ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
420                                         x[0] = '\0';
421                         }
422                 }
423                 if( ! ok ) break;
424
425                 /* Is there a valid mode change? */
426                 if( ! x[0] ) continue;
427
428                 if( set )
429                 {
430                         /* Set mode */
431                         if( client )
432                         {
433                                 /* Channel-User-Mode */
434                                 if( Channel_UserModeAdd( Channel, client, x[0] ))
435                                 {
436                                         strcat( the_modes, x );
437                                         strcat( the_args, Client_ID( client ));
438                                         strcat( the_args, " " );
439                                 }
440                         }
441                         else
442                         {
443                                 /* Channel-Mode */
444                                 if( Channel_ModeAdd( Channel, x[0] )) strcat( the_modes, x );
445                         }
446                 }
447                 else
448                 {
449                         /* Unset mode */
450                         if( client )
451                         {
452                                 /* Channel-User-Mode */
453                                 if( Channel_UserModeDel( Channel, client, x[0] ))
454                                 {
455                                         strcat( the_modes, x );
456                                         strcat( the_args, Client_ID( client ));
457                                         strcat( the_args, " " );
458                                 }
459                         }
460                         else
461                         {
462                                 /* Channel-Mode */
463                                 if( Channel_ModeDel( Channel, x[0] )) strcat( the_modes, x );
464                         }
465                 }               
466         }
467
468         /* Are there changed modes? */
469         if( the_modes[1] )
470         {
471                 /* Clean up argument string if there are none */
472                 if( ! the_args[1] ) the_args[0] = '\0';
473
474                 if( Client_Type( Client ) == CLIENT_SERVER )
475                 {
476                         /* Forward mode changes to channel users and other servers */
477                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
478                         IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
479                 }
480                 else
481                 {
482                         /* Send reply to client and inform other servers and channel users */
483                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
484                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
485                         IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
486                 }
487                 Log( LOG_DEBUG, "User \"%s\" changes modes on %s: %s%s", Client_ID( Origin ), Channel_Name( Channel ), the_modes, the_args );
488         }
489
490         return CONNECTED;
491 } /* Channel_Mode */
492
493
494 GLOBAL BOOLEAN
495 IRC_AWAY( CLIENT *Client, REQUEST *Req )
496 {
497         assert( Client != NULL );
498         assert( Req != NULL );
499
500         /* Falsche Anzahl Parameter? */
501         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
502
503         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
504         {
505                 /* AWAY setzen */
506                 Client_SetAway( Client, Req->argv[0] );
507                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
508                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
509         }
510         else
511         {
512                 /* AWAY loeschen */
513                 Client_SetAway( Client, NULL );
514                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
515                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
516         }
517 } /* IRC_AWAY */
518
519
520 LOCAL BOOLEAN
521 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
522 {
523         CHAR *mask;
524
525         assert( Client != NULL );
526         assert( Channel != NULL );
527         assert( Pattern != NULL );
528
529         mask = Lists_MakeMask( Pattern );
530
531         if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
532         return Send_ListChange( "+I", Prefix, Client, Channel, mask );
533 } /* Add_Invite */
534
535
536 LOCAL BOOLEAN
537 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
538 {
539         CHAR *mask;
540
541         assert( Client != NULL );
542         assert( Channel != NULL );
543         assert( Pattern != NULL );
544
545         mask = Lists_MakeMask( Pattern );
546
547         if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
548         return Send_ListChange( "+b", Prefix, Client, Channel, mask );
549 } /* Add_Ban */
550
551
552 LOCAL BOOLEAN
553 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
554 {
555         CHAR *mask;
556
557         assert( Client != NULL );
558         assert( Channel != NULL );
559         assert( Pattern != NULL );
560
561         mask = Lists_MakeMask( Pattern );
562         Lists_DelInvited( mask, Channel );
563         return Send_ListChange( "-I", Prefix, Client, Channel, mask );
564 } /* Del_Invite */
565
566
567 LOCAL BOOLEAN
568 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
569 {
570         CHAR *mask;
571
572         assert( Client != NULL );
573         assert( Channel != NULL );
574         assert( Pattern != NULL );
575
576         mask = Lists_MakeMask( Pattern );
577         Lists_DelBanned( mask, Channel );
578         return Send_ListChange( "-b", Prefix, Client, Channel, mask );
579 } /* Del_Ban */
580
581
582 LOCAL BOOLEAN
583 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
584 {
585         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
586
587         BOOLEAN ok;
588
589         if( Client_Type( Client ) == CLIENT_USER )
590         {
591                 /* Bestaetigung an Client */
592                 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
593         }
594         else ok = TRUE;
595
596         /* an andere Server */
597         IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
598
599         /* und lokale User im Channel */
600         IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
601         
602         return ok;
603 } /* Send_ListChange */
604
605
606 /* -eof- */