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