1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2010, 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 list_add_tail(&rootChan->flatlist_node, &channels);
157 if (strcmp(defaultChannelName, chdesc.name) == 0)
158 defaultChan = rootChan;
161 channel_t *ch, *ch_itr = NULL;
162 ch = Chan_createChannel(chdesc.name, chdesc.description);
163 ch->noenter = chdesc.noenter;
165 if (strcmp(defaultChannelName, chdesc.name) == 0) {
166 Log_info("Setting default channel %s", ch->name);
171 Chan_iterate(&ch_itr);
172 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
175 Log_fatal("Error in channel configuration: parent not found");
177 Chan_addChannel(ch_itr, ch);
178 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
182 if (defaultChan == NULL)
183 defaultChan = rootChan;
185 if (defaultChan->noenter)
186 Log_fatal("Error in channel configuration: default channel is marked as noenter");
190 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
191 if (Conf_getNextChannelLink(&chlink, i) < 0) {
193 Log_info("No channel links found in configuration file.");
198 Chan_iterate(&ch_itr);
199 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
201 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
208 Chan_iterate(&ch_itr);
209 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
211 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
216 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
218 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
224 struct dlist *itr, *save;
227 list_iterate_safe(itr, save, &channels) {
228 ch = list_get_entry(itr, channel_t, flatlist_node);
229 Log_debug("Free channel '%s'", ch->name);
237 channel_t *Chan_createChannel(const char *name, const char *desc)
239 int id = findFreeId();
241 Log_fatal("No free channel ID found");
242 return createChannel(id, name, desc);
245 void Chan_freeChannel(channel_t *ch)
248 list_del(&ch->flatlist_node);
252 void Chan_addChannel(channel_t *parent, channel_t *ch)
254 list_add_tail(&ch->node, &parent->subs);
256 list_add_tail(&ch->flatlist_node, &channels);
260 int Chan_userLeave(client_t *client)
262 channel_t *leaving = NULL;
265 if (client->channel) {
266 list_del(&client->chan_node);
267 leaving = (channel_t *)client->channel;
268 if (leaving->temporary && list_empty(&leaving->clients)) {
269 leaving_id = leaving->id;
270 Chan_freeChannel(leaving);
276 int Chan_userJoin(channel_t *ch, client_t *client)
280 Log_debug("Add user %s to channel %s", client->username, ch->name);
282 /* Only allowed in one channel at a time */
283 leaving_id = Chan_userLeave(client);
284 list_add_tail(&client->chan_node, &ch->clients);
285 client->channel = (void *)ch;
289 int Chan_userJoin_id(int channelid, client_t *client)
291 channel_t *ch_itr = NULL;
293 Chan_iterate(&ch_itr);
294 } while (ch_itr != NULL && ch_itr->id != channelid);
295 if (ch_itr == NULL) {
296 Log_warn("Channel id %d not found - ignoring.", channelid);
300 return Chan_userJoin(ch_itr, client);
303 bool_t Chan_userJoin_id_test(int channelid)
305 channel_t *ch_itr = NULL;
307 Chan_iterate(&ch_itr);
308 } while (ch_itr != NULL && ch_itr->id != channelid);
309 if (ch_itr == NULL) {
310 Log_warn("Channel id %d not found - ignoring.", channelid);
320 void Chan_addChannel_id(int parentId, channel_t *ch)
322 channel_t *ch_itr = NULL;
324 Chan_iterate(&ch_itr);
325 } while (ch_itr != NULL && ch_itr->id != parentId);
327 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
329 list_add_tail(&ch->node, &ch_itr->subs);
333 channel_t *Chan_fromId(int channelid)
335 channel_t *ch_itr = NULL;
337 Chan_iterate(&ch_itr);
338 } while (ch_itr != NULL && ch_itr->id != channelid);
340 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
344 void Chan_removeChannel(channel_t *ch)
349 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
355 chl = malloc(sizeof(channellist_t));
357 init_list_entry(&chl->node);
358 list_add_tail(&chl->node, head);
360 list_iterate(itr, &ch->subs) {
361 sub = list_get_entry(itr, channel_t, node);
362 Chan_buildTreeList(sub, head);
366 void Chan_freeTreeList(struct dlist *head)
368 struct dlist *itr, *save;
369 list_iterate_safe(itr, save, head) {
370 free(list_get_entry(itr, channellist_t, node));