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