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.4 2002/03/25 17:11:45 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 "channel.h"
25 #include "defines.h"
26 #include "irc-write.h"
27 #include "log.h"
28 #include "messages.h"
30 #include "exp.h"
31 #include "irc-mode.h"
34 GLOBAL BOOLEAN IRC_MODE( CLIENT *Client, REQUEST *Req )
35 {
36 CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
37 CLIENT *cl, *chan_cl, *prefix;
38 BOOLEAN set, ok;
39 CHANNEL *chan;
41 assert( Client != NULL );
42 assert( Req != NULL );
44 cl = chan_cl = prefix = NULL;
45 chan = NULL;
47 /* Valider Client? */
48 if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
50 /* Keine Parameter? */
51 if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
53 /* Ziel suchen: Client bzw. Channel */
54 if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
55 if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
57 /* Kein Ziel gefunden? */
58 if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
60 assert(( cl && chan ) != TRUE );
62 /* Falsche Anzahl Parameter? */
63 if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
64 if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
66 /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
67 if(( chan ) && (Req->argc == 3 ))
68 {
69 chan_cl = Client_Search( Req->argv[2] );
70 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
71 }
73 /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
74 if( Client_Type( Client ) == CLIENT_USER )
75 {
76 if( cl )
77 {
78 /* MODE ist nur fuer sich selber zulaessig! */
79 if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
80 }
81 if( chan )
82 {
83 /* Darf der User die Channel-Modes ermitteln? */
84 }
85 }
87 /* Werden die Modes "nur" erfragt? */
88 if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
89 if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
91 mode_ptr = Req->argv[1];
93 /* Sollen Modes gesetzt oder geloescht werden? */
94 if( cl )
95 {
96 if( *mode_ptr == '+' ) set = TRUE;
97 else if( *mode_ptr == '-' ) set = FALSE;
98 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
99 mode_ptr++;
101 else
103 if( *mode_ptr == '-' ) set = FALSE;
104 else set = TRUE;
105 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
108 /* Prefix fuer Antworten etc. ermitteln */
109 if( Client_Type( Client ) == CLIENT_SERVER )
111 prefix = Client_Search( Req->prefix );
112 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
114 else prefix = Client;
116 /* Reply-String mit Aenderungen vorbereiten */
117 if( set ) strcpy( the_modes, "+" );
118 else strcpy( the_modes, "-" );
120 ok = TRUE;
121 x[1] = '\0';
122 while( *mode_ptr )
124 x[0] = '\0';
125 if( Client_Type( Client ) == CLIENT_SERVER )
127 /* Befehl kommt von einem Server, daher
128 * trauen wir ihm "unbesehen" ... */
129 x[0] = *mode_ptr;
131 else
133 /* Modes validieren */
134 if( cl )
136 /* User-Modes */
137 switch( *mode_ptr )
139 case 'i':
140 /* invisible */
141 x[0] = 'i';
142 break;
143 case 'r':
144 /* restricted (kann nur gesetzt werden) */
145 if( set ) x[0] = 'r';
146 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
147 break;
148 case 'o':
149 /* operator (kann nur geloescht werden) */
150 if( ! set )
152 Client_SetOperByMe( Client, FALSE );
153 x[0] = 'o';
155 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
156 break;
157 case 's':
158 /* server messages */
159 x[0] = 's';
160 break;
161 default:
162 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
163 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
164 x[0] = '\0';
167 if( chan )
169 /* Ist der User ein Channel Operator? */
170 if( ! strchr( Channel_UserModes( chan, Client ), 'o' ))
172 Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
173 ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
174 break;
177 /* Channel-Modes oder Channel-User-Modes */
178 if( chan_cl )
180 /* Channel-User-Modes */
181 switch( *mode_ptr )
183 case 'o':
184 /* Channel Operator */
185 x[0] = 'o';
186 break;
187 case 'v':
188 /* Voice */
189 x[0] = 'v';
190 break;
191 default:
192 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 ));
193 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
194 x[0] = '\0';
197 else
199 /* Channel-Modes */
200 switch( *mode_ptr )
202 case 'a':
203 /* Anonymous */
204 x[0] = 'a';
205 break;
206 case 'm':
207 /* Moderated */
208 x[0] = 'm';
209 break;
210 case 'n':
211 /* kein Schreiben in den Channel von aussen */
212 x[0] = 'n';
213 break;
214 case 'p':
215 /* Private */
216 x[0] = 'p';
217 break;
218 case 'q':
219 /* Quiet */
220 x[0] = 'q';
221 break;
222 case 's':
223 /* Secret */
224 x[0] = 's';
225 break;
226 case 't':
227 /* Topic Lock */
228 x[0] = 't';
229 break;
230 default:
231 Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
232 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
233 x[0] = '\0';
238 if( ! ok ) break;
240 mode_ptr++;
241 if( ! x[0] ) continue;
243 /* Okay, gueltigen Mode gefunden */
244 if( cl )
246 /* Es geht um User-Modes */
247 if( set )
249 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
250 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
253 else
255 /* Modes geloescht. Wenn der Client ihn hatte: merken */
256 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
259 /* "nachbearbeiten" */
260 if( x[0] == 'a' )
262 /* away */
263 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
264 else Client_SetAway( cl, NULL );
267 if( chan )
269 /* Es geht um Channel-Modes oder Channel-User-Modes */
270 if( chan_cl )
272 /* Channel-User-Modes */
273 if( set )
275 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
276 if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
278 else
280 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
281 if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
284 else
286 /* Channel-Mode */
287 if( set )
289 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
290 if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
292 else
294 /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
295 if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
301 /* Wurden Modes geaendert? */
302 if( the_modes[1] )
304 if( cl )
306 /* Client-Mode */
307 if( Client_Type( Client ) == CLIENT_SERVER )
309 /* Modes an andere Server forwarden */
310 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
312 else
314 /* Bestaetigung an Client schicken & andere Server informieren */
315 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
316 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
318 Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
320 if( chan )
322 /* Channel-Modes oder Channel-User-Mode */
323 if( chan_cl )
325 /* Channel-User-Mode */
326 if( Client_Type( Client ) == CLIENT_SERVER )
328 /* Modes an andere Server und Channel-User forwarden */
329 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
330 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
332 else
334 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
335 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
336 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
337 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
339 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
341 else
343 /* Channel-Mode */
344 if( Client_Type( Client ) == CLIENT_SERVER )
346 /* Modes an andere Server und Channel-User forwarden */
347 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
348 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
350 else
352 /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
353 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
354 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
355 IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
357 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
362 return ok;
363 } /* IRC_MODE */
366 GLOBAL BOOLEAN IRC_AWAY( CLIENT *Client, REQUEST *Req )
368 assert( Client != NULL );
369 assert( Req != NULL );
371 if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
373 /* Falsche Anzahl Parameter? */
374 if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
376 if(( Req->argc == 1 ) && (Req->argv[0][0] ))
378 /* AWAY setzen */
379 Client_SetAway( Client, Req->argv[0] );
380 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
381 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
383 else
385 /* AWAY loeschen */
386 Client_SetAway( Client, NULL );
387 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
388 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
390 } /* IRC_AWAY */
393 /* -eof- */