00001
00013 #include <assert.h>
00014 #include <stdarg.h>
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018
00019 #include "boris.h"
00020 #include "list.h"
00021 #include "plugin.h"
00022
00023 #define LOGBASIC_LENGTH_MAX 1024
00024
00025
00026
00027
00028
00029 struct room {
00030 LIST_ENTRY(struct room) room_cache;
00031 int refcount;
00032 int dirty_fl;
00033 unsigned id;
00034 struct {
00035 char *short_str, *long_str;
00036 } name;
00037 struct {
00038 char *short_str, *long_str;
00039 } desc;
00040 char *owner, *creator;
00041 struct attr_list extra_values;
00042 };
00043
00044 struct plugin_room_class {
00045 struct plugin_basic_class base_class;
00046 struct plugin_room_interface room_interface;
00047 };
00048
00049 LIST_HEAD(struct room_cache, struct room);
00050
00051
00052
00053
00054 extern const struct plugin_room_class plugin_class;
00055
00056
00057
00058
00059
00061 static struct room_cache room_cache;
00062
00063
00064
00065
00066
00070 static void room_ll_free(struct room *r) {
00071 assert(r != NULL);
00072
00073 LIST_REMOVE(r, room_cache);
00074 LIST_ENTRY_INIT(r, room_cache);
00075
00076 free(r->name.short_str); r->name.short_str=NULL;
00077 free(r->name.long_str); r->name.long_str=NULL;
00078
00079 free(r->desc.short_str); r->desc.short_str=NULL;
00080 free(r->desc.long_str); r->desc.long_str=NULL;
00081
00082 free(r->owner); r->owner=NULL;
00083 free(r->creator); r->creator=NULL;
00084
00085 attr_list_free(&r->extra_values);
00086
00087 free(r);
00088 }
00089
00093 static int room_attr_set(struct room *r, const char *name, const char *value) {
00094 int res;
00095
00096 assert(r != NULL);
00097 assert(name != NULL);
00098 assert(value != NULL);
00099
00100 if(!r) return 0;
00101
00102 if(!strcasecmp("id", name))
00103 res=parse_uint(name, value, &r->id);
00104 else if(!strcasecmp("name.short", name))
00105 res=parse_str(name, value, &r->name.short_str);
00106 else if(!strcasecmp("name.long", name))
00107 res=parse_str(name, value, &r->name.long_str);
00108 else if(!strcasecmp("desc.short", name))
00109 res=parse_str(name, value, &r->desc.short_str);
00110 else if(!strcasecmp("desc.long", name))
00111 res=parse_str(name, value, &r->desc.long_str);
00112 else if(!strcasecmp("creator", name))
00113 res=parse_str(name, value, &r->creator);
00114 else if(!strcasecmp("owner", name))
00115 res=parse_str(name, value, &r->owner);
00116 else
00117 res=parse_attr(name, value, &r->extra_values);
00118
00119 if(res)
00120 r->dirty_fl=1;
00121 return res;
00122 }
00123
00124 static const char *room_attr_get(struct room *r, const char *name) {
00125 static char numbuf[22];
00126
00127 if(!strcasecmp("id", name)) {
00128 snprintf(numbuf, sizeof numbuf, "%u", r->id);
00129 return numbuf;
00130 } else if(!strcasecmp("name.short", name))
00131 return r->name.short_str;
00132 else if(!strcasecmp("name.long", name))
00133 return r->name.long_str;
00134 else if(!strcasecmp("desc.short", name))
00135 return r->desc.short_str;
00136 else if(!strcasecmp("desc.long", name))
00137 return r->desc.long_str;
00138 else if(!strcasecmp("creator", name))
00139 return r->creator;
00140 else if(!strcasecmp("owner", name))
00141 return r->owner;
00142 else {
00143 struct attr_entry *at;
00144 at=attr_find(&r->extra_values, name);
00145 if(at) return at->value;
00146 }
00147
00148 return NULL;
00149 }
00150
00151 static struct room *room_load(unsigned room_id) {
00152 struct room *r;
00153 char numbuf[22];
00154 struct fdb_read_handle *h;
00155 const char *name, *value;
00156
00157 assert(room_id > 0);
00158 if(room_id<=0) return NULL;
00159
00160 snprintf(numbuf, sizeof numbuf, "%u", room_id);
00161
00162 h=fdb.read_begin("rooms", numbuf);
00163 if(!h) {
00164 b_log(B_LOG_ERROR, "room", "could not load room \"%s\"", numbuf);
00165 return NULL;
00166 }
00167
00168 r=calloc(1, sizeof *r);
00169 if(!r) {
00170
00171 b_log(B_LOG_ERROR, "calloc", "not allocate room \"%s\"", numbuf);
00172 fdb.read_end(h);
00173 return NULL;
00174 }
00175
00176 while(fdb.read_next(h, &name, &value)) {
00177 if(!room_attr_set(r, name, value)) {
00178 b_log(B_LOG_ERROR, "room", "could not load room \"%s\"", numbuf);
00179 room_ll_free(r);
00180 fdb.read_end(h);
00181 return NULL;
00182 }
00183 }
00184
00185 fdb.read_end(h);
00186
00187
00188 if(!r->id) {
00189 b_log(B_LOG_ERROR, "room", "id not set for room \"%u\"", room_id);
00190 room_ll_free(r);
00191 return NULL;
00192 }
00193
00194
00195 if(r->id!=room_id) {
00196 b_log(B_LOG_ERROR, "room", "id was set to \"%u\" but should be \"%u\"", r->id, room_id);
00197 room_ll_free(r);
00198 return NULL;
00199 }
00200
00201 return r;
00202 }
00203
00207 static int room_save(struct room *r) {
00208 struct attr_entry *curr;
00209 struct fdb_write_handle *h;
00210 char numbuf[22];
00211
00212 assert(r != NULL);
00213 if(!r->dirty_fl) return 1;
00214
00215
00216 if(!r->id) {
00217 b_log(B_LOG_ERROR, "room", "attempted to save room \"%u\", but it is reserved", r->id);
00218 return 0;
00219 }
00220
00221 snprintf(numbuf, sizeof numbuf, "%u", r->id);
00222
00223 h=fdb.write_begin("rooms", numbuf);
00224 if(!h) {
00225 b_log(B_LOG_ERROR, "room", "could not save room \"%s\"", numbuf);
00226 return 0;
00227 }
00228
00229 fdb.write_format(h, "id", "%u", r->id);
00230 if(r->name.short_str)
00231 fdb.write_pair(h, "name.short", r->name.short_str);
00232 if(r->name.long_str)
00233 fdb.write_pair(h, "name.long", r->name.long_str);
00234 if(r->desc.short_str)
00235 fdb.write_pair(h, "desc.short", r->desc.short_str);
00236 if(r->desc.long_str)
00237 fdb.write_pair(h, "desc.long", r->desc.long_str);
00238 if(r->owner)
00239 fdb.write_pair(h, "owner", r->owner);
00240 if(r->creator)
00241 fdb.write_pair(h, "creator", r->creator);
00242
00243 for(curr=LIST_TOP(r->extra_values);curr;curr=LIST_NEXT(curr, list)) {
00244 fdb.write_pair(h, curr->name, curr->value);
00245 }
00246
00247 if(!fdb.write_end(h)) {
00248 b_log(B_LOG_ERROR, "room", "could not save room \"%s\"", numbuf);
00249 return 0;
00250 }
00251
00252 r->dirty_fl=0;
00253 b_log(B_LOG_INFO, "room", "saved room \"%s\"", numbuf);
00254 return 1;
00255 }
00256
00261 static struct room *room_get(unsigned room_id) {
00262 struct room *curr;
00263
00264
00265 if(!room_id) return NULL;
00266
00267
00268 for(curr=LIST_TOP(room_cache);curr;curr=LIST_NEXT(curr, room_cache)) {
00269 if(curr->id==room_id) break;
00270 }
00271
00272 if(!curr) {
00273
00274 curr=room_load(room_id);
00275 }
00276 if(curr) {
00277
00278 LIST_INSERT_HEAD(&room_cache, curr, room_cache);
00279 curr->refcount++;
00280 }
00281 if(!curr) {
00282 b_log(B_LOG_WARN, "room", "could not access room \"%u\"", room_id);
00283 }
00284 return curr;
00285 }
00286
00290 static void room_put(struct room *r) {
00291 assert(r != NULL);
00292
00293 r->refcount--;
00294
00295 if(r->refcount<=0) {
00296 room_save(r);
00297 room_ll_free(r);
00298 }
00299 }
00300
00301 static int initialize(void) {
00302 struct fdb_iterator *it;
00303 const char *id;
00304
00305 b_log(B_LOG_INFO, "room", "Room system loaded (" __FILE__ " compiled " __TIME__ " " __DATE__ ")");
00306 LIST_INIT(&room_cache);
00307
00308 fdb.domain_init("rooms");
00309
00310 it=fdb.iterator_begin("rooms");
00311 if(!it) {
00312 b_log(B_LOG_CRIT, "room", "could not load rooms!");
00313 return 0;
00314 }
00315
00316
00317 while((id=fdb.iterator_next(it))) {
00318 struct room *r;
00319 unsigned room_id;
00320 char *endptr;
00321 b_log(B_LOG_DEBUG, "room", "Found room: \"%s\"", id);
00322 room_id=strtoul(id, &endptr, 10);
00323 if(*endptr) {
00324 b_log(B_LOG_CRIT, "room", "room id \"%s\" is invalid!", id);
00325 fdb.iterator_end(it);
00326 return 0;
00327 }
00328 r=room_load(room_id);
00329 if(!r) {
00330 b_log(B_LOG_CRIT, "room", "could not load rooms!");
00331 fdb.iterator_end(it);
00332 return 0;
00333 }
00334 room_ll_free(r);
00335 }
00336 fdb.iterator_end(it);
00337
00338 service_attach_room(&plugin_class.base_class, &plugin_class.room_interface);
00339 return 1;
00340 }
00341
00342 static int shutdown(void) {
00343 struct room *curr;
00344 b_log(B_LOG_INFO, "room", "Room system shutting down..");
00345
00346
00347 for(curr=LIST_TOP(room_cache);curr;curr=LIST_NEXT(curr, room_cache)) {
00348 if(curr->refcount>0) {
00349 b_log(B_LOG_ERROR, "room", "cannot shut down, room \"%u\" still in use.", curr->id);
00350 return 0;
00351 }
00352 }
00353
00354
00355 while((curr=LIST_TOP(room_cache))) {
00356 LIST_REMOVE(curr, room_cache);
00357 room_save(curr);
00358 room_ll_free(curr);
00359 }
00360 service_detach_room(&plugin_class.base_class);
00361 b_log(B_LOG_INFO, "room", "Room system ended.");
00362 return 1;
00363 }
00364
00365
00366
00367
00368
00369 const struct plugin_room_class plugin_class = {
00370 .base_class = { PLUGIN_API, "room", initialize, shutdown },
00371 .room_interface = { room_get, room_put, room_attr_set, room_attr_get, room_save }
00372 };