]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-mode.c
675164d652600d811e55a0876d42c7b317f1316d
[ngircd-alex.git] / src / ngircd / irc-mode.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2005 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.52 2008/02/24 18:44:41 fw Exp $";
18
19 #include "imp.h"
20 #include <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24
25 #include "defines.h"
26 #include "conn.h"
27 #include "client.h"
28 #include "channel.h"
29 #include "irc-write.h"
30 #include "lists.h"
31 #include "log.h"
32 #include "parse.h"
33 #include "messages.h"
34 #include "resolve.h"
35 #include "conf.h"
36
37 #include "exp.h"
38 #include "irc-mode.h"
39
40
41 static bool Client_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target ));
42 static bool Channel_Mode PARAMS(( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel ));
43
44 static bool Add_Ban_Invite PARAMS((int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
45
46 static bool Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
47 static bool Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern ));
48
49 static bool Send_ListChange PARAMS(( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Mask ));
50
51
52 GLOBAL bool
53 IRC_MODE( CLIENT *Client, REQUEST *Req )
54 {
55         CLIENT *cl, *origin;
56         CHANNEL *chan;
57
58         assert( Client != NULL );
59         assert( Req != NULL );
60
61         /* No parameters? */
62         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
63
64         /* Origin for answers */
65         if( Client_Type( Client ) == CLIENT_SERVER )
66         {
67                 origin = Client_Search( Req->prefix );
68                 if( ! origin ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
69         }
70         else origin = Client;
71
72         /* Channel or user mode? */
73         cl = NULL; chan = NULL;
74         if (Client_IsValidNick(Req->argv[0]))
75                 cl = Client_Search(Req->argv[0]);
76         if (Channel_IsValidName(Req->argv[0]))
77                 chan = Channel_Search(Req->argv[0]);
78
79         if (cl)
80                 return Client_Mode(Client, Req, origin, cl);
81         if (chan)
82                 return Channel_Mode(Client, Req, origin, chan);
83
84         /* No target found! */
85         return IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
86                         Client_ID(Client), Req->argv[0]);
87 } /* IRC_MODE */
88
89
90 static bool
91 Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
92 {
93         /* Handle client mode requests */
94
95         char the_modes[COMMAND_LEN], x[2], *mode_ptr;
96         bool ok, set;
97         int mode_arg;
98         size_t len;
99
100         /* Is the client allowed to request or change the modes? */
101         if( Client_Type( Client ) == CLIENT_USER )
102         {
103                 /* Users are only allowed to manipulate their own modes! */
104                 if( Target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
105         }
106
107         /* Mode request: let's answer it :-) */
108         if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_UMODEIS_MSG, Client_ID( Origin ), Client_Modes( Target ));
109
110         mode_arg = 1;
111         mode_ptr = Req->argv[mode_arg];
112
113         /* Initial state: set or unset modes? */
114         if( *mode_ptr == '+' ) set = true;
115         else if( *mode_ptr == '-' ) set = false;
116         else return IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Origin ));
117
118         /* Prepare reply string */
119         if( set ) strcpy( the_modes, "+" );
120         else strcpy( the_modes, "-" );
121
122         x[1] = '\0';
123         ok = CONNECTED;
124         while( mode_ptr )
125         {
126                 mode_ptr++;
127                 if( ! *mode_ptr )
128                 {
129                         /* Try next argument if there's any */
130                         mode_arg++;
131                         if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
132                         else break;
133                 }
134                 
135                 switch( *mode_ptr )
136                 {
137                         case '+':
138                         case '-':
139                                 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
140                                 {
141                                         /* Action modifier ("+"/"-") must be changed ... */
142                                         len = strlen( the_modes ) - 1;
143                                         if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' ))
144                                         {
145                                                 /* Adjust last action modifier in result */
146                                                 the_modes[len] = *mode_ptr;
147                                         }
148                                         else
149                                         {
150                                                 /* Append modifier character to result string */
151                                                 x[0] = *mode_ptr;
152                                                 strlcat( the_modes, x, sizeof( the_modes ));
153                                         }
154                                         if( *mode_ptr == '+' ) set = true;
155                                         else set = false;
156                                 }
157                                 continue;
158                 }
159                 
160                 /* Validate modes */
161                 x[0] = '\0';
162                 switch( *mode_ptr )
163                 {
164                         case 'i': /* Invisible */
165                         case 's': /* Server messages */
166                         case 'w': /* Wallops messages */
167                                 x[0] = *mode_ptr;
168                                 break;
169
170                         case 'a': /* Away */
171                                 if( Client_Type( Client ) == CLIENT_SERVER )
172                                 {
173                                         x[0] = 'a';
174                                         Client_SetAway( Origin, DEFAULT_AWAY_MSG );
175                                 }
176                                 else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
177                                 break;
178
179                         case 'o': /* IRC operator (only unsettable!) */
180                                 if(( ! set ) || ( Client_Type( Client ) == CLIENT_SERVER ))
181                                 {
182                                         Client_SetOperByMe( Target, false );
183                                         x[0] = 'o';
184                                 }
185                                 else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
186                                 break;
187
188                         case 'r': /* Restricted (only settable) */
189                                 if(( set ) || ( Client_Type( Client ) == CLIENT_SERVER )) x[0] = 'r';
190                                 else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
191                                 break;
192
193                         default:
194                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ));
195                                 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
196                                 x[0] = '\0';
197                                 goto client_exit;
198                 }
199                 if( ! ok ) break;
200
201                 /* Is there a valid mode change? */
202                 if( ! x[0] ) continue;
203
204                 if( set )
205                 {
206                         /* Set mode */
207                         if( Client_ModeAdd( Target, x[0] )) strlcat( the_modes, x, sizeof( the_modes ));
208
209                 }
210                 else
211                 {
212                         /* Unset mode */
213                         if( Client_ModeDel( Target, x[0] )) strlcat( the_modes, x, sizeof( the_modes ));
214                 }               
215         }
216 client_exit:
217         
218         /* Are there changed modes? */
219         if( the_modes[1] )
220         {
221                 /* Remoce needless action modifier characters */
222                 len = strlen( the_modes ) - 1;
223                 if(( the_modes[len] == '+' ) || ( the_modes[len] == '-' )) the_modes[len] = '\0';
224
225                 if( Client_Type( Client ) == CLIENT_SERVER )
226                 {
227                         /* Forward modes to other servers */
228                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
229                 }
230                 else
231                 {
232                         /* Send reply to client and inform other servers */
233                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
234                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
235                 }
236                 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( Target ), Client_Modes( Target ));
237         }
238         
239         IRC_SetPenalty( Client, 1 );    
240         return ok;
241 } /* Client_Mode */
242
243
244 static bool
245 Channel_Mode_Answer_Request(CLIENT *Origin, CHANNEL *Channel)
246 {
247         char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], argadd[CLIENT_PASS_LEN];
248         const char *mode_ptr;
249
250         /* Member or not? -- That's the question! */
251         if (!Channel_IsMemberOf(Channel, Origin))
252                 return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
253                         Client_ID(Origin), Channel_Name(Channel), Channel_Modes(Channel));
254
255         /* The sender is a member: generate extended reply */
256         strlcpy(the_modes, Channel_Modes(Channel), sizeof(the_modes));
257         mode_ptr = the_modes;
258         the_args[0] = '\0';
259
260         while(*mode_ptr) {
261                 switch(*mode_ptr) {
262                 case 'l':
263                         snprintf(argadd, sizeof(argadd), " %lu", Channel_MaxUsers(Channel));
264                         strlcat(the_args, argadd, sizeof(the_args));
265                         break;
266                 case 'k':
267                         strlcat(the_args, " ", sizeof(the_args));
268                         strlcat(the_args, Channel_Key(Channel), sizeof(the_args));
269                         break;
270                 }
271                 mode_ptr++;
272         }
273         if (the_args[0])
274                 strlcat(the_modes, the_args, sizeof(the_modes));
275
276         return IRC_WriteStrClient(Origin, RPL_CHANNELMODEIS_MSG,
277                 Client_ID(Origin), Channel_Name(Channel), the_modes);
278 }
279
280
281 static bool
282 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
283 {
284         /* Handle channel and channel-user modes */
285
286         char the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], argadd[CLIENT_PASS_LEN], *mode_ptr;
287         bool ok, set, modeok = true, skiponce, use_servermode = false;
288         int mode_arg, arg_arg;
289         CLIENT *client;
290         long l;
291         size_t len;
292
293         /* Mode request: let's answer it :-) */
294         if (Req->argc <= 1)
295                 return Channel_Mode_Answer_Request(Origin, Channel);
296
297         /* Is the user allowed to change modes? */
298         if (Client_Type(Client) == CLIENT_USER) {
299                 /* Is the originating user on that channel? */
300                 if (!Channel_IsMemberOf(Channel, Origin))
301                         return IRC_WriteStrClient(Origin, ERR_NOTONCHANNEL_MSG,
302                                 Client_ID(Origin), Channel_Name(Channel));
303                 modeok = false;
304                 /* channel operator? */
305                 if (strchr(Channel_UserModes(Channel, Origin), 'o'))
306                         modeok = true;
307                 else if(Conf_OperCanMode) {
308                         /* IRC-Operators can use MODE as well */
309                         if (Client_OperByMe(Origin)) {
310                                 modeok = true;
311                                 if (Conf_OperServerMode)
312                                         use_servermode = true; /* Change Origin to Server */
313                         }
314                 }
315         }
316
317         mode_arg = 1;
318         mode_ptr = Req->argv[mode_arg];
319         if (Req->argc > mode_arg + 1)
320                 arg_arg = mode_arg + 1;
321         else
322                 arg_arg = -1;
323
324         /* Initial state: set or unset modes? */
325         skiponce = false;
326         switch (*mode_ptr) {
327         case '-': set = false; break;
328         case '+': set = true; break;
329         default:
330                 set = true;
331                 skiponce = true;
332         }
333
334         /* Prepare reply string */
335         strcpy(the_modes, set ? "+" : "-");
336         the_args[0] = '\0';
337
338         x[1] = '\0';
339         ok = CONNECTED;
340         while (mode_ptr) {
341                 if (! skiponce)
342                         mode_ptr++;
343                 if (!*mode_ptr) {
344                         /* Try next argument if there's any */
345                         if (arg_arg > mode_arg)
346                                 mode_arg = arg_arg;
347                         else
348                                 mode_arg++;
349
350                         if (mode_arg >= Req->argc)
351                                 break;
352                         mode_ptr = Req->argv[mode_arg];
353
354                         if (Req->argc > mode_arg + 1)
355                                 arg_arg = mode_arg + 1;
356                         else
357                                 arg_arg = -1;
358                 }
359                 skiponce = false;
360
361                 switch (*mode_ptr) {
362                 case '+':
363                 case '-':
364                         if (((*mode_ptr == '+') && !set) || ((*mode_ptr == '-') && set)) {
365                                 /* Action modifier ("+"/"-") must be changed ... */
366                                 len = strlen( the_modes ) - 1;
367                                 if ((the_modes[len] == '+') || (the_modes[len] == '-')) {
368                                         /* Adjust last action modifier in result */
369                                         the_modes[len] = *mode_ptr;
370                                 } else {
371                                         /* Append modifier character to result string */
372                                         x[0] = *mode_ptr;
373                                         strlcat(the_modes, x, sizeof(the_modes));
374                                 }
375                                 set = *mode_ptr == '+';
376                         }
377                         continue;
378                 }
379
380                 /* Are there arguments left? */
381                 if( arg_arg >= Req->argc ) arg_arg = -1;
382
383                 /* Validate modes */
384                 x[0] = '\0';
385                 argadd[0] = '\0';
386                 client = NULL;
387                 switch( *mode_ptr )
388                 {
389                         /* --- Channel modes --- */
390
391                         case 'i': /* Invite only */
392                         case 'm': /* Moderated */
393                         case 'n': /* Only members can write */
394                         case 's': /* Secret channel */
395                         case 't': /* Topic locked */
396                                 if( modeok ) x[0] = *mode_ptr;
397                                 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
398                                 break;
399
400                         case 'k': /* Channel key */
401                                 if( ! set )
402                                 {
403                                         if( modeok ) x[0] = *mode_ptr;
404                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
405                                         break;
406                                 }
407                                 if( arg_arg > mode_arg )
408                                 {
409                                         if( modeok )
410                                         {
411                                                 Channel_ModeDel( Channel, 'k' );
412                                                 Channel_SetKey( Channel, Req->argv[arg_arg] );
413                                                 strlcpy( argadd, Channel_Key( Channel ), sizeof( argadd ));
414                                                 x[0] = *mode_ptr;
415                                         }
416                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
417                                         Req->argv[arg_arg][0] = '\0';
418                                         arg_arg++;
419                                 }
420                                 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
421                                 break;
422
423                         case 'l': /* Member limit */
424                                 if( ! set )
425                                 {
426                                         if( modeok ) x[0] = *mode_ptr;
427                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
428                                         break;
429                                 }
430                                 if( arg_arg > mode_arg )
431                                 {
432                                         if( modeok )
433                                         {
434                                                 l = atol( Req->argv[arg_arg] );
435                                                 if( l > 0 && l < 0xFFFF )
436                                                 {
437                                                         Channel_ModeDel( Channel, 'l' );
438                                                         Channel_SetMaxUsers( Channel, l );
439                                                         snprintf( argadd, sizeof( argadd ), "%ld", l );
440                                                         x[0] = *mode_ptr;
441                                                 }
442                                         }
443                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
444                                         Req->argv[arg_arg][0] = '\0';
445                                         arg_arg++;
446                                 }
447                                 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
448                                 break;
449
450                         case 'P': /* Persistent channel */
451                                 if (modeok) {
452                                         /* Only IRC operators are allowed to
453                                          * set the 'P' channel mode! */
454                                         if (set && ! (Client_OperByMe(Client)
455                                             || Client_Type(Client) == CLIENT_SERVER)) {
456                                                 ok = IRC_WriteStrClient(Origin,
457                                                         ERR_NOPRIVILEGES_MSG,
458                                                         Client_ID(Origin));
459                                         } else
460                                                 x[0] = 'P';
461                                 } else
462                                         ok = IRC_WriteStrClient(Origin,
463                                                 ERR_CHANOPRIVSNEEDED_MSG,
464                                                 Client_ID(Origin),
465                                                 Channel_Name(Channel));
466                                 break;
467
468                         /* --- Channel user modes --- */
469
470                         case 'o': /* Channel operator */
471                         case 'v': /* Voice */
472                                 if( arg_arg > mode_arg )
473                                 {
474                                         if( modeok )
475                                         {
476                                                 client = Client_Search( Req->argv[arg_arg] );
477                                                 if( client ) x[0] = *mode_ptr;
478                                                 else ok = IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[arg_arg] );
479                                         }
480                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
481                                         Req->argv[arg_arg][0] = '\0';
482                                         arg_arg++;
483                                 }
484                                 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
485                                 break;
486
487                         /* --- Channel lists --- */
488
489                         case 'I': /* Invite lists */
490                                 if( arg_arg > mode_arg )
491                                 {
492                                         /* modify list */
493                                         if( modeok )
494                                         {
495                                                 if( set ) Add_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg] );
496                                                 else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
497                                         }
498                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
499                                         Req->argv[arg_arg][0] = '\0';
500                                         arg_arg++;
501                                 }
502                                 else Channel_ShowInvites( Origin, Channel );
503                                 break;
504
505                         case 'b': /* Ban lists */
506                                 if( arg_arg > mode_arg )
507                                 {
508                                         /* modify list */
509                                         if( modeok )
510                                         {
511                                                 if( set ) Add_Ban_Invite(*mode_ptr, Origin, Client, Channel, Req->argv[arg_arg] );
512                                                 else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
513                                         }
514                                         else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
515                                         Req->argv[arg_arg][0] = '\0';
516                                         arg_arg++;
517                                 }
518                                 else Channel_ShowBans( Origin, Channel );
519                                 break;
520
521                         default:
522                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
523                                 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
524                                 x[0] = '\0';
525                                 goto chan_exit;
526                 }
527                 if( ! ok ) break;
528
529                 /* Is there a valid mode change? */
530                 if( ! x[0] ) continue;
531
532                 /* Validate target client */
533                 if( client && ( ! Channel_IsMemberOf( Channel, client )))
534                 {
535                         if( ! IRC_WriteStrClient( Origin, ERR_USERNOTINCHANNEL_MSG, Client_ID( Origin ), Client_ID( client ), Channel_Name( Channel ))) break;
536                         continue;
537                 }
538
539                 if( set )
540                 {
541                         /* Set mode */
542                         if( client )
543                         {
544                                 /* Channel-User-Mode */
545                                 if( Channel_UserModeAdd( Channel, client, x[0] ))
546                                 {
547                                         strlcat( the_args, " ", sizeof( the_args ));
548                                         strlcat( the_args, Client_ID( client ), sizeof( the_args ));
549                                         strlcat( the_modes, x, sizeof( the_modes ));
550                                         Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
551                                 }
552                         }
553                         else
554                         {
555                                 /* Channel-Mode */
556                                 if( Channel_ModeAdd( Channel, x[0] ))
557                                 {
558                                         strlcat( the_modes, x, sizeof( the_modes ));
559                                         Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
560                                 }
561                         }
562                 }
563                 else
564                 {
565                         /* Unset mode */
566                         if( client )
567                         {
568                                 /* Channel-User-Mode */
569                                 if( Channel_UserModeDel( Channel, client, x[0] ))
570                                 {
571                                         strlcat( the_args, " ", sizeof( the_args ));
572                                         strlcat( the_args, Client_ID( client ), sizeof( the_args ));
573                                         strlcat( the_modes, x, sizeof( the_modes ));
574                                         Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
575                                 }
576                         }
577                         else
578                         {
579                                 /* Channel-Mode */
580                                 if( Channel_ModeDel( Channel, x[0] ))
581                                 {
582                                         strlcat( the_modes, x, sizeof( the_modes ));
583                                         Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
584                                 }
585                         }
586                 }
587
588                 /* Are there additional arguments to add? */
589                 if( argadd[0] )
590                 {
591                         strlcat( the_args, " ", sizeof( the_args ));
592                         strlcat( the_args, argadd, sizeof( the_args ));
593                 }
594         }
595 chan_exit:
596
597         /* Are there changed modes? */
598         if (the_modes[1]) {
599                 /* Clean up mode string */
600                 len = strlen(the_modes) - 1;
601                 if ((the_modes[len] == '+') || (the_modes[len] == '-'))
602                         the_modes[len] = '\0';
603
604                 if (Client_Type(Client) == CLIENT_SERVER) {
605                         /* Forward mode changes to channel users and other servers */
606                         IRC_WriteStrServersPrefix(Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args);
607                         IRC_WriteStrChannelPrefix(Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args);
608                 } else {
609                         if (use_servermode)
610                                 Origin = Client_ThisServer();
611                         /* Send reply to client and inform other servers and channel users */
612                         ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
613                         IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
614                         IRC_WriteStrChannelPrefix( Client, Channel, Origin, false, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
615                 }
616         }
617
618         IRC_SetPenalty( Client, 1 );
619         return CONNECTED;
620 } /* Channel_Mode */
621
622
623 GLOBAL bool
624 IRC_AWAY( CLIENT *Client, REQUEST *Req )
625 {
626         assert( Client != NULL );
627         assert( Req != NULL );
628
629         /* Falsche Anzahl Parameter? */
630         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
631
632         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
633         {
634                 /* AWAY setzen */
635                 Client_SetAway( Client, Req->argv[0] );
636                 Client_ModeAdd( Client, 'a' );
637                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
638                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
639         }
640         else
641         {
642                 /* AWAY loeschen */
643                 Client_ModeDel( Client, 'a' );
644                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
645                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
646         }
647 } /* IRC_AWAY */
648
649
650 static bool
651 Add_Ban_Invite(int what, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
652 {
653         const char *mask;
654         bool already;
655         bool ret;
656
657         assert( Client != NULL );
658         assert( Channel != NULL );
659         assert( Pattern != NULL );
660         assert(what == 'I' || what == 'b');
661
662         mask = Lists_MakeMask(Pattern);
663
664         already = Lists_CheckDupeMask(Channel_GetListInvites(Channel), mask);
665         if (!already) {
666                 if (what == 'I')
667                         ret = Channel_AddInvite(Channel, mask, false);
668                 else
669                         ret = Channel_AddBan(Channel, mask);
670                 if (!ret)
671                         return CONNECTED;
672         }
673         if (already && (Client_Type(Prefix) == CLIENT_SERVER))
674                 return CONNECTED;
675
676         if (what == 'I')
677                 return Send_ListChange("+I", Prefix, Client, Channel, mask);
678         return Send_ListChange("+b", Prefix, Client, Channel, mask);
679 }
680
681
682 static bool
683 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
684 {
685         char *mask;
686
687         assert( Client != NULL );
688         assert( Channel != NULL );
689         assert( Pattern != NULL );
690
691         mask = Lists_MakeMask( Pattern );
692         Lists_Del(Channel_GetListInvites(Channel), mask);
693         return Send_ListChange( "-I", Prefix, Client, Channel, mask );
694 } /* Del_Invite */
695
696
697 static bool
698 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, char *Pattern )
699 {
700         char *mask;
701
702         assert( Client != NULL );
703         assert( Channel != NULL );
704         assert( Pattern != NULL );
705
706         mask = Lists_MakeMask( Pattern );
707         Lists_Del(Channel_GetListBans(Channel), mask);
708         return Send_ListChange( "-b", Prefix, Client, Channel, mask );
709 } /* Del_Ban */
710
711
712 static bool
713 Send_ListChange( char *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, const char *Mask )
714 {
715         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
716
717         bool ok;
718
719         if( Client_Type( Client ) == CLIENT_USER )
720         {
721                 /* Bestaetigung an Client */
722                 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
723         }
724         else ok = true;
725
726         /* an andere Server */
727         IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
728
729         /* und lokale User im Channel */
730         IRC_WriteStrChannelPrefix( Client, Channel, Prefix, false, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
731         
732         return ok;
733 } /* Send_ListChange */
734
735
736 /* -eof- */