1 /* Copyright (C) 2009-2011, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2011, 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 ch->password = strdup(chdesc.password);
166 if (strcmp(defaultChannelName, chdesc.name) == 0) {
167 Log_info("Setting default channel %s", ch->name);
172 Chan_iterate(&ch_itr);
173 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
176 Log_fatal("Error in channel configuration: parent not found");
178 Chan_addChannel(ch_itr, ch);
179 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
183 if (defaultChan == NULL)
184 defaultChan = rootChan;
186 if (defaultChan->noenter)
187 Log_fatal("Error in channel configuration: default channel is marked as noenter");
188 if (defaultChan->password)
189 Log_fatal("Error in channel configuration: default channel has a password");
193 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
194 if (Conf_getNextChannelLink(&chlink, i) < 0) {
196 Log_info("No channel links found in configuration file.");
201 Chan_iterate(&ch_itr);
202 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
204 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
211 Chan_iterate(&ch_itr);
212 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
214 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
219 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
221 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
227 struct dlist *itr, *save;
230 list_iterate_safe(itr, save, &channels) {
231 ch = list_get_entry(itr, channel_t, flatlist_node);
232 Log_debug("Free channel '%s'", ch->name);
242 channel_t *Chan_createChannel(const char *name, const char *desc)
244 int id = findFreeId();
246 Log_fatal("No free channel ID found");
247 return createChannel(id, name, desc);
250 void Chan_freeChannel(channel_t *ch)
253 list_del(&ch->flatlist_node);
257 void Chan_addChannel(channel_t *parent, channel_t *ch)
259 list_add_tail(&ch->node, &parent->subs);
261 list_add_tail(&ch->flatlist_node, &channels);
265 int Chan_userLeave(client_t *client)
267 channel_t *leaving = NULL;
270 if (client->channel) {
271 list_del(&client->chan_node);
272 leaving = (channel_t *)client->channel;
273 if (leaving->temporary && list_empty(&leaving->clients)) {
274 leaving_id = leaving->id;
275 Chan_freeChannel(leaving);
281 int Chan_userJoin(channel_t *ch, client_t *client)
285 /* Do nothing if user already is in this channel */
286 if ((channel_t *)client->channel == ch)
289 Log_debug("Add user %s to channel %s", client->username, ch->name);
290 /* Only allowed in one channel at a time */
291 leaving_id = Chan_userLeave(client);
292 list_add_tail(&client->chan_node, &ch->clients);
293 client->channel = (void *)ch;
297 int Chan_userJoin_id(int channelid, client_t *client)
299 channel_t *ch_itr = NULL;
301 Chan_iterate(&ch_itr);
302 } while (ch_itr != NULL && ch_itr->id != channelid);
303 if (ch_itr == NULL) {
304 Log_warn("Channel id %d not found - ignoring.", channelid);
308 return Chan_userJoin(ch_itr, client);
311 channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client)
313 channel_t *ch_itr = NULL;
315 Chan_iterate(&ch_itr);
316 } while (ch_itr != NULL && ch_itr->id != channelid);
317 if (ch_itr == NULL) {
318 Log_warn("Channel id %d not found - ignoring.", channelid);
319 return CHJOIN_NOTFOUND;
321 else if (ch_itr->noenter)
322 return CHJOIN_NOENTER;
323 else if (ch_itr->password && !Client_token_match(client, ch_itr->password))
324 return CHJOIN_WRONGPW;
325 else return CHJOIN_OK;
329 void Chan_addChannel_id(int parentId, channel_t *ch)
331 channel_t *ch_itr = NULL;
333 Chan_iterate(&ch_itr);
334 } while (ch_itr != NULL && ch_itr->id != parentId);
336 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
338 list_add_tail(&ch->node, &ch_itr->subs);
342 channel_t *Chan_fromId(int channelid)
344 channel_t *ch_itr = NULL;
346 Chan_iterate(&ch_itr);
347 } while (ch_itr != NULL && ch_itr->id != channelid);
349 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
353 void Chan_removeChannel(channel_t *ch)
358 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
364 chl = malloc(sizeof(channellist_t));
366 init_list_entry(&chl->node);
367 list_add_tail(&chl->node, head);
369 list_iterate(itr, &ch->subs) {
370 sub = list_get_entry(itr, channel_t, node);
371 Chan_buildTreeList(sub, head);
375 void Chan_freeTreeList(struct dlist *head)
377 struct dlist *itr, *save;
378 list_iterate_safe(itr, save, head) {
379 free(list_get_entry(itr, channellist_t, node));