1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2014, Thorvald Natvig <thorvald@natvig.com>
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 - Redistributions of source code must retain the above copyright notice,
11 this list of conditions and the following disclaimer.
12 - Redistributions in binary form must reproduce the above copyright notice,
13 this list of conditions and the following disclaimer in the documentation
14 and/or other materials provided with the distribution.
15 - Neither the name of the Developers nor the names of its contributors may
16 be used to endorse or promote products derived from this software without
17 specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 static channel_t *rootChan;
42 channel_t *defaultChan;
43 declare_list(channels); /* A flat list of the channels */
45 static channel_t *createChannel(int id, const char *name, const char *desc)
49 ch = malloc(sizeof(channel_t));
51 Log_fatal("out of memory");
52 memset(ch, 0, sizeof(channel_t));
54 ch->name = strdup(name);
56 ch->desc = strdup(desc);
57 init_list_entry(&ch->subs);
58 init_list_entry(&ch->node);
59 init_list_entry(&ch->clients);
60 init_list_entry(&ch->flatlist_node);
61 init_list_entry(&ch->channel_links);
65 static int findFreeId()
68 channel_t *ch_itr = NULL;
69 for (id = 0; id < INT_MAX; id++) {
71 while ((ch_itr = Chan_iterate(&ch_itr)) != NULL) {
75 if (ch_itr == NULL) /* Found free id */
82 /* Might be used when tree traversal becomes neccessary */
83 static channel_t *first_subchannel(channel_t *ch)
85 if (list_empty(&ch->subs))
88 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
91 static channel_t *next_channel(channel_t *ch)
93 if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
96 return list_get_entry(list_get_next(&ch->node), channel_t, node);
100 channel_t *Chan_iterate(channel_t **channelpptr)
102 channel_t *ch = *channelpptr;
104 if (!list_empty(&channels)) {
106 ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
108 if (list_get_next(&ch->flatlist_node) == &channels)
111 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
119 channel_t *Chan_iterate_siblings(channel_t *parent, channel_t **channelpptr)
121 channel_t *ch = *channelpptr;
123 if (!list_empty(&parent->subs)) {
125 ch = list_get_entry(list_get_first(&parent->subs), channel_t, node);
127 if (list_get_next(&ch->node) == &parent->subs)
130 ch = list_get_entry(list_get_next(&ch->node), channel_t, node);
141 conf_channel_t chdesc;
142 conf_channel_link_t chlink;
143 const char *defaultChannelName;
145 defaultChannelName = getStrConf(DEFAULT_CHANNEL);
148 if (Conf_getNextChannel(&chdesc, i) < 0) {
150 Log_fatal("No valid channels found in configuration file. Exiting.");
154 rootChan = createChannel(0, chdesc.name, chdesc.description);
155 rootChan->noenter = chdesc.noenter;
156 rootChan->silent = chdesc.silent;
157 list_add_tail(&rootChan->flatlist_node, &channels);
158 if (strcmp(defaultChannelName, chdesc.name) == 0)
159 defaultChan = rootChan;
162 channel_t *ch, *ch_itr = NULL;
163 ch = Chan_createChannel(chdesc.name, chdesc.description);
164 ch->noenter = chdesc.noenter;
165 ch->position = chdesc.position;
166 ch->silent = chdesc.silent;
167 if (chdesc.password) {
168 Log_info("Setting password on channel '%s'", ch->name);
169 ch->password = strdup(chdesc.password);
171 if (strcmp(defaultChannelName, chdesc.name) == 0) {
172 Log_info("Setting default channel '%s'", ch->name);
177 Chan_iterate(&ch_itr);
178 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
181 Log_fatal("Error in channel configuration: parent '%s' not found", chdesc.parent);
183 Chan_addChannel(ch_itr, ch);
184 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
188 if (defaultChan == NULL)
189 defaultChan = rootChan;
191 if (defaultChan->noenter)
192 Log_fatal("Error in channel configuration: default channel is marked as noenter");
193 if (defaultChan->password)
194 Log_fatal("Error in channel configuration: default channel has a password");
198 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
200 if (Conf_getNextChannelLink(&chlink, i) < 0) {
202 Log_info("No channel links found in configuration file.");
207 Chan_iterate(&ch_itr);
208 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
210 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
217 Chan_iterate(&ch_itr);
218 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
220 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
225 chl = malloc(sizeof(channellist_t));
227 Log_fatal("Out of memory");
229 init_list_entry(&chl->node);
230 list_add_tail(&chl->node, &ch_src->channel_links);
232 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
238 struct dlist *itr, *save;
239 struct dlist *linkitr, *linksave;
242 list_iterate_safe(itr, save, &channels) {
243 ch = list_get_entry(itr, channel_t, flatlist_node);
244 Log_debug("Free channel '%s'", ch->name);
250 list_iterate_safe(linkitr, linksave, &ch->channel_links) {
252 chl = list_get_entry(linkitr, channellist_t, node);
259 channel_t *Chan_createChannel(const char *name, const char *desc)
261 int id = findFreeId();
263 Log_fatal("No free channel ID found");
264 return createChannel(id, name, desc);
267 void Chan_freeChannel(channel_t *ch)
270 list_del(&ch->flatlist_node);
274 void Chan_addChannel(channel_t *parent, channel_t *ch)
276 list_add_tail(&ch->node, &parent->subs);
278 list_add_tail(&ch->flatlist_node, &channels);
282 int Chan_userLeave(client_t *client)
284 channel_t *leaving = NULL;
287 if (client->channel) {
288 list_del(&client->chan_node);
289 leaving = (channel_t *)client->channel;
290 if (leaving->temporary && list_empty(&leaving->clients)) {
291 leaving_id = leaving->id;
292 Chan_freeChannel(leaving);
298 int Chan_userJoin(channel_t *ch, client_t *client)
302 /* Do nothing if user already is in this channel */
303 if ((channel_t *)client->channel == ch)
306 Log_debug("Add user %s to channel %s", client->username, ch->name);
307 /* Only allowed in one channel at a time */
308 leaving_id = Chan_userLeave(client);
309 list_add_tail(&client->chan_node, &ch->clients);
310 client->channel = (void *)ch;
314 int Chan_userJoin_id(int channelid, client_t *client)
316 channel_t *ch_itr = NULL;
318 Chan_iterate(&ch_itr);
319 } while (ch_itr != NULL && ch_itr->id != channelid);
320 if (ch_itr == NULL) {
321 Log_warn("Channel id %d not found - ignoring.", channelid);
325 return Chan_userJoin(ch_itr, client);
328 channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client)
330 channelJoinResult_t result;
331 channel_t *ch_itr = NULL;
333 Chan_iterate(&ch_itr);
334 } while (ch_itr != NULL && ch_itr->id != channelid);
335 if (ch_itr == NULL) {
336 Log_warn("Channel id %d not found - ignoring.", channelid);
337 result.CHJOIN_NOTFOUND = true;
340 result.CHJOIN_NOTFOUND = false;
342 result.CHJOIN_NOENTER = ch_itr->noenter;
343 result.CHJOIN_WRONGPW = ch_itr->password && !Client_token_match(client, ch_itr->password) && !client->isAdmin;
344 result.CHJOIN_SILENT = ch_itr->silent;
350 void Chan_addChannel_id(int parentId, channel_t *ch)
352 channel_t *ch_itr = NULL;
354 Chan_iterate(&ch_itr);
355 } while (ch_itr != NULL && ch_itr->id != parentId);
357 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
359 list_add_tail(&ch->node, &ch_itr->subs);
363 channel_t *Chan_fromId(int channelid)
365 channel_t *ch_itr = NULL;
367 Chan_iterate(&ch_itr);
368 } while (ch_itr != NULL && ch_itr->id != channelid);
370 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
374 void Chan_removeChannel(channel_t *ch)
379 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
385 chl = malloc(sizeof(channellist_t));
387 Log_fatal("Out of memory");
389 init_list_entry(&chl->node);
390 list_add_tail(&chl->node, head);
392 list_iterate(itr, &ch->subs) {
393 sub = list_get_entry(itr, channel_t, node);
394 Chan_buildTreeList(sub, head);
398 void Chan_freeTreeList(struct dlist *head)
400 struct dlist *itr, *save;
401 list_iterate_safe(itr, save, head) {
402 free(list_get_entry(itr, channellist_t, node));