]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/irc-channel.c
- ein "banned client" darf in einen Channel, wenn er "invited" ist.
[ngircd-alex.git] / src / ngircd / irc-channel.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-channel.c,v 1.14 2002/09/08 00:50:25 alex Exp $
13  *
14  * irc-channel.c: IRC-Channel-Befehle
15  */
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <string.h>
23
24 #include "defines.h"
25 #include "conn.h"
26 #include "client.h"
27 #include "channel.h"
28 #include "lists.h"
29 #include "log.h"
30 #include "match.h"
31 #include "messages.h"
32 #include "parse.h"
33 #include "irc.h"
34 #include "irc-write.h"
35
36 #include "exp.h"
37 #include "irc-channel.h"
38
39
40 GLOBAL BOOLEAN
41 IRC_JOIN( CLIENT *Client, REQUEST *Req )
42 {
43         CHAR *channame, *flags, *topic, modes[8];
44         BOOLEAN is_new_chan, is_invited, is_banned;
45         CLIENT *target;
46         CHANNEL *chan;
47
48         assert( Client != NULL );
49         assert( Req != NULL );
50
51         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
52
53         /* Falsche Anzahl Parameter? */
54         if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
55
56         /* Wer ist der Absender? */
57         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
58         else target = Client;
59         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
60
61         /* Channel-Namen durchgehen */
62         chan = NULL;
63         channame = strtok( Req->argv[0], "," );
64         while( channame )
65         {
66                 chan = flags = NULL;
67
68                 /* wird der Channel neu angelegt? */
69                 if( Channel_Search( channame )) is_new_chan = FALSE;
70                 else is_new_chan = TRUE;
71
72                 /* Hat ein Server Channel-User-Modes uebergeben? */
73                 if( Client_Type( Client ) == CLIENT_SERVER )
74                 {
75                         /* Channel-Flags extrahieren */
76                         flags = strchr( channame, 0x7 );
77                         if( flags )
78                         {
79                                 *flags = '\0';
80                                 flags++;
81                         }
82                 }
83
84                 /* Lokaler Client? */
85                 if( Client_Type( Client ) == CLIENT_USER )
86                 {
87                         /* Existiert der Channel bereits, oder wird er im Moment neu erzeugt? */
88                         if( is_new_chan )
89                         {
90                                 /* Erster User im Channel: Operator-Flag setzen */
91                                 flags = "o";
92                         }
93                         else
94                         {
95                                 /* Existierenden Channel suchen */
96                                 chan = Channel_Search( channame );
97                                 assert( chan != NULL );
98
99                                 is_banned = Lists_CheckBanned( target, chan );
100                                 is_invited = Lists_CheckInvited( target, chan );
101
102                                 /* Testen, ob Client gebanned ist */
103                                 if(( is_banned == TRUE ) &&  ( is_invited == FALSE ))
104                                 {
105                                         /* Client ist gebanned (und nicht invited): */
106                                         IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
107
108                                         /* naechsten Namen ermitteln */
109                                         channame = strtok( NULL, "," );
110                                         continue;
111                                 }
112
113                                 /* Ist der Channel "invite-only"? */
114                                 if(( strchr( Channel_Modes( chan ), 'i' ) != NULL ) && ( is_invited == FALSE ))
115                                 {
116                                         /* Channel ist "invite-only" und Client wurde nicht invited: */
117                                         IRC_WriteStrClient( Client, ERR_INVITEONLYCHAN_MSG, Client_ID( Client ), channame );
118
119                                         /* naechsten Namen ermitteln */
120                                         channame = strtok( NULL, "," );
121                                         continue;
122                                 }
123                         }
124                 }
125
126                 /* Channel joinen (und ggf. anlegen) */
127                 if( ! Channel_Join( target, channame ))
128                 {
129                         /* naechsten Namen ermitteln */
130                         channame = strtok( NULL, "," );
131                         continue;
132                 }
133                 if( ! chan ) chan = Channel_Search( channame );
134                 assert( chan != NULL );
135
136                 /* Modes setzen (wenn vorhanden) */
137                 while( flags && *flags )
138                 {
139                         Channel_UserModeAdd( chan, target, *flags );
140                         flags++;
141                 }
142
143                 /* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
144                 if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
145
146                 /* Muessen Modes an andere Server gemeldet werden? */
147                 strcpy( &modes[1], Channel_UserModes( chan, target ));
148                 if( modes[1] ) modes[0] = 0x7;
149                 else modes[0] = '\0';
150
151                 /* An andere Server weiterleiten */
152                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
153
154                 /* im Channel bekannt machen */
155                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
156                 if( modes[1] )
157                 {
158                         /* Modes im Channel bekannt machen */
159                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s +%s %s", channame, &modes[1], Client_ID( target ));
160                 }
161
162                 if( Client_Type( Client ) == CLIENT_USER )
163                 {
164                         /* an Client bestaetigen */
165                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
166
167                         /* Topic an Client schicken */
168                         topic = Channel_Topic( chan );
169                         if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
170
171                         /* Mitglieder an Client Melden */
172                         IRC_Send_NAMES( Client, chan );
173                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
174                 }
175
176                 /* naechsten Namen ermitteln */
177                 channame = strtok( NULL, "," );
178         }
179         return CONNECTED;
180 } /* IRC_JOIN */
181
182
183 GLOBAL BOOLEAN
184 IRC_PART( CLIENT *Client, REQUEST *Req )
185 {
186         CLIENT *target;
187         CHAR *chan;
188
189         assert( Client != NULL );
190         assert( Req != NULL );
191
192         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
193
194         /* Falsche Anzahl Parameter? */
195         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
196
197         /* Wer ist der Absender? */
198         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
199         else target = Client;
200         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
201
202         /* Channel-Namen durchgehen */
203         chan = strtok( Req->argv[0], "," );
204         while( chan )
205         {
206                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
207                 {
208                         /* naechsten Namen ermitteln */
209                         chan = strtok( NULL, "," );
210                         continue;
211                 }
212
213                 /* naechsten Namen ermitteln */
214                 chan = strtok( NULL, "," );
215         }
216         return CONNECTED;
217 } /* IRC_PART */
218
219
220 GLOBAL BOOLEAN
221 IRC_TOPIC( CLIENT *Client, REQUEST *Req )
222 {
223         CHANNEL *chan;
224         CLIENT *from;
225         CHAR *topic;
226
227         assert( Client != NULL );
228         assert( Req != NULL );
229
230         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
231
232         /* Falsche Anzahl Parameter? */
233         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
234
235         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
236         else from = Client;
237         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
238
239         /* Welcher Channel? */
240         chan = Channel_Search( Req->argv[0] );
241         if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
242
243         /* Ist der User Mitglied in dem Channel? */
244         if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
245
246         if( Req->argc == 1 )
247         {
248                 /* Topic erfragen */
249                 topic = Channel_Topic( chan );
250                 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
251                 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
252         }
253
254         if( strchr( Channel_Modes( chan ), 't' ))
255         {
256                 /* Topic Lock. Ist der User ein Channel Operator? */
257                 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
258         }
259
260         /* Topic setzen */
261         Channel_SetTopic( chan, Req->argv[1] );
262         Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
263
264         /* im Channel bekannt machen und an Server weiterleiten */
265         IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
266         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
267
268         if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
269         else return CONNECTED;
270 } /* IRC_TOPIC */
271
272
273 GLOBAL BOOLEAN
274 IRC_LIST( CLIENT *Client, REQUEST *Req )
275 {
276         CHAR *pattern;
277         CHANNEL *chan;
278
279         assert( Client != NULL );
280         assert( Req != NULL );
281
282         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
283
284         /* Falsche Anzahl Parameter? */
285         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
286
287         if( Req->argc > 0 ) pattern = strtok( Req->argv[0], "," );
288         else pattern = "*";
289         
290         while( pattern )
291         {
292                 /* alle Channel durchgehen */
293                 chan = Channel_First( );
294                 while( chan )
295                 {
296                         /* Passt die Suchmaske auf diesen Channel? */
297                         if( Match( pattern, Channel_Name( chan )))
298                         {
299                                 /* Treffer! */
300                                 if( ! IRC_WriteStrClient( Client, RPL_LIST_MSG, Client_ID( Client), Channel_Name( chan ), Channel_MemberCount( chan ), Channel_Topic( chan ))) return DISCONNECTED;
301                         }
302                         chan = Channel_Next( chan );
303                 }
304                 
305                 /* naechsten Namen ermitteln */
306                 if( Req->argc > 0 ) pattern = strtok( NULL, "," );
307                 else pattern = NULL;
308         }
309         
310         return IRC_WriteStrClient( Client, RPL_LISTEND_MSG, Client_ID( Client ));
311 } /* IRC_LIST */
312
313
314 GLOBAL BOOLEAN
315 IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
316 {
317         CLIENT *from;
318         CHANNEL *chan;
319         CHAR *ptr;
320
321         assert( Client != NULL );
322         assert( Req != NULL );
323
324         if( Client_Type( Client ) != CLIENT_SERVER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
325
326         /* Falsche Anzahl Parameter? */
327         if(( Req->argc < 1 ) || ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
328
329         /* From-Server suchen */
330         from = Client_Search( Req->prefix );
331         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
332
333         /* Channel suchen bzw. erzeugen */
334         chan = Channel_Search( Req->argv[0] );
335         if( ! chan ) chan = Channel_Create( Req->argv[0] );
336         if( ! chan ) return CONNECTED;
337
338         if( Req->argv[1][0] == '+' )
339         {
340                 ptr = Channel_Modes( chan );
341                 if( ! *ptr )
342                 {
343                         /* OK, es sind noch keine Modes gesetzt */
344                         Channel_SetModes( chan, &Req->argv[1][1] );
345                         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "MODE %s +%s", Req->argv[0], &Req->argv[1][1] );
346                 }
347         }
348         else Log( LOG_WARNING, "CHANNELINFO: invalid MODE format ignored!" );
349
350         if( Req->argc == 3 )
351         {
352                 /* Es wurde auch ein Topic mit uebermittelt */
353                 ptr = Channel_Topic( chan );
354                 if( ! *ptr )
355                 {
356                         /* OK, es ist bisher kein Topic gesetzt */
357                         Channel_SetTopic( chan, Req->argv[2] );
358                         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[2] );
359                 }
360         }
361
362         /* an andere Server forwarden */
363         IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2] );
364         return CONNECTED;
365 } /* IRC_CHANINFO */
366
367
368 /* -eof- */