1 |
/** |
2 |
* flatfile.C: This file contains the implementation of the Atheme 0.1 flatfile database format, with metadata extensions. |
3 |
* |
4 |
* Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team |
5 |
* Rights to this code are as documented in COPYING. |
6 |
* |
7 |
* |
8 |
* Portions of this file were derived from sources bearing the following license: |
9 |
* Copyright © 2005-2006 Atheme Development Group |
10 |
* Rights to this code are as documented in doc/pod/license.pod. |
11 |
* |
12 |
* $Id: flatfile.C,v 1.10 2007-09-16 18:54:42 pippijn Exp $ |
13 |
*/ |
14 |
|
15 |
#include <boost/foreach.hpp> |
16 |
|
17 |
#include "atheme.h" |
18 |
#include <libermyth.h> |
19 |
#include <util/string.h> |
20 |
#include <ermyth/database.h> |
21 |
#include <account/chanacs.h> |
22 |
#include <account/kline.h> |
23 |
#include <account/metadata.h> |
24 |
#include <account/mychan.h> |
25 |
#include <account/mymemo.h> |
26 |
#include <account/mynick.h> |
27 |
#include <account/myuser.h> |
28 |
#include <account/svsignore.h> |
29 |
|
30 |
static char const rcsid[] = "$Id: flatfile.C,v 1.10 2007-09-16 18:54:42 pippijn Exp $"; |
31 |
|
32 |
/* database versions */ |
33 |
#define DB_SHRIKE 1 |
34 |
#define DB_ATHEME 2 |
35 |
|
36 |
namespace database |
37 |
{ |
38 |
/* flatfile state */ |
39 |
unsigned int muout = 0, mcout = 0, caout = 0, kout = 0; |
40 |
|
41 |
struct flatfile : handler |
42 |
{ |
43 |
virtual void save (); |
44 |
virtual void load (); |
45 |
}; |
46 |
|
47 |
struct flatfile_save_myusers_cb |
48 |
{ |
49 |
flatfile_save_myusers_cb (FILE *file) |
50 |
: f (file) |
51 |
{ |
52 |
} |
53 |
|
54 |
void operator () (myuser_t::pair_type &it) |
55 |
{ |
56 |
myuser_t *mu = it.second; |
57 |
metadata::map_type::iterator mdit, mdet; |
58 |
myuser_t::memo_vector::iterator mzit, mzet; |
59 |
myuser_t::mzignore_vector::iterator miit, miet; |
60 |
node_t *tn; |
61 |
|
62 |
/* MU <name> <pass> <email> <registered> [lastlogin] [failnum*] [lastfail*] |
63 |
* [lastfailon*] [flags] |
64 |
* |
65 |
* * failnum, lastfail, and lastfailon are deprecated (moved to metadata) |
66 |
*/ |
67 |
fprintf (f, "MU %s %s %s %ld", mu->name, mu->pass, mu->email, mu->registered); |
68 |
fprintf (f, " %ld", mu->lastlogin); |
69 |
fprintf (f, " 0 0 0"); |
70 |
if (!mu->logins.empty ()) |
71 |
fprintf (f, " %d\n", mu->flags & ~MU_NOBURSTLOGIN); |
72 |
else |
73 |
fprintf (f, " %d\n", mu->flags); |
74 |
|
75 |
muout++; |
76 |
|
77 |
for (mdit = mu->mdmap.begin (), mdet = mu->mdmap.end (); mdit != mdet; ++mdit) |
78 |
{ |
79 |
metadata *md = mdit->second; |
80 |
fprintf (f, "MD U %s %s %s\n", mu->name, md->key, md->value); |
81 |
} |
82 |
|
83 |
for (mzit = mu->memos.begin (), mzet = mu->memos.end (); mzit != mzet; ++mzit) |
84 |
{ |
85 |
mymemo_t *mz = *mzit; |
86 |
fprintf (f, "ME %s %s %lu %u %s\n", mu->name, mz->sender, mz->sent, mz->status, mz->text); |
87 |
} |
88 |
|
89 |
for (miit = mu->memo_ignores.begin (), miet = mu->memo_ignores.end (); miit != miet; ++miit) |
90 |
fprintf (f, "MI %s %s\n", mu->name, *miit); |
91 |
|
92 |
LIST_FOREACH (tn, mu->access_list.head) |
93 |
{ |
94 |
fprintf (f, "AC %s %s\n", mu->name, (char *) tn->data); |
95 |
} |
96 |
|
97 |
LIST_FOREACH (tn, mu->nicks.head) |
98 |
{ |
99 |
mynick_t *mn = static_cast<mynick_t *> (tn->data); |
100 |
|
101 |
fprintf (f, "MN %s %s %ld %ld\n", mu->name, mn->nick, (long) mn->registered, (long) mn->lastseen); |
102 |
} |
103 |
} |
104 |
|
105 |
private: |
106 |
FILE *f; |
107 |
}; |
108 |
|
109 |
/* write db */ |
110 |
void |
111 |
flatfile::save () |
112 |
{ |
113 |
myuser_t *mu; |
114 |
mychan_t *mc; |
115 |
chanacs_t *ca; |
116 |
kline_t *k; |
117 |
svsignore_t *svsignore; |
118 |
node_t *n, *tn; |
119 |
FILE *f; |
120 |
int errno1, was_errored = 0; |
121 |
svsignore_vector::iterator siit, siet; |
122 |
kline_t::list_type::iterator klit, klet; |
123 |
metadata::map_type::iterator mdit, mdet; |
124 |
|
125 |
errno = 0; |
126 |
|
127 |
/* reset state */ |
128 |
muout = 0, mcout = 0, caout = 0, kout = 0; |
129 |
|
130 |
/* write to a temporary file first */ |
131 |
if (!(f = fopen (DATADIR "/" PACKAGE_NAME ".db.new", "w"))) |
132 |
{ |
133 |
errno1 = errno; |
134 |
slog (LG_ERROR, "flatfile::save(): cannot create " PACKAGE_NAME ".db.new: %s", strerror (errno1)); |
135 |
wallops (_("\2DATABASE ERROR\2: flatfile::save(): cannot create %s.db.new: %s"), PACKAGE_NAME, strerror (errno1)); |
136 |
snoop (_("\2DATABASE ERROR\2: flatfile::save(): cannot create %s.db.new: %s"), PACKAGE_NAME, strerror (errno1)); |
137 |
return; |
138 |
} |
139 |
|
140 |
/* write the database version */ |
141 |
fprintf (f, "DBV 6\n"); |
142 |
fprintf (f, "CF %s\n", bitmask_to_flags (ca_all, chanacs_flags)); |
143 |
|
144 |
slog (LG_DEBUG, "flatfile::save(): saving myusers"); |
145 |
|
146 |
std::for_each (myuser_t::map.begin (), myuser_t::map.end (), flatfile_save_myusers_cb (f)); |
147 |
|
148 |
slog (LG_DEBUG, "flatfile::save(): saving mychans"); |
149 |
|
150 |
foreach (mychan_t::pair_type &mp, mychan_t::map) |
151 |
{ |
152 |
mc = mp.second; |
153 |
/* find a founder */ |
154 |
mu = NULL; |
155 |
LIST_FOREACH (tn, mc->chanacs.head) |
156 |
{ |
157 |
ca = static_cast<chanacs_t *> (tn->data); |
158 |
if (ca->myuser != NULL && ca->level & CA_FOUNDER) |
159 |
{ |
160 |
mu = ca->myuser; |
161 |
break; |
162 |
} |
163 |
} |
164 |
/* MC <name> <pass> <founder> <registered> [used] [flags] |
165 |
* [mlock_on] [mlock_off] [mlock_limit] [mlock_key] |
166 |
* PASS is now ignored -- replaced with a "0" to avoid having to special-case this version |
167 |
*/ |
168 |
fprintf (f, "MC %s %s %s %ld %ld", mc->name, "0", mu != NULL ? mu->name : "*", (long)mc->registered, (long)mc->used); |
169 |
fprintf (f, " %d", mc->flags); |
170 |
fprintf (f, " %d", mc->mlock_on); |
171 |
fprintf (f, " %d", mc->mlock_off); |
172 |
fprintf (f, " %d", mc->mlock_limit); |
173 |
|
174 |
if (mc->mlock_key) |
175 |
fprintf (f, " %s\n", mc->mlock_key); |
176 |
else |
177 |
fprintf (f, "\n"); |
178 |
|
179 |
mcout++; |
180 |
|
181 |
LIST_FOREACH (tn, mc->chanacs.head) |
182 |
{ |
183 |
ca = (chanacs_t *) tn->data; |
184 |
|
185 |
fprintf (f, "CA %s %s %s %ld\n", ca->mychan->name, ca->myuser ? ca->myuser->name : ca->host, bitmask_to_flags (ca->level, chanacs_flags), ca->ts); |
186 |
|
187 |
for (mdit = ca->mdmap.begin (), mdet = ca->mdmap.end (); mdit != mdet; ++mdit) |
188 |
{ |
189 |
metadata *md = mdit->second; |
190 |
|
191 |
fprintf (f, "MD A %s:%s %s %s\n", ca->mychan->name, (ca->myuser) ? ca->myuser->name : ca->host, md->key, md->value); |
192 |
} |
193 |
|
194 |
caout++; |
195 |
} |
196 |
|
197 |
for (mdit = mc->mdmap.begin (), mdet = mc->mdmap.end (); mdit != mdet; ++mdit) |
198 |
{ |
199 |
metadata *md = mdit->second; |
200 |
|
201 |
fprintf (f, "MD C %s %s %s\n", mc->name, md->key, md->value); |
202 |
} |
203 |
} |
204 |
|
205 |
/* subscriptions -- we have to walk the myuser table again |
206 |
because otherwise we could encounter unknowns on restart. */ |
207 |
slog (LG_DEBUG, "flatfile::save(): saving subscriptions"); |
208 |
|
209 |
myuser_t::map_type::iterator muit = myuser_t::map.begin (); |
210 |
myuser_t::map_type::iterator muet = myuser_t::map.end (); |
211 |
while (muit != muet) |
212 |
{ |
213 |
mu = muit->second; |
214 |
metadata_subscription_t *subscriptor; |
215 |
|
216 |
LIST_FOREACH (n, mu->subscriptions.head) |
217 |
{ |
218 |
node_t *i; |
219 |
dynstr str (64); |
220 |
subscriptor = (metadata_subscription_t *) n->data; |
221 |
|
222 |
LIST_FOREACH (i, subscriptor->taglist.head) |
223 |
{ |
224 |
str.add (static_cast<char *> (i->data), strlen (static_cast<char *> (i->data))); |
225 |
|
226 |
if (i->next) |
227 |
str.add (','); |
228 |
} |
229 |
|
230 |
fprintf (f, "SU %s %s %s\n", mu->name, subscriptor->mu->name, str.c_str ()); |
231 |
} |
232 |
++muit; |
233 |
} |
234 |
|
235 |
/* Services ignores */ |
236 |
slog (LG_DEBUG, "flatfile::save(): saving svsignores"); |
237 |
|
238 |
for (siit = svs_ignore_list.begin (), siet = svs_ignore_list.end (); siit != siet; ++siit) |
239 |
{ |
240 |
svsignore = *siit; |
241 |
|
242 |
/* SI <mask> <settime> <setby> <reason> */ |
243 |
fprintf (f, "SI %s %ld %s %s\n", svsignore->mask, (long) svsignore->settime, svsignore->setby, svsignore->reason); |
244 |
} |
245 |
|
246 |
/* Services operators */ |
247 |
slog (LG_DEBUG, "flatfile::save(): saving sopers"); |
248 |
|
249 |
foreach (soper_t *soper, soper_t::list) |
250 |
{ |
251 |
if (soper->flags & SOPER_CONF || soper->myuser == NULL) |
252 |
continue; |
253 |
|
254 |
/* SO <account> <operclass> <flags> */ |
255 |
fprintf (f, "SO %s %s %d\n", soper->myuser->name, soper->classname, soper->flags); |
256 |
} |
257 |
|
258 |
slog (LG_DEBUG, "flatfile::save(): saving klines"); |
259 |
|
260 |
for (klit = kline_t::list.begin (), klet = kline_t::list.end (); klit != klet; ++klit) |
261 |
{ |
262 |
k = *klit; |
263 |
|
264 |
/* KL <user> <host> <duration> <settime> <setby> <reason> */ |
265 |
fprintf (f, "KL %s %s %ld %ld %s %s\n", k->user, k->host, k->duration, (long) k->settime, k->setby, k->reason); |
266 |
|
267 |
kout++; |
268 |
} |
269 |
|
270 |
/* DE <muout> <mcout> <caout> <kout> */ |
271 |
fprintf (f, "DE %d %d %d %d\n", muout, mcout, caout, kout); |
272 |
|
273 |
was_errored = ferror (f); |
274 |
was_errored |= fclose (f); |
275 |
if (was_errored) |
276 |
{ |
277 |
errno1 = errno; |
278 |
slog (LG_ERROR, "flatfile::save(): cannot write to " PACKAGE_NAME ".db.new: %s", strerror (errno1)); |
279 |
wallops (_("\2DATABASE ERROR\2: flatfile::save(): cannot write to %s.db.new: %s"), PACKAGE_NAME, strerror (errno1)); |
280 |
snoop (_("\2DATABASE ERROR\2: flatfile::save(): cannot write to %s.db.new: %s"), PACKAGE_NAME, strerror (errno1)); |
281 |
return; |
282 |
} |
283 |
|
284 |
/* now, replace the old database with the new one, using an atomic rename */ |
285 |
unlink (DATADIR "/" PACKAGE_NAME ".db"); |
286 |
|
287 |
if ((rename (DATADIR "/" PACKAGE_NAME ".db.new", DATADIR "/" PACKAGE_NAME ".db")) < 0) |
288 |
{ |
289 |
errno1 = errno; |
290 |
slog (LG_ERROR, "flatfile::save(): cannot rename " PACKAGE_NAME ".db.new to " PACKAGE_NAME ".db: %s", strerror (errno1)); |
291 |
wallops (_("\2DATABASE ERROR\2: flatfile::save(): cannot rename %s.db.new to %s.db: %s"), PACKAGE_NAME, strerror (errno1)); |
292 |
snoop (_("\2DATABASE ERROR\2: flatfile::save(): cannot rename %s.db.new to %s.db: %s"), PACKAGE_NAME, strerror (errno1)); |
293 |
return; |
294 |
} |
295 |
} |
296 |
|
297 |
/* loads db */ |
298 |
void |
299 |
flatfile::load () |
300 |
{ |
301 |
myuser_t *mu, *founder = NULL; |
302 |
mychan_t *mc; |
303 |
kline_t *k; |
304 |
svsignore_t *svsignore; |
305 |
unsigned int i = 0, linecnt = 0, muin = 0, mcin = 0, cain = 0, kin = 0; |
306 |
FILE *f; |
307 |
char *item, *s, dBuf[BUFSIZE]; |
308 |
unsigned int their_ca_all = ca_all; |
309 |
|
310 |
f = fopen (DATADIR "/" PACKAGE_NAME ".db", "r"); |
311 |
if (f == NULL) |
312 |
{ |
313 |
if (errno == ENOENT) |
314 |
{ |
315 |
slog (LG_ERROR, "flatfile::load(): %s does not exist, creating it", DATADIR "/" PACKAGE_NAME ".db"); |
316 |
return; |
317 |
} |
318 |
else |
319 |
{ |
320 |
slog (LG_ERROR, "flatfile::load(): can't open %s for reading: %s", DATADIR "/" PACKAGE_NAME ".db", strerror (errno)); |
321 |
slog (LG_ERROR, "flatfile::load(): exiting to avoid data loss"); |
322 |
exit (1); |
323 |
} |
324 |
} |
325 |
|
326 |
slog (LG_DEBUG, "flatfile::load(): ----------------------- loading ------------------------"); |
327 |
|
328 |
/* start reading it, one line at a time */ |
329 |
while (fgets (dBuf, BUFSIZE, f)) |
330 |
{ |
331 |
linecnt++; |
332 |
|
333 |
/* check for unimportant lines */ |
334 |
item = strtok (dBuf, " "); |
335 |
strip (item); |
336 |
|
337 |
if (*item == '#' || *item == '\n' || *item == '\t' || *item == ' ' || *item == '\0' || *item == '\r' || !*item) |
338 |
continue; |
339 |
|
340 |
/* database version */ |
341 |
if (!strcmp ("DBV", item)) |
342 |
{ |
343 |
i = atoi (strtok (NULL, " ")); |
344 |
if (i > 6) |
345 |
{ |
346 |
slog (LG_INFO, "flatfile::load(): database version is %d; I only understand " |
347 |
"6 (Ermyth 2.3), " |
348 |
"5 (Atheme 2.0, 2.1), " |
349 |
"4 (Atheme 0.2), " |
350 |
"3 (Atheme 0.2 without CA_ACLVIEW), " |
351 |
"2 (Atheme 0.1) or " |
352 |
"1 (Shrike)", i); |
353 |
exit (EXIT_FAILURE); |
354 |
} |
355 |
} |
356 |
|
357 |
/* enabled chanacs flags */ |
358 |
if (!strcmp ("CF", item)) |
359 |
{ |
360 |
s = strtok (NULL, " "); |
361 |
if (s == NULL) |
362 |
slog (LG_INFO, "flatfile::load(): missing param to CF"); |
363 |
else |
364 |
{ |
365 |
their_ca_all = flags_to_bitmask (s, chanacs_flags, 0); |
366 |
if (their_ca_all & ~ca_all) |
367 |
slog (LG_ERROR, "flatfile::load(): losing flags %s from file", bitmask_to_flags (their_ca_all & ~ca_all, chanacs_flags)); |
368 |
if (~their_ca_all & ca_all) |
369 |
slog (LG_ERROR, "flatfile::load(): making up flags %s not present in file", bitmask_to_flags (~their_ca_all & ca_all, chanacs_flags)); |
370 |
} |
371 |
} |
372 |
|
373 |
/* myusers */ |
374 |
if (!strcmp ("MU", item)) |
375 |
{ |
376 |
char *muname, *mupass, *muemail; |
377 |
|
378 |
if ((s = strtok (NULL, " "))) |
379 |
{ |
380 |
/* We need to know the flags before we myuser_t::create, |
381 |
* so we need a few temporary places to put stuff. |
382 |
*/ |
383 |
unsigned int registered, lastlogin; |
384 |
char *failnum, *lastfailaddr, *lastfailtime; |
385 |
|
386 |
if ((mu = myuser_t::find (s))) |
387 |
continue; |
388 |
|
389 |
muin++; |
390 |
|
391 |
muname = s; |
392 |
mupass = strtok (NULL, " "); |
393 |
muemail = strtok (NULL, " "); |
394 |
|
395 |
registered = atoi (strtok (NULL, " ")); |
396 |
lastlogin = atoi (strtok (NULL, " ")); |
397 |
failnum = strtok (NULL, " "); |
398 |
lastfailaddr = strtok (NULL, " "); |
399 |
lastfailtime = strtok (NULL, " "); |
400 |
|
401 |
mu = myuser_t::create (muname, mupass, muemail, atol (strtok (NULL, " "))); |
402 |
|
403 |
mu->registered = registered; |
404 |
mu->lastlogin = lastlogin; |
405 |
|
406 |
if (strcmp (failnum, "0")) |
407 |
mu->add_metadata ("private:loginfail:failnum", failnum); |
408 |
if (strcmp (lastfailaddr, "0")) |
409 |
mu->add_metadata ("private:loginfail:lastfailaddr", lastfailaddr); |
410 |
if (strcmp (lastfailtime, "0")) |
411 |
mu->add_metadata ("private:loginfail:lastfailtime", lastfailtime); |
412 |
|
413 |
/* Verification keys were moved to metadata, |
414 |
* but we'll still accept them from legacy |
415 |
* databases. Note that we only transfer over |
416 |
* initial registration keys -- I don't think |
417 |
* we saved mu->temp, so we can't transition |
418 |
* e-mail change keys anyway. --alambert |
419 |
*/ |
420 |
if ((s = strtok (NULL, " "))) |
421 |
{ |
422 |
strip (s); |
423 |
mu->add_metadata ("private:verify:register:key", s); |
424 |
mu->add_metadata ("private:verify:register:timestamp", "0"); |
425 |
} |
426 |
} |
427 |
} |
428 |
|
429 |
if (!strcmp ("ME", item)) |
430 |
{ |
431 |
char *sender, *text; |
432 |
time_t mtime; |
433 |
unsigned int status; |
434 |
mymemo_t *mz; |
435 |
|
436 |
mu = myuser_t::find (strtok (NULL, " ")); |
437 |
sender = strtok (NULL, " "); |
438 |
mtime = atoi (strtok (NULL, " ")); |
439 |
status = atoi (strtok (NULL, " ")); |
440 |
text = strtok (NULL, "\n"); |
441 |
|
442 |
if (!mu) |
443 |
{ |
444 |
slog (LG_DEBUG, "flatfile::load(): memo for unknown account"); |
445 |
continue; |
446 |
} |
447 |
|
448 |
if (!sender || !mtime || !text) |
449 |
continue; |
450 |
|
451 |
mz = new mymemo_t; |
452 |
|
453 |
strlcpy (mz->sender, sender, NICKLEN); |
454 |
strlcpy (mz->text, text, MEMOLEN); |
455 |
mz->sent = mtime; |
456 |
mz->status = status; |
457 |
|
458 |
if (!(mz->status & MEMO_READ)) |
459 |
mu->memoct_new++; |
460 |
|
461 |
mu->memos.insert (mz); |
462 |
} |
463 |
|
464 |
if (!strcmp ("MI", item)) |
465 |
{ |
466 |
char *user, *target; |
467 |
|
468 |
user = strtok (NULL, " "); |
469 |
target = strtok (NULL, "\n"); |
470 |
|
471 |
mu = myuser_t::find (user); |
472 |
|
473 |
if (!mu) |
474 |
{ |
475 |
slog (LG_DEBUG, "flatfile::load(): invalid ignore (MI %s %s)", user, target); |
476 |
continue; |
477 |
} |
478 |
|
479 |
mu->memo_ignores.insert (sstrdup (target)); |
480 |
} |
481 |
|
482 |
/* myuser access list */ |
483 |
if (!strcmp ("AC", item)) |
484 |
{ |
485 |
char *user, *mask; |
486 |
|
487 |
user = strtok (NULL, " "); |
488 |
mask = strtok (NULL, "\n"); |
489 |
|
490 |
mu = myuser_t::find (user); |
491 |
|
492 |
if (mu == NULL) |
493 |
{ |
494 |
slog (LG_DEBUG, "flatfile::load(): invalid access entry<%s> for unknown user<%s>", mask, user); |
495 |
continue; |
496 |
} |
497 |
|
498 |
mu->access_add (mask); |
499 |
} |
500 |
|
501 |
/* registered nick */ |
502 |
if (!strcmp ("MN", item)) |
503 |
{ |
504 |
char *user, *nick, *treg, *tseen; |
505 |
mynick_t *mn; |
506 |
|
507 |
user = strtok (NULL, " "); |
508 |
nick = strtok (NULL, " "); |
509 |
treg = strtok (NULL, " "); |
510 |
tseen = strtok (NULL, " "); |
511 |
|
512 |
mu = myuser_t::find (user); |
513 |
if (mu == NULL || nick == NULL || tseen == NULL) |
514 |
{ |
515 |
slog (LG_DEBUG, "flatfile::load(): invalid registered nick<%s> for user<%s>", nick, user); |
516 |
continue; |
517 |
} |
518 |
|
519 |
mn = mynick_t::create (mu, nick); |
520 |
mn->registered = atoi (treg); |
521 |
mn->lastseen = atoi (tseen); |
522 |
} |
523 |
|
524 |
/* subscriptions */ |
525 |
if (!strcmp ("SU", item)) |
526 |
{ |
527 |
char *user, *sub_user, *tags, *tag; |
528 |
myuser_t *subscriptor; |
529 |
metadata_subscription_t *md; |
530 |
|
531 |
user = strtok (NULL, " "); |
532 |
sub_user = strtok (NULL, " "); |
533 |
tags = strtok (NULL, "\n"); |
534 |
if (!user || !sub_user || !tags) |
535 |
{ |
536 |
slog (LG_INFO, "flatfile::load(): invalid subscription (line %d)", linecnt); |
537 |
continue; |
538 |
} |
539 |
|
540 |
strip (tags); |
541 |
|
542 |
mu = myuser_t::find (user); |
543 |
subscriptor = myuser_t::find (sub_user); |
544 |
if (!mu || !subscriptor) |
545 |
{ |
546 |
slog (LG_INFO, "flatfile::load(): invalid subscription <%s,%s> (line %d)", user, sub_user, linecnt); |
547 |
continue; |
548 |
} |
549 |
|
550 |
md = new metadata_subscription_t; |
551 |
md->mu = subscriptor; |
552 |
|
553 |
tag = strtok (tags, ","); |
554 |
do |
555 |
node_add (sstrdup (tag), node_create (), &md->taglist); |
556 |
while ((tag = strtok (NULL, ",")) != NULL); |
557 |
|
558 |
node_add (md, node_create (), &mu->subscriptions); |
559 |
} |
560 |
|
561 |
/* services oper */ |
562 |
if (!strcmp ("SO", item)) |
563 |
{ |
564 |
char *user, *classname, *flagstr; |
565 |
|
566 |
user = strtok (NULL, " "); |
567 |
classname = strtok (NULL, " "); |
568 |
flagstr = strtok (NULL, "\n"); |
569 |
|
570 |
mu = myuser_t::find (user); |
571 |
|
572 |
if (!mu || !classname || !flagstr) |
573 |
{ |
574 |
slog (LG_DEBUG, "flatfile::load(): invalid services oper (SO %s %s %s)", user, classname, flagstr); |
575 |
continue; |
576 |
} |
577 |
soper_add (mu->name, classname, atoi (flagstr) & ~SOPER_CONF); |
578 |
} |
579 |
|
580 |
/* mychans */ |
581 |
if (!strcmp ("MC", item)) |
582 |
{ |
583 |
char *mcname, *mcpass; |
584 |
|
585 |
if ((s = strtok (NULL, " "))) |
586 |
{ |
587 |
if ((mc = mychan_t::find (s))) |
588 |
continue; |
589 |
|
590 |
mcin++; |
591 |
|
592 |
mcname = s; |
593 |
/* unused */ |
594 |
mcpass = strtok (NULL, " "); |
595 |
|
596 |
mc = mychan_t::create (mcname); |
597 |
|
598 |
founder = myuser_t::find (strtok (NULL, " ")); |
599 |
|
600 |
mc->registered = atoi (strtok (NULL, " ")); |
601 |
mc->used = atoi (strtok (NULL, " ")); |
602 |
mc->flags = atoi (strtok (NULL, " ")); |
603 |
|
604 |
mc->mlock_on = atoi (strtok (NULL, " ")); |
605 |
mc->mlock_off = atoi (strtok (NULL, " ")); |
606 |
mc->mlock_limit = atoi (strtok (NULL, " ")); |
607 |
|
608 |
if ((s = strtok (NULL, " "))) |
609 |
{ |
610 |
strip (s); |
611 |
if (*s != '\0' && *s != ':' && !strchr (s, ',')) |
612 |
mc->mlock_key = sstrdup (s); |
613 |
} |
614 |
|
615 |
if (i < 5 && config_options.join_chans) |
616 |
mc->flags |= MC_GUARD; |
617 |
} |
618 |
} |
619 |
|
620 |
/* Metadata entry */ |
621 |
if (!strcmp ("MD", item)) |
622 |
{ |
623 |
char *type = strtok (NULL, " "); |
624 |
char *name = strtok (NULL, " "); |
625 |
char *property = strtok (NULL, " "); |
626 |
char *value = strtok (NULL, ""); |
627 |
|
628 |
if (!type || !name || !property || !value) |
629 |
continue; |
630 |
|
631 |
strip (value); |
632 |
|
633 |
if (*type == 'U') |
634 |
{ |
635 |
mu = myuser_t::find (name); |
636 |
if (mu != NULL) |
637 |
mu->add_metadata (property, value); |
638 |
} |
639 |
else if (*type == 'C') |
640 |
{ |
641 |
mc = mychan_t::find (name); |
642 |
if (mc != NULL) |
643 |
mc->add_metadata (property, value); |
644 |
} |
645 |
else if (*type == 'A') |
646 |
{ |
647 |
chanacs_t *ca; |
648 |
char *mask; |
649 |
|
650 |
mask = strrchr (name, ':'); |
651 |
if (mask != NULL) |
652 |
{ |
653 |
*mask++ = '\0'; |
654 |
ca = chanacs_find_by_mask (mychan_t::find (name), mask, CA_NONE); |
655 |
if (ca != NULL) |
656 |
ca->add_metadata (property, value); |
657 |
} |
658 |
} |
659 |
} |
660 |
|
661 |
/* Channel URLs */ |
662 |
if (!strcmp ("UR", item)) |
663 |
{ |
664 |
char *chan, *url; |
665 |
|
666 |
chan = strtok (NULL, " "); |
667 |
url = strtok (NULL, " "); |
668 |
|
669 |
strip (url); |
670 |
|
671 |
if (chan && url) |
672 |
{ |
673 |
mc = mychan_t::find (chan); |
674 |
|
675 |
if (mc) |
676 |
mc->add_metadata ("url", url); |
677 |
} |
678 |
} |
679 |
|
680 |
/* Channel entry messages */ |
681 |
if (!strcmp ("EM", item)) |
682 |
{ |
683 |
char *chan, *message; |
684 |
|
685 |
chan = strtok (NULL, " "); |
686 |
message = strtok (NULL, ""); |
687 |
|
688 |
strip (message); |
689 |
|
690 |
if (chan && message) |
691 |
{ |
692 |
mc = mychan_t::find (chan); |
693 |
|
694 |
if (mc) |
695 |
mc->add_metadata ("private:entrymsg", message); |
696 |
} |
697 |
} |
698 |
|
699 |
/* chanacs */ |
700 |
if (!strcmp ("CA", item)) |
701 |
{ |
702 |
chanacs_t *ca; |
703 |
char *cachan, *causer; |
704 |
|
705 |
cachan = strtok (NULL, " "); |
706 |
causer = strtok (NULL, " "); |
707 |
|
708 |
if (cachan && causer) |
709 |
{ |
710 |
mc = mychan_t::find (cachan); |
711 |
mu = myuser_t::find (causer); |
712 |
|
713 |
if (mc == NULL || (mu == NULL && !validhostmask (causer))) |
714 |
{ |
715 |
slog (LG_ERROR, "flatfile::load(): invalid chanacs (line %d)", linecnt); |
716 |
continue; |
717 |
} |
718 |
|
719 |
cain++; |
720 |
|
721 |
if (i >= DB_ATHEME) |
722 |
{ |
723 |
unsigned int fl = flags_to_bitmask (strtok (NULL, " "), chanacs_flags, 0x0); |
724 |
char const * const tsstr = strtok (NULL, " "); |
725 |
time_t ts = 0; |
726 |
|
727 |
/* Compatibility with oldworld databases. --nenolod */ |
728 |
/* arbitrary cutoff to avoid touching newer +voOt entries -- jilles */ |
729 |
if (fl == OLD_CA_AOP && i < 4) |
730 |
fl = CA_AOP_DEF; |
731 |
|
732 |
/* |
733 |
* If the database revision is version 6 or newer, CA entries are |
734 |
* timestamped... otherwise we use 0 as the last modified TS |
735 |
* --nenolod/jilles |
736 |
*/ |
737 |
if (tsstr != NULL) |
738 |
ts = atoi (tsstr); |
739 |
|
740 |
/* previous to CA_ACLVIEW, everyone could view |
741 |
* access lists. If they aren't AKICKed, upgrade |
742 |
* them. This keeps us from breaking old XOPs. |
743 |
*/ |
744 |
if (i < 4) |
745 |
if (!(fl & CA_AKICK)) |
746 |
fl |= CA_ACLVIEW; |
747 |
|
748 |
/* Grant +h if they have +o, |
749 |
* the file does not have +h enabled |
750 |
* and we currently have +h enabled. |
751 |
* This preserves AOP, SOP and +*. |
752 |
*/ |
753 |
if (fl & CA_OP && !(their_ca_all & CA_HALFOP) && ca_all & CA_HALFOP) |
754 |
fl |= CA_HALFOP; |
755 |
|
756 |
/* Set new-style founder flag */ |
757 |
if (founder != NULL && mu == founder && !(their_ca_all & CA_FOUNDER)) |
758 |
fl |= CA_FOUNDER; |
759 |
|
760 |
if ((!mu) && (validhostmask (causer))) |
761 |
ca = chanacs_add_host (mc, causer, fl, ts); |
762 |
else |
763 |
ca = chanacs_add (mc, mu, fl, ts); |
764 |
} |
765 |
else if (i == DB_SHRIKE) /* DB_SHRIKE */ |
766 |
{ |
767 |
unsigned int fl = atol (strtok (NULL, " ")); |
768 |
unsigned int fl2 = 0x0; |
769 |
time_t ts = NOW; |
770 |
|
771 |
switch (fl) |
772 |
{ |
773 |
case SHRIKE_CA_VOP: |
774 |
fl2 = chansvs.ca_vop; |
775 |
case SHRIKE_CA_AOP: |
776 |
fl2 = chansvs.ca_aop; |
777 |
case SHRIKE_CA_SOP: |
778 |
fl2 = chansvs.ca_sop; |
779 |
case SHRIKE_CA_SUCCESSOR: |
780 |
fl2 = CA_SUCCESSOR_0; |
781 |
case SHRIKE_CA_FOUNDER: |
782 |
fl2 = CA_FOUNDER_0; |
783 |
} |
784 |
|
785 |
if ((!mu) && (validhostmask (causer))) |
786 |
ca = chanacs_add_host (mc, causer, fl2, ts); |
787 |
else |
788 |
ca = chanacs_add (mc, mu, fl2, ts); |
789 |
} |
790 |
} |
791 |
} |
792 |
|
793 |
|
794 |
/* Services ignores */ |
795 |
if (!strcmp ("SI", item)) |
796 |
{ |
797 |
char *mask, *setby, *reason, *tmp; |
798 |
time_t settime; |
799 |
|
800 |
mask = strtok (NULL, " "); |
801 |
tmp = strtok (NULL, " "); |
802 |
settime = atol (tmp); |
803 |
setby = strtok (NULL, " "); |
804 |
reason = strtok (NULL, ""); |
805 |
|
806 |
strip (reason); |
807 |
|
808 |
svsignore = svsignore_add (mask, reason); |
809 |
svsignore->settime = settime; |
810 |
svsignore->setby = sstrdup (setby); |
811 |
|
812 |
} |
813 |
|
814 |
/* klines */ |
815 |
if (!strcmp ("KL", item)) |
816 |
{ |
817 |
char *user, *host, *reason, *setby, *tmp; |
818 |
time_t settime; |
819 |
long duration; |
820 |
|
821 |
user = strtok (NULL, " "); |
822 |
host = strtok (NULL, " "); |
823 |
tmp = strtok (NULL, " "); |
824 |
duration = atol (tmp); |
825 |
tmp = strtok (NULL, " "); |
826 |
settime = atol (tmp); |
827 |
setby = strtok (NULL, " "); |
828 |
reason = strtok (NULL, ""); |
829 |
|
830 |
strip (reason); |
831 |
|
832 |
k = kline_t::create (user, host, reason, duration); |
833 |
k->settime = settime; |
834 |
/* XXX this is not nice, oh well -- jilles */ |
835 |
k->expires = k->settime + k->duration; |
836 |
k->setby = sstrdup (setby); |
837 |
|
838 |
kin++; |
839 |
} |
840 |
|
841 |
/* end */ |
842 |
if (!strcmp ("DE", item)) |
843 |
{ |
844 |
i = atoi (strtok (NULL, " ")); |
845 |
if (i != muin) |
846 |
slog (LG_ERROR, "flatfile::load(): got %d myusers; expected %d", muin, i); |
847 |
|
848 |
i = atoi (strtok (NULL, " ")); |
849 |
if (i != mcin) |
850 |
slog (LG_ERROR, "flatfile::load(): got %d mychans; expected %d", mcin, i); |
851 |
|
852 |
i = atoi (strtok (NULL, " ")); |
853 |
if (i != cain) |
854 |
slog (LG_ERROR, "flatfile::load(): got %d chanacs; expected %d", cain, i); |
855 |
|
856 |
if ((s = strtok (NULL, " "))) |
857 |
if ((i = atoi (s)) != kin) |
858 |
slog (LG_ERROR, "flatfile::load(): got %d klines; expected %d", kin, i); |
859 |
} |
860 |
} |
861 |
|
862 |
fclose (f); |
863 |
|
864 |
slog (LG_DEBUG, "flatfile::load(): ------------------------- done -------------------------"); |
865 |
} |
866 |
} // namespace database |
867 |
|
868 |
#define FACREG_TYPE database::flatfile |
869 |
#define FACREG_TYPE_NAME "flatfile" |
870 |
#define FACREG_INTERFACE_TYPE database::handler |
871 |
#include <ermyth/factory_reg.h> |