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