2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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.
11 * IRC commands for mode changes (MODE, AWAY, ...)
17 static char UNUSED id[] = "$Id: irc-mode.c,v 1.22 2002/12/16 10:52:53 alex Exp $";
27 #include "irc-write.h"
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 ));
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 ));
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 ));
48 LOCAL BOOLEAN Send_ListChange PARAMS(( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask ));
52 IRC_MODE( CLIENT *Client, REQUEST *Req )
57 assert( Client != NULL );
58 assert( Req != NULL );
61 if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
63 /* Origin for answers */
64 if( Client_Type( Client ) == CLIENT_SERVER )
66 origin = Client_Search( Req->prefix );
67 if( ! origin ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
71 /* Channel or user mode? */
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] );
76 if( cl ) return Client_Mode( Client, Req, origin, cl );
77 if( chan ) return Channel_Mode( Client, Req, origin, chan );
79 /* No target found! */
80 return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
85 Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
87 /* Handle client mode requests */
89 CHAR the_modes[COMMAND_LEN], x[2], *mode_ptr;
93 /* Is the client allowed to request or change the modes? */
94 if( Client_Type( Client ) == CLIENT_USER )
96 /* Users are only allowed to manipulate their own modes! */
97 if( Target != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
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 ));
104 mode_ptr = Req->argv[mode_arg];
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 ));
111 /* Prepare reply string */
112 if( set ) strcpy( the_modes, "+" );
113 else strcpy( the_modes, "-" );
122 /* Try next argument if there's any */
124 if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
132 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
134 /* Action modifier ("+"/"-") must be changed ... */
135 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
137 /* Adjust last action modifier in result */
138 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
142 /* Append modifier character to result string */
143 x[0] = *mode_ptr; strcat( the_modes, x );
145 if( *mode_ptr == '+' ) set = TRUE;
160 /* IRC operator (only unsetable!) */
163 Client_SetOperByMe( Target, FALSE );
166 else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
169 /* Restricted (only setable) */
170 if( set ) x[0] = 'r';
171 else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
174 /* Server messages */
178 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ));
179 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
184 /* Is there a valid mode change? */
185 if( ! x[0] ) continue;
190 if( Client_ModeAdd( Target, x[0] )) strcat( the_modes, x );
196 if( Client_ModeDel( Target, x[0] )) strcat( the_modes, x );
200 /* Are there changed modes? */
203 /* Remoce needless action modifier characters */
204 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
206 if( Client_Type( Client ) == CLIENT_SERVER )
208 /* Forward modes to other servers */
209 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
213 /* Send reply to client and inform other servers */
214 ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s", Client_ID( Target ), the_modes );
215 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
217 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( Target ), Client_Modes( Target ));
225 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
227 /* Handle channel and channel-user modes */
229 CHAR the_modes[COMMAND_LEN], the_args[COMMAND_LEN], x[2], *mode_ptr;
230 BOOLEAN ok, set, modeok, skiponce;
231 INT mode_arg, arg_arg;
234 /* Mode request: let's answer it :-) */
235 if( Req->argc == 1 ) return IRC_WriteStrClient( Origin, RPL_CHANNELMODEIS_MSG, Client_ID( Origin ), Channel_Name( Channel ), Channel_Modes( Channel ));
237 /* Is the user allowed to change modes? */
238 if( Client_Type( Client ) == CLIENT_USER )
240 if( strchr( Channel_UserModes( Channel, Origin ), 'o' )) modeok = TRUE;
242 if( Conf_OperCanMode )
244 /* auch IRC-Operatoren duerfen MODE verwenden */
245 if( Client_OperByMe( Origin )) modeok = TRUE;
251 mode_ptr = Req->argv[mode_arg];
252 if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
255 /* Initial state: set or unset modes? */
257 if( *mode_ptr == '-' ) set = FALSE;
258 else if( *mode_ptr == '+' ) set = TRUE;
259 else set = skiponce = TRUE;
261 /* Prepare reply string */
262 if( set ) strcpy( the_modes, "+" );
263 else strcpy( the_modes, "-" );
264 strcpy( the_args, " " );
270 if( ! skiponce ) mode_ptr++;
273 /* Try next argument if there's any */
274 if( arg_arg > mode_arg ) mode_arg = arg_arg;
276 if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
278 if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
287 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
289 /* Action modifier ("+"/"-") must be changed ... */
290 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
292 /* Adjust last action modifier in result */
293 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
297 /* Append modifier character to result string */
298 x[0] = *mode_ptr; strcat( the_modes, x );
300 if( *mode_ptr == '+' ) set = TRUE;
306 /* Are there arguments left? */
307 if( arg_arg >= Req->argc ) arg_arg = -1;
317 if( modeok ) x[0] = 'i';
318 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
322 if( modeok ) x[0] = 'm';
323 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
326 /* kein Schreiben in den Channel von aussen */
327 if( modeok ) x[0] = 'n';
328 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
332 if( modeok ) x[0] = 't';
333 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
336 /* Persistent channel */
339 if( set && ( ! Client_OperByMe( Client )))
341 /* Only IRC operators are allowed to set P mode */
342 ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
346 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
349 /* Channel user modes */
351 /* Channel operator */
354 if( arg_arg > mode_arg )
358 client = Client_Search( Req->argv[arg_arg] );
359 if( client ) x[0] = *mode_ptr;
360 else ok = IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[arg_arg] );
362 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
363 Req->argv[arg_arg][0] = '\0';
366 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
372 if( arg_arg > mode_arg )
377 if( set ) Add_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
378 else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
380 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
381 Req->argv[arg_arg][0] = '\0';
384 else Lists_ShowInvites( Origin, Channel );
388 if( arg_arg > mode_arg )
393 if( set ) Add_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
394 else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
396 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
397 Req->argv[arg_arg][0] = '\0';
400 else Lists_ShowBans( Origin, Channel );
404 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
405 if( Client_Type( Client ) != CLIENT_SERVER ) ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
410 /* Is there a valid mode change? */
411 if( ! x[0] ) continue;
418 /* Channel-User-Mode */
419 if( Channel_UserModeAdd( Channel, client, x[0] ))
421 strcat( the_args, Client_ID( client ));
422 strcat( the_args, " " ); strcat( the_modes, x );
423 Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
429 if( Channel_ModeAdd( Channel, x[0] ))
431 strcat( the_modes, x );
432 Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
441 /* Channel-User-Mode */
442 if( Channel_UserModeDel( Channel, client, x[0] ))
444 strcat( the_args, Client_ID( client ));
445 strcat( the_args, " " ); strcat( the_modes, x );
446 Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
452 if( Channel_ModeDel( Channel, x[0] ))
454 strcat( the_modes, x );
455 Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
461 /* Are there changed modes? */
464 /* Clean up mode string */
465 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
467 /* Clean up argument string if there are none */
468 if( ! the_args[1] ) the_args[0] = '\0';
470 if( Client_Type( Client ) == CLIENT_SERVER )
472 /* Forward mode changes to channel users and other servers */
473 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
474 IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
478 /* Send reply to client and inform other servers and channel users */
479 ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
480 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
481 IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
490 IRC_AWAY( CLIENT *Client, REQUEST *Req )
492 assert( Client != NULL );
493 assert( Req != NULL );
495 /* Falsche Anzahl Parameter? */
496 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
498 if(( Req->argc == 1 ) && (Req->argv[0][0] ))
501 Client_SetAway( Client, Req->argv[0] );
502 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
503 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
508 Client_SetAway( Client, NULL );
509 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
510 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
516 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
520 assert( Client != NULL );
521 assert( Channel != NULL );
522 assert( Pattern != NULL );
524 mask = Lists_MakeMask( Pattern );
526 if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
527 return Send_ListChange( "+I", Prefix, Client, Channel, mask );
532 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
536 assert( Client != NULL );
537 assert( Channel != NULL );
538 assert( Pattern != NULL );
540 mask = Lists_MakeMask( Pattern );
542 if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
543 return Send_ListChange( "+b", Prefix, Client, Channel, mask );
548 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
552 assert( Client != NULL );
553 assert( Channel != NULL );
554 assert( Pattern != NULL );
556 mask = Lists_MakeMask( Pattern );
557 Lists_DelInvited( mask, Channel );
558 return Send_ListChange( "-I", Prefix, Client, Channel, mask );
563 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
567 assert( Client != NULL );
568 assert( Channel != NULL );
569 assert( Pattern != NULL );
571 mask = Lists_MakeMask( Pattern );
572 Lists_DelBanned( mask, Channel );
573 return Send_ListChange( "-b", Prefix, Client, Channel, mask );
578 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
580 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
584 if( Client_Type( Client ) == CLIENT_USER )
586 /* Bestaetigung an Client */
587 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
591 /* an andere Server */
592 IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
594 /* und lokale User im Channel */
595 IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
598 } /* Send_ListChange */