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