e4ec9ad8fe97344838839276dc11d00c8c26c040
[umurmur.git] / channel.c
1 /* Copyright (C) 2009, Martin Johansson <martin@fatbob.nu>
2    Copyright (C) 2005-2009, 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         return ch;
59 }
60
61 #if 0
62 /* Might be used when tree travesal becomes neccessary */
63 static channel_t *first_subchannel(channel_t *ch)
64 {
65         if (list_empty(&ch->subs))
66                 return NULL;
67         else
68                 return list_get_entry(list_get_first(&ch->subs), channel_t, node);
69 }
70
71 static channel_t *next_channel(channel_t *ch)
72 {
73         if (list_get_next(&ch->node) == &list_get_entry(&ch->node, channel_t, node)->parent->subs)
74                 return NULL;
75         else
76                 return list_get_entry(list_get_next(&ch->node), channel_t, node);       
77 }
78 #endif
79
80 void Chan_iterate(channel_t **channelpptr)
81 {
82         channel_t *ch = *channelpptr;
83
84         if (!list_empty(&channels)) {
85                 if (ch == NULL)
86                         ch = list_get_entry(list_get_first(&channels), channel_t, flatlist_node);
87                 else {
88                         if (list_get_next(&ch->flatlist_node) == &channels)
89                                 ch = NULL;
90                         else
91                                 ch = list_get_entry(list_get_next(&ch->flatlist_node), channel_t, flatlist_node);
92                 }
93                 if (ch)
94                         Log_debug("Channel %d", ch->id);
95         }
96
97         *channelpptr = ch;
98 }
99                         
100 void Chan_init()
101 {
102         int i;
103         conf_channel_t chdesc;
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
145 void Chan_free()
146 {
147         struct dlist *itr, *save;
148         
149         list_iterate_safe(itr, save, &channels) {
150                 Log_debug("Free channel %s", list_get_entry(itr, channel_t, flatlist_node)->name);
151                 free(list_get_entry(itr, channel_t, flatlist_node));
152         }
153 }
154
155 channel_t *Chan_createChannel(const char *name, const char *desc)
156 {
157         /* Get an ID */
158         nextchanId += 1; 
159         return createChannel(nextchanId, name, desc);
160 }
161
162 void Chan_freeChannel(channel_t *ch)
163 {
164         list_del(&ch->node);
165         list_del(&ch->flatlist_node);
166         free(ch);
167 }
168
169 void Chan_addChannel(channel_t *parent, channel_t *ch)
170 {
171         list_add_tail(&ch->node, &parent->subs);
172         ch->parent = parent;
173         list_add_tail(&ch->flatlist_node, &channels);
174 }
175
176
177 void Chan_playerJoin(channel_t *ch, client_t *client)
178 {
179         /* Only allowed in one channel at a time */
180         Log_debug("Add player %s to channel %s", client->playerName, ch->name); 
181
182         if (client->channel)
183                 list_del(&client->chan_node);
184         list_add_tail(&client->chan_node, &ch->clients);
185         client->channel = (void *)ch;
186         
187 }
188
189 void Chan_playerJoin_id(int channelid, client_t *client)
190 {
191         channel_t *ch_itr = NULL;
192         do {
193                 Chan_iterate(&ch_itr);
194         } while (ch_itr != NULL && ch_itr->id != channelid);
195         if (ch_itr == NULL)
196                 Log_warn("Channel id %d not found - ignoring.", channelid);
197         else
198                 Chan_playerJoin(ch_itr, client);
199         
200 }
201
202 void Chan_addChannel_id(int parentId, channel_t *ch)
203 {
204         channel_t *ch_itr = NULL;
205         do {
206                 Chan_iterate(&ch_itr);
207         } while (ch_itr != NULL && ch_itr->id != parentId);
208         if (ch_itr == NULL)
209                 Log_warn("Channel id %d not found - ignoring.", parentId);
210         else
211                 list_add_tail(&ch->node, &ch_itr->subs);
212 }
213
214 void Chan_removeChannel(channel_t *ch)
215 {
216         list_del(&ch->node);
217 }