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