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.
39 static channel_t *rootChan;
40 channel_t *defaultChan;
41 declare_list(channels); /* A flat list of the channels */
43 static channel_t *createChannel(int id, const char *name, const char *desc)
47 ch = malloc(sizeof(channel_t));
49 Log_fatal("out of memory");
50 memset(ch, 0, sizeof(channel_t));
52 ch->name = strdup(name);
54 ch->desc = strdup(desc);
55 init_list_entry(&ch->subs);
56 init_list_entry(&ch->node);
57 init_list_entry(&ch->clients);
58 init_list_entry(&ch->flatlist_node);
59 init_list_entry(&ch->channel_links);
63 static int findFreeId()
66 channel_t *ch_itr = NULL;
67 for (id = 0; id < INT_MAX; id++) {
69 while ((ch_itr = Chan_iterate(&ch_itr)) != NULL) {
73 if (ch_itr == NULL) /* Found free id */
80 /* Might be used when tree traversal becomes neccessary */
81 static channel_t *first_subchannel(channel_t *ch)
83 if (list_empty(&ch->subs))
86 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
89 static channel_t *next_channel(channel_t *ch)
91 if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
94 return list_get_entry(list_get_next(&ch->node), channel_t, node);
98 channel_t *Chan_iterate(channel_t **channelpptr)
100 channel_t *ch = *channelpptr;
102 if (!list_empty(&channels)) {
104 ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
106 if (list_get_next(&ch->flatlist_node) == &channels)
109 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
117 channel_t *Chan_iterate_siblings(channel_t *parent, channel_t **channelpptr)
119 channel_t *ch = *channelpptr;
121 if (!list_empty(&parent->subs)) {
123 ch = list_get_entry(list_get_first(&parent->subs), channel_t, node);
125 if (list_get_next(&ch->node) == &parent->subs)
128 ch = list_get_entry(list_get_next(&ch->node), channel_t, node);
139 conf_channel_t chdesc;
140 conf_channel_link_t chlink;
141 const char *defaultChannelName;
143 defaultChannelName = getStrConf(DEFAULT_CHANNEL);
146 if (Conf_getNextChannel(&chdesc, i) < 0) {
148 Log_fatal("No valid channels found in configuration file. Exiting.");
152 rootChan = createChannel(0, chdesc.name, chdesc.description);
153 rootChan->noenter = chdesc.noenter;
154 list_add_tail(&rootChan->flatlist_node, &channels);
155 if (strcmp(defaultChannelName, chdesc.name) == 0)
156 defaultChan = rootChan;
159 channel_t *ch, *ch_itr = NULL;
160 ch = Chan_createChannel(chdesc.name, chdesc.description);
161 ch->noenter = chdesc.noenter;
163 if (strcmp(defaultChannelName, chdesc.name) == 0) {
164 Log_info("Setting default channel %s", ch->name);
169 Chan_iterate(&ch_itr);
170 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
173 Log_fatal("Error in channel configuration: parent not found");
175 Chan_addChannel(ch_itr, ch);
176 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
180 if (defaultChan == NULL)
181 defaultChan = rootChan;
183 if (defaultChan->noenter)
184 Log_fatal("Error in channel configuration: default channel is marked as noenter");
188 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
189 if (Conf_getNextChannelLink(&chlink, i) < 0) {
191 Log_info("No channel links found in configuration file.");
196 Chan_iterate(&ch_itr);
197 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
199 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
206 Chan_iterate(&ch_itr);
207 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
209 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
214 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
216 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
222 struct dlist *itr, *save;
225 list_iterate_safe(itr, save, &channels) {
226 ch = list_get_entry(itr, channel_t, flatlist_node);
227 Log_debug("Free channel '%s'", ch->name);
235 channel_t *Chan_createChannel(const char *name, const char *desc)
237 int id = findFreeId();
239 Log_fatal("No free channel ID found");
240 return createChannel(id, name, desc);
243 void Chan_freeChannel(channel_t *ch)
246 list_del(&ch->flatlist_node);
250 void Chan_addChannel(channel_t *parent, channel_t *ch)
252 list_add_tail(&ch->node, &parent->subs);
254 list_add_tail(&ch->flatlist_node, &channels);
258 int Chan_userLeave(client_t *client)
260 channel_t *leaving = NULL;
263 if (client->channel) {
264 list_del(&client->chan_node);
265 leaving = (channel_t *)client->channel;
266 if (leaving->temporary && list_empty(&leaving->clients)) {
267 leaving_id = leaving->id;
268 Chan_freeChannel(leaving);
274 int Chan_userJoin(channel_t *ch, client_t *client)
278 Log_debug("Add user %s to channel %s", client->username, ch->name);
280 /* Only allowed in one channel at a time */
281 leaving_id = Chan_userLeave(client);
282 list_add_tail(&client->chan_node, &ch->clients);
283 client->channel = (void *)ch;
287 int Chan_userJoin_id(int channelid, client_t *client)
289 channel_t *ch_itr = NULL;
291 Chan_iterate(&ch_itr);
292 } while (ch_itr != NULL && ch_itr->id != channelid);
293 if (ch_itr == NULL) {
294 Log_warn("Channel id %d not found - ignoring.", channelid);
298 return Chan_userJoin(ch_itr, client);
301 bool_t Chan_userJoin_id_test(int channelid)
303 channel_t *ch_itr = NULL;
305 Chan_iterate(&ch_itr);
306 } while (ch_itr != NULL && ch_itr->id != channelid);
307 if (ch_itr == NULL) {
308 Log_warn("Channel id %d not found - ignoring.", channelid);
318 void Chan_addChannel_id(int parentId, channel_t *ch)
320 channel_t *ch_itr = NULL;
322 Chan_iterate(&ch_itr);
323 } while (ch_itr != NULL && ch_itr->id != parentId);
325 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
327 list_add_tail(&ch->node, &ch_itr->subs);
331 channel_t *Chan_fromId(int channelid)
333 channel_t *ch_itr = NULL;
335 Chan_iterate(&ch_itr);
336 } while (ch_itr != NULL && ch_itr->id != channelid);
338 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
342 void Chan_removeChannel(channel_t *ch)
347 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
353 chl = malloc(sizeof(channellist_t));
355 init_list_entry(&chl->node);
356 list_add_tail(&chl->node, head);
358 list_iterate(itr, &ch->subs) {
359 sub = list_get_entry(itr, channel_t, node);
360 Chan_buildTreeList(sub, head);
364 void Chan_freeTreeList(struct dlist *head)
366 struct dlist *itr, *save;
367 list_iterate_safe(itr, save, head) {
368 free(list_get_entry(itr, channellist_t, node));