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