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.21 2002/12/15 16:29:18 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;
152 if( Client_Type( Client ) == CLIENT_SERVER )
154 /* MODE request was received from a server:
155 * therefore don't validate but trust it! */
168 /* IRC operator (only unsetable!) */
171 Client_SetOperByMe( Target, FALSE );
174 else ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
177 /* Restricted (only setable) */
178 if( set ) x[0] = 'r';
179 else ok = IRC_WriteStrClient( Origin, ERR_RESTRICTED_MSG, Client_ID( Origin ));
182 /* Server messages */
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 );
193 /* Is there a valid mode change? */
194 if( ! x[0] ) continue;
199 if( Client_ModeAdd( Target, x[0] )) strcat( the_modes, x );
205 if( Client_ModeDel( Target, x[0] )) strcat( the_modes, x );
209 /* Are there changed modes? */
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';
215 if( Client_Type( Client ) == CLIENT_SERVER )
217 /* Forward modes to other servers */
218 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s :%s", Client_ID( Target ), the_modes );
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 );
226 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( Target ), Client_Modes( Target ));
234 Channel_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel )
236 /* Handle channel and channel-user modes */
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;
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 ));
246 /* Is the user allowed to change modes? */
247 if( Client_Type( Client ) == CLIENT_USER )
249 if( strchr( Channel_UserModes( Channel, Origin ), 'o' )) modeok = TRUE;
251 if( Conf_OperCanMode )
253 /* auch IRC-Operatoren duerfen MODE verwenden */
254 if( Client_OperByMe( Origin )) modeok = TRUE;
260 mode_ptr = Req->argv[mode_arg];
261 if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
264 /* Initial state: set or unset modes? */
266 if( *mode_ptr == '-' ) set = FALSE;
267 else if( *mode_ptr == '+' ) set = TRUE;
268 else set = skiponce = TRUE;
270 /* Prepare reply string */
271 if( set ) strcpy( the_modes, "+" );
272 else strcpy( the_modes, "-" );
273 strcpy( the_args, " " );
279 if( ! skiponce ) mode_ptr++;
282 /* Try next argument if there's any */
283 if( arg_arg > mode_arg ) mode_arg = arg_arg;
285 if( mode_arg < Req->argc ) mode_ptr = Req->argv[mode_arg];
287 if( Req->argc > mode_arg + 1 ) arg_arg = mode_arg + 1;
296 if((( *mode_ptr == '+' ) && ( ! set )) || (( *mode_ptr == '-' ) && ( set )))
298 /* Action modifier ("+"/"-") must be changed ... */
299 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' ))
301 /* Adjust last action modifier in result */
302 the_modes[strlen( the_modes ) - 1] = *mode_ptr;
306 /* Append modifier character to result string */
307 x[0] = *mode_ptr; strcat( the_modes, x );
309 if( *mode_ptr == '+' ) set = TRUE;
315 /* Are there arguments left? */
316 if( arg_arg >= Req->argc ) arg_arg = -1;
320 if( Client_Type( Client ) == CLIENT_SERVER )
322 /* MODE request was received from a server:
323 * therefore don't validate but trust it! */
334 if( modeok ) x[0] = 'i';
335 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
339 if( modeok ) x[0] = 'm';
340 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
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 ));
349 if( modeok ) x[0] = 't';
350 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
353 /* Persistent channel */
356 if( set && ( ! Client_OperByMe( Client )))
358 /* Only IRC operators are allowed to set P mode */
359 ok = IRC_WriteStrClient( Origin, ERR_NOPRIVILEGES_MSG, Client_ID( Origin ));
363 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
366 /* Channel user modes */
368 /* Channel operator */
371 if( arg_arg > mode_arg )
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] );
379 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
380 Req->argv[arg_arg][0] = '\0';
383 else ok = IRC_WriteStrClient( Origin, ERR_NEEDMOREPARAMS_MSG, Client_ID( Origin ), Req->command );
389 if( arg_arg > mode_arg )
394 if( set ) Add_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
395 else Del_Invite( Origin, Client, Channel, Req->argv[arg_arg] );
397 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
398 Req->argv[arg_arg][0] = '\0';
401 else Lists_ShowInvites( Origin, Channel );
405 if( arg_arg > mode_arg )
410 if( set ) Add_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
411 else Del_Ban( Origin, Client, Channel, Req->argv[arg_arg] );
413 else ok = IRC_WriteStrClient( Origin, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Origin ), Channel_Name( Channel ));
414 Req->argv[arg_arg][0] = '\0';
417 else Lists_ShowBans( Origin, Channel );
421 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\" on %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Origin ), Channel_Name( Channel ));
422 ok = IRC_WriteStrClient( Origin, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Origin ), set ? '+' : '-', *mode_ptr );
428 /* Is there a valid mode change? */
429 if( ! x[0] ) continue;
436 /* Channel-User-Mode */
437 if( Channel_UserModeAdd( Channel, client, x[0] ))
439 strcat( the_args, Client_ID( client ));
440 strcat( the_args, " " ); strcat( the_modes, x );
441 Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
447 if( Channel_ModeAdd( Channel, x[0] ))
449 strcat( the_modes, x );
450 Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
459 /* Channel-User-Mode */
460 if( Channel_UserModeDel( Channel, client, x[0] ))
462 strcat( the_args, Client_ID( client ));
463 strcat( the_args, " " ); strcat( the_modes, x );
464 Log( LOG_DEBUG, "User \"%s\": Mode change on %s, now \"%s\"", Client_Mask( client ), Channel_Name( Channel ), Channel_UserModes( Channel, client ));
470 if( Channel_ModeDel( Channel, x[0] ))
472 strcat( the_modes, x );
473 Log( LOG_DEBUG, "Channel %s: Mode change, now \"%s\".", Channel_Name( Channel ), Channel_Modes( Channel ));
479 /* Are there changed modes? */
482 /* Clean up mode string */
483 if(( the_modes[strlen( the_modes ) - 1] == '+' ) || ( the_modes[strlen( the_modes ) - 1] == '-' )) the_modes[strlen( the_modes ) - 1] = '\0';
485 /* Clean up argument string if there are none */
486 if( ! the_args[1] ) the_args[0] = '\0';
488 if( Client_Type( Client ) == CLIENT_SERVER )
490 /* Forward mode changes to channel users and other servers */
491 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
492 IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
496 /* Send reply to client and inform other servers and channel users */
497 ok = IRC_WriteStrClientPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
498 IRC_WriteStrServersPrefix( Client, Origin, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
499 IRC_WriteStrChannelPrefix( Client, Channel, Origin, FALSE, "MODE %s %s%s", Channel_Name( Channel ), the_modes, the_args );
508 IRC_AWAY( CLIENT *Client, REQUEST *Req )
510 assert( Client != NULL );
511 assert( Req != NULL );
513 /* Falsche Anzahl Parameter? */
514 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
516 if(( Req->argc == 1 ) && (Req->argv[0][0] ))
519 Client_SetAway( Client, Req->argv[0] );
520 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
521 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
526 Client_SetAway( Client, NULL );
527 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
528 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
534 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
538 assert( Client != NULL );
539 assert( Channel != NULL );
540 assert( Pattern != NULL );
542 mask = Lists_MakeMask( Pattern );
544 if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
545 return Send_ListChange( "+I", Prefix, Client, Channel, mask );
550 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
554 assert( Client != NULL );
555 assert( Channel != NULL );
556 assert( Pattern != NULL );
558 mask = Lists_MakeMask( Pattern );
560 if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
561 return Send_ListChange( "+b", Prefix, Client, Channel, mask );
566 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
570 assert( Client != NULL );
571 assert( Channel != NULL );
572 assert( Pattern != NULL );
574 mask = Lists_MakeMask( Pattern );
575 Lists_DelInvited( mask, Channel );
576 return Send_ListChange( "-I", Prefix, Client, Channel, mask );
581 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
585 assert( Client != NULL );
586 assert( Channel != NULL );
587 assert( Pattern != NULL );
589 mask = Lists_MakeMask( Pattern );
590 Lists_DelBanned( mask, Channel );
591 return Send_ListChange( "-b", Prefix, Client, Channel, mask );
596 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
598 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
602 if( Client_Type( Client ) == CLIENT_USER )
604 /* Bestaetigung an Client */
605 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
609 /* an andere Server */
610 IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
612 /* und lokale User im Channel */
613 IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
616 } /* Send_ListChange */