1 /* Copyright (C) 2009-2012, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2012, 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 if (chdesc.password) {
165 Log_info("Setting password on channel '%s'", ch->name);
166 ch->password = strdup(chdesc.password);
168 if (strcmp(defaultChannelName, chdesc.name) == 0) {
169 Log_info("Setting default channel '%s'", ch->name);
174 Chan_iterate(&ch_itr);
175 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
178 Log_fatal("Error in channel configuration: parent '%s' not found", chdesc.parent);
180 Chan_addChannel(ch_itr, ch);
181 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
185 if (defaultChan == NULL)
186 defaultChan = rootChan;
188 if (defaultChan->noenter)
189 Log_fatal("Error in channel configuration: default channel is marked as noenter");
190 if (defaultChan->password)
191 Log_fatal("Error in channel configuration: default channel has a password");
195 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
196 if (Conf_getNextChannelLink(&chlink, i) < 0) {
198 Log_info("No channel links found in configuration file.");
203 Chan_iterate(&ch_itr);
204 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
206 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
213 Chan_iterate(&ch_itr);
214 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
216 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
221 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
223 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
229 struct dlist *itr, *save;
232 list_iterate_safe(itr, save, &channels) {
233 ch = list_get_entry(itr, channel_t, flatlist_node);
234 Log_debug("Free channel '%s'", ch->name);
244 channel_t *Chan_createChannel(const char *name, const char *desc)
246 int id = findFreeId();
248 Log_fatal("No free channel ID found");
249 return createChannel(id, name, desc);
252 void Chan_freeChannel(channel_t *ch)
255 list_del(&ch->flatlist_node);
259 void Chan_addChannel(channel_t *parent, channel_t *ch)
261 list_add_tail(&ch->node, &parent->subs);
263 list_add_tail(&ch->flatlist_node, &channels);
267 int Chan_userLeave(client_t *client)
269 channel_t *leaving = NULL;
272 if (client->channel) {
273 list_del(&client->chan_node);
274 leaving = (channel_t *)client->channel;
275 if (leaving->temporary && list_empty(&leaving->clients)) {
276 leaving_id = leaving->id;
277 Chan_freeChannel(leaving);
283 int Chan_userJoin(channel_t *ch, client_t *client)
287 /* Do nothing if user already is in this channel */
288 if ((channel_t *)client->channel == ch)
291 Log_debug("Add user %s to channel %s", client->username, ch->name);
292 /* Only allowed in one channel at a time */
293 leaving_id = Chan_userLeave(client);
294 list_add_tail(&client->chan_node, &ch->clients);
295 client->channel = (void *)ch;
299 int Chan_userJoin_id(int channelid, client_t *client)
301 channel_t *ch_itr = NULL;
303 Chan_iterate(&ch_itr);
304 } while (ch_itr != NULL && ch_itr->id != channelid);
305 if (ch_itr == NULL) {
306 Log_warn("Channel id %d not found - ignoring.", channelid);
310 return Chan_userJoin(ch_itr, client);
313 channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client)
315 channel_t *ch_itr = NULL;
317 Chan_iterate(&ch_itr);
318 } while (ch_itr != NULL && ch_itr->id != channelid);
319 if (ch_itr == NULL) {
320 Log_warn("Channel id %d not found - ignoring.", channelid);
321 return CHJOIN_NOTFOUND;
323 else if (ch_itr->noenter)
324 return CHJOIN_NOENTER;
325 else if (ch_itr->password && !Client_token_match(client, ch_itr->password))
326 return CHJOIN_WRONGPW;
327 else return CHJOIN_OK;
331 void Chan_addChannel_id(int parentId, channel_t *ch)
333 channel_t *ch_itr = NULL;
335 Chan_iterate(&ch_itr);
336 } while (ch_itr != NULL && ch_itr->id != parentId);
338 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
340 list_add_tail(&ch->node, &ch_itr->subs);
344 channel_t *Chan_fromId(int channelid)
346 channel_t *ch_itr = NULL;
348 Chan_iterate(&ch_itr);
349 } while (ch_itr != NULL && ch_itr->id != channelid);
351 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
355 void Chan_removeChannel(channel_t *ch)
360 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
366 chl = malloc(sizeof(channellist_t));
368 init_list_entry(&chl->node);
369 list_add_tail(&chl->node, head);
371 list_iterate(itr, &ch->subs) {
372 sub = list_get_entry(itr, channel_t, node);
373 Chan_buildTreeList(sub, head);
377 void Chan_freeTreeList(struct dlist *head)
379 struct dlist *itr, *save;
380 list_iterate_safe(itr, save, head) {
381 free(list_get_entry(itr, channellist_t, node));