Update copyright year. Fix a typo in logging.
[umurmur.git] / src / channel.c
1 /* Copyright (C) 2010, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2010, Thorvald Natvig <thorvald@natvig.com>
3
4    All rights reserved.
5
6    Redistribution and use in source and binary forms, with or without
7    modification, are permitted provided that the following conditions
8    are met:
9
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.
18
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.
30 */
31 #include "log.h"
32 #include "list.h"
33 #include "client.h"
34 #include "channel.h"
35 #include "conf.h"
36
37
38 static int nextchanId;
39 static channel_t *rootChan;
40 channel_t *defaultChan;
41 declare_list(channels); /* A flat list of the channels */
42
43 static channel_t *createChannel(int id, const char *name, const char *desc)
44 {
45         channel_t *ch;
46
47         ch = malloc(sizeof(channel_t));
48         if (ch == NULL)
49                 Log_fatal("out of memory");
50         memset(ch, 0, sizeof(channel_t));
51         ch->id = id;
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);
59         return ch;
60 }
61
62 #if 0
63 /* Might be used when tree travesal becomes neccessary */
64 static channel_t *first_subchannel(channel_t *ch)
65 {
66         if (list_empty(&ch->subs))
67                 return NULL;
68         else
69                 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
70 }
71
72 static channel_t *next_channel(channel_t *ch)
73 {
74         if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
75                 return NULL;
76         else
77                 return list_get_entry(list_get_next(&ch->node), channel_t, node);       
78 }
79 #endif
80
81 void Chan_iterate(channel_t **channelpptr)
82 {
83         channel_t *ch = *channelpptr;
84
85         if (!list_empty(&channels)) {
86                 if (ch == NULL)
87                         ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
88                 else {
89                         if (list_get_next(&ch->flatlist_node) == &channels)
90                                 ch = NULL;
91                         else
92                                 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
93                 }
94         }
95
96         *channelpptr = ch;
97 }
98                         
99 void Chan_init()
100 {
101         int i;
102         conf_channel_t chdesc;
103         conf_channel_link_t chlink;
104         const char *defaultChannelName;
105
106         defaultChannelName = getStrConf(DEAFULT_CHANNEL);
107         
108         for (i = 0; ; i++) {
109                 if (Conf_getNextChannel(&chdesc, i) < 0) {
110                         if (i == 0)
111                                 Log_fatal("No valid channels found in configuration file. Exiting.");
112                         break;
113                 }
114                 if (i == 0) {
115                         rootChan = createChannel(0, chdesc.name, chdesc.description);
116                         list_add_tail(&rootChan->flatlist_node, &channels);
117                         if (strcmp(defaultChannelName, chdesc.name) == 0)
118                                 defaultChan = rootChan;
119                 }
120                 else {
121                         channel_t *ch, *ch_itr = NULL;
122                         ch = Chan_createChannel(chdesc.name, chdesc.description);
123                         
124                         if (strcmp(defaultChannelName, chdesc.name) == 0) {
125                                 Log_info("Setting default channel %s", ch->name); 
126                                 defaultChan = ch;
127                         }
128                         
129                         do {
130                                 Chan_iterate(&ch_itr);
131                         } while (ch_itr != NULL && strcmp(ch_itr->name, chdesc.parent) != 0);
132                         
133                         if (ch_itr == NULL)
134                                 Log_fatal("Error in channel configuration: parent not found");
135                         else {
136                                 Chan_addChannel(ch_itr, ch);
137                                 Log_info("Adding channel '%s' parent '%s'", ch->name, chdesc.parent);
138                         }
139                 }
140         }
141         if (defaultChan == NULL)
142                 defaultChan = rootChan;
143
144         /* Channel links */
145         for (i = 0; ; i++) {
146                 channel_t *ch_src, *ch_dst, *ch_itr = NULL;
147                 if (Conf_getNextChannelLink(&chlink, i) < 0) {
148                         if (i == 0)
149                                 Log_info("No channel links found in configuration file.");
150                         break;
151                 }
152                 ch_itr = NULL;
153                 do {
154                         Chan_iterate(&ch_itr);
155                 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.source) != 0);
156                 if (ch_itr == NULL)
157                         Log_fatal("Error in channel link configuration: source channel '%s' not found.", chlink.source);
158                 else
159                         ch_src = ch_itr;
160                 
161                 ch_itr = NULL;          
162                 do {
163                         Chan_iterate(&ch_itr);
164                 } while (ch_itr != NULL && strcmp(ch_itr->name, chlink.destination) != 0);
165                 if (ch_itr == NULL)
166                         Log_fatal("Error in channel link configuration: destination channel '%s' not found", chlink.destination);
167                 else
168                         ch_dst = ch_itr;
169                 
170                 list_add_tail(&ch_dst->link_node, &ch_src->channel_links);
171                 Log_debug("Adding channel link %s -> %s", ch_src->name, ch_dst->name);
172         }
173 }
174
175 void Chan_free()
176 {
177         struct dlist *itr, *save;
178         
179         list_iterate_safe(itr, save, &channels) {
180                 Log_debug("Free channel %s", list_get_entry(itr, channel_t, flatlist_node)->name);
181                 free(list_get_entry(itr, channel_t, flatlist_node));
182         }
183 }
184
185 channel_t *Chan_createChannel(const char *name, const char *desc)
186 {
187         /* Get an ID */
188         nextchanId += 1; 
189         return createChannel(nextchanId, name, desc);
190 }
191
192 void Chan_freeChannel(channel_t *ch)
193 {
194         list_del(&ch->node);
195         list_del(&ch->flatlist_node);
196         free(ch);
197 }
198
199 void Chan_addChannel(channel_t *parent, channel_t *ch)
200 {
201         list_add_tail(&ch->node, &parent->subs);
202         ch->parent = parent;
203         list_add_tail(&ch->flatlist_node, &channels);
204 }
205
206
207 void Chan_playerJoin(channel_t *ch, client_t *client)
208 {
209         /* Only allowed in one channel at a time */
210         Log_debug("Add player %s to channel %s", client->playerName, ch->name); 
211
212         if (client->channel)
213                 list_del(&client->chan_node);
214         list_add_tail(&client->chan_node, &ch->clients);
215         client->channel = (void *)ch;
216         
217 }
218
219 void Chan_playerJoin_id(int channelid, client_t *client)
220 {
221         channel_t *ch_itr = NULL;
222         do {
223                 Chan_iterate(&ch_itr);
224         } while (ch_itr != NULL && ch_itr->id != channelid);
225         if (ch_itr == NULL)
226                 Log_warn("Channel id %d not found - ignoring.", channelid);
227         else
228                 Chan_playerJoin(ch_itr, client);
229         
230 }
231
232 void Chan_addChannel_id(int parentId, channel_t *ch)
233 {
234         channel_t *ch_itr = NULL;
235         do {
236                 Chan_iterate(&ch_itr);
237         } while (ch_itr != NULL && ch_itr->id != parentId);
238         if (ch_itr == NULL)
239                 Log_warn("Chan_addChannel_id: Channel id %d not found - ignoring.", parentId);
240         else
241                 list_add_tail(&ch->node, &ch_itr->subs);
242 }
243
244 channel_t *Chan_fromId(int channelid)
245 {
246         channel_t *ch_itr = NULL;
247         do {
248                 Chan_iterate(&ch_itr);
249         } while (ch_itr != NULL && ch_itr->id != channelid);
250         if (ch_itr == NULL)
251                 Log_warn("Chan_fromId: Channel id %d not found.", channelid);
252         return ch_itr;
253 }
254
255 void Chan_removeChannel(channel_t *ch)
256 {
257         list_del(&ch->node);
258 }