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);
215 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
221 struct dlist *itr, *save;
224 list_iterate_safe(itr, save, &channels) {
225 ch = list_get_entry(itr, channel_t, flatlist_node);
226 Log_debug("Free channel '%s'", ch->name);
234 channel_t *Chan_createChannel(const char *name, const char *desc)
236 int id = findFreeId();
238 Log_fatal("No free channel ID found");
239 return createChannel(id, name, desc);
242 void Chan_freeChannel(channel_t *ch)
245 list_del(&ch->flatlist_node);
249 void Chan_addChannel(channel_t *parent, channel_t *ch)
251 list_add_tail(&ch->node, &parent->subs);
253 list_add_tail(&ch->flatlist_node, &channels);
257 int Chan_userLeave(client_t *client)
259 channel_t *leaving = NULL;
262 if (client->channel) {
263 list_del(&client->chan_node);
264 leaving = (channel_t *)client->channel;
265 if (leaving->temporary && list_empty(&leaving->clients)) {
266 leaving_id = leaving->id;
267 Chan_freeChannel(leaving);
273 int Chan_userJoin(channel_t *ch, client_t *client)
277 Log_debug("Add user %s to channel %s", client->username, ch->name);
279 /* Only allowed in one channel at a time */
280 leaving_id = Chan_userLeave(client);
281 list_add_tail(&client->chan_node, &ch->clients);
282 client->channel = (void *)ch;
286 int Chan_userJoin_id(int channelid, client_t *client)
288 channel_t *ch_itr = NULL;
290 Chan_iterate(&ch_itr);
291 } while (ch_itr != NULL && ch_itr->id != channelid);
292 if (ch_itr == NULL) {
293 Log_warn("Channel id %d not found - ignoring.", channelid);
297 return Chan_userJoin(ch_itr, client);
300 bool_t Chan_userJoin_id_test(int channelid)
302 channel_t *ch_itr = NULL;
304 Chan_iterate(&ch_itr);
305 } while (ch_itr != NULL && ch_itr->id != channelid);
306 if (ch_itr == NULL) {
307 Log_warn("Channel id %d not found - ignoring.", channelid);
317 void Chan_addChannel_id(int parentId, channel_t *ch)
319 channel_t *ch_itr = NULL;
321 Chan_iterate(&ch_itr);
322 } while (ch_itr != NULL && ch_itr->id != parentId);
324 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
326 list_add_tail(&ch->node, &ch_itr->subs);
330 channel_t *Chan_fromId(int channelid)
332 channel_t *ch_itr = NULL;
334 Chan_iterate(&ch_itr);
335 } while (ch_itr != NULL && ch_itr->id != channelid);
337 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
341 void Chan_removeChannel(channel_t *ch)