ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/backend/flatfile.C
Revision: 1.10
Committed: Sun Sep 16 18:54:42 2007 UTC (19 years, 1 month ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.9: +10 -6 lines
Log Message:
#defines to enum

File Contents

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