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