2 * ngIRCd -- The Next Generation IRC Daemon
3 * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
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.
12 * $Id: channel.c,v 1.19 2002/03/12 14:37:52 alex Exp $
14 * channel.c: Management der Channels
29 #include "irc-write.h"
37 LOCAL CHANNEL *My_Channels;
38 LOCAL CL2CHAN *My_Cl2Chan;
41 LOCAL CHANNEL *New_Chan( CHAR *Name );
42 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client );
43 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client );
44 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART );
45 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan );
46 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan );
47 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan );
50 GLOBAL VOID Channel_Init( VOID )
57 GLOBAL VOID Channel_Exit( VOID )
60 CL2CHAN *cl2chan, *cl2chan_next;
62 /* Channel-Strukturen freigeben */
71 /* Channel-Zuordnungstabelle freigeben */
75 cl2chan_next = cl2chan->next;
77 cl2chan = cl2chan_next;
82 GLOBAL BOOLEAN Channel_Join( CLIENT *Client, CHAR *Name )
86 assert( Client != NULL );
87 assert( Name != NULL );
89 /* Valider Channel-Name? */
90 if( ! Channel_IsValidName( Name ))
92 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
97 chan = Channel_Search( Name );
100 /* Ist der Client bereits Mitglied? */
101 if( Get_Cl2Chan( chan, Client )) return FALSE;
105 /* Gibt es noch nicht? Dann neu anlegen: */
106 chan = New_Chan( Name );
107 if( ! chan ) return FALSE;
110 chan->next = My_Channels;
114 /* User dem Channel hinzufuegen */
115 if( ! Add_Client( chan, Client )) return FALSE;
120 GLOBAL BOOLEAN Channel_Part( CLIENT *Client, CLIENT *Origin, CHAR *Name, CHAR *Reason )
124 assert( Client != NULL );
125 assert( Name != NULL );
128 chan = Channel_Search( Name );
129 if(( ! chan ) || ( ! Get_Cl2Chan( chan, Client )))
131 IRC_WriteStrClient( Client, ERR_NOSUCHCHANNEL_MSG, Client_ID( Client ), Name );
135 /* User aus Channel entfernen */
136 if( ! Remove_Client( chan, Client, Origin, Reason, TRUE )) return FALSE;
141 GLOBAL VOID Channel_RemoveClient( CLIENT *Client, CHAR *Reason )
145 assert( Client != NULL );
151 Remove_Client( c, Client, Client_ThisServer( ), Reason, FALSE );
154 } /* Channel_RemoveClient */
157 GLOBAL INT Channel_Count( VOID )
170 } /* Channel_Count */
173 GLOBAL CHAR *Channel_Name( CHANNEL *Chan )
175 assert( Chan != NULL );
180 GLOBAL CHAR *Channel_Modes( CHANNEL *Chan )
182 assert( Chan != NULL );
184 } /* Channel_Modes */
187 GLOBAL CHANNEL *Channel_First( VOID )
190 } /* Channel_First */
193 GLOBAL CHANNEL *Channel_Next( CHANNEL *Chan )
195 assert( Chan != NULL );
200 GLOBAL CHANNEL *Channel_Search( CHAR *Name )
202 /* Channel-Struktur suchen */
206 assert( Name != NULL );
210 if( strcasecmp( Name, c->name ) == 0 ) return c;
214 } /* Channel_Search */
217 GLOBAL CL2CHAN *Channel_FirstMember( CHANNEL *Chan )
219 assert( Chan != NULL );
220 return Get_First_Cl2Chan( NULL, Chan );
221 } /* Channel_FirstMember */
224 GLOBAL CL2CHAN *Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
226 assert( Chan != NULL );
227 assert( Cl2Chan != NULL );
228 return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
229 } /* Channel_NextMember */
232 GLOBAL CL2CHAN *Channel_FirstChannelOf( CLIENT *Client )
234 assert( Client != NULL );
235 return Get_First_Cl2Chan( Client, NULL );
236 } /* Channel_FirstChannelOf */
239 GLOBAL CL2CHAN *Channel_NextChannelOf( CLIENT *Client, CL2CHAN *Cl2Chan )
241 assert( Client != NULL );
242 assert( Cl2Chan != NULL );
243 return Get_Next_Cl2Chan( Cl2Chan->next, Client, NULL );
244 } /* Channel_NextChannelOf */
247 GLOBAL CLIENT *Channel_GetClient( CL2CHAN *Cl2Chan )
249 assert( Cl2Chan != NULL );
250 return Cl2Chan->client;
251 } /* Channel_GetClient */
254 GLOBAL CHANNEL *Channel_GetChannel( CL2CHAN *Cl2Chan )
256 assert( Cl2Chan != NULL );
257 return Cl2Chan->channel;
258 } /* Channel_GetChannel */
261 GLOBAL BOOLEAN Channel_IsValidName( CHAR *Name )
263 /* Pr
\9ffen, ob Name als Channelname gueltig */
265 CHAR *ptr, badchars[] = " ,:\x07";
267 assert( Name != NULL );
269 if(( Name[0] != '#' ) || ( strlen( Name ) >= CHANNEL_NAME_LEN )) return FALSE;
274 if( strchr( badchars, *ptr )) return FALSE;
279 } /* Channel_IsValidName */
282 GLOBAL BOOLEAN Channel_ModeAdd( CHANNEL *Chan, CHAR Mode )
284 /* Mode soll gesetzt werden. TRUE wird geliefert, wenn der
285 * Mode neu gesetzt wurde, FALSE, wenn der Channel den Mode
290 assert( Chan != NULL );
292 x[0] = Mode; x[1] = '\0';
293 if( ! strchr( Chan->modes, x[0] ))
295 /* Client hat den Mode noch nicht -> setzen */
296 strcat( Chan->modes, x );
300 } /* Channel_ModeAdd */
303 GLOBAL BOOLEAN Channel_ModeDel( CHANNEL *Chan, CHAR Mode )
305 /* Mode soll geloescht werden. TRUE wird geliefert, wenn der
306 * Mode entfernt wurde, FALSE, wenn der Channel den Mode
307 * ueberhaupt nicht hatte. */
311 assert( Chan != NULL );
313 x[0] = Mode; x[1] = '\0';
315 p = strchr( Chan->modes, x[0] );
316 if( ! p ) return FALSE;
318 /* Client hat den Mode -> loeschen */
325 } /* Channel_ModeDel */
328 GLOBAL BOOLEAN Channel_UserModeAdd( CHANNEL *Chan, CLIENT *Client, CHAR Mode )
330 /* Channel-User-Mode soll gesetzt werden. TRUE wird geliefert,
331 * wenn der Mode neu gesetzt wurde, FALSE, wenn der User den
332 * Channel-Mode bereits hatte. */
337 assert( Chan != NULL );
338 assert( Client != NULL );
340 cl2chan = Get_Cl2Chan( Chan, Client );
341 assert( cl2chan != NULL );
343 x[0] = Mode; x[1] = '\0';
344 if( ! strchr( cl2chan->modes, x[0] ))
346 /* Client hat den Mode noch nicht -> setzen */
347 strcat( cl2chan->modes, x );
351 } /* Channel_UserModeAdd */
354 GLOBAL BOOLEAN Channel_UserModeDel( CHANNEL *Chan, CLIENT *Client, CHAR Mode )
356 /* Channel-User-Mode soll geloescht werden. TRUE wird geliefert,
357 * wenn der Mode entfernt wurde, FALSE, wenn der User den Channel-Mode
358 * ueberhaupt nicht hatte. */
363 assert( Chan != NULL );
364 assert( Client != NULL );
366 cl2chan = Get_Cl2Chan( Chan, Client );
367 assert( cl2chan != NULL );
369 x[0] = Mode; x[1] = '\0';
371 p = strchr( cl2chan->modes, x[0] );
372 if( ! p ) return FALSE;
374 /* Client hat den Mode -> loeschen */
381 } /* Channel_UserModeDel */
384 GLOBAL CHAR *Channel_UserModes( CHANNEL *Chan, CLIENT *Client )
386 /* Channel-Modes eines Users liefern */
390 assert( Chan != NULL );
391 assert( Client != NULL );
393 cl2chan = Get_Cl2Chan( Chan, Client );
394 assert( cl2chan != NULL );
396 return cl2chan->modes;
397 } /* Channel_UserModes */
400 GLOBAL BOOLEAN Channel_IsMemberOf( CHANNEL *Chan, CLIENT *Client )
402 /* Pruefen, ob Client Mitglied in Channel ist */
404 assert( Chan != NULL );
405 assert( Client != NULL );
407 if( Get_Cl2Chan( Chan, Client )) return TRUE;
409 } /* Channel_IsMemberOf */
412 GLOBAL CHAR *Channel_Topic( CHANNEL *Chan )
414 assert( Chan != NULL );
416 } /* Channel_Topic */
419 GLOBAL VOID Channel_SetTopic( CHANNEL *Chan, CHAR *Topic )
421 assert( Chan != NULL );
422 assert( Topic != NULL );
424 strncpy( Chan->topic, Topic, CHANNEL_TOPIC_LEN - 1 );
425 Chan->topic[CHANNEL_TOPIC_LEN - 1] = '\0';
426 } /* Channel_SetTopic */
429 LOCAL CHANNEL *New_Chan( CHAR *Name )
431 /* Neue Channel-Struktur anlegen */
435 assert( Name != NULL );
437 c = malloc( sizeof( CHANNEL ));
440 Log( LOG_EMERG, "Can't allocate memory!" );
444 strncpy( c->name, Name, CHANNEL_NAME_LEN - 1 );
445 c->name[CHANNEL_NAME_LEN - 1] = '\0';
446 strcpy( c->modes, "" );
447 strcpy( c->topic, "" );
449 Log( LOG_DEBUG, "Created new channel structure for \"%s\".", Name );
455 LOCAL CL2CHAN *Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
459 assert( Chan != NULL );
460 assert( Client != NULL );
462 cl2chan = My_Cl2Chan;
465 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
466 cl2chan = cl2chan->next;
472 LOCAL CL2CHAN *Add_Client( CHANNEL *Chan, CLIENT *Client )
476 assert( Chan != NULL );
477 assert( Client != NULL );
479 /* neue CL2CHAN-Struktur anlegen */
480 cl2chan = malloc( sizeof( CL2CHAN ));
483 Log( LOG_EMERG, "Can't allocate memory!" );
486 cl2chan->channel = Chan;
487 cl2chan->client = Client;
488 strcpy( cl2chan->modes, "" );
491 cl2chan->next = My_Cl2Chan;
492 My_Cl2Chan = cl2chan;
494 Log( LOG_DEBUG, "User \"%s\" joined channel \"%s\".", Client_Mask( Client ), Chan->name );
500 LOCAL BOOLEAN Remove_Client( CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, CHAR *Reason, BOOLEAN ServerPART )
502 CL2CHAN *cl2chan, *last_cl2chan;
505 assert( Chan != NULL );
506 assert( Client != NULL );
507 assert( Origin != NULL );
508 assert( Reason != NULL );
511 cl2chan = My_Cl2Chan;
514 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
515 last_cl2chan = cl2chan;
516 cl2chan = cl2chan->next;
518 if( ! cl2chan ) return FALSE;
520 c = cl2chan->channel;
523 /* Aus Verkettung loesen und freigeben */
524 if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
525 else My_Cl2Chan = cl2chan->next;
528 if( ServerPART ) IRC_WriteStrServersPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
529 IRC_WriteStrChannelPrefix( Origin, c, Client, FALSE, "PART %s :%s", c->name, Reason );
530 if(( Client_Conn( Origin ) > NONE ) && ( Client_Type( Origin ) == CLIENT_USER )) IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason );
532 Log( LOG_DEBUG, "User \"%s\" left channel \"%s\" (%s).", Client_Mask( Client ), c->name, Reason );
534 /* Wenn Channel nun leer: loeschen */
535 if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
538 } /* Remove_Client */
541 LOCAL CL2CHAN *Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
543 return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
544 } /* Get_First_Cl2Chan */
547 LOCAL CL2CHAN *Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
551 assert( Client != NULL || Channel != NULL );
556 if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
557 if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
558 cl2chan = cl2chan->next;
561 } /* Get_Next_Cl2Chan */
564 LOCAL BOOLEAN Delete_Channel( CHANNEL *Chan )
566 /* Channel-Struktur loeschen */
568 CHANNEL *chan, *last_chan;
574 if( chan == Chan ) break;
578 if( ! chan ) return FALSE;
580 Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name );
582 /* Neu verketten und freigeben */
583 if( last_chan ) last_chan->next = chan->next;
584 else My_Channels = chan->next;
588 } /* Delete_Channel */