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_safeMalloc(1, sizeof(channel_t));
51 memset(ch, 0, sizeof(channel_t));
53 ch->name = strdup(name);
55 ch->desc = strdup(desc);
56 init_list_entry(&ch->subs);
57 init_list_entry(&ch->node);
58 init_list_entry(&ch->clients);
59 init_list_entry(&ch->flatlist_node);
60 init_list_entry(&ch->channel_links);
64 static int findFreeId()
67 channel_t *ch_itr = NULL;
68 for (id = 0; id < INT_MAX; id++) {
70 while ((ch_itr = Chan_iterate(&ch_itr)) != NULL) {
74 if (ch_itr == NULL) /* Found free id */
81 /* Might be used when tree traversal becomes neccessary */
82 static channel_t *first_subchannel(channel_t *ch)
84 if (list_empty(&ch->subs))
87 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
90 static channel_t *next_channel(channel_t *ch)
92 if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
95 return list_get_entry(list_get_next(&ch->node), channel_t, node);
99 channel_t *Chan_iterate(channel_t **channelpptr)
101 channel_t *ch = *channelpptr;
103 if (!list_empty(&channels)) {
105 ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
107 if (list_get_next(&ch->flatlist_node) == &channels)
110 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
118 channel_t *Chan_iterate_siblings(channel_t *parent, channel_t **channelpptr)
120 channel_t *ch = *channelpptr;
122 if (!list_empty(&parent->subs)) {
124 ch = list_get_entry(list_get_first(&parent->subs), channel_t, node);
126 if (list_get_next(&ch->node) == &parent->subs)
129 ch = list_get_entry(list_get_next(&ch->node), channel_t, node);
140 conf_channel_t chdesc;
141 conf_channel_link_t chlink;
142 const char *defaultChannelName;
144 defaultChannelName = getStrConf(DEFAULT_CHANNEL);
147 if (Conf_getNextChannel(&chdesc, i) < 0) {
149 Log_fatal("No valid channels found in configuration file. Exiting.");
153 rootChan = createChannel(0, chdesc.name, chdesc.description);
154 rootChan->noenter = chdesc.noenter;
155 rootChan->silent = chdesc.silent;
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 ch->silent = chdesc.silent;
166 if (chdesc.password) {
167 Log_info("Setting password on channel '%s'", ch->name);
168 ch->password = strdup(chdesc.password);
170 if (strcmp(defaultChannelName, chdesc.name) == 0) {
171 Log_info("Setting default channel '%s'", ch->name);
176 Chan_iterate(&ch_itr);
177 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
180 Log_fatal("Error in channel configuration: parent '%s' not found", chdesc.parent);
182 Chan_addChannel(ch_itr, ch);
183 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
187 if (defaultChan == NULL)
188 defaultChan = rootChan;
190 if (defaultChan->noenter)
191 Log_fatal("Error in channel configuration: default channel is marked as noenter");
192 if (defaultChan->password)
193 Log_fatal("Error in channel configuration: default channel has a password");
197 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
199 if (Conf_getNextChannelLink(&chlink, i) < 0) {
201 Log_info("No channel links found in configuration file.");
206 Chan_iterate(&ch_itr);
207 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
209 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
216 Chan_iterate(&ch_itr);
217 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
219 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
224 chl = Memory_safeMalloc(1, sizeof(channellist_t));
226 init_list_entry(&chl->node);
227 list_add_tail(&chl->node, &ch_src->channel_links);
229 Log_info("Adding channel link '%s' -> '%s'", ch_src->name, ch_dst->name);
235 struct dlist *itr, *save;
236 struct dlist *linkitr, *linksave;
239 list_iterate_safe(itr, save, &channels) {
240 ch = list_get_entry(itr, channel_t, flatlist_node);
241 Log_debug("Free channel '%s'", ch->name);
247 list_iterate_safe(linkitr, linksave, &ch->channel_links) {
249 chl = list_get_entry(linkitr, channellist_t, node);
256 channel_t *Chan_createChannel(const char *name, const char *desc)
258 int id = findFreeId();
260 Log_fatal("No free channel ID found");
261 return createChannel(id, name, desc);
264 void Chan_freeChannel(channel_t *ch)
267 list_del(&ch->flatlist_node);
271 void Chan_addChannel(channel_t *parent, channel_t *ch)
273 list_add_tail(&ch->node, &parent->subs);
275 list_add_tail(&ch->flatlist_node, &channels);
279 int Chan_userLeave(client_t *client)
281 channel_t *leaving = NULL;
284 if (client->channel) {
285 list_del(&client->chan_node);
286 leaving = (channel_t *)client->channel;
287 if (leaving->temporary && list_empty(&leaving->clients)) {
288 leaving_id = leaving->id;
289 Chan_freeChannel(leaving);
295 int Chan_userJoin(channel_t *ch, client_t *client)
299 /* Do nothing if user already is in this channel */
300 if ((channel_t *)client->channel == ch)
303 Log_debug("Add user %s to channel %s", client->username, ch->name);
304 /* Only allowed in one channel at a time */
305 leaving_id = Chan_userLeave(client);
306 list_add_tail(&client->chan_node, &ch->clients);
307 client->channel = (void *)ch;
311 int Chan_userJoin_id(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);
322 return Chan_userJoin(ch_itr, client);
325 channelJoinResult_t Chan_userJoin_id_test(int channelid, client_t *client)
327 channelJoinResult_t result;
328 channel_t *ch_itr = NULL;
330 Chan_iterate(&ch_itr);
331 } while (ch_itr != NULL && ch_itr->id != channelid);
332 if (ch_itr == NULL) {
333 Log_warn("Channel id %d not found - ignoring.", channelid);
334 result.CHJOIN_NOTFOUND = true;
337 result.CHJOIN_NOTFOUND = false;
339 result.CHJOIN_NOENTER = ch_itr->noenter;
340 result.CHJOIN_WRONGPW = ch_itr->password && !Client_token_match(client, ch_itr->password) && !client->isAdmin;
341 result.CHJOIN_SILENT = ch_itr->silent;
347 void Chan_addChannel_id(int parentId, channel_t *ch)
349 channel_t *ch_itr = NULL;
351 Chan_iterate(&ch_itr);
352 } while (ch_itr != NULL && ch_itr->id != parentId);
354 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
356 list_add_tail(&ch->node, &ch_itr->subs);
360 channel_t *Chan_fromId(int channelid)
362 channel_t *ch_itr = NULL;
364 Chan_iterate(&ch_itr);
365 } while (ch_itr != NULL && ch_itr->id != channelid);
367 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
371 void Chan_removeChannel(channel_t *ch)
376 void Chan_buildTreeList(channel_t *ch, struct dlist *head)
382 chl = Memory_safeMalloc(1, sizeof(channellist_t));
384 init_list_entry(&chl->node);
385 list_add_tail(&chl->node, head);
387 list_iterate(itr, &ch->subs) {
388 sub = list_get_entry(itr, channel_t, node);
389 Chan_buildTreeList(sub, head);
393 void Chan_freeTreeList(struct dlist *head)
395 struct dlist *itr, *save;
396 list_iterate_safe(itr, save, head) {
397 free(list_get_entry(itr, channellist_t, node));