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