- an Clients wurden Modes mit fuehrendem ":" geliefert. Das ist zwar RFC-
[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.12 2002/08/27 13:57:03 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;
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                                 /* Testen, ob Client gebanned ist */
100                                 if( Lists_CheckBanned( target, chan ))
101                                 {
102                                         /* Client ist gebanned: */
103                                         IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
104
105                                         /* naechsten Namen ermitteln */
106                                         channame = strtok( NULL, "," );
107                                         continue;
108                                 }
109
110                                 /* Ist der Channel "invite-only"? */
111                                 if( strchr( Channel_Modes( chan ), 'i' ))
112                                 {
113                                         /* Wurde der Client invited? */
114                                         if( ! Lists_CheckInvited( target, chan ))
115                                         {
116                                                 /* 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
127                 /* Channel joinen (und ggf. anlegen) */
128                 if( ! Channel_Join( target, channame ))
129                 {
130                         /* naechsten Namen ermitteln */
131                         channame = strtok( NULL, "," );
132                         continue;
133                 }
134                 if( ! chan ) chan = Channel_Search( channame );
135                 assert( chan != NULL );
136
137                 /* Modes setzen (wenn vorhanden) */
138                 while( flags && *flags )
139                 {
140                         Channel_UserModeAdd( chan, target, *flags );
141                         flags++;
142                 }
143
144                 /* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
145                 if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
146
147                 /* Muessen Modes an andere Server gemeldet werden? */
148                 strcpy( &modes[1], Channel_UserModes( chan, target ));
149                 if( modes[1] ) modes[0] = 0x7;
150                 else modes[0] = '\0';
151
152                 /* An andere Server weiterleiten */
153                 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
154
155                 /* im Channel bekannt machen */
156                 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
157                 if( modes[1] )
158                 {
159                         /* Modes im Channel bekannt machen */
160                         IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s +%s %s", channame, &modes[1], Client_ID( target ));
161                 }
162
163                 if( Client_Type( Client ) == CLIENT_USER )
164                 {
165                         /* an Client bestaetigen */
166                         IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
167
168                         /* Topic an Client schicken */
169                         topic = Channel_Topic( chan );
170                         if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
171
172                         /* Mitglieder an Client Melden */
173                         IRC_Send_NAMES( Client, chan );
174                         IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
175                 }
176
177                 /* naechsten Namen ermitteln */
178                 channame = strtok( NULL, "," );
179         }
180         return CONNECTED;
181 } /* IRC_JOIN */
182
183
184 GLOBAL BOOLEAN
185 IRC_PART( CLIENT *Client, REQUEST *Req )
186 {
187         CLIENT *target;
188         CHAR *chan;
189
190         assert( Client != NULL );
191         assert( Req != NULL );
192
193         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
194
195         /* Falsche Anzahl Parameter? */
196         if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
197
198         /* Wer ist der Absender? */
199         if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
200         else target = Client;
201         if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
202
203         /* Channel-Namen durchgehen */
204         chan = strtok( Req->argv[0], "," );
205         while( chan )
206         {
207                 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
208                 {
209                         /* naechsten Namen ermitteln */
210                         chan = strtok( NULL, "," );
211                         continue;
212                 }
213
214                 /* naechsten Namen ermitteln */
215                 chan = strtok( NULL, "," );
216         }
217         return CONNECTED;
218 } /* IRC_PART */
219
220
221 GLOBAL BOOLEAN
222 IRC_TOPIC( CLIENT *Client, REQUEST *Req )
223 {
224         CHANNEL *chan;
225         CLIENT *from;
226         CHAR *topic;
227
228         assert( Client != NULL );
229         assert( Req != NULL );
230
231         if(( Client_Type( Client ) != CLIENT_USER ) && ( Client_Type( Client ) != CLIENT_SERVER )) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
232
233         /* Falsche Anzahl Parameter? */
234         if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
235
236         if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
237         else from = Client;
238         if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
239
240         /* Welcher Channel? */
241         chan = Channel_Search( Req->argv[0] );
242         if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
243
244         /* Ist der User Mitglied in dem Channel? */
245         if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
246
247         if( Req->argc == 1 )
248         {
249                 /* Topic erfragen */
250                 topic = Channel_Topic( chan );
251                 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
252                 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
253         }
254
255         if( strchr( Channel_Modes( chan ), 't' ))
256         {
257                 /* Topic Lock. Ist der User ein Channel Operator? */
258                 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
259         }
260
261         /* Topic setzen */
262         Channel_SetTopic( chan, Req->argv[1] );
263         Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
264
265         /* im Channel bekannt machen und an Server weiterleiten */
266         IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
267         IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
268
269         if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
270         else return CONNECTED;
271 } /* IRC_TOPIC */
272
273
274 GLOBAL BOOLEAN
275 IRC_LIST( CLIENT *Client, REQUEST *Req )
276 {
277         CHAR *pattern;
278         CHANNEL *chan;
279
280         assert( Client != NULL );
281         assert( Req != NULL );
282
283         if( Client_Type( Client ) != CLIENT_USER ) return IRC_WriteStrClient( Client, ERR_NOTREGISTERED_MSG, Client_ID( Client ));
284
285         /* Falsche Anzahl Parameter? */
286         if( Req->argc > 1 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
287
288         if( Req->argc > 0 ) pattern = strtok( Req->argv[0], "," );
289         else pattern = "*";
290         
291         while( pattern )
292         {
293                 /* alle Channel durchgehen */
294                 chan = Channel_First( );
295                 while( chan )
296                 {
297                         /* Passt die Suchmaske auf diesen Channel? */
298                         if( Match( pattern, Channel_Name( chan )))
299                         {
300                                 /* Treffer! */
301                                 if( ! IRC_WriteStrClient( Client, RPL_LIST_MSG, Client_ID( Client), Channel_Name( chan ), Channel_MemberCount( chan ), Channel_Topic( chan ))) return DISCONNECTED;
302                         }
303                         chan = Channel_Next( chan );
304                 }
305                 
306                 /* naechsten Namen ermitteln */
307                 if( Req->argc > 0 ) pattern = strtok( NULL, "," );
308                 else pattern = NULL;
309         }
310         
311         return IRC_WriteStrClient( Client, RPL_LISTEND_MSG, Client_ID( Client ));
312 } /* IRC_LIST */
313
314
315 /* -eof- */