]> arthur.barton.de Git - ngircd-alex.git/blob - src/ngircd/channel.c
Create local &SERVER channel and log server messages to it
[ngircd-alex.git] / src / ngircd / channel.c
1 /*
2  * ngIRCd -- The Next Generation IRC Daemon
3  * Copyright (c)2001-2008 by Alexander Barton (alex@barton.de)
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * Please read the file COPYING, README and AUTHORS for more information.
10  *
11  * Channel management
12  */
13
14
15 #define __channel_c__
16
17
18 #include "portab.h"
19
20 #include "imp.h"
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <strings.h>
26
27 #include "defines.h"
28 #include "conn-func.h"
29 #include "client.h"
30
31 #include "exp.h"
32 #include "channel.h"
33
34 #include "imp.h"
35 #include "irc-write.h"
36 #include "resolve.h"
37 #include "conf.h"
38 #include "hash.h"
39 #include "lists.h"
40 #include "log.h"
41 #include "messages.h"
42
43 #include "exp.h"
44
45
46 #define REMOVE_PART 0
47 #define REMOVE_QUIT 1
48 #define REMOVE_KICK 2
49
50
51 static CHANNEL *My_Channels;
52 static CL2CHAN *My_Cl2Chan;
53
54
55 static CL2CHAN *Get_Cl2Chan PARAMS(( CHANNEL *Chan, CLIENT *Client ));
56 static CL2CHAN *Add_Client PARAMS(( CHANNEL *Chan, CLIENT *Client ));
57 static bool Remove_Client PARAMS(( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer ));
58 static CL2CHAN *Get_First_Cl2Chan PARAMS(( CLIENT *Client, CHANNEL *Chan ));
59 static CL2CHAN *Get_Next_Cl2Chan PARAMS(( CL2CHAN *Start, CLIENT *Client, CHANNEL *Chan ));
60 static bool Delete_Channel PARAMS(( CHANNEL *Chan ));
61
62
63 GLOBAL void
64 Channel_Init( void )
65 {
66         CHANNEL *sc;
67
68         My_Channels = NULL;
69         My_Cl2Chan = NULL;
70
71         sc = Channel_Create("&SERVER");
72         if (sc) {
73                 Channel_SetModes(sc, "mnPt");
74                 Channel_SetTopic(sc, Client_ThisServer(), "Server Messages");
75         }
76 } /* Channel_Init */
77
78
79 GLOBAL struct list_head *
80 Channel_GetListBans(CHANNEL *c)
81 {
82         assert(c != NULL);
83         return &c->list_bans;
84 }
85
86
87 GLOBAL struct list_head *
88 Channel_GetListInvites(CHANNEL *c)
89 {
90         assert(c != NULL);
91         return &c->list_invites;
92 }
93
94
95 GLOBAL void
96 Channel_InitPredefined( void )
97 {
98         /* Generate predefined persistent channels */
99
100         CHANNEL *chan;
101         char *c;
102         unsigned int i;
103
104         for( i = 0; i < Conf_Channel_Count; i++ )
105         {
106                 /* Check for Name configuration */
107                 if( ! Conf_Channel[i].name[0] ) continue;
108
109                 /* Check for invalid channel name */
110                 if( ! Channel_IsValidName( Conf_Channel[i].name ))
111                 {
112                         Log( LOG_ERR, "Can't create pre-defined channel: invalid name: \"%s\"!", Conf_Channel[i].name );
113                         array_free(&Conf_Channel[i].topic);
114                         continue;
115                 }
116
117                 /* Check if the channel name is already in use */
118                 chan = Channel_Search( Conf_Channel[i].name );
119                 if( chan )
120                 {
121                         Log( LOG_INFO, "Can't create pre-defined channel \"%s\": name already in use.", Conf_Channel[i].name );
122                         array_free(&Conf_Channel[i].topic);
123                         continue;
124                 }
125
126                 /* Create channel */
127                 chan = Channel_Create(Conf_Channel[i].name);
128                 if (chan) {
129                         Channel_ModeAdd(chan, 'P');
130
131                         if (array_start(&Conf_Channel[i].topic) != NULL)
132                                 Channel_SetTopic(chan, NULL,
133                                          array_start(&Conf_Channel[i].topic));
134                         array_free(&Conf_Channel[i].topic);
135
136                         c = Conf_Channel[i].modes;
137                         while (*c)
138                                 Channel_ModeAdd(chan, *c++);
139
140                         Channel_SetKey(chan, Conf_Channel[i].key);
141                         Channel_SetMaxUsers(chan, Conf_Channel[i].maxusers);
142
143                         Log(LOG_INFO, "Created pre-defined channel \"%s\".",
144                                                         Conf_Channel[i].name );
145                 }
146                 else Log(LOG_ERR, "Can't create pre-defined channel \"%s\"!",
147                                                         Conf_Channel[i].name );
148         }
149 } /* Channel_InitPredefined */
150
151
152 GLOBAL void
153 Channel_Exit( void )
154 {
155         CHANNEL *c, *c_next;
156         CL2CHAN *cl2chan, *cl2chan_next;
157
158         /* free struct Channel */
159         c = My_Channels;
160         while( c )
161         {
162                 c_next = c->next;
163                 array_free(&c->topic);
164                 free( c );
165                 c = c_next;
166         }
167
168         /* Free Channel allocation table */
169         cl2chan = My_Cl2Chan;
170         while( c )
171         {
172                 cl2chan_next = cl2chan->next;
173                 free( cl2chan );
174                 cl2chan = cl2chan_next;
175         }
176 } /* Channel_Exit */
177
178
179 /**
180  * Join Channel
181  * This function lets a client join a channel.  First, the function
182  * checks that the specified channel name is valid and that the client
183  * isn't already a member.  If the specified channel doesn't exist,
184  * a new channel is created.  Client is added to channel by function
185  * Add_Client().
186  */
187 GLOBAL bool
188 Channel_Join( CLIENT *Client, char *Name )
189 {
190         CHANNEL *chan;
191
192         assert(Client != NULL);
193         assert(Name != NULL);
194
195         /* Check that the channel name is valid */
196         if (! Channel_IsValidName(Name)) {
197                 IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG,
198                                    Client_ID(Client), Name);
199                 return false;
200         }
201
202         chan = Channel_Search(Name);
203         if(chan) {
204                 /* Check if the client is already in the channel */
205                 if (Get_Cl2Chan(chan, Client))
206                         return false;
207         } else {
208                 /* If the specified channel does not exist, the channel
209                  * is now created */
210                 chan = Channel_Create(Name);
211                 if (!chan)
212                         return false;
213         }
214
215         /* Add user to Channel */
216         if (! Add_Client(chan, Client))
217                 return false;
218
219         return true;
220 } /* Channel_Join */
221
222
223 /**
224  * Part client from channel.
225  * This function lets a client part from a channel. First, the function checks
226  * if the channel exists and the client is a member of it and sends out
227  * appropriate error messages if not. The real work is done by the function
228  * Remove_Client().
229  */
230 GLOBAL bool
231 Channel_Part(CLIENT * Client, CLIENT * Origin, const char *Name, const char *Reason)
232 {
233         CHANNEL *chan;
234
235         assert(Client != NULL);
236         assert(Name != NULL);
237         assert(Reason != NULL);
238
239         /* Check that specified channel exists */
240         chan = Channel_Search(Name);
241         if (!chan) {
242                 IRC_WriteStrClient(Client, ERR_NOSUCHCHANNEL_MSG,
243                                    Client_ID(Client), Name);
244                 return false;
245         }
246
247         /* Check that the client is in the channel */
248         if (!Get_Cl2Chan(chan, Client)) {
249                 IRC_WriteStrClient(Client, ERR_NOTONCHANNEL_MSG,
250                                    Client_ID(Client), Name);
251                 return false;
252         }
253
254         /* Part client from channel */
255         if (!Remove_Client(REMOVE_PART, chan, Client, Origin, Reason, true))
256                 return false;
257         else
258                 return true;
259 } /* Channel_Part */
260
261
262 /**
263  * Kick user from Channel
264  */
265 GLOBAL void
266 Channel_Kick(CLIENT *Peer, CLIENT *Target, CLIENT *Origin, const char *Name,
267              const char *Reason )
268 {
269         CHANNEL *chan;
270
271         assert(Peer != NULL);
272         assert(Target != NULL);
273         assert(Origin != NULL);
274         assert(Name != NULL);
275         assert(Reason != NULL);
276
277         /* Check that channel exists */
278         chan = Channel_Search( Name );
279         if( ! chan )
280         {
281                 IRC_WriteStrClient( Origin, ERR_NOSUCHCHANNEL_MSG, Client_ID( Origin ), Name );
282                 return;
283         }
284
285         if (Client_Type(Peer) != CLIENT_SERVER &&
286             Client_Type(Origin) != CLIENT_SERVICE) {
287                 /* Check that user is on the specified channel */
288                 if (!Channel_IsMemberOf(chan, Origin)) {
289                         IRC_WriteStrClient( Origin, ERR_NOTONCHANNEL_MSG,
290                                            Client_ID(Origin), Name);
291                         return;
292                 }
293
294                 /* Check if user has operator status */
295                 if (!strchr(Channel_UserModes(chan, Origin), 'o')) {
296                         IRC_WriteStrClient(Origin, ERR_CHANOPRIVSNEEDED_MSG,
297                                            Client_ID(Origin), Name);
298                         return;
299                 }
300         }
301
302         /* Check that the client to be kicked is on the specified channel */
303         if (!Channel_IsMemberOf(chan, Target)) {
304                 IRC_WriteStrClient(Origin, ERR_USERNOTINCHANNEL_MSG,
305                                    Client_ID(Origin), Client_ID(Target), Name );
306                 return;
307         }
308
309         /* Kick Client from channel */
310         Remove_Client( REMOVE_KICK, chan, Target, Origin, Reason, true);
311 } /* Channel_Kick */
312
313
314 GLOBAL void
315 Channel_Quit( CLIENT *Client, char *Reason )
316 {
317         CHANNEL *c, *next_c;
318
319         assert( Client != NULL );
320         assert( Reason != NULL );
321
322         IRC_WriteStrRelatedPrefix( Client, Client, false, "QUIT :%s", Reason );
323
324         c = My_Channels;
325         while( c )
326         {
327                 next_c = c->next;
328                 Remove_Client( REMOVE_QUIT, c, Client, Client, Reason, false );
329                 c = next_c;
330         }
331 } /* Channel_Quit */
332
333
334 GLOBAL unsigned long
335 Channel_Count( void )
336 {
337         CHANNEL *c;
338         unsigned long count = 0;
339
340         c = My_Channels;
341         while( c )
342         {
343                 count++;
344                 c = c->next;
345         }
346         return count;
347 } /* Channel_Count */
348
349
350 GLOBAL unsigned long
351 Channel_MemberCount( CHANNEL *Chan )
352 {
353         CL2CHAN *cl2chan;
354         unsigned long count = 0;
355
356         assert( Chan != NULL );
357
358         cl2chan = My_Cl2Chan;
359         while( cl2chan )
360         {
361                 if( cl2chan->channel == Chan ) count++;
362                 cl2chan = cl2chan->next;
363         }
364         return count;
365 } /* Channel_MemberCount */
366
367
368 GLOBAL int
369 Channel_CountForUser( CLIENT *Client )
370 {
371         /* Count number of channels a user is member of. */
372
373         CL2CHAN *cl2chan;
374         int count = 0;
375
376         assert( Client != NULL );
377
378         cl2chan = My_Cl2Chan;
379         while( cl2chan )
380         {
381                 if( cl2chan->client == Client ) count++;
382                 cl2chan = cl2chan->next;
383         }
384
385         return count;
386 } /* Channel_CountForUser */
387
388
389 GLOBAL const char *
390 Channel_Name( const CHANNEL *Chan )
391 {
392         assert( Chan != NULL );
393         return Chan->name;
394 } /* Channel_Name */
395
396
397 GLOBAL char *
398 Channel_Modes( CHANNEL *Chan )
399 {
400         assert( Chan != NULL );
401         return Chan->modes;
402 } /* Channel_Modes */
403
404
405 GLOBAL char *
406 Channel_Key( CHANNEL *Chan )
407 {
408         assert( Chan != NULL );
409         return Chan->key;
410 } /* Channel_Key */
411
412
413 GLOBAL unsigned long
414 Channel_MaxUsers( CHANNEL *Chan )
415 {
416         assert( Chan != NULL );
417         return Chan->maxusers;
418 } /* Channel_MaxUsers */
419
420
421 GLOBAL CHANNEL *
422 Channel_First( void )
423 {
424         return My_Channels;
425 } /* Channel_First */
426
427
428 GLOBAL CHANNEL *
429 Channel_Next( CHANNEL *Chan )
430 {
431         assert( Chan != NULL );
432         return Chan->next;
433 } /* Channel_Next */
434
435
436 GLOBAL CHANNEL *
437 Channel_Search( const char *Name )
438 {
439         /* Search channel structure */
440
441         CHANNEL *c;
442         UINT32 search_hash;
443
444         assert( Name != NULL );
445
446         search_hash = Hash( Name );
447         c = My_Channels;
448         while( c )
449         {
450                 if( search_hash == c->hash )
451                 {
452                         /* hash hit */
453                         if( strcasecmp( Name, c->name ) == 0 ) return c;
454                 }
455                 c = c->next;
456         }
457         return NULL;
458 } /* Channel_Search */
459
460
461 GLOBAL CL2CHAN *
462 Channel_FirstMember( CHANNEL *Chan )
463 {
464         assert( Chan != NULL );
465         return Get_First_Cl2Chan( NULL, Chan );
466 } /* Channel_FirstMember */
467
468
469 GLOBAL CL2CHAN *
470 Channel_NextMember( CHANNEL *Chan, CL2CHAN *Cl2Chan )
471 {
472         assert( Chan != NULL );
473         assert( Cl2Chan != NULL );
474         return Get_Next_Cl2Chan( Cl2Chan->next, NULL, Chan );
475 } /* Channel_NextMember */
476
477
478 GLOBAL CL2CHAN *
479 Channel_FirstChannelOf( CLIENT *Client )
480 {
481         assert( Client != NULL );
482         return Get_First_Cl2Chan( Client, NULL );
483 } /* Channel_FirstChannelOf */
484
485
486 GLOBAL CL2CHAN *
487 Channel_NextChannelOf( CLIENT *Client, CL2CHAN *Cl2Chan )
488 {
489         assert( Client != NULL );
490         assert( Cl2Chan != NULL );
491         return Get_Next_Cl2Chan( Cl2Chan->next, Client, NULL );
492 } /* Channel_NextChannelOf */
493
494
495 GLOBAL CLIENT *
496 Channel_GetClient( CL2CHAN *Cl2Chan )
497 {
498         assert( Cl2Chan != NULL );
499         return Cl2Chan->client;
500 } /* Channel_GetClient */
501
502
503 GLOBAL CHANNEL *
504 Channel_GetChannel( CL2CHAN *Cl2Chan )
505 {
506         assert( Cl2Chan != NULL );
507         return Cl2Chan->channel;
508 } /* Channel_GetChannel */
509
510
511 GLOBAL bool
512 Channel_IsValidName( const char *Name )
513 {
514         assert( Name != NULL );
515
516 #ifdef STRICT_RFC
517         if (strlen(Name) <= 1)
518                 return false;
519 #endif
520         if (strchr("#&+", Name[0]) == NULL)
521                 return false;
522         if (strlen(Name) >= CHANNEL_NAME_LEN)
523                 return false;
524
525         return Name[strcspn(Name, " ,:\007")] == 0;
526 } /* Channel_IsValidName */
527
528
529 GLOBAL bool
530 Channel_ModeAdd( CHANNEL *Chan, char Mode )
531 {
532         /* set Mode.
533          * If the channel already had this mode, return false.
534          * If the channel mode was newly set return true.
535          */
536
537         char x[2];
538
539         assert( Chan != NULL );
540
541         x[0] = Mode; x[1] = '\0';
542         if( ! strchr( Chan->modes, x[0] ))
543         {
544                 /* Channel does not have this mode yet, set it */
545                 strlcat( Chan->modes, x, sizeof( Chan->modes ));
546                 return true;
547         }
548         else return false;
549 } /* Channel_ModeAdd */
550
551
552 GLOBAL bool
553 Channel_ModeDel( CHANNEL *Chan, char Mode )
554 {
555         /* Delete mode.
556          * if the mode was removed return true.
557          * if the channel did not have the mode, return false.
558         */
559         char *p;
560
561         assert( Chan != NULL );
562
563         p = strchr( Chan->modes, Mode );
564         if( ! p ) return false;
565
566         /* Channel has mode -> delete */
567         while( *p )
568         {
569                 *p = *(p + 1);
570                 p++;
571         }
572         return true;
573 } /* Channel_ModeDel */
574
575
576 GLOBAL bool
577 Channel_UserModeAdd( CHANNEL *Chan, CLIENT *Client, char Mode )
578 {
579         /* Set Channel-User-Mode.
580          * if mode was newly set, return true.
581          * if the User already had this channel-mode, return false.
582          */
583
584         CL2CHAN *cl2chan;
585         char x[2];
586
587         assert( Chan != NULL );
588         assert( Client != NULL );
589
590         cl2chan = Get_Cl2Chan( Chan, Client );
591         assert( cl2chan != NULL );
592
593         x[0] = Mode; x[1] = '\0';
594         if( ! strchr( cl2chan->modes, x[0] ))
595         {
596                 /* mode not set, -> set it */
597                 strlcat( cl2chan->modes, x, sizeof( cl2chan->modes ));
598                 return true;
599         }
600         else return false;
601 } /* Channel_UserModeAdd */
602
603
604 GLOBAL bool
605 Channel_UserModeDel( CHANNEL *Chan, CLIENT *Client, char Mode )
606 {
607         /* Delete Channel-User-Mode.
608          * If Mode was removed, return true.
609          * If User did not have the Channel-Mode, return false.
610          */
611
612         CL2CHAN *cl2chan;
613         char *p;
614
615         assert( Chan != NULL );
616         assert( Client != NULL );
617
618         cl2chan = Get_Cl2Chan( Chan, Client );
619         assert( cl2chan != NULL );
620
621         p = strchr( cl2chan->modes, Mode );
622         if( ! p ) return false;
623
624         /* Client has Mode -> delete */
625         while( *p )
626         {
627                 *p = *(p + 1);
628                 p++;
629         }
630         return true;
631 } /* Channel_UserModeDel */
632
633
634 GLOBAL char *
635 Channel_UserModes( CHANNEL *Chan, CLIENT *Client )
636 {
637         /* return Users' Channel-Modes */
638
639         CL2CHAN *cl2chan;
640
641         assert( Chan != NULL );
642         assert( Client != NULL );
643
644         cl2chan = Get_Cl2Chan( Chan, Client );
645         assert( cl2chan != NULL );
646
647         return cl2chan->modes;
648 } /* Channel_UserModes */
649
650
651 GLOBAL bool
652 Channel_IsMemberOf( CHANNEL *Chan, CLIENT *Client )
653 {
654         /* Test if Client is on Channel Chan */
655
656         assert( Chan != NULL );
657         assert( Client != NULL );
658         return Get_Cl2Chan(Chan, Client) != NULL;
659 } /* Channel_IsMemberOf */
660
661
662 GLOBAL char *
663 Channel_Topic( CHANNEL *Chan )
664 {
665         char *ret;
666         assert( Chan != NULL );
667         ret = array_start(&Chan->topic);
668         return ret ? ret : "";
669 } /* Channel_Topic */
670
671
672 #ifndef STRICT_RFC
673
674 GLOBAL unsigned int
675 Channel_TopicTime(CHANNEL *Chan)
676 {
677         assert(Chan != NULL);
678         return (unsigned int) Chan->topic_time;
679 } /* Channel_TopicTime */
680
681
682 GLOBAL char *
683 Channel_TopicWho(CHANNEL *Chan)
684 {
685         assert(Chan != NULL);
686         return Chan->topic_who;
687 } /* Channel_TopicWho */
688
689 #endif
690
691
692 GLOBAL void
693 Channel_SetTopic(CHANNEL *Chan, CLIENT *Client, char *Topic)
694 {
695         size_t len;
696         assert( Chan != NULL );
697         assert( Topic != NULL );
698
699         len = strlen(Topic);
700         if (len < array_bytes(&Chan->topic))
701                 array_free(&Chan->topic);
702
703         if (len >= COMMAND_LEN || !array_copyb(&Chan->topic, Topic, len+1))
704                 Log(LOG_WARNING, "could not set new Topic \"%s\" on %s: %s",
705                                         Topic, Chan->name, strerror(errno));
706 #ifndef STRICT_RFC
707         Chan->topic_time = time(NULL);
708         if (Client != NULL && Client_Type(Client) != CLIENT_SERVER)
709                 strlcpy(Chan->topic_who, Client_ID(Client),
710                         sizeof Chan->topic_who);
711         else
712                 strlcpy(Chan->topic_who, DEFAULT_TOPIC_ID,
713                         sizeof Chan->topic_who);
714 #else
715         (void) Client;
716 #endif
717 } /* Channel_SetTopic */
718
719
720 GLOBAL void
721 Channel_SetModes( CHANNEL *Chan, char *Modes )
722 {
723         assert( Chan != NULL );
724         assert( Modes != NULL );
725
726         strlcpy( Chan->modes, Modes, sizeof( Chan->modes ));
727 } /* Channel_SetModes */
728
729
730 GLOBAL void
731 Channel_SetKey( CHANNEL *Chan, char *Key )
732 {
733         assert( Chan != NULL );
734         assert( Key != NULL );
735
736         strlcpy( Chan->key, Key, sizeof( Chan->key ));
737         LogDebug("Channel %s: Key is now \"%s\".", Chan->name, Chan->key );
738 } /* Channel_SetKey */
739
740
741 GLOBAL void
742 Channel_SetMaxUsers(CHANNEL *Chan, unsigned long Count)
743 {
744         assert( Chan != NULL );
745
746         Chan->maxusers = Count;
747         LogDebug("Channel %s: Member limit is now %lu.", Chan->name, Chan->maxusers );
748 } /* Channel_SetMaxUsers */
749
750
751 static bool
752 Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
753 {
754         bool is_member, has_voice, is_op;
755
756         is_member = has_voice = is_op = false;
757
758         /* The server itself always can send messages :-) */
759         if (Client_ThisServer() == From)
760                 return true;
761
762         if (Channel_IsMemberOf(Chan, From)) {
763                 is_member = true;
764                 if (strchr(Channel_UserModes(Chan, From), 'v'))
765                         has_voice = true;
766                 if (strchr(Channel_UserModes(Chan, From), 'o'))
767                         is_op = true;
768         }
769
770         /*
771          * Is the client allowed to write to channel?
772          *
773          * If channel mode n set: non-members cannot send to channel.
774          * If channel mode m set: need voice.
775          */
776         if (strchr(Channel_Modes(Chan), 'n') && !is_member)
777                 return false;
778
779         if (is_op || has_voice)
780                 return true;
781
782         if (strchr(Channel_Modes(Chan), 'm'))
783                 return false;
784
785         return !Lists_Check(&Chan->list_bans, From);
786 }
787
788
789 GLOBAL bool
790 Channel_Write(CHANNEL *Chan, CLIENT *From, CLIENT *Client, const char *Command,
791               bool SendErrors, const char *Text)
792 {
793         if (!Can_Send_To_Channel(Chan, From)) {
794                 if (! SendErrors)
795                         return CONNECTED;       /* no error, see RFC 2812 */
796                 return IRC_WriteStrClient(From, ERR_CANNOTSENDTOCHAN_MSG,
797                                           Client_ID(From), Channel_Name(Chan));
798         }
799
800         if (Client_Conn(From) > NONE)
801                 Conn_UpdateIdle(Client_Conn(From));
802
803         return IRC_WriteStrChannelPrefix(Client, Chan, From, true,
804                         "%s %s :%s", Command, Channel_Name(Chan), Text);
805 }
806
807
808 GLOBAL CHANNEL *
809 Channel_Create( char *Name )
810 {
811         /* Create new CHANNEL structure and add it to linked list */
812         CHANNEL *c;
813
814         assert( Name != NULL );
815
816         c = (CHANNEL *)malloc( sizeof( CHANNEL ));
817         if( ! c )
818         {
819                 Log( LOG_EMERG, "Can't allocate memory! [New_Chan]" );
820                 return NULL;
821         }
822         memset( c, 0, sizeof( CHANNEL ));
823         strlcpy( c->name, Name, sizeof( c->name ));
824         c->hash = Hash( c->name );
825         c->next = My_Channels;
826         My_Channels = c;
827         LogDebug("Created new channel structure for \"%s\".", Name);
828         return c;
829 } /* Channel_Create */
830
831
832 static CL2CHAN *
833 Get_Cl2Chan( CHANNEL *Chan, CLIENT *Client )
834 {
835         CL2CHAN *cl2chan;
836
837         assert( Chan != NULL );
838         assert( Client != NULL );
839
840         cl2chan = My_Cl2Chan;
841         while( cl2chan )
842         {
843                 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) return cl2chan;
844                 cl2chan = cl2chan->next;
845         }
846         return NULL;
847 } /* Get_Cl2Chan */
848
849
850 static CL2CHAN *
851 Add_Client( CHANNEL *Chan, CLIENT *Client )
852 {
853         CL2CHAN *cl2chan;
854
855         assert( Chan != NULL );
856         assert( Client != NULL );
857
858         /* Create new CL2CHAN structure */
859         cl2chan = (CL2CHAN *)malloc( sizeof( CL2CHAN ));
860         if( ! cl2chan )
861         {
862                 Log( LOG_EMERG, "Can't allocate memory! [Add_Client]" );
863                 return NULL;
864         }
865         cl2chan->channel = Chan;
866         cl2chan->client = Client;
867         strcpy( cl2chan->modes, "" );
868
869         /* concatenate */
870         cl2chan->next = My_Cl2Chan;
871         My_Cl2Chan = cl2chan;
872
873         Log( LOG_DEBUG, "User \"%s\" joined channel \"%s\".", Client_Mask( Client ), Chan->name );
874
875         return cl2chan;
876 } /* Add_Client */
877
878
879 static bool
880 Remove_Client( int Type, CHANNEL *Chan, CLIENT *Client, CLIENT *Origin, const char *Reason, bool InformServer )
881 {
882         CL2CHAN *cl2chan, *last_cl2chan;
883         CHANNEL *c;
884
885         assert( Chan != NULL );
886         assert( Client != NULL );
887         assert( Origin != NULL );
888         assert( Reason != NULL );
889
890         /* Do not inform other servers if the channel is local to this server,
891          * regardless of what the caller requested! */
892         if(InformServer)
893                 InformServer = !Channel_IsLocal(Chan);
894
895         last_cl2chan = NULL;
896         cl2chan = My_Cl2Chan;
897         while( cl2chan )
898         {
899                 if(( cl2chan->channel == Chan ) && ( cl2chan->client == Client )) break;
900                 last_cl2chan = cl2chan;
901                 cl2chan = cl2chan->next;
902         }
903         if( ! cl2chan ) return false;
904
905         c = cl2chan->channel;
906         assert( c != NULL );
907
908         /* maintain cl2chan list */
909         if( last_cl2chan ) last_cl2chan->next = cl2chan->next;
910         else My_Cl2Chan = cl2chan->next;
911         free( cl2chan );
912
913         switch( Type )
914         {
915                 case REMOVE_QUIT:
916                         /* QUIT: other servers have already been notified, 
917                          * see Client_Destroy(); so only inform other clients
918                          * in same channel. */
919                         assert( InformServer == false );
920                         LogDebug("User \"%s\" left channel \"%s\" (%s).",
921                                         Client_Mask( Client ), c->name, Reason );
922                         break;
923                 case REMOVE_KICK:
924                         /* User was KICKed: inform other servers (public
925                          * channels) and all users in the channel */
926                         if( InformServer )
927                                 IRC_WriteStrServersPrefix( Client_NextHop( Origin ),
928                                         Origin, "KICK %s %s :%s", c->name, Client_ID( Client ), Reason);
929                         IRC_WriteStrChannelPrefix(Client, c, Origin, false, "KICK %s %s :%s",
930                                                         c->name, Client_ID( Client ), Reason );
931                         if ((Client_Conn(Client) > NONE) &&
932                                         (Client_Type(Client) == CLIENT_USER))
933                         {
934                                 IRC_WriteStrClientPrefix(Client, Origin, "KICK %s %s :%s",
935                                                                 c->name, Client_ID( Client ), Reason);
936                         }
937                         LogDebug("User \"%s\" has been kicked off \"%s\" by \"%s\": %s.",
938                                 Client_Mask( Client ), c->name, Client_ID(Origin), Reason);
939                         break;
940                 default: /* PART */
941                         if (InformServer)
942                                 IRC_WriteStrServersPrefix(Origin, Client, "PART %s :%s", c->name, Reason);
943
944                         IRC_WriteStrChannelPrefix(Origin, c, Client, false, "PART %s :%s",
945                                                                         c->name, Reason);
946
947                         if ((Client_Conn(Origin) > NONE) &&
948                                         (Client_Type(Origin) == CLIENT_USER))
949                         {
950                                 IRC_WriteStrClientPrefix( Origin, Client, "PART %s :%s", c->name, Reason);
951                                 LogDebug("User \"%s\" left channel \"%s\" (%s).",
952                                         Client_Mask(Client), c->name, Reason);
953                         }
954         }
955
956         /* When channel is empty and is not pre-defined, delete */
957         if( ! strchr( Channel_Modes( Chan ), 'P' ))
958         {
959                 if( ! Get_First_Cl2Chan( NULL, Chan )) Delete_Channel( Chan );
960         }
961
962         return true;
963 } /* Remove_Client */
964
965
966 GLOBAL bool
967 Channel_AddBan(CHANNEL *c, const char *mask )
968 {
969         struct list_head *h = Channel_GetListBans(c);
970         return Lists_Add(h, mask, false);
971 }
972
973
974 GLOBAL bool
975 Channel_AddInvite(CHANNEL *c, const char *mask, bool onlyonce)
976 {
977         struct list_head *h = Channel_GetListInvites(c);
978         return Lists_Add(h, mask, onlyonce);
979 }
980
981
982 static bool
983 ShowInvitesBans(struct list_head *head, CLIENT *Client, CHANNEL *Channel, bool invite)
984 {
985         struct list_elem *e;
986         char *msg = invite ? RPL_INVITELIST_MSG : RPL_BANLIST_MSG;
987         char *msg_end;
988
989         assert( Client != NULL );
990         assert( Channel != NULL );
991
992         e = Lists_GetFirst(head);
993         while (e) {
994                 if( ! IRC_WriteStrClient( Client, msg, Client_ID( Client ),
995                                 Channel_Name( Channel ), Lists_GetMask(e) )) return DISCONNECTED;
996                 e = Lists_GetNext(e);
997         }
998
999         msg_end = invite ? RPL_ENDOFINVITELIST_MSG : RPL_ENDOFBANLIST_MSG;
1000         return IRC_WriteStrClient( Client, msg_end, Client_ID( Client ), Channel_Name( Channel ));
1001 }
1002
1003
1004 GLOBAL bool
1005 Channel_ShowBans( CLIENT *Client, CHANNEL *Channel )
1006 {
1007         struct list_head *h;
1008
1009         assert( Channel != NULL );
1010
1011         h = Channel_GetListBans(Channel);
1012         return ShowInvitesBans(h, Client, Channel, false);
1013 }
1014
1015
1016 GLOBAL bool
1017 Channel_ShowInvites( CLIENT *Client, CHANNEL *Channel )
1018 {
1019         struct list_head *h;
1020
1021         assert( Channel != NULL );
1022
1023         h = Channel_GetListInvites(Channel);
1024         return ShowInvitesBans(h, Client, Channel, true);
1025 }
1026
1027
1028 /**
1029  * Log a message to the local &SERVER channel, if it exists.
1030  */
1031 GLOBAL void
1032 Channel_LogServer(char *msg)
1033 {
1034         CHANNEL *sc;
1035         CLIENT *c;
1036
1037         assert(msg != NULL);
1038
1039         sc = Channel_Search("&SERVER");
1040         if (!sc)
1041                 return;
1042
1043         c = Client_ThisServer();
1044         Channel_Write(sc, c, c, "PRIVMSG", false, msg);
1045 } /* Channel_LogServer */
1046
1047
1048 static CL2CHAN *
1049 Get_First_Cl2Chan( CLIENT *Client, CHANNEL *Chan )
1050 {
1051         return Get_Next_Cl2Chan( My_Cl2Chan, Client, Chan );
1052 } /* Get_First_Cl2Chan */
1053
1054
1055 static CL2CHAN *
1056 Get_Next_Cl2Chan( CL2CHAN *Start, CLIENT *Client, CHANNEL *Channel )
1057 {
1058         CL2CHAN *cl2chan;
1059
1060         assert( Client != NULL || Channel != NULL );
1061
1062         cl2chan = Start;
1063         while( cl2chan )
1064         {
1065                 if(( Client ) && ( cl2chan->client == Client )) return cl2chan;
1066                 if(( Channel ) && ( cl2chan->channel == Channel )) return cl2chan;
1067                 cl2chan = cl2chan->next;
1068         }
1069         return NULL;
1070 } /* Get_Next_Cl2Chan */
1071
1072
1073 static bool
1074 Delete_Channel( CHANNEL *Chan )
1075 {
1076         /* delete channel structure */
1077
1078         CHANNEL *chan, *last_chan;
1079
1080         last_chan = NULL;
1081         chan = My_Channels;
1082         while( chan )
1083         {
1084                 if( chan == Chan ) break;
1085                 last_chan = chan;
1086                 chan = chan->next;
1087         }
1088         if( ! chan ) return false;
1089
1090         Log( LOG_DEBUG, "Freed channel structure for \"%s\".", Chan->name );
1091
1092         /* free invite and ban lists */
1093         Lists_Free( &chan->list_bans );
1094         Lists_Free( &chan->list_invites );
1095
1096         /* maintain channel list */
1097         if( last_chan ) last_chan->next = chan->next;
1098         else My_Channels = chan->next;
1099         free( chan );
1100
1101         return true;
1102 } /* Delete_Channel */
1103
1104 /* -eof- */