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.19 2002/12/14 13:36:19 alex Exp $";
27 #include "irc-write.h"
39 LOCAL BOOLEAN Add_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
40 LOCAL BOOLEAN Add_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
42 LOCAL BOOLEAN Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
43 LOCAL BOOLEAN Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
45 LOCAL BOOLEAN Send_ListChange PARAMS(( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask ));
49 IRC_MODE( CLIENT *Client, REQUEST *Req )
51 CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
52 CLIENT *cl, *chan_cl, *prefix;
53 BOOLEAN set, ok, modeok;
56 assert( Client != NULL );
57 assert( Req != NULL );
59 cl = chan_cl = prefix = NULL;
62 /* Keine Parameter? */
63 if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
65 /* Ziel suchen: Client bzw. Channel */
66 if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
67 if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
69 /* Kein Ziel gefunden? */
70 if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
72 assert(( cl && chan ) != TRUE );
74 /* Falsche Anzahl Parameter? */
75 if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
76 if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
78 /* Prefix fuer Antworten etc. ermitteln */
79 if( Client_Type( Client ) == CLIENT_SERVER )
81 prefix = Client_Search( Req->prefix );
82 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
86 if(( chan ) && (( Req->argc == 2 ) || ( Req->argc == 3 )))
88 /* pruefen, ob "Listen-Operation": Invite, Ban */
89 if(( Req->argv[1][0] == '-' ) || ( Req->argv[1][0] == '+' )) mode_ptr = &Req->argv[1][1];
90 else mode_ptr = &Req->argv[1][0];
95 if( *mode_ptr == 'I' ) return Lists_ShowInvites( prefix, chan );
96 if( *mode_ptr == 'b' ) return Lists_ShowBans( prefix, chan );
100 /* Listen veraendern */
102 if( Client_Type( Client ) == CLIENT_USER )
104 /* Ist der User Channel-Operator? */
106 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
107 if( Conf_OperCanMode )
109 /* auch IRC-Operatoren duerfen MODE verwenden */
110 if( Client_OperByMe( Client )) modeok = TRUE;
115 Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
116 return IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
120 if( Req->argv[1][0] == '+' )
122 /* Listen-Eintrag hinzufuegen */
123 if( *mode_ptr == 'I' ) return Add_Invite( prefix, Client, chan, Req->argv[2] );
124 if( *mode_ptr == 'b' ) return Add_Ban( prefix, Client, chan, Req->argv[2] );
126 else if( Req->argv[1][0] == '-' )
128 /* Listen-Eintrag loeschen */
129 if( *mode_ptr == 'I' ) return Del_Invite( prefix, Client, chan, Req->argv[2] );
130 if( *mode_ptr == 'b' ) return Del_Ban( prefix, Client, chan, Req->argv[2] );
135 /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
136 if(( chan ) && (Req->argc == 3 ))
138 chan_cl = Client_Search( Req->argv[2] );
139 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
142 /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
143 if( Client_Type( Client ) == CLIENT_USER )
147 /* MODE ist nur fuer sich selber zulaessig! */
148 if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
152 /* Darf der User die Channel-Modes ermitteln? */
156 /* Werden die Modes "nur" erfragt? */
157 if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
158 if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
160 mode_ptr = Req->argv[1];
162 /* Sollen Modes gesetzt oder geloescht werden? */
165 if( *mode_ptr == '+' ) set = TRUE;
166 else if( *mode_ptr == '-' ) set = FALSE;
167 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
172 if( *mode_ptr == '-' ) set = FALSE;
174 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
177 /* Reply-String mit Aenderungen vorbereiten */
178 if( set ) strcpy( the_modes, "+" );
179 else strcpy( the_modes, "-" );
186 if( Client_Type( Client ) == CLIENT_SERVER )
188 /* Befehl kommt von einem Server, daher
189 * trauen wir ihm "unbesehen" ... */
194 /* Modes validieren */
205 /* operator (kann nur geloescht werden) */
208 Client_SetOperByMe( Client, FALSE );
211 else ok = IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
214 /* restricted (kann nur gesetzt werden) */
215 if( set ) x[0] = 'r';
216 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
219 /* server messages */
223 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
224 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
230 /* Ist der User ein Channel Operator? */
232 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
233 if( Conf_OperCanMode )
235 /* auch IRC-Operatoren duerfen MODE verwenden */
236 if( Client_OperByMe( Client )) modeok = TRUE;
241 Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
242 ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
246 /* Channel-Modes oder Channel-User-Modes */
249 /* Channel-User-Modes */
253 /* Channel Operator */
261 Log( LOG_DEBUG, "Unknown channel-user-mode \"%c%c\" from \"%s\" on \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Client_ID( chan_cl ), Channel_Name( chan ));
262 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
280 /* kein Schreiben in den Channel von aussen */
288 /* Persistent channel */
289 if( set && ( ! Client_OperByMe( Client )))
291 /* there are too many persistent channels in the network! */
292 ok = IRC_WriteStrClient( Client, ERR_NOPRIVILEGES_MSG, Client_ID( Client ));
297 Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
298 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
307 if( ! x[0] ) continue;
309 /* Okay, gueltigen Mode gefunden */
312 /* Es geht um User-Modes */
315 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
316 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
321 /* Modes geloescht. Wenn der Client ihn hatte: merken */
322 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
325 /* "nachbearbeiten" */
329 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
330 else Client_SetAway( cl, NULL );
335 /* Es geht um Channel-Modes oder Channel-User-Modes */
338 /* Channel-User-Modes */
341 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
342 if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
346 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
347 if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
355 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
356 if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
360 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
361 if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
367 /* Wurden Modes geaendert? */
373 if( Client_Type( Client ) == CLIENT_SERVER )
375 /* Modes an andere Server forwarden */
376 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
380 /* Bestaetigung an Client schicken & andere Server informieren */
381 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
382 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
384 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
388 /* Channel-Modes oder Channel-User-Mode */
391 /* Channel-User-Mode */
392 if( Client_Type( Client ) == CLIENT_SERVER )
394 /* Modes an andere Server und Channel-User forwarden */
395 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
396 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
400 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
401 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
402 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
403 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
405 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
410 if( Client_Type( Client ) == CLIENT_SERVER )
412 /* Modes an andere Server und Channel-User forwarden */
413 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
414 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
418 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
419 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
420 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
421 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
423 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
433 IRC_AWAY( CLIENT *Client, REQUEST *Req )
435 assert( Client != NULL );
436 assert( Req != NULL );
438 /* Falsche Anzahl Parameter? */
439 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
441 if(( Req->argc == 1 ) && (Req->argv[0][0] ))
444 Client_SetAway( Client, Req->argv[0] );
445 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
446 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
451 Client_SetAway( Client, NULL );
452 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
453 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
459 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
463 assert( Client != NULL );
464 assert( Channel != NULL );
465 assert( Pattern != NULL );
467 mask = Lists_MakeMask( Pattern );
469 if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
470 return Send_ListChange( "+I", Prefix, Client, Channel, mask );
475 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
479 assert( Client != NULL );
480 assert( Channel != NULL );
481 assert( Pattern != NULL );
483 mask = Lists_MakeMask( Pattern );
485 if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
486 return Send_ListChange( "+b", Prefix, Client, Channel, mask );
491 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
495 assert( Client != NULL );
496 assert( Channel != NULL );
497 assert( Pattern != NULL );
499 mask = Lists_MakeMask( Pattern );
500 Lists_DelInvited( mask, Channel );
501 return Send_ListChange( "-I", Prefix, Client, Channel, mask );
506 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
510 assert( Client != NULL );
511 assert( Channel != NULL );
512 assert( Pattern != NULL );
514 mask = Lists_MakeMask( Pattern );
515 Lists_DelBanned( mask, Channel );
516 return Send_ListChange( "-b", Prefix, Client, Channel, mask );
521 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
523 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
527 if( Client_Type( Client ) == CLIENT_USER )
529 /* Bestaetigung an Client */
530 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
534 /* an andere Server */
535 IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
537 /* und lokale User im Channel */
538 IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
541 } /* Send_ListChange */