- Bans/Invites: andere Server wurden nicht informiert.
[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.12 2002/09/08 01:16: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 "lists.h"
30 #include "log.h"
31 #include "parse.h"
32 #include "messages.h"
33 #include "resolve.h"
34 #include "conf.h"
35
36 #include "exp.h"
37 #include "irc-mode.h"
38
39
40 LOCAL BOOLEAN Add_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
41 LOCAL BOOLEAN Add_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
42
43 LOCAL BOOLEAN Del_Invite PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
44 LOCAL BOOLEAN Del_Ban PARAMS(( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern ));
45
46 LOCAL BOOLEAN Send_ListChange PARAMS(( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask ));
47
48
49 GLOBAL BOOLEAN
50 IRC_MODE( CLIENT *Client, REQUEST *Req )
51 {
52         CHAR *mode_ptr, the_modes[CLIENT_MODE_LEN], x[2];
53         CLIENT *cl, *chan_cl, *prefix;
54         BOOLEAN set, ok, modeok;
55         CHANNEL *chan;
56         
57         assert( Client != NULL );
58         assert( Req != NULL );
59
60         cl = chan_cl = prefix = NULL;
61         chan = NULL;
62
63         /* Valider Client? */
64         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
65
66         /* Keine Parameter? */
67         if( Req->argc < 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
68
69         /* Ziel suchen: Client bzw. Channel */
70         if( Client_IsValidNick( Req->argv[0] )) cl = Client_Search( Req->argv[0] );
71         if( Channel_IsValidName( Req->argv[0] )) chan = Channel_Search( Req->argv[0] );
72
73         /* Kein Ziel gefunden? */
74         if(( ! cl ) && ( ! chan )) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
75
76         assert(( cl && chan ) != TRUE );
77
78         /* Falsche Anzahl Parameter? */
79         if(( cl ) && ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
80         if(( chan ) && ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
81
82         /* Prefix fuer Antworten etc. ermitteln */
83         if( Client_Type( Client ) == CLIENT_SERVER )
84         {
85                 prefix = Client_Search( Req->prefix );
86                 if( ! prefix ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
87         }
88         else prefix = Client;
89         
90         if(( chan ) && (( Req->argc == 2 ) || ( Req->argc == 3 )))
91         {
92                 /* pruefen, ob "Listen-Operation": Invite, Ban */
93                 if(( Req->argv[1][0] == '-'  ) || ( Req->argv[1][0] == '+' )) mode_ptr = &Req->argv[1][1];
94                 else mode_ptr = &Req->argv[1][0];
95
96                 if( Req->argc == 2 )
97                 {
98                         /* Liste anzeigen */
99                         if( *mode_ptr == 'I' ) return Lists_ShowInvites( prefix, chan );
100                         if( *mode_ptr == 'b' ) return Lists_ShowBans( prefix, chan );
101                 }
102                 else
103                 {
104                         if( Req->argv[1][0] == '+' )
105                         {
106                                 /* Listen-Eintrag hinzufuegen */
107                                 if( *mode_ptr == 'I' ) return Add_Invite( prefix, Client, chan, Req->argv[2] );
108                                 if( *mode_ptr == 'b' ) return Add_Ban( prefix, Client, chan, Req->argv[2] );
109                         }
110                         else if( Req->argv[1][0] == '-' )
111                         {
112                                 /* Listen-Eintrag loeschen */
113                                 if( *mode_ptr == 'I' ) return Del_Invite( prefix, Client, chan, Req->argv[2] );
114                                 if( *mode_ptr == 'b' ) return Del_Ban( prefix, Client, chan, Req->argv[2] );
115                         }
116                 }
117         }
118
119         /* Client ermitteln, wenn bei Channel-Modes mit 3 Parametern */
120         if(( chan ) && (Req->argc == 3 ))
121         {
122                 chan_cl = Client_Search( Req->argv[2] );
123                 if( ! chan_cl ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->argv[0] );
124         }
125         
126         /* Wenn Anfragender ein User ist: Zugriff erlaubt? */
127         if( Client_Type( Client ) == CLIENT_USER )
128         {
129                 if( cl )
130                 {
131                         /* MODE ist nur fuer sich selber zulaessig! */
132                         if( cl != Client ) return IRC_WriteStrClient( Client, ERR_USERSDONTMATCH_MSG, Client_ID( Client ));
133                 }
134                 if( chan )
135                 {
136                         /* Darf der User die Channel-Modes ermitteln? */
137                 }
138         }
139
140         /* Werden die Modes "nur" erfragt? */
141         if(( cl ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_UMODEIS_MSG, Client_ID( Client ), Client_Modes( cl ));
142         if(( chan ) && ( Req->argc == 1 )) return IRC_WriteStrClient( Client, RPL_CHANNELMODEIS_MSG, Client_ID( Client ), Channel_Name( chan ), Channel_Modes( chan ));
143
144         mode_ptr = Req->argv[1];
145
146         /* Sollen Modes gesetzt oder geloescht werden? */
147         if( cl )
148         {
149                 if( *mode_ptr == '+' ) set = TRUE;
150                 else if( *mode_ptr == '-' ) set = FALSE;
151                 else return IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
152                 mode_ptr++;
153         }
154         else
155         {
156                 if( *mode_ptr == '-' ) set = FALSE;
157                 else set = TRUE;
158                 if(( *mode_ptr == '-' ) || ( *mode_ptr == '+' )) mode_ptr++;
159         }
160
161         /* Reply-String mit Aenderungen vorbereiten */
162         if( set ) strcpy( the_modes, "+" );
163         else strcpy( the_modes, "-" );
164
165         ok = TRUE;
166         x[1] = '\0';
167         while( *mode_ptr )
168         {
169                 x[0] = '\0';
170                 if( Client_Type( Client ) == CLIENT_SERVER )
171                 {
172                         /* Befehl kommt von einem Server, daher
173                          * trauen wir ihm "unbesehen" ... */
174                         x[0] = *mode_ptr;
175                 }
176                 else
177                 {
178                         /* Modes validieren */
179                         if( cl )
180                         {
181                                 /* User-Modes */
182                                 switch( *mode_ptr )
183                                 {
184                                         case 'i':
185                                                 /* invisible */
186                                                 x[0] = 'i';
187                                                 break;
188                                         case 'o':
189                                                 /* operator (kann nur geloescht werden) */
190                                                 if( ! set )
191                                                 {
192                                                         Client_SetOperByMe( Client, FALSE );
193                                                         x[0] = 'o';
194                                                 }
195                                                 else ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG_MSG, Client_ID( Client ));
196                                                 break;
197                                         case 'r':
198                                                 /* restricted (kann nur gesetzt werden) */
199                                                 if( set ) x[0] = 'r';
200                                                 else ok = IRC_WriteStrClient( Client, ERR_RESTRICTED_MSG, Client_ID( Client ));
201                                                 break;
202                                         case 's':
203                                                 /* server messages */
204                                                 x[0] = 's';
205                                                 break;
206                                         default:
207                                                 Log( LOG_DEBUG, "Unknown mode \"%c%c\" from \"%s\"!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ));
208                                                 ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
209                                                 x[0] = '\0';
210                                 }
211                         }
212                         if( chan )
213                         {
214                                 /* Ist der User ein Channel Operator? */
215                                 modeok = FALSE;
216                                 if( strchr( Channel_UserModes( chan, Client ), 'o' )) modeok = TRUE;
217                                 if( Conf_OperCanMode )
218                                 {
219                                         /* auch IRC-Operatoren duerfen MODE verwenden */
220                                         if( Client_OperByMe( Client )) modeok = TRUE;
221                                 }
222
223                                 if( ! modeok )
224                                 {
225                                         Log( LOG_DEBUG, "Can't change modes: \"%s\" is not operator on %s!", Client_ID( Client ), Channel_Name( chan ));
226                                         ok = IRC_WriteStrClient( Client, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( Client ), Channel_Name( chan ));
227                                         break;
228                                 }
229                                 
230                                 /* Channel-Modes oder Channel-User-Modes */
231                                 if( chan_cl )
232                                 {
233                                         /* Channel-User-Modes */
234                                         switch( *mode_ptr )
235                                         {
236                                                 case 'o':
237                                                         /* Channel Operator */
238                                                         x[0] = 'o';
239                                                         break;
240                                                 case 'v':
241                                                         /* Voice */
242                                                         x[0] = 'v';
243                                                         break;
244                                                 default:
245                                                         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 ));
246                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
247                                                         x[0] = '\0';
248                                         }
249                                 }
250                                 else
251                                 {
252                                         /* Channel-Modes */
253                                         switch( *mode_ptr )
254                                         {
255                                                 case 'i':
256                                                         /* Invite-Only */
257                                                         x[0] = 'i';
258                                                         break;
259                                                 case 'm':
260                                                         /* Moderated */
261                                                         x[0] = 'm';
262                                                         break;
263                                                 case 'n':
264                                                         /* kein Schreiben in den Channel von aussen */
265                                                         x[0] = 'n';
266                                                         break;
267                                                 case 't':
268                                                         /* Topic Lock */
269                                                         x[0] = 't';
270                                                         break;
271                                                 case 'P':
272                                                         /* Persistent */
273                                                         x[0] = 'P';
274                                                         break;
275                                                 default:
276                                                         Log( LOG_DEBUG, "Unknown channel-mode \"%c%c\" from \"%s\" at %s!?", set ? '+' : '-', *mode_ptr, Client_ID( Client ), Channel_Name( chan ));
277                                                         ok = IRC_WriteStrClient( Client, ERR_UMODEUNKNOWNFLAG2_MSG, Client_ID( Client ), set ? '+' : '-', *mode_ptr );
278                                                         x[0] = '\0';
279                                         }
280                                 }
281                         }
282                 }
283                 if( ! ok ) break;
284                 
285                 mode_ptr++;
286                 if( ! x[0] ) continue;
287
288                 /* Okay, gueltigen Mode gefunden */
289                 if( cl )
290                 {
291                         /* Es geht um User-Modes */
292                         if( set )
293                         {
294                                 /* Mode setzen. Wenn der Client ihn noch nicht hatte: merken */
295                                 if( Client_ModeAdd( cl, x[0] )) strcat( the_modes, x );
296                                 
297                         }
298                         else
299                         {
300                                 /* Modes geloescht. Wenn der Client ihn hatte: merken */
301                                 if( Client_ModeDel( cl, x[0] )) strcat( the_modes, x );
302                         }
303
304                         /* "nachbearbeiten" */
305                         if( x[0] == 'a' )
306                         {
307                                 /* away */
308                                 if( set ) Client_SetAway( cl, DEFAULT_AWAY_MSG );
309                                 else Client_SetAway( cl, NULL );
310                         }
311                 }
312                 if( chan )
313                 {
314                         /* Es geht um Channel-Modes oder Channel-User-Modes */
315                         if( chan_cl )
316                         {
317                                 /* Channel-User-Modes */
318                                 if( set )
319                                 {
320                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
321                                         if( Channel_UserModeAdd( chan, chan_cl, x[0] )) strcat( the_modes, x );
322                                 }
323                                 else
324                                 {
325                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
326                                         if( Channel_UserModeDel( chan, chan_cl, x[0] )) strcat( the_modes, x );
327                                 }
328                         }
329                         else
330                         {
331                                 /* Channel-Mode */
332                                 if( set )
333                                 {
334                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
335                                         if( Channel_ModeAdd( chan, x[0] )) strcat( the_modes, x );
336                                 }
337                                 else
338                                 {
339                                         /* Mode setzen. Wenn der Channel ihn noch nicht hatte: merken */
340                                         if( Channel_ModeDel( chan, x[0] )) strcat( the_modes, x );
341                                 }
342                         }
343                 }
344         }
345
346         /* Wurden Modes geaendert? */
347         if( the_modes[1] )
348         {
349                 if( cl )
350                 {
351                         /* Client-Mode */
352                         if( Client_Type( Client ) == CLIENT_SERVER )
353                         {
354                                 /* Modes an andere Server forwarden */
355                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
356                         }
357                         else
358                         {
359                                 /* Bestaetigung an Client schicken & andere Server informieren */
360                                 ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Client_ID( cl ), the_modes );
361                                 IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Client_ID( cl ), the_modes );
362                         }
363                         Log( LOG_DEBUG, "User \"%s\": Mode change, now \"%s\".", Client_Mask( cl ), Client_Modes( cl ));
364                 }
365                 if( chan )
366                 {
367                         /* Channel-Modes oder Channel-User-Mode */
368                         if( chan_cl )
369                         {
370                                 /* Channel-User-Mode */
371                                 if( Client_Type( Client ) == CLIENT_SERVER )
372                                 {
373                                         /* Modes an andere Server und Channel-User forwarden */
374                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
375                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
376                                 }
377                                 else
378                                 {
379                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
380                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
381                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s %s :%s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
382                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s %s", Channel_Name( chan ), the_modes, Client_ID( chan_cl));
383                                 }
384                                 Log( LOG_DEBUG, "User \"%s\" on %s: Mode change, now \"%s\".", Client_Mask( chan_cl), Channel_Name( chan ), Channel_UserModes( chan, chan_cl ));
385                         }
386                         else
387                         {
388                                 /* Channel-Mode */
389                                 if( Client_Type( Client ) == CLIENT_SERVER )
390                                 {
391                                         /* Modes an andere Server und Channel-User forwarden */
392                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
393                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
394                                 }
395                                 else
396                                 {
397                                         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
398                                         ok = IRC_WriteStrClientPrefix( Client, prefix, "MODE %s %s", Channel_Name( chan ), the_modes );
399                                         IRC_WriteStrServersPrefix( Client, prefix, "MODE %s :%s", Channel_Name( chan ), the_modes );
400                                         IRC_WriteStrChannelPrefix( Client, chan, prefix, FALSE, "MODE %s %s", Channel_Name( chan ), the_modes );
401                                 }
402                                 Log( LOG_DEBUG, "Channel \"%s\": Mode change, now \"%s\".", Channel_Name( chan ), Channel_Modes( chan ));
403                         }
404                 }
405         }
406
407         return ok;
408 } /* IRC_MODE */
409
410
411 GLOBAL BOOLEAN
412 IRC_AWAY( CLIENT *Client, REQUEST *Req )
413 {
414         assert( Client != NULL );
415         assert( Req != NULL );
416
417         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
418
419         /* Falsche Anzahl Parameter? */
420         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
421
422         if(( Req->argc == 1 ) && (Req->argv[0][0] ))
423         {
424                 /* AWAY setzen */
425                 Client_SetAway( Client, Req->argv[0] );
426                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :+a", Client_ID( Client ));
427                 return IRC_WriteStrClient( Client, RPL_NOWAWAY_MSG, Client_ID( Client ));
428         }
429         else
430         {
431                 /* AWAY loeschen */
432                 Client_SetAway( Client, NULL );
433                 IRC_WriteStrServersPrefix( Client, Client, "MODE %s :-a", Client_ID( Client ));
434                 return IRC_WriteStrClient( Client, RPL_UNAWAY_MSG, Client_ID( Client ));
435         }
436 } /* IRC_AWAY */
437
438
439 LOCAL BOOLEAN
440 Add_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
441 {
442         CHAR *mask;
443
444         assert( Client != NULL );
445         assert( Channel != NULL );
446         assert( Pattern != NULL );
447
448         mask = Lists_MakeMask( Pattern );
449
450         if( ! Lists_AddInvited( mask, Channel, FALSE )) return CONNECTED;
451         return Send_ListChange( "+I", Prefix, Client, Channel, mask );
452 } /* Add_Invite */
453
454
455 LOCAL BOOLEAN
456 Add_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
457 {
458         CHAR *mask;
459
460         assert( Client != NULL );
461         assert( Channel != NULL );
462         assert( Pattern != NULL );
463
464         mask = Lists_MakeMask( Pattern );
465
466         if( ! Lists_AddBanned( mask, Channel )) return CONNECTED;
467         return Send_ListChange( "+b", Prefix, Client, Channel, mask );
468 } /* Add_Ban */
469
470
471 LOCAL BOOLEAN
472 Del_Invite( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
473 {
474         CHAR *mask;
475
476         assert( Client != NULL );
477         assert( Channel != NULL );
478         assert( Pattern != NULL );
479
480         mask = Lists_MakeMask( Pattern );
481         Lists_DelInvited( mask, Channel );
482         return Send_ListChange( "-I", Prefix, Client, Channel, mask );
483 } /* Del_Invite */
484
485
486 LOCAL BOOLEAN
487 Del_Ban( CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Pattern )
488 {
489         CHAR *mask;
490
491         assert( Client != NULL );
492         assert( Channel != NULL );
493         assert( Pattern != NULL );
494
495         mask = Lists_MakeMask( Pattern );
496         Lists_DelBanned( mask, Channel );
497         return Send_ListChange( "-b", Prefix, Client, Channel, mask );
498 } /* Del_Ban */
499
500
501 LOCAL BOOLEAN
502 Send_ListChange( CHAR *Mode, CLIENT *Prefix, CLIENT *Client, CHANNEL *Channel, CHAR *Mask )
503 {
504         /* Bestaetigung an Client schicken & andere Server sowie Channel-User informieren */
505
506         BOOLEAN ok;
507
508         if( Client_Type( Client ) == CLIENT_USER )
509         {
510                 /* Bestaetigung an Client */
511                 ok = IRC_WriteStrClientPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
512         }
513         else ok = TRUE;
514
515         /* an andere Server */
516         IRC_WriteStrServersPrefix( Client, Prefix, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
517
518         /* und lokale User im Channel */
519         IRC_WriteStrChannelPrefix( Client, Channel, Prefix, FALSE, "MODE %s %s %s", Channel_Name( Channel ), Mode, Mask );
520         
521         return ok;
522 } /* Send_ListChange */
523
524
525 /* -eof- */