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 strncpy(ch->name, name, MAX_TEXT);
53 strncpy(ch->desc, desc, MAX_TEXT);
54 init_list_entry(&ch->subs);
55 init_list_entry(&ch->node);
56 init_list_entry(&ch->clients);
57 init_list_entry(&ch->flatlist_node);
58 init_list_entry(&ch->channel_links);
62 static int findFreeId()
65 channel_t *ch_itr = NULL;
66 for (id = 0; id < INT_MAX; id++) {
68 while ((ch_itr = Chan_iterate(&ch_itr)) != NULL) {
72 if (ch_itr == NULL) /* Found free id */
79 /* Might be used when tree traversal becomes neccessary */
80 static channel_t *first_subchannel(channel_t *ch)
82 if (list_empty(&ch->subs))
85 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
88 static channel_t *next_channel(channel_t *ch)
90 if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
93 return list_get_entry(list_get_next(&ch->node), channel_t, node);
97 channel_t *Chan_iterate(channel_t **channelpptr)
99 channel_t *ch = *channelpptr;
101 if (!list_empty(&channels)) {
103 ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
105 if (list_get_next(&ch->flatlist_node) == &channels)
108 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
116 channel_t *Chan_iterate_siblings(channel_t *parent, channel_t **channelpptr)
118 channel_t *ch = *channelpptr;
120 if (!list_empty(&parent->subs)) {
122 ch = list_get_entry(list_get_first(&parent->subs), channel_t, node);
124 if (list_get_next(&ch->node) == &parent->subs)
127 ch = list_get_entry(list_get_next(&ch->node), channel_t, node);
138 conf_channel_t chdesc;
139 conf_channel_link_t chlink;
140 const char *defaultChannelName;
142 defaultChannelName = getStrConf(DEAFULT_CHANNEL);
145 if (Conf_getNextChannel(&chdesc, i) < 0) {
147 Log_fatal("No valid channels found in configuration file. Exiting.");
151 rootChan = createChannel(0, chdesc.name, chdesc.description);
152 rootChan->noenter = chdesc.noenter;
153 list_add_tail(&rootChan->flatlist_node, &channels);
154 if (strcmp(defaultChannelName, chdesc.name) == 0)
155 defaultChan = rootChan;
158 channel_t *ch, *ch_itr = NULL;
159 ch = Chan_createChannel(chdesc.name, chdesc.description);
160 ch->noenter = chdesc.noenter;
162 if (strcmp(defaultChannelName, chdesc.name) == 0) {
163 Log_info("Setting default channel %s", ch->name);
168 Chan_iterate(&ch_itr);
169 } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
172 Log_fatal("Error in channel configuration: parent not found");
174 Chan_addChannel(ch_itr, ch);
175 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
179 if (defaultChan == NULL)
180 defaultChan = rootChan;
182 if (defaultChan->noenter)
183 Log_fatal("Error in channel configuration: default channel is marked as noenter");
187 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
188 if (Conf_getNextChannelLink(&chlink, i) < 0) {
190 Log_info("No channel links found in configuration file.");
195 Chan_iterate(&ch_itr);
196 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
198 Log_fatal("Error in channel link configuration: source channel '%s' not found.", chlink.source);
204 Chan_iterate(&ch_itr);
205 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
207 Log_fatal("Error in channel link configuration: destination channel '%s' not found", chlink.destination);
211 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
212 Log_info("Adding channel link %s -> %s", ch_src->name, ch_dst->name);
218 struct dlist *itr, *save;
220 list_iterate_safe(itr, save, &channels) {
221 Log_debug("Free channel %s", list_get_entry(itr, channel_t, flatlist_node)->name);
222 free(list_get_entry(itr, channel_t, flatlist_node));
226 channel_t *Chan_createChannel(const char *name, const char *desc)
228 int id = findFreeId();
230 Log_fatal("No free channel ID found");
231 return createChannel(id, name, desc);
234 void Chan_freeChannel(channel_t *ch)
237 list_del(&ch->flatlist_node);
241 void Chan_addChannel(channel_t *parent, channel_t *ch)
243 list_add_tail(&ch->node, &parent->subs);
245 list_add_tail(&ch->flatlist_node, &channels);
249 int Chan_playerJoin(channel_t *ch, client_t *client)
251 channel_t *leaving = NULL;
254 /* Only allowed in one channel at a time */
255 Log_debug("Add player %s to channel %s", client->playerName, ch->name);
257 if (client->channel) {
258 list_del(&client->chan_node);
259 leaving = (channel_t *)client->channel;
260 if (leaving->temporary && list_empty(&leaving->clients)) {
261 leaving_id = leaving->id;
262 Chan_freeChannel(leaving);
265 list_add_tail(&client->chan_node, &ch->clients);
266 client->channel = (void *)ch;
270 int Chan_playerJoin_id(int channelid, client_t *client)
272 channel_t *ch_itr = NULL;
274 Chan_iterate(&ch_itr);
275 } while (ch_itr != NULL && ch_itr->id != channelid);
276 if (ch_itr == NULL) {
277 Log_warn("Channel id %d not found - ignoring.", channelid);
281 return Chan_playerJoin(ch_itr, client);
284 bool_t Chan_playerJoin_id_test(int channelid)
286 channel_t *ch_itr = NULL;
288 Chan_iterate(&ch_itr);
289 } while (ch_itr != NULL && ch_itr->id != channelid);
290 if (ch_itr == NULL) {
291 Log_warn("Channel id %d not found - ignoring.", channelid);
301 void Chan_addChannel_id(int parentId, channel_t *ch)
303 channel_t *ch_itr = NULL;
305 Chan_iterate(&ch_itr);
306 } while (ch_itr != NULL && ch_itr->id != parentId);
308 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
310 list_add_tail(&ch->node, &ch_itr->subs);
314 channel_t *Chan_fromId(int channelid)
316 channel_t *ch_itr = NULL;
318 Chan_iterate(&ch_itr);
319 } while (ch_itr != NULL && ch_itr->id != channelid);
321 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
325 void Chan_removeChannel(channel_t *ch)