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: channel.c,v 1.6 2002/01/26 18:41:55 alex Exp $
14 * channel.c: Management der Channels
17 * Revision 1.6 2002/01/26 18:41:55 alex
18 * - CHANNEL- und CL2CHAN-Strukturen in Header verlegt,
19 * - einige neue Funktionen (Channel_GetChannel(), Channel_FirstMember(), ...)
21 * Revision 1.5 2002/01/21 00:12:29 alex
22 * - begonnen, Channels zu implementieren :-)
24 * Revision 1.4 2002/01/16 22:09:07 alex
25 * - neue Funktion Channel_Count().
27 * Revision 1.3 2002/01/02 02:42:58 alex
28 * - Copyright-Texte aktualisiert.
30 * Revision 1.2 2001/12/31 02:18:51 alex
31 * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
32 * - neuen Header "defines.h" mit (fast) allen Konstanten.
33 * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
35 * Revision 1.1 2001/12/14 08:13:43 alex
36 * - neues Modul begonnen :-)
60 LOCAL CHANNEL *My_Channels;
61 LOCAL CL2CHAN *My_Cl2Chan;
64 LOCAL CHANNEL *New_Chan( CHAR *Name );
65 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client );
66 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client );
67 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason );
68 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan );
69 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan );
70 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan );
73 GLOBAL VOID Channel_Init( VOID )
80 GLOBAL VOID Channel_Exit( VOID )
83 CL2CHAN *cl2chan, *cl2chan_next;
85 /* Channel-Strukturen freigeben */
94 /* Channel-Zuordnungstabelle freigeben */
98 cl2chan_next = cl2chan->next;
100 cl2chan = cl2chan_next;
105 GLOBAL BOOLEAN Channel_Join( CLIENT *Client, CHAR *Name )
109 assert( Client != NULL );
110 assert( Name != NULL );
112 /* Valider Channel-Name? */
113 if(( Name[0] != '#' ) || ( strlen( Name ) >= CHANNEL_NAME_LEN ))
115 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
120 chan = Channel_Search( Name );
123 /* Ist der Client bereits Mitglied? */
124 if( Get_Cl2Chan( chan, Client )) return FALSE;
128 /* Gibt es noch nicht? Dann neu anlegen: */
129 chan = New_Chan( Name );
130 if( ! chan ) return FALSE;
133 chan->next = My_Channels;
137 /* User dem Channel hinzufuegen */
138 if( ! Add_Client( chan, Client )) return FALSE;
143 GLOBAL BOOLEAN Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason )
147 assert( Client != NULL );
148 assert( Name != NULL );
151 chan = Channel_Search( Name );
152 if(( ! chan ) || ( ! Get_Cl2Chan( chan, Client )))
154 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
158 /* User aus Channel entfernen */
159 if( ! Remove_Client( chan, Client, Origin, Reason )) return FALSE;
164 GLOBAL VOID Channel_RemoveClient( CLIENT *Client, CHAR *Reason )
168 assert( Client != NULL );
174 Remove_Client( c, Client, Client_ThisServer( ), Reason );
177 } /* Channel_RemoveClient */
180 GLOBAL INT Channel_Count( VOID )
193 } /* Channel_Count */
196 GLOBAL CHANNEL *Channel_Search( CHAR *Name )
198 /* Channel-Struktur suchen */
202 assert( Name != NULL );
206 if( strcasecmp( Name, c->name ) == 0 ) return c;
210 } /* Channel_Search */
213 GLOBAL CL2CHAN *Channel_FirstMember( CHANNEL *Chan )
215 assert( Chan != NULL );
216 return Get_First_Cl2Chan( NULL, Chan );
217 } /* Channel_IsMember */
220 GLOBAL CL2CHAN *Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
222 assert( Chan != NULL );
223 assert( Cl2Chan != NULL );
224 return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
225 } /* Channel_NextMember */
228 GLOBAL CLIENT *Channel_GetClient( CL2CHAN *Cl2Chan )
230 assert( Cl2Chan != NULL );
231 return Cl2Chan->client;
232 } /* Channel_GetClient */
235 GLOBAL CHANNEL *Channel_GetChannel( CL2CHAN *Cl2Chan )
237 assert( Cl2Chan != NULL );
238 return Cl2Chan->channel;
239 } /* Channel_GetChannel */
242 LOCAL CHANNEL *New_Chan( CHAR *Name )
244 /* Neue Channel-Struktur anlegen */
248 assert( Name != NULL );
250 c = malloc( sizeof( CHANNEL ));
253 Log( LOG_EMERG, "Can't allocate memory!" );
257 strncpy( c->name, Name, CHANNEL_NAME_LEN );
258 c->name[CHANNEL_NAME_LEN - 1] = '\0';
259 strcpy( c->modes, "" );
261 Log( LOG_DEBUG, "Created new channel structure for \"%s\".", Name );
267 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
271 assert( Chan != NULL );
272 assert( Client != NULL );
274 cl2chan = My_Cl2Chan;
277 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
278 cl2chan = cl2chan->next;
284 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client )
288 assert( Chan != NULL );
289 assert( Client != NULL );
291 cl2chan = malloc( sizeof( CL2CHAN ));
294 Log( LOG_EMERG, "Can't allocate memory!" );
297 cl2chan->channel = Chan;
298 cl2chan->client = Client;
301 cl2chan->next = My_Cl2Chan;
302 My_Cl2Chan = cl2chan;
308 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason )
310 CL2CHAN *cl2chan, *last_cl2chan;
313 assert( Chan != NULL );
314 assert( Client != NULL );
315 assert( Origin != NULL );
316 assert( Reason != NULL );
319 cl2chan = My_Cl2Chan;
322 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
323 last_cl2chan = cl2chan;
324 cl2chan = cl2chan->next;
326 if( ! cl2chan ) return FALSE;
328 c = cl2chan->channel;
331 /* Aus Verkettung loesen und freigeben */
332 if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
333 else My_Cl2Chan = cl2chan->next;
336 if( Client_Conn( Origin ) > NONE ) IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
337 IRC_WriteStrServersPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
338 IRC_WriteStrChannelPrefix( Origin, c, Client, "PART %s :%s", c->name, Reason );
340 Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason );
342 /* Wenn Channel nun leer: loeschen */
343 if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
346 } /* Remove_Client */
349 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
351 return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
352 } /* Get_First_Cl2Chan */
355 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
359 assert( Client != NULL || Channel != NULL );
364 if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
365 if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
366 cl2chan = cl2chan->next;
369 } /* Get_Next_Cl2Chan */
372 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan )
374 /* Channel-Struktur loeschen */
376 CHANNEL *chan, *last_chan;
382 if( chan == Chan ) break;
386 if( ! chan ) return FALSE;
388 Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name );
390 /* Neu verketten und freigeben */
391 if( last_chan ) last_chan->next = chan->next;
392 else My_Channels = chan->next;
396 } /* Delete_Channel */