1 /* Copyright (C) 2009-2013, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2013, 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;
164 ch->position = chdesc.position;
165 if (chdesc.password) {
166 Log_info("Setting password on channel '%s'", ch->name);
167 ch->password = strdup(chdesc.password);
169 if (strcmp(defaultChannelName, chdesc.name) == 0) {
170 Log_info("Setting default channel '%s'", ch->name);
175 Chan_iterate(&ch_itr);
176 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
179 Log_fatal("Error in channel configuration: parent '%s' not found", chdesc.parent);
181 Chan_addChannel(ch_itr, ch);
182 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
186 if (defaultChan == NULL)
187 defaultChan = rootChan;
189 if (defaultChan->noenter)
190 Log_fatal("Error in channel configuration: default channel is marked as noenter");
191 if (defaultChan->password)
192 Log_fatal("Error in channel configuration: default channel has a password");
196 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
197 if (Conf_getNextChannelLink(&chlink, i) < 0) {
199 Log_info("No channel links found in configuration file.");
204 Chan_iterate(&ch_itr);
205 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
207 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
214 Chan_iterate(&ch_itr);
215 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
217 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
222 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
224 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
230 struct dlist *itr, *save;
233 list_iterate_safe(itr, save, &channels) {
234 ch = list_get_entry(itr, channel_t, flatlist_node);
235 Log_debug("Free channel '%s'", ch->name);
245 channel_t *Chan_createChannel(const char *name, const char *desc)
247 int id = findFreeId();
249 Log_fatal("No free channel ID found");
250 return createChannel(id, name, desc);
253 void Chan_freeChannel(channel_t *ch)
256 list_del(&ch->flatlist_node);
260 void Chan_addChannel(channel_t *parent, channel_t *ch)
262 list_add_tail(&ch->node, &parent->subs);
264 list_add_tail(&ch->flatlist_node, &channels);
268 int Chan_userLeave(client_t *client)
270 channel_t *leaving = NULL;
273 if (client->channel) {
274 list_del(&client->chan_node);
275 leaving = (channel_t *)client->channel;
276 if (leaving->temporary && list_empty(&leaving->clients)) {
277 leaving_id = leaving->id;
278 Chan_freeChannel(leaving);
284 int Chan_userJoin(channel_t *ch, client_t *client)
288 /* Do nothing if user already is in this channel */
289 if ((channel_t *)client->channel == ch)
292 Log_debug("Add user %s to channel %s", client->username, ch->name);
293 /* Only allowed in one channel at a time */
294 leaving_id = Chan_userLeave(client);
295 list_add_tail(&client->chan_node, &ch->clients);
296 client->channel = (void *)ch;
300 int Chan_userJoin_id(int channelid, client_t *client)
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);
311 return Chan_userJoin(ch_itr, client);
314 channelJoinResult_t Chan_userJoin_id_test(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);
322 return CHJOIN_NOTFOUND;
324 else if (ch_itr->noenter)
325 return CHJOIN_NOENTER;
326 else if (ch_itr->password && !Client_token_match(client, ch_itr->password))
327 return CHJOIN_WRONGPW;
328 else return CHJOIN_OK;
332 void Chan_addChannel_id(int parentId, channel_t *ch)
334 channel_t *ch_itr = NULL;
336 Chan_iterate(&ch_itr);
337 } while (ch_itr != NULL && ch_itr->id != parentId);
339 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
341 list_add_tail(&ch->node, &ch_itr->subs);
345 channel_t *Chan_fromId(int channelid)
347 channel_t *ch_itr = NULL;
349 Chan_iterate(&ch_itr);
350 } while (ch_itr != NULL && ch_itr->id != channelid);
352 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
356 void Chan_removeChannel(channel_t *ch)
361 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
367 chl = malloc(sizeof(channellist_t));
369 init_list_entry(&chl->node);
370 list_add_tail(&chl->node, head);
372 list_iterate(itr, &ch->subs) {
373 sub = list_get_entry(itr, channel_t, node);
374 Chan_buildTreeList(sub, head);
378 void Chan_freeTreeList(struct dlist *head)
380 struct dlist *itr, *save;
381 list_iterate_safe(itr, save, head) {
382 free(list_get_entry(itr, channellist_t, node));