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.10 2002/01/28 01:16:15 alex Exp $
14 * channel.c: Management der Channels
17 * Revision 1.10 2002/01/28 01:16:15 alex
18 * - neue Funktionen Channel_Name(), Channel_First() und Channel_Next().
20 * Revision 1.9 2002/01/27 22:47:11 alex
21 * - PART wird nicht mehr an den Server verschickt, von dem es empfangen wurde.
23 * Revision 1.8 2002/01/27 21:56:54 alex
24 * - weitere Anpassungen an Chennals, v.a. ueber Server-Links.
26 * Revision 1.7 2002/01/27 17:14:33 alex
27 * - diverse Aenderungen fuer Channels ueber mehrere Server.
29 * Revision 1.6 2002/01/26 18:41:55 alex
30 * - CHANNEL- und CL2CHAN-Strukturen in Header verlegt,
31 * - einige neue Funktionen (Channel_GetChannel(), Channel_FirstMember(), ...)
33 * Revision 1.5 2002/01/21 00:12:29 alex
34 * - begonnen, Channels zu implementieren :-)
36 * Revision 1.4 2002/01/16 22:09:07 alex
37 * - neue Funktion Channel_Count().
39 * Revision 1.3 2002/01/02 02:42:58 alex
40 * - Copyright-Texte aktualisiert.
42 * Revision 1.2 2001/12/31 02:18:51 alex
43 * - viele neue Befehle (WHOIS, ISON, OPER, DIE, RESTART),
44 * - neuen Header "defines.h" mit (fast) allen Konstanten.
45 * - Code Cleanups und viele "kleine" Aenderungen & Bugfixes.
47 * Revision 1.1 2001/12/14 08:13:43 alex
48 * - neues Modul begonnen :-)
72 LOCAL CHANNEL *My_Channels;
73 LOCAL CL2CHAN *My_Cl2Chan;
76 LOCAL CHANNEL *New_Chan( CHAR *Name );
77 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client );
78 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client );
79 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART );
80 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan );
81 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan );
82 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan );
85 GLOBAL VOID Channel_Init( VOID )
92 GLOBAL VOID Channel_Exit( VOID )
95 CL2CHAN *cl2chan, *cl2chan_next;
97 /* Channel-Strukturen freigeben */
106 /* Channel-Zuordnungstabelle freigeben */
107 cl2chan = My_Cl2Chan;
110 cl2chan_next = cl2chan->next;
112 cl2chan = cl2chan_next;
117 GLOBAL BOOLEAN Channel_Join( CLIENT *Client, CHAR *Name )
121 assert( Client != NULL );
122 assert( Name != NULL );
124 /* Valider Channel-Name? */
125 if(( Name[0] != '#' ) || ( strlen( Name ) >= CHANNEL_NAME_LEN ))
127 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
132 chan = Channel_Search( Name );
135 /* Ist der Client bereits Mitglied? */
136 if( Get_Cl2Chan( chan, Client )) return FALSE;
140 /* Gibt es noch nicht? Dann neu anlegen: */
141 chan = New_Chan( Name );
142 if( ! chan ) return FALSE;
145 chan->next = My_Channels;
149 /* User dem Channel hinzufuegen */
150 if( ! Add_Client( chan, Client )) return FALSE;
155 GLOBAL BOOLEAN Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason )
159 assert( Client != NULL );
160 assert( Name != NULL );
163 chan = Channel_Search( Name );
164 if(( ! chan ) || ( ! Get_Cl2Chan( chan, Client )))
166 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
170 /* User aus Channel entfernen */
171 if( ! Remove_Client( chan, Client, Origin, Reason, TRUE )) return FALSE;
176 GLOBAL VOID Channel_RemoveClient( CLIENT *Client, CHAR *Reason )
180 assert( Client != NULL );
186 Remove_Client( c, Client, Client_ThisServer( ), Reason, FALSE );
189 } /* Channel_RemoveClient */
192 GLOBAL INT Channel_Count( VOID )
205 } /* Channel_Count */
208 GLOBAL CHAR *Channel_Name( CHANNEL *Chan )
210 assert( Chan != NULL );
215 GLOBAL CHANNEL *Channel_First( VOID )
218 } /* Channel_First */
221 GLOBAL CHANNEL *Channel_Next( CHANNEL *Chan )
223 assert( Chan != NULL );
228 GLOBAL CHANNEL *Channel_Search( CHAR *Name )
230 /* Channel-Struktur suchen */
234 assert( Name != NULL );
238 if( strcasecmp( Name, c->name ) == 0 ) return c;
242 } /* Channel_Search */
245 GLOBAL CL2CHAN *Channel_FirstMember( CHANNEL *Chan )
247 assert( Chan != NULL );
248 return Get_First_Cl2Chan( NULL, Chan );
249 } /* Channel_IsMember */
252 GLOBAL CL2CHAN *Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
254 assert( Chan != NULL );
255 assert( Cl2Chan != NULL );
256 return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
257 } /* Channel_NextMember */
260 GLOBAL CLIENT *Channel_GetClient( CL2CHAN *Cl2Chan )
262 assert( Cl2Chan != NULL );
263 return Cl2Chan->client;
264 } /* Channel_GetClient */
267 GLOBAL CHANNEL *Channel_GetChannel( CL2CHAN *Cl2Chan )
269 assert( Cl2Chan != NULL );
270 return Cl2Chan->channel;
271 } /* Channel_GetChannel */
274 LOCAL CHANNEL *New_Chan( CHAR *Name )
276 /* Neue Channel-Struktur anlegen */
280 assert( Name != NULL );
282 c = malloc( sizeof( CHANNEL ));
285 Log( LOG_EMERG, "Can't allocate memory!" );
289 strncpy( c->name, Name, CHANNEL_NAME_LEN );
290 c->name[CHANNEL_NAME_LEN - 1] = '\0';
291 strcpy( c->modes, "" );
293 Log( LOG_DEBUG, "Created new channel structure for \"%s\".", Name );
299 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
303 assert( Chan != NULL );
304 assert( Client != NULL );
306 cl2chan = My_Cl2Chan;
309 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
310 cl2chan = cl2chan->next;
316 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client )
320 assert( Chan != NULL );
321 assert( Client != NULL );
323 cl2chan = malloc( sizeof( CL2CHAN ));
326 Log( LOG_EMERG, "Can't allocate memory!" );
329 cl2chan->channel = Chan;
330 cl2chan->client = Client;
333 cl2chan->next = My_Cl2Chan;
334 My_Cl2Chan = cl2chan;
336 Log( LOG_DEBUG, "User \"%s\" joined channel \"%s\".", Client_Mask( Client ), Chan->name );
342 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART )
344 CL2CHAN *cl2chan, *last_cl2chan;
347 assert( Chan != NULL );
348 assert( Client != NULL );
349 assert( Origin != NULL );
350 assert( Reason != NULL );
353 cl2chan = My_Cl2Chan;
356 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
357 last_cl2chan = cl2chan;
358 cl2chan = cl2chan->next;
360 if( ! cl2chan ) return FALSE;
362 c = cl2chan->channel;
365 /* Aus Verkettung loesen und freigeben */
366 if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
367 else My_Cl2Chan = cl2chan->next;
370 if( ServerPART ) IRC_WriteStrServersPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
371 IRC_WriteStrChannelPrefix( Origin, c, Client, FALSE, "PART %s :%s", c->name, Reason );
372 if(( Client_Conn( Origin ) > NONE ) && ( Client_Type( Origin ) == CLIENT_USER )) IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
374 Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason );
376 /* Wenn Channel nun leer: loeschen */
377 if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
380 } /* Remove_Client */
383 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
385 return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
386 } /* Get_First_Cl2Chan */
389 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
393 assert( Client != NULL || Channel != NULL );
398 if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
399 if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
400 cl2chan = cl2chan->next;
403 } /* Get_Next_Cl2Chan */
406 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan )
408 /* Channel-Struktur loeschen */
410 CHANNEL *chan, *last_chan;
416 if( chan == Chan ) break;
420 if( ! chan ) return FALSE;
422 Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name );
424 /* Neu verketten und freigeben */
425 if( last_chan ) last_chan->next = chan->next;
426 else My_Channels = chan->next;
430 } /* Delete_Channel */