Blob


1 /*
2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
4 *
5 * Dieses Programm ist freie Software. Sie koennen es unter den Bedingungen
6 * der GNU General Public License (GPL), wie von der Free Software Foundation
7 * herausgegeben, weitergeben und/oder modifizieren, entweder unter Version 2
8 * der Lizenz oder (wenn Sie es wuenschen) jeder spaeteren Version.
9 * Naehere Informationen entnehmen Sie bitter der Datei COPYING. Eine Liste
10 * der an ngIRCd beteiligten Autoren finden Sie in der Datei AUTHORS.
11 *
12 * $Id: irc-mode.c,v 1.14 2002/09/08 17:07:14 alex Exp $
13 *
14 * irc-mode.c: IRC-Befehle zur Mode-Aenderung (MODE, AWAY, ...)
15 */
18 #include "portab.h"
20 #include "imp.h"
21 #include <assert.h>
22 #include <string.h>
24 #include "conn.h"
25 #include "client.h"
26 #include "channel.h"
27 #include "defines.h"
28 #include "irc-write.h"
29 #include "lists.h"
30 #include "log.h"
31 #include "parse.h"
32 #include "messages.h"
33 #include "resolve.h"
34 #include "conf.h"
36 #include "exp.h"
37 #include "irc-mode.h"
40 LOCAL BOOLEAN Add_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
41 LOCAL BOOLEAN Add_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
43 LOCAL BOOLEAN Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
44 LOCAL BOOLEAN Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
46 LOCAL BOOLEAN Send_ListChange PARAMS(( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask ));
49 GLOBAL BOOLEAN
50 IRC_MODE( CLIENT *Client, REQUEST *Req )
51 {
52 CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
53 CLIENT *cl, *chan_cl, *prefix;
54 BOOLEAN set, ok, modeok;
55 CHANNEL *chan;
57 assert( Client != NULL );
58 assert( Req != NULL );
60 cl = chan_cl = prefix = NULL;
61 chan = NULL;
63 /* Valider Client? */
64 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
66 /* Keine Parameter? */
67 if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
69 /* Ziel suchen: Client bzw. Channel */
70 if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
71 if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
73 /* Kein Ziel gefunden? */
74 if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
76 assert(( cl && chan ) != TRUE );
78 /* Falsche Anzahl Parameter? */
79 if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
80 if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
82 /* Prefix fuer Antworten etc. ermitteln */
83 if( Client_Type( Client ) == CLIENT_SERVER )
84 {
85 prefix = Client_Search( Req->prefix );
86 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
87 }
88 else prefix = Client;
90 if(( chan ) && (( Req->argc == 2 ) || ( Req->argc == 3 )))
91 {
92 /* pruefen, ob "Listen-Operation": Invite, Ban */
93 if(( Req->argv[1][0] == '-' ) || ( Req->argv[1][0] == '+' )) mode_ptr = &Req->argv[1][1];
94 else mode_ptr = &Req->argv[1][0];
96 if( Req->argc == 2 )
97 {
98 /* Liste anzeigen */
99 if( *mode_ptr == 'I' ) return Lists_ShowInvites( prefix, chan );
100 if( *mode_ptr == 'b' ) return Lists_ShowBans( prefix, chan );
102 else
104 /* Listen veraendern */
106 if( Client_Type( Client ) == CLIENT_USER )
108 /* Ist der User Channel-Operator? */
109 modeok = FALSE;
110 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
111 if( Conf_OperCanMode )
113 /* auch IRC-Operatoren duerfen MODE verwenden */
114 if( Client_OperByMe( Client )) modeok = TRUE;
117 if( ! modeok )
119 Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
120 return IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
124 if( Req->argv[1][0] == '+' )
126 /* Listen-Eintrag hinzufuegen */
127 if( *mode_ptr == 'I' ) return Add_Invite( prefix, Client, chan, Req->argv[2] );
128 if( *mode_ptr == 'b' ) return Add_Ban( prefix, Client, chan, Req->argv[2] );
130 else if( Req->argv[1][0] == '-' )
132 /* Listen-Eintrag loeschen */
133 if( *mode_ptr == 'I' ) return Del_Invite( prefix, Client, chan, Req->argv[2] );
134 if( *mode_ptr == 'b' ) return Del_Ban( prefix, Client, chan, Req->argv[2] );
139 /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
140 if(( chan ) && (Req->argc == 3 ))
142 chan_cl = Client_Search( Req->argv[2] );
143 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
146 /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
147 if( Client_Type( Client ) == CLIENT_USER )
149 if( cl )
151 /* MODE ist nur fuer sich selber zulaessig! */
152 if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
154 if( chan )
156 /* Darf der User die Channel-Modes ermitteln? */
160 /* Werden die Modes "nur" erfragt? */
161 if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
162 if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
164 mode_ptr = Req->argv[1];
166 /* Sollen Modes gesetzt oder geloescht werden? */
167 if( cl )
169 if( *mode_ptr == '+' ) set = TRUE;
170 else if( *mode_ptr == '-' ) set = FALSE;
171 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
172 mode_ptr++;
174 else
176 if( *mode_ptr == '-' ) set = FALSE;
177 else set = TRUE;
178 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
181 /* Reply-String mit Aenderungen vorbereiten */
182 if( set ) strcpy( the_modes, "+" );
183 else strcpy( the_modes, "-" );
185 ok = TRUE;
186 x[1] = '\0';
187 while( *mode_ptr )
189 x[0] = '\0';
190 if( Client_Type( Client ) == CLIENT_SERVER )
192 /* Befehl kommt von einem Server, daher
193 * trauen wir ihm "unbesehen" ... */
194 x[0] = *mode_ptr;
196 else
198 /* Modes validieren */
199 if( cl )
201 /* User-Modes */
202 switch( *mode_ptr )
204 case 'i':
205 /* invisible */
206 x[0] = 'i';
207 break;
208 case 'o':
209 /* operator (kann nur geloescht werden) */
210 if( ! set )
212 Client_SetOperByMe( Client, FALSE );
213 x[0] = 'o';
215 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
216 break;
217 case 'r':
218 /* restricted (kann nur gesetzt werden) */
219 if( set ) x[0] = 'r';
220 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
221 break;
222 case 's':
223 /* server messages */
224 x[0] = 's';
225 break;
226 default:
227 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
228 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
229 x[0] = '\0';
232 if( chan )
234 /* Ist der User ein Channel Operator? */
235 modeok = FALSE;
236 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
237 if( Conf_OperCanMode )
239 /* auch IRC-Operatoren duerfen MODE verwenden */
240 if( Client_OperByMe( Client )) modeok = TRUE;
243 if( ! modeok )
245 Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
246 ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
247 break;
250 /* Channel-Modes oder Channel-User-Modes */
251 if( chan_cl )
253 /* Channel-User-Modes */
254 switch( *mode_ptr )
256 case 'o':
257 /* Channel Operator */
258 x[0] = 'o';
259 break;
260 case 'v':
261 /* Voice */
262 x[0] = 'v';
263 break;
264 default:
265 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 ));
266 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
267 x[0] = '\0';
270 else
272 /* Channel-Modes */
273 switch( *mode_ptr )
275 case 'i':
276 /* Invite-Only */
277 x[0] = 'i';
278 break;
279 case 'm':
280 /* Moderated */
281 x[0] = 'm';
282 break;
283 case 'n':
284 /* kein Schreiben in den Channel von aussen */
285 x[0] = 'n';
286 break;
287 case 't':
288 /* Topic Lock */
289 x[0] = 't';
290 break;
291 case 'P':
292 /* Persistent */
293 x[0] = 'P';
294 break;
295 default:
296 Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
297 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
298 x[0] = '\0';
303 if( ! ok ) break;
305 mode_ptr++;
306 if( ! x[0] ) continue;
308 /* Okay, gueltigen Mode gefunden */
309 if( cl )
311 /* Es geht um User-Modes */
312 if( set )
314 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
315 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
318 else
320 /* Modes geloescht. Wenn der Client ihn hatte: merken */
321 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
324 /* "nachbearbeiten" */
325 if( x[0] == 'a' )
327 /* away */
328 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
329 else Client_SetAway( cl, NULL );
332 if( chan )
334 /* Es geht um Channel-Modes oder Channel-User-Modes */
335 if( chan_cl )
337 /* Channel-User-Modes */
338 if( set )
340 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
341 if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
343 else
345 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
346 if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
349 else
351 /* Channel-Mode */
352 if( set )
354 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
355 if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
357 else
359 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
360 if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
366 /* Wurden Modes geaendert? */
367 if( the_modes[1] )
369 if( cl )
371 /* Client-Mode */
372 if( Client_Type( Client ) == CLIENT_SERVER )
374 /* Modes an andere Server forwarden */
375 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
377 else
379 /* Bestaetigung an Client schicken & andere Server informieren */
380 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
381 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
383 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
385 if( chan )
387 /* Channel-Modes oder Channel-User-Mode */
388 if( chan_cl )
390 /* Channel-User-Mode */
391 if( Client_Type( Client ) == CLIENT_SERVER )
393 /* Modes an andere Server und Channel-User forwarden */
394 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
395 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
397 else
399 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
400 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
401 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
402 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
404 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
406 else
408 /* Channel-Mode */
409 if( Client_Type( Client ) == CLIENT_SERVER )
411 /* Modes an andere Server und Channel-User forwarden */
412 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
413 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
415 else
417 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
418 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
419 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
420 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
422 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
427 return ok;
428 } /* IRC_MODE */
431 GLOBAL BOOLEAN
432 IRC_AWAY( CLIENT *Client, REQUEST *Req )
434 assert( Client != NULL );
435 assert( Req != NULL );
437 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
439 /* Falsche Anzahl Parameter? */
440 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
442 if(( Req->argc == 1 ) && (Req->argv[0][0] ))
444 /* AWAY setzen */
445 Client_SetAway( Client, Req->argv[0] );
446 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
447 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
449 else
451 /* AWAY loeschen */
452 Client_SetAway( Client, NULL );
453 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
454 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
456 } /* IRC_AWAY */
459 LOCAL BOOLEAN
460 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
462 CHAR *mask;
464 assert( Client != NULL );
465 assert( Channel != NULL );
466 assert( Pattern != NULL );
468 mask = Lists_MakeMask( Pattern );
470 if( ! Lists_AddInvited( Prefix, mask, Channel, FALSE )) return CONNECTED;
471 return Send_ListChange( "+I", Prefix, Client, Channel, mask );
472 } /* Add_Invite */
475 LOCAL BOOLEAN
476 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
478 CHAR *mask;
480 assert( Client != NULL );
481 assert( Channel != NULL );
482 assert( Pattern != NULL );
484 mask = Lists_MakeMask( Pattern );
486 if( ! Lists_AddBanned( Prefix, mask, Channel )) return CONNECTED;
487 return Send_ListChange( "+b", Prefix, Client, Channel, mask );
488 } /* Add_Ban */
491 LOCAL BOOLEAN
492 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
494 CHAR *mask;
496 assert( Client != NULL );
497 assert( Channel != NULL );
498 assert( Pattern != NULL );
500 mask = Lists_MakeMask( Pattern );
501 Lists_DelInvited( mask, Channel );
502 return Send_ListChange( "-I", Prefix, Client, Channel, mask );
503 } /* Del_Invite */
506 LOCAL BOOLEAN
507 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
509 CHAR *mask;
511 assert( Client != NULL );
512 assert( Channel != NULL );
513 assert( Pattern != NULL );
515 mask = Lists_MakeMask( Pattern );
516 Lists_DelBanned( mask, Channel );
517 return Send_ListChange( "-b", Prefix, Client, Channel, mask );
518 } /* Del_Ban */
521 LOCAL BOOLEAN
522 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
524 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
526 BOOLEAN ok;
528 if( Client_Type( Client ) == CLIENT_USER )
530 /* Bestaetigung an Client */
531 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
533 else ok = TRUE;
535 /* an andere Server */
536 IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
538 /* und lokale User im Channel */
539 IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
541 return ok;
542 } /* Send_ListChange */
545 /* -eof- */