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