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