- neue Konfigurationsoption "OperCanUseMode" (Sektion "Global"):
[ngircd-alex.git] / src / ngircd / irc-mode.c
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.10 2002/09/02 14:59:18 alex Exp $
13  *
14  * irc-mode.c: IRC-Befehle zur Mode-Aenderung (MODE, AWAY, ...)
15  */
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <string.h>
23
24 #include "conn.h"
25 #include "client.h"
26 #include "channel.h"
27 #include "defines.h"
28 #include "irc-write.h"
29 #include "log.h"
30 #include "parse.h"
31 #include "messages.h"
32 #include "resolve.h"
33 #include "conf.h"
34
35 #include "exp.h"
36 #include "irc-mode.h"
37
38
39 GLOBAL BOOLEAN
40 IRC_MODE( CLIENT *Client, REQUEST *Req )
41 {
42         CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
43         CLIENT *cl, *chan_cl, *prefix;
44         BOOLEAN set, ok, modeok;
45         CHANNEL *chan;
46         
47         assert( Client != NULL );
48         assert( Req != NULL );
49
50         cl = chan_cl = prefix = NULL;
51         chan = NULL;
52
53         /* Valider Client? */
54         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
55
56         /* Keine Parameter? */
57         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
58
59         /* Ziel suchen: Client bzw. Channel */
60         if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
61         if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
62
63         /* Kein Ziel gefunden? */
64         if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
65
66         assert(( cl && chan ) != TRUE );
67
68         /* Falsche Anzahl Parameter? */
69         if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
70         if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
71
72         /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
73         if(( chan ) && (Req->argc == 3 ))
74         {
75                 chan_cl = Client_Search( Req->argv[2] );
76                 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
77         }
78         
79         /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
80         if( Client_Type( Client ) == CLIENT_USER )
81         {
82                 if( cl )
83                 {
84                         /* MODE ist nur fuer sich selber zulaessig! */
85                         if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
86                 }
87                 if( chan )
88                 {
89                         /* Darf der User die Channel-Modes ermitteln? */
90                 }
91         }
92
93         /* Werden die Modes "nur" erfragt? */
94         if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
95         if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
96
97         mode_ptr = Req->argv[1];
98
99         /* Sollen Modes gesetzt oder geloescht werden? */
100         if( cl )
101         {
102                 if( *mode_ptr == '+' ) set = TRUE;
103                 else if( *mode_ptr == '-' ) set = FALSE;
104                 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
105                 mode_ptr++;
106         }
107         else
108         {
109                 if( *mode_ptr == '-' ) set = FALSE;
110                 else set = TRUE;
111                 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
112         }
113         
114         /* Prefix fuer Antworten etc. ermitteln */
115         if( Client_Type( Client ) == CLIENT_SERVER )
116         {
117                 prefix = Client_Search( Req->prefix );
118                 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
119         }
120         else prefix = Client;
121
122         /* Reply-String mit Aenderungen vorbereiten */
123         if( set ) strcpy( the_modes, "+" );
124         else strcpy( the_modes, "-" );
125
126         ok = TRUE;
127         x[1] = '\0';
128         while( *mode_ptr )
129         {
130                 x[0] = '\0';
131                 if( Client_Type( Client ) == CLIENT_SERVER )
132                 {
133                         /* Befehl kommt von einem Server, daher
134                          * trauen wir ihm "unbesehen" ... */
135                         x[0] = *mode_ptr;
136                 }
137                 else
138                 {
139                         /* Modes validieren */
140                         if( cl )
141                         {
142                                 /* User-Modes */
143                                 switch( *mode_ptr )
144                                 {
145                                         case 'i':
146                                                 /* invisible */
147                                                 x[0] = 'i';
148                                                 break;
149                                         case 'o':
150                                                 /* operator (kann nur geloescht werden) */
151                                                 if( ! set )
152                                                 {
153                                                         Client_SetOperByMe( Client, FALSE );
154                                                         x[0] = 'o';
155                                                 }
156                                                 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
157                                                 break;
158                                         case 'r':
159                                                 /* restricted (kann nur gesetzt werden) */
160                                                 if( set ) x[0] = 'r';
161                                                 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
162                                                 break;
163                                         case 's':
164                                                 /* server messages */
165                                                 x[0] = 's';
166                                                 break;
167                                         default:
168                                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
169                                                 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
170                                                 x[0] = '\0';
171                                 }
172                         }
173                         if( chan )
174                         {
175                                 /* Ist der User ein Channel Operator? */
176                                 modeok = FALSE;
177                                 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
178                                 if( Conf_OperCanMode )
179                                 {
180                                         /* auch IRC-Operatoren duerfen MODE verwenden */
181                                         if( Client_OperByMe( Client )) modeok = TRUE;
182                                 }
183
184                                 if( ! modeok )
185                                 {
186                                         Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
187                                         ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
188                                         break;
189                                 }
190                                 
191                                 /* Channel-Modes oder Channel-User-Modes */
192                                 if( chan_cl )
193                                 {
194                                         /* Channel-User-Modes */
195                                         switch( *mode_ptr )
196                                         {
197                                                 case 'o':
198                                                         /* Channel Operator */
199                                                         x[0] = 'o';
200                                                         break;
201                                                 case 'v':
202                                                         /* Voice */
203                                                         x[0] = 'v';
204                                                         break;
205                                                 default:
206                                                         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 ));
207                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
208                                                         x[0] = '\0';
209                                         }
210                                 }
211                                 else
212                                 {
213                                         /* Channel-Modes */
214                                         switch( *mode_ptr )
215                                         {
216                                                 case 'i':
217                                                         /* Invite-Only */
218                                                         x[0] = 'i';
219                                                         break;
220                                                 case 'm':
221                                                         /* Moderated */
222                                                         x[0] = 'm';
223                                                         break;
224                                                 case 'n':
225                                                         /* kein Schreiben in den Channel von aussen */
226                                                         x[0] = 'n';
227                                                         break;
228                                                 case 't':
229                                                         /* Topic Lock */
230                                                         x[0] = 't';
231                                                         break;
232                                                 case 'P':
233                                                         /* Persistent */
234                                                         x[0] = 'P';
235                                                         break;
236                                                 default:
237                                                         Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
238                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
239                                                         x[0] = '\0';
240                                         }
241                                 }
242                         }
243                 }
244                 if( ! ok ) break;
245                 
246                 mode_ptr++;
247                 if( ! x[0] ) continue;
248
249                 /* Okay, gueltigen Mode gefunden */
250                 if( cl )
251                 {
252                         /* Es geht um User-Modes */
253                         if( set )
254                         {
255                                 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
256                                 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
257                                 
258                         }
259                         else
260                         {
261                                 /* Modes geloescht. Wenn der Client ihn hatte: merken */
262                                 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
263                         }
264
265                         /* "nachbearbeiten" */
266                         if( x[0] == 'a' )
267                         {
268                                 /* away */
269                                 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
270                                 else Client_SetAway( cl, NULL );
271                         }
272                 }
273                 if( chan )
274                 {
275                         /* Es geht um Channel-Modes oder Channel-User-Modes */
276                         if( chan_cl )
277                         {
278                                 /* Channel-User-Modes */
279                                 if( set )
280                                 {
281                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
282                                         if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
283                                 }
284                                 else
285                                 {
286                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
287                                         if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
288                                 }
289                         }
290                         else
291                         {
292                                 /* Channel-Mode */
293                                 if( set )
294                                 {
295                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
296                                         if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
297                                 }
298                                 else
299                                 {
300                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
301                                         if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
302                                 }
303                         }
304                 }
305         }
306
307         /* Wurden Modes geaendert? */
308         if( the_modes[1] )
309         {
310                 if( cl )
311                 {
312                         /* Client-Mode */
313                         if( Client_Type( Client ) == CLIENT_SERVER )
314                         {
315                                 /* Modes an andere Server forwarden */
316                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
317                         }
318                         else
319                         {
320                                 /* Bestaetigung an Client schicken & andere Server informieren */
321                                 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
322                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
323                         }
324                         Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
325                 }
326                 if( chan )
327                 {
328                         /* Channel-Modes oder Channel-User-Mode */
329                         if( chan_cl )
330                         {
331                                 /* Channel-User-Mode */
332                                 if( Client_Type( Client ) == CLIENT_SERVER )
333                                 {
334                                         /* Modes an andere Server und Channel-User forwarden */
335                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
336                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
337                                 }
338                                 else
339                                 {
340                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
341                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
342                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
343                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
344                                 }
345                                 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
346                         }
347                         else
348                         {
349                                 /* Channel-Mode */
350                                 if( Client_Type( Client ) == CLIENT_SERVER )
351                                 {
352                                         /* Modes an andere Server und Channel-User forwarden */
353                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
354                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
355                                 }
356                                 else
357                                 {
358                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
359                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
360                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
361                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
362                                 }
363                                 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
364                         }
365                 }
366         }
367
368         return ok;
369 } /* IRC_MODE */
370
371
372 GLOBAL BOOLEAN
373 IRC_AWAY( CLIENT *Client, REQUEST *Req )
374 {
375         assert( Client != NULL );
376         assert( Req != NULL );
377
378         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
379
380         /* Falsche Anzahl Parameter? */
381         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
382
383         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
384         {
385                 /* AWAY setzen */
386                 Client_SetAway( Client, Req->argv[0] );
387                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
388                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
389         }
390         else
391         {
392                 /* AWAY loeschen */
393                 Client_SetAway( Client, NULL );
394                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
395                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
396         }
397 } /* IRC_AWAY */
398
399
400 /* -eof- */