1 /* Copyright (C) 2009-2010, Martin Johansson <martin@fatbob.nu>
2 Copyright (C) 2005-2010, 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.
39 static channel_t *rootChan;
40 channel_t *defaultChan;
41 declare_list(channels); /* A flat list of the channels */
43 static channel_t *createChannel(int id, const char *name, const char *desc)
47 ch = malloc(sizeof(channel_t));
49 Log_fatal("out of memory");
50 memset(ch, 0, 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 list_add_tail(&rootChan->flatlist_node, &channels);
155 if (strcmp(defaultChannelName, chdesc.name) == 0)
156 defaultChan = rootChan;
159 channel_t *ch, *ch_itr = NULL;
160 ch = Chan_createChannel(chdesc.name, chdesc.description);
161 ch->noenter = chdesc.noenter;
163 if (strcmp(defaultChannelName, chdesc.name) == 0) {
164 Log_info("Setting default channel %s", ch->name);
169 Chan_iterate(&ch_itr);
170 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
173 Log_fatal("Error in channel configuration: parent not found");
175 Chan_addChannel(ch_itr, ch);
176 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
180 if (defaultChan == NULL)
181 defaultChan = rootChan;
183 if (defaultChan->noenter)
184 Log_fatal("Error in channel configuration: default channel is marked as noenter");
188 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
189 if (Conf_getNextChannelLink(&chlink, i) < 0) {
191 Log_info("No channel links found in configuration file.");
196 Chan_iterate(&ch_itr);
197 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
199 Log_fatal("Error in channel link configuration: source channel '%s' not found.",
206 Chan_iterate(&ch_itr);
207 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
209 Log_fatal("Error in channel link configuration: destination channel '%s' not found",
214 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
215 Log_info("Adding channel link %s -> %s", ch_src->name, ch_dst->name);
221 struct dlist *itr, *save;
224 list_iterate_safe(itr, save, &channels) {
225 ch = list_get_entry(itr, channel_t, flatlist_node);
226 Log_debug("Free channel %s", ch->name);
234 channel_t *Chan_createChannel(const char *name, const char *desc)
236 int id = findFreeId();
238 Log_fatal("No free channel ID found");
239 return createChannel(id, name, desc);
242 void Chan_freeChannel(channel_t *ch)
245 list_del(&ch->flatlist_node);
249 void Chan_addChannel(channel_t *parent, channel_t *ch)
251 list_add_tail(&ch->node, &parent->subs);
253 list_add_tail(&ch->flatlist_node, &channels);
257 int Chan_playerJoin(channel_t *ch, client_t *client)
259 channel_t *leaving = NULL;
262 /* Only allowed in one channel at a time */
263 Log_debug("Add player %s to channel %s", client->playerName, ch->name);
265 if (client->channel) {
266 list_del(&client->chan_node);
267 leaving = (channel_t *)client->channel;
268 if (leaving->temporary && list_empty(&leaving->clients)) {
269 leaving_id = leaving->id;
270 Chan_freeChannel(leaving);
273 list_add_tail(&client->chan_node, &ch->clients);
274 client->channel = (void *)ch;
278 int Chan_playerJoin_id(int channelid, client_t *client)
280 channel_t *ch_itr = NULL;
282 Chan_iterate(&ch_itr);
283 } while (ch_itr != NULL && ch_itr->id != channelid);
284 if (ch_itr == NULL) {
285 Log_warn("Channel id %d not found - ignoring.", channelid);
289 return Chan_playerJoin(ch_itr, client);
292 bool_t Chan_playerJoin_id_test(int channelid)
294 channel_t *ch_itr = NULL;
296 Chan_iterate(&ch_itr);
297 } while (ch_itr != NULL && ch_itr->id != channelid);
298 if (ch_itr == NULL) {
299 Log_warn("Channel id %d not found - ignoring.", channelid);
309 void Chan_addChannel_id(int parentId, channel_t *ch)
311 channel_t *ch_itr = NULL;
313 Chan_iterate(&ch_itr);
314 } while (ch_itr != NULL && ch_itr->id != parentId);
316 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
318 list_add_tail(&ch->node, &ch_itr->subs);
322 channel_t *Chan_fromId(int channelid)
324 channel_t *ch_itr = NULL;
326 Chan_iterate(&ch_itr);
327 } while (ch_itr != NULL && ch_itr->id != channelid);
329 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
333 void Chan_removeChannel(channel_t *ch)