1 /* Copyright (C) 2009-2014, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2014, 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.
42 static channel_t *rootChan;
43 channel_t *defaultChan;
44 declare_list(channels); /* A flat list of the channels */
46 static channel_t *createChannel(int id, const char *name, const char *desc)
50 ch = Memory_safeCalloc(1, 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 rootChan->silent = chdesc.silent;
155 list_add_tail(&rootChan->flatlist_node, &channels);
156 if (strcmp(defaultChannelName, chdesc.name) == 0)
157 defaultChan = rootChan;
160 channel_t *ch, *ch_itr = NULL;
161 ch = Chan_createChannel(chdesc.name, chdesc.description);
162 ch->noenter = chdesc.noenter;
163 ch->position = chdesc.position;
164 ch->silent = chdesc.silent;
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;
198 if (Conf_getNextChannelLink(&chlink, i) < 0) {
200 Log_info("No channel links found in configuration file.");
205 Chan_iterate(&ch_itr);
206 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
208 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
215 Chan_iterate(&ch_itr);
216 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
218 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
223 chl = Memory_safeMalloc(1, sizeof(channellist_t));
225 init_list_entry(&chl->node);
226 list_add_tail(&chl->node, &ch_src->channel_links);
228 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
234 struct dlist *itr, *save;
235 struct dlist *linkitr, *linksave;
238 list_iterate_safe(itr, save, &channels) {
239 ch = list_get_entry(itr, channel_t, flatlist_node);
240 Log_debug("Free channel '%s'", ch->name);
246 list_iterate_safe(linkitr, linksave, &ch->channel_links) {
248 chl = list_get_entry(linkitr, channellist_t, node);
255 channel_t *Chan_createChannel(const char *name, const char *desc)
257 int id = findFreeId();
259 Log_fatal("No free channel ID found");
260 return createChannel(id, name, desc);
263 void Chan_freeChannel(channel_t *ch)
266 list_del(&ch->flatlist_node);
270 void Chan_addChannel(channel_t *parent, channel_t *ch)
272 list_add_tail(&ch->node, &parent->subs);
274 list_add_tail(&ch->flatlist_node, &channels);
278 int Chan_userLeave(client_t *client)
280 channel_t *leaving = NULL;
283 if (client->channel) {
284 list_del(&client->chan_node);
285 leaving = client->channel;
286 if (leaving->temporary && list_empty(&leaving->clients)) {
287 leaving_id = leaving->id;
288 Chan_freeChannel(leaving);
294 int Chan_userJoin(channel_t *ch, client_t *client)
298 /* Do nothing if user already is in this channel */
299 if (client->channel == ch)
302 Log_debug("Add user %s to channel %s", client->username, ch->name);
303 /* Only allowed in one channel at a time */
304 leaving_id = Chan_userLeave(client);
305 list_add_tail(&client->chan_node, &ch->clients);
306 client->channel = ch;
310 int Chan_userJoin_id(int channelid, client_t *client)
312 channel_t *ch_itr = NULL;
314 Chan_iterate(&ch_itr);
315 } while (ch_itr != NULL && ch_itr->id != channelid);
316 if (ch_itr == NULL) {
317 Log_warn("Channel id %d not found - ignoring.", channelid);
321 return Chan_userJoin(ch_itr, client);
324 channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client)
326 channelJoinResult_t result;
327 channel_t *ch_itr = NULL;
329 Chan_iterate(&ch_itr);
330 } while (ch_itr != NULL && ch_itr->id != channelid);
331 if (ch_itr == NULL) {
332 Log_warn("Channel id %d not found - ignoring.", channelid);
333 result.CHJOIN_NOTFOUND = true;
336 result.CHJOIN_NOTFOUND = false;
338 result.CHJOIN_NOENTER = ch_itr->noenter;
339 result.CHJOIN_WRONGPW = ch_itr->password && !Client_token_match(client, ch_itr->password) && !client->isAdmin;
340 result.CHJOIN_SILENT = ch_itr->silent;
346 void Chan_addChannel_id(int parentId, channel_t *ch)
348 channel_t *ch_itr = NULL;
350 Chan_iterate(&ch_itr);
351 } while (ch_itr != NULL && ch_itr->id != parentId);
353 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
355 list_add_tail(&ch->node, &ch_itr->subs);
359 channel_t *Chan_fromId(int channelid)
361 channel_t *ch_itr = NULL;
363 Chan_iterate(&ch_itr);
364 } while (ch_itr != NULL && ch_itr->id != channelid);
366 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
370 void Chan_removeChannel(channel_t *ch)
375 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
381 chl = Memory_safeMalloc(1, sizeof(channellist_t));
383 init_list_entry(&chl->node);
384 list_add_tail(&chl->node, head);
386 list_iterate(itr, &ch->subs) {
387 sub = list_get_entry(itr, channel_t, node);
388 Chan_buildTreeList(sub, head);
392 void Chan_freeTreeList(struct dlist *head)
394 struct dlist *itr, *save;
395 list_iterate_safe(itr, save, head) {
396 free(list_get_entry(itr, channellist_t, node));