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