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