- persistente und vordefinierte Channels implementiert.
[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.5 2002/05/21 00:10:16 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 "channel.h"
25 #include "defines.h"
26 #include "irc-write.h"
27 #include "log.h"
28 #include "messages.h"
29
30 #include "exp.h"
31 #include "irc-mode.h"
32
33
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;
40         
41         assert( Client != NULL );
42         assert( Req != NULL );
43
44         cl = chan_cl = prefix = NULL;
45         chan = NULL;
46
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 ));
49
50         /* Keine Parameter? */
51         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
52
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] );
56
57         /* Kein Ziel gefunden? */
58         if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
59
60         assert(( cl && chan ) != TRUE );
61
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 );
65
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         }
72         
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         }
86
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 ));
90
91         mode_ptr = Req->argv[1];
92
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++;
100         }
101         else
102         {
103                 if( *mode_ptr == '-' ) set = FALSE;
104                 else set = TRUE;
105                 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
106         }
107         
108         /* Prefix fuer Antworten etc. ermitteln */
109         if( Client_Type( Client ) == CLIENT_SERVER )
110         {
111                 prefix = Client_Search( Req->prefix );
112                 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
113         }
114         else prefix = Client;
115
116         /* Reply-String mit Aenderungen vorbereiten */
117         if( set ) strcpy( the_modes, "+" );
118         else strcpy( the_modes, "-" );
119
120         ok = TRUE;
121         x[1] = '\0';
122         while( *mode_ptr )
123         {
124                 x[0] = '\0';
125                 if( Client_Type( Client ) == CLIENT_SERVER )
126                 {
127                         /* Befehl kommt von einem Server, daher
128                          * trauen wir ihm "unbesehen" ... */
129                         x[0] = *mode_ptr;
130                 }
131                 else
132                 {
133                         /* Modes validieren */
134                         if( cl )
135                         {
136                                 /* User-Modes */
137                                 switch( *mode_ptr )
138                                 {
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 )
151                                                 {
152                                                         Client_SetOperByMe( Client, FALSE );
153                                                         x[0] = 'o';
154                                                 }
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';
165                                 }
166                         }
167                         if( chan )
168                         {
169                                 /* Ist der User ein Channel Operator? */
170                                 if( ! strchr( Channel_UserModes( chan, Client ), 'o' ))
171                                 {
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;
175                                 }
176                                 
177                                 /* Channel-Modes oder Channel-User-Modes */
178                                 if( chan_cl )
179                                 {
180                                         /* Channel-User-Modes */
181                                         switch( *mode_ptr )
182                                         {
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';
195                                         }
196                                 }
197                                 else
198                                 {
199                                         /* Channel-Modes */
200                                         switch( *mode_ptr )
201                                         {
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                                                 case 'P':
231                                                         /* Persistent */
232                                                         x[0] = 'P';
233                                                         break;
234                                                 default:
235                                                         Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
236                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
237                                                         x[0] = '\0';
238                                         }
239                                 }
240                         }
241                 }
242                 if( ! ok ) break;
243                 
244                 mode_ptr++;
245                 if( ! x[0] ) continue;
246
247                 /* Okay, gueltigen Mode gefunden */
248                 if( cl )
249                 {
250                         /* Es geht um User-Modes */
251                         if( set )
252                         {
253                                 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
254                                 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
255                                 
256                         }
257                         else
258                         {
259                                 /* Modes geloescht. Wenn der Client ihn hatte: merken */
260                                 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
261                         }
262
263                         /* "nachbearbeiten" */
264                         if( x[0] == 'a' )
265                         {
266                                 /* away */
267                                 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
268                                 else Client_SetAway( cl, NULL );
269                         }
270                 }
271                 if( chan )
272                 {
273                         /* Es geht um Channel-Modes oder Channel-User-Modes */
274                         if( chan_cl )
275                         {
276                                 /* Channel-User-Modes */
277                                 if( set )
278                                 {
279                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
280                                         if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
281                                 }
282                                 else
283                                 {
284                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
285                                         if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
286                                 }
287                         }
288                         else
289                         {
290                                 /* Channel-Mode */
291                                 if( set )
292                                 {
293                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
294                                         if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
295                                 }
296                                 else
297                                 {
298                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
299                                         if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
300                                 }
301                         }
302                 }
303         }
304
305         /* Wurden Modes geaendert? */
306         if( the_modes[1] )
307         {
308                 if( cl )
309                 {
310                         /* Client-Mode */
311                         if( Client_Type( Client ) == CLIENT_SERVER )
312                         {
313                                 /* Modes an andere Server forwarden */
314                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
315                         }
316                         else
317                         {
318                                 /* Bestaetigung an Client schicken & andere Server informieren */
319                                 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
320                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
321                         }
322                         Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
323                 }
324                 if( chan )
325                 {
326                         /* Channel-Modes oder Channel-User-Mode */
327                         if( chan_cl )
328                         {
329                                 /* Channel-User-Mode */
330                                 if( Client_Type( Client ) == CLIENT_SERVER )
331                                 {
332                                         /* Modes an andere Server und Channel-User forwarden */
333                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
334                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
335                                 }
336                                 else
337                                 {
338                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
339                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
340                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
341                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
342                                 }
343                                 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
344                         }
345                         else
346                         {
347                                 /* Channel-Mode */
348                                 if( Client_Type( Client ) == CLIENT_SERVER )
349                                 {
350                                         /* Modes an andere Server und Channel-User forwarden */
351                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
352                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
353                                 }
354                                 else
355                                 {
356                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
357                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
358                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
359                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
360                                 }
361                                 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
362                         }
363                 }
364         }
365
366         return ok;
367 } /* IRC_MODE */
368
369
370 GLOBAL BOOLEAN IRC_AWAY( CLIENT *Client, REQUEST *Req )
371 {
372         assert( Client != NULL );
373         assert( Req != NULL );
374
375         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
376
377         /* Falsche Anzahl Parameter? */
378         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
379
380         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
381         {
382                 /* AWAY setzen */
383                 Client_SetAway( Client, Req->argv[0] );
384                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
385                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
386         }
387         else
388         {
389                 /* AWAY loeschen */
390                 Client_SetAway( Client, NULL );
391                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
392                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
393         }
394 } /* IRC_AWAY */
395
396
397 /* -eof- */