2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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.
12 * $Id: irc-channel.c,v 1.16 2002/11/30 15:04:57 alex Exp $
14 * irc-channel.c: IRC-Channel-Befehle
34 #include "irc-write.h"
37 #include "irc-channel.h"
41 IRC_JOIN( CLIENT *Client, REQUEST *Req )
43 CHAR *channame, *flags, *topic, modes[8];
44 BOOLEAN is_new_chan, is_invited, is_banned;
48 assert( Client != NULL );
49 assert( Req != NULL );
51 /* Falsche Anzahl Parameter? */
52 if(( Req->argc > 1 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
54 /* Wer ist der Absender? */
55 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
57 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
59 /* Channel-Namen durchgehen */
61 channame = strtok( Req->argv[0], "," );
66 /* wird der Channel neu angelegt? */
67 if( Channel_Search( channame )) is_new_chan = FALSE;
68 else is_new_chan = TRUE;
70 /* Hat ein Server Channel-User-Modes uebergeben? */
71 if( Client_Type( Client ) == CLIENT_SERVER )
73 /* Channel-Flags extrahieren */
74 flags = strchr( channame, 0x7 );
83 if( Client_Type( Client ) == CLIENT_USER )
85 /* Existiert der Channel bereits, oder wird er im Moment neu erzeugt? */
88 /* Erster User im Channel: Operator-Flag setzen */
93 /* Existierenden Channel suchen */
94 chan = Channel_Search( channame );
95 assert( chan != NULL );
97 is_banned = Lists_CheckBanned( target, chan );
98 is_invited = Lists_CheckInvited( target, chan );
100 /* Testen, ob Client gebanned ist */
101 if(( is_banned == TRUE ) && ( is_invited == FALSE ))
103 /* Client ist gebanned (und nicht invited): */
104 IRC_WriteStrClient( Client, ERR_BANNEDFROMCHAN_MSG, Client_ID( Client ), channame );
106 /* naechsten Namen ermitteln */
107 channame = strtok( NULL, "," );
111 /* Ist der Channel "invite-only"? */
112 if(( strchr( Channel_Modes( chan ), 'i' ) != NULL ) && ( is_invited == FALSE ))
114 /* Channel ist "invite-only" und Client wurde nicht invited: */
115 IRC_WriteStrClient( Client, ERR_INVITEONLYCHAN_MSG, Client_ID( Client ), channame );
117 /* naechsten Namen ermitteln */
118 channame = strtok( NULL, "," );
124 /* Channel joinen (und ggf. anlegen) */
125 if( ! Channel_Join( target, channame ))
127 /* naechsten Namen ermitteln */
128 channame = strtok( NULL, "," );
131 if( ! chan ) chan = Channel_Search( channame );
132 assert( chan != NULL );
134 /* Modes setzen (wenn vorhanden) */
135 while( flags && *flags )
137 Channel_UserModeAdd( chan, target, *flags );
141 /* Wenn persistenter Channel und IRC-Operator: zum Channel-OP machen */
142 if(( strchr( Channel_Modes( chan ), 'P' )) && ( strchr( Client_Modes( target ), 'o' ))) Channel_UserModeAdd( chan, target, 'o' );
144 /* Muessen Modes an andere Server gemeldet werden? */
145 strcpy( &modes[1], Channel_UserModes( chan, target ));
146 if( modes[1] ) modes[0] = 0x7;
147 else modes[0] = '\0';
149 /* An andere Server weiterleiten */
150 IRC_WriteStrServersPrefix( Client, target, "JOIN :%s%s", channame, modes );
152 /* im Channel bekannt machen */
153 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "JOIN :%s", channame );
156 /* Modes im Channel bekannt machen */
157 IRC_WriteStrChannelPrefix( Client, chan, target, FALSE, "MODE %s +%s %s", channame, &modes[1], Client_ID( target ));
160 if( Client_Type( Client ) == CLIENT_USER )
162 /* an Client bestaetigen */
163 IRC_WriteStrClientPrefix( Client, target, "JOIN :%s", channame );
165 /* Topic an Client schicken */
166 topic = Channel_Topic( chan );
167 if( *topic ) IRC_WriteStrClient( Client, RPL_TOPIC_MSG, Client_ID( Client ), channame, topic );
169 /* Mitglieder an Client Melden */
170 IRC_Send_NAMES( Client, chan );
171 IRC_WriteStrClient( Client, RPL_ENDOFNAMES_MSG, Client_ID( Client ), Channel_Name( chan ));
174 /* naechsten Namen ermitteln */
175 channame = strtok( NULL, "," );
182 IRC_PART( CLIENT *Client, REQUEST *Req )
187 assert( Client != NULL );
188 assert( Req != NULL );
190 /* Falsche Anzahl Parameter? */
191 if(( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
193 /* Wer ist der Absender? */
194 if( Client_Type( Client ) == CLIENT_SERVER ) target = Client_Search( Req->prefix );
195 else target = Client;
196 if( ! target ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
198 /* Channel-Namen durchgehen */
199 chan = strtok( Req->argv[0], "," );
202 if( ! Channel_Part( target, Client, chan, Req->argc > 1 ? Req->argv[1] : Client_ID( target )))
204 /* naechsten Namen ermitteln */
205 chan = strtok( NULL, "," );
209 /* naechsten Namen ermitteln */
210 chan = strtok( NULL, "," );
217 IRC_TOPIC( CLIENT *Client, REQUEST *Req )
223 assert( Client != NULL );
224 assert( Req != NULL );
226 /* Falsche Anzahl Parameter? */
227 if(( Req->argc < 1 ) || ( Req->argc > 2 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
229 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
231 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
233 /* Welcher Channel? */
234 chan = Channel_Search( Req->argv[0] );
235 if( ! chan ) return IRC_WriteStrClient( from, ERR_NOSUCHCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
237 /* Ist der User Mitglied in dem Channel? */
238 if( ! Channel_IsMemberOf( chan, from )) return IRC_WriteStrClient( from, ERR_NOTONCHANNEL_MSG, Client_ID( from ), Req->argv[0] );
243 topic = Channel_Topic( chan );
244 if( *topic ) return IRC_WriteStrClient( from, RPL_TOPIC_MSG, Client_ID( from ), Channel_Name( chan ), topic );
245 else return IRC_WriteStrClient( from, RPL_NOTOPIC_MSG, Client_ID( from ), Channel_Name( chan ));
248 if( strchr( Channel_Modes( chan ), 't' ))
250 /* Topic Lock. Ist der User ein Channel Operator? */
251 if( ! strchr( Channel_UserModes( chan, from ), 'o' )) return IRC_WriteStrClient( from, ERR_CHANOPRIVSNEEDED_MSG, Client_ID( from ), Channel_Name( chan ));
255 Channel_SetTopic( chan, Req->argv[1] );
256 Log( LOG_DEBUG, "User \"%s\" set topic on \"%s\": %s", Client_Mask( from ), Channel_Name( chan ), Req->argv[1][0] ? Req->argv[1] : "<none>" );
258 /* im Channel bekannt machen und an Server weiterleiten */
259 IRC_WriteStrServersPrefix( Client, from, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
260 IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
262 if( Client_Type( Client ) == CLIENT_USER ) return IRC_WriteStrClientPrefix( Client, Client, "TOPIC %s :%s", Req->argv[0], Req->argv[1] );
263 else return CONNECTED;
268 IRC_LIST( CLIENT *Client, REQUEST *Req )
272 CLIENT *from, *target;
274 assert( Client != NULL );
275 assert( Req != NULL );
277 /* Falsche Anzahl Parameter? */
278 if( Req->argc > 2 ) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
280 if( Req->argc > 0 ) pattern = strtok( Req->argv[0], "," );
283 /* From aus Prefix ermitteln */
284 if( Client_Type( Client ) == CLIENT_SERVER ) from = Client_Search( Req->prefix );
286 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->prefix );
290 /* an anderen Server forwarden */
291 target = Client_Search( Req->argv[1] );
292 if( ! target ) return IRC_WriteStrClient( from, ERR_NOSUCHSERVER_MSG, Client_ID( Client ), Req->argv[1] );
294 if( target != Client_ThisServer( ))
296 /* Ok, anderer Server ist das Ziel: forwarden */
297 return IRC_WriteStrClientPrefix( target, from, "LIST %s :%s", from, Req->argv[1] );
303 /* alle Channel durchgehen */
304 chan = Channel_First( );
307 /* Passt die Suchmaske auf diesen Channel? */
308 if( Match( pattern, Channel_Name( chan )))
311 if( ! IRC_WriteStrClient( from, RPL_LIST_MSG, from, Channel_Name( chan ), Channel_MemberCount( chan ), Channel_Topic( chan ))) return DISCONNECTED;
313 chan = Channel_Next( chan );
316 /* naechsten Namen ermitteln */
317 if( Req->argc > 0 ) pattern = strtok( NULL, "," );
321 return IRC_WriteStrClient( from, RPL_LISTEND_MSG, from );
326 IRC_CHANINFO( CLIENT *Client, REQUEST *Req )
332 assert( Client != NULL );
333 assert( Req != NULL );
335 /* Falsche Anzahl Parameter? */
336 if(( Req->argc < 1 ) || ( Req->argc > 3 )) return IRC_WriteStrClient( Client, ERR_NEEDMOREPARAMS_MSG, Client_ID( Client ), Req->command );
338 /* From-Server suchen */
339 from = Client_Search( Req->prefix );
340 if( ! from ) return IRC_WriteStrClient( Client, ERR_NOSUCHNICK_MSG, Client_ID( Client ), Req->prefix );
342 /* Channel suchen bzw. erzeugen */
343 chan = Channel_Search( Req->argv[0] );
344 if( ! chan ) chan = Channel_Create( Req->argv[0] );
345 if( ! chan ) return CONNECTED;
347 if( Req->argv[1][0] == '+' )
349 ptr = Channel_Modes( chan );
352 /* OK, es sind noch keine Modes gesetzt */
353 Channel_SetModes( chan, &Req->argv[1][1] );
354 IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "MODE %s +%s", Req->argv[0], &Req->argv[1][1] );
357 else Log( LOG_WARNING, "CHANNELINFO: invalid MODE format ignored!" );
361 /* Es wurde auch ein Topic mit uebermittelt */
362 ptr = Channel_Topic( chan );
365 /* OK, es ist bisher kein Topic gesetzt */
366 Channel_SetTopic( chan, Req->argv[2] );
367 IRC_WriteStrChannelPrefix( Client, chan, from, FALSE, "TOPIC %s :%s", Req->argv[0], Req->argv[2] );
371 /* an andere Server forwarden */
372 IRC_WriteStrServersPrefixFlag( Client, from, 'C', "CHANINFO %s %s :%s", Req->argv[0], Req->argv[1], Req->argv[2] );