]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/channel.c
3f140064647f44241609bfb928793ee50670b974
[ngircd-alex.git] / src / ngircd / 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: channel.c,v 1.6 2002/01/26 18:41:55 alex Exp $
13  *
14  * channel.c: Management der Channels
15  *
16  * $Log: channel.c,v $
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(), ...)
20  *
21  * Revision 1.5  2002/01/21 00:12:29  alex
22  * - begonnen, Channels zu implementieren :-)
23  *
24  * Revision 1.4  2002/01/16 22:09:07  alex
25  * - neue Funktion Channel_Count().
26  *
27  * Revision 1.3  2002/01/02 02:42:58  alex
28  * - Copyright-Texte aktualisiert.
29  *
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.
34  *
35  * Revision 1.1  2001/12/14 08:13:43  alex
36  * - neues Modul begonnen :-)
37  */
38
39
40 #define __channel_c__
41
42
43 #include <portab.h>
44 #include "global.h"
45
46 #include <imp.h>
47 #include <assert.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "client.h"
52 #include "irc.h"
53 #include "log.h"
54 #include "messages.h"
55
56 #include <exp.h>
57 #include "channel.h"
58
59
60 LOCAL CHANNEL *My_Channels;
61 LOCAL CL2CHAN *My_Cl2Chan;
62
63
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 );
71
72
73 GLOBAL VOID Channel_Init( VOID )
74 {
75         My_Channels = NULL;
76         My_Cl2Chan = NULL;
77 } /* Channel_Init */
78
79
80 GLOBAL VOID Channel_Exit( VOID )
81 {
82         CHANNEL *c, *c_next;
83         CL2CHAN *cl2chan, *cl2chan_next;
84         
85         /* Channel-Strukturen freigeben */
86         c = My_Channels;
87         while( c )
88         {
89                 c_next = c->next;
90                 free( c );
91                 c = c_next;
92         }
93
94         /* Channel-Zuordnungstabelle freigeben */
95         cl2chan = My_Cl2Chan;
96         while( c )
97         {
98                 cl2chan_next = cl2chan->next;
99                 free( cl2chan );
100                 cl2chan = cl2chan_next;
101         }
102 } /* Channel_Exit */
103
104
105 GLOBAL BOOLEAN Channel_Join( CLIENT *Client, CHAR *Name )
106 {
107         CHANNEL *chan;
108         
109         assert( Client != NULL );
110         assert( Name != NULL );
111
112         /* Valider Channel-Name? */
113         if(( Name[0] != '#' ) || ( strlen( Name ) >= CHANNEL_NAME_LEN ))
114         {
115                 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
116                 return FALSE;
117         }
118
119         /* Channel suchen */
120         chan = Channel_Search( Name );
121         if( chan )
122         {
123                 /* Ist der Client bereits Mitglied? */
124                 if( Get_Cl2Chan( chan, Client )) return FALSE;
125         }
126         else
127         {
128                 /* Gibt es noch nicht? Dann neu anlegen: */
129                 chan = New_Chan( Name );
130                 if( ! chan ) return FALSE;
131
132                 /* Verketten */
133                 chan->next = My_Channels;
134                 My_Channels = chan;
135         }
136
137         /* User dem Channel hinzufuegen */
138         if( ! Add_Client( chan, Client )) return FALSE;
139         else return TRUE;
140 } /* Channel_Join */
141
142
143 GLOBAL BOOLEAN Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason )
144 {
145         CHANNEL *chan;
146
147         assert( Client != NULL );
148         assert( Name != NULL );
149
150         /* Channel suchen */
151         chan = Channel_Search( Name );
152         if(( ! chan ) || ( ! Get_Cl2Chan( chan, Client )))
153         {
154                 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
155                 return FALSE;
156         }
157
158         /* User aus Channel entfernen */
159         if( ! Remove_Client( chan, Client, Origin, Reason )) return FALSE;
160         else return TRUE;
161 } /* Channel_Part */
162
163
164 GLOBAL VOID Channel_RemoveClient( CLIENT *Client, CHAR *Reason )
165 {
166         CHANNEL *c, *next_c;
167
168         assert( Client != NULL );
169
170         c = My_Channels;
171         while( c )
172         {
173                 next_c = c->next;
174                 Remove_Client( c, Client, Client_ThisServer( ), Reason );
175                 c = next_c;
176         }
177 } /* Channel_RemoveClient */
178
179
180 GLOBAL INT Channel_Count( VOID )
181 {
182         CHANNEL *c;
183         INT count;
184         
185         count = 0;
186         c = My_Channels;
187         while( c )
188         {
189                 count++;
190                 c = c->next;
191         }
192         return count;
193 } /* Channel_Count */
194
195
196 GLOBAL CHANNEL *Channel_Search( CHAR *Name )
197 {
198         /* Channel-Struktur suchen */
199         
200         CHANNEL *c;
201
202         assert( Name != NULL );
203         c = My_Channels;
204         while( c )
205         {
206                 if( strcasecmp( Name, c->name ) == 0 ) return c;
207                 c = c->next;
208         }
209         return NULL;
210 } /* Channel_Search */
211
212
213 GLOBAL CL2CHAN *Channel_FirstMember( CHANNEL *Chan )
214 {
215         assert( Chan != NULL );
216         return Get_First_Cl2Chan( NULL, Chan );
217 } /* Channel_IsMember */
218
219
220 GLOBAL CL2CHAN *Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
221 {
222         assert( Chan != NULL );
223         assert( Cl2Chan != NULL );
224         return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
225 } /* Channel_NextMember */
226
227
228 GLOBAL CLIENT *Channel_GetClient( CL2CHAN *Cl2Chan )
229 {
230         assert( Cl2Chan != NULL );
231         return Cl2Chan->client;
232 } /* Channel_GetClient */
233
234
235 GLOBAL CHANNEL *Channel_GetChannel( CL2CHAN *Cl2Chan )
236 {
237         assert( Cl2Chan != NULL );
238         return Cl2Chan->channel;
239 } /* Channel_GetChannel */
240
241
242 LOCAL CHANNEL *New_Chan( CHAR *Name )
243 {
244         /* Neue Channel-Struktur anlegen */
245         
246         CHANNEL *c;
247
248         assert( Name != NULL );
249         
250         c = malloc( sizeof( CHANNEL ));
251         if( ! c )
252         {
253                 Log( LOG_EMERG, "Can't allocate memory!" );
254                 return NULL;
255         }
256         c->next = NULL;
257         strncpy( c->name, Name, CHANNEL_NAME_LEN );
258         c->name[CHANNEL_NAME_LEN - 1] = '\0';
259         strcpy( c->modes, "" );
260
261         Log( LOG_DEBUG, "Created new channel structure for \"%s\".", Name );
262         
263         return c;
264 } /* New_Chan */
265
266
267 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
268 {
269         CL2CHAN *cl2chan;
270
271         assert( Chan != NULL );
272         assert( Client != NULL );
273
274         cl2chan = My_Cl2Chan;
275         while( cl2chan )
276         {
277                 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
278                 cl2chan = cl2chan->next;
279         }
280         return NULL;
281 } /* Get_Cl2Chan */
282
283
284 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client )
285 {
286         CL2CHAN *cl2chan;
287
288         assert( Chan != NULL );
289         assert( Client != NULL );
290
291         cl2chan = malloc( sizeof( CL2CHAN ));
292         if( ! cl2chan )
293         {
294                 Log( LOG_EMERG, "Can't allocate memory!" );
295                 return NULL;
296         }
297         cl2chan->channel = Chan;
298         cl2chan->client = Client;
299
300         /* Verketten */
301         cl2chan->next = My_Cl2Chan;
302         My_Cl2Chan = cl2chan;
303         
304         return cl2chan;
305 } /* Add_Client */
306
307
308 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason )
309 {
310         CL2CHAN *cl2chan, *last_cl2chan;
311         CHANNEL *c;
312         
313         assert( Chan != NULL );
314         assert( Client != NULL );
315         assert( Origin != NULL );
316         assert( Reason != NULL );
317
318         last_cl2chan = NULL;
319         cl2chan = My_Cl2Chan;
320         while( cl2chan )
321         {
322                 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
323                 last_cl2chan = cl2chan;
324                 cl2chan = cl2chan->next;
325         }
326         if( ! cl2chan ) return FALSE;
327
328         c = cl2chan->channel;
329         assert( c != NULL );
330
331         /* Aus Verkettung loesen und freigeben */
332         if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
333         else My_Cl2Chan = cl2chan->next;
334         free( cl2chan );
335
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 );
339
340         Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason );
341
342         /* Wenn Channel nun leer: loeschen */
343         if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
344                 
345         return TRUE;
346 } /* Remove_Client */
347
348
349 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
350 {
351         return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
352 } /* Get_First_Cl2Chan */
353
354
355 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
356 {
357         CL2CHAN *cl2chan;
358
359         assert( Client != NULL || Channel != NULL );
360         
361         cl2chan = Start;
362         while( cl2chan )
363         {
364                 if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
365                 if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
366                 cl2chan = cl2chan->next;
367         }
368         return NULL;
369 } /* Get_Next_Cl2Chan */
370
371
372 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan )
373 {
374         /* Channel-Struktur loeschen */
375         
376         CHANNEL *chan, *last_chan;
377
378         last_chan = NULL;
379         chan = My_Channels;
380         while( chan )
381         {
382                 if( chan == Chan ) break;
383                 last_chan = chan;
384                 chan = chan->next;
385         }
386         if( ! chan ) return FALSE;
387
388         Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name );
389
390         /* Neu verketten und freigeben */
391         if( last_chan ) last_chan->next = chan->next;
392         else My_Channels = chan->next;
393         free( chan );
394                 
395         return TRUE;
396 } /* Delete_Channel */
397
398
399 /* -eof- */