ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/ermyth/modules/backend/flatfile.C
Revision: 1.11
Committed: Sat Sep 22 14:27:26 2007 UTC (19 years ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.10: +14 -16 lines
Log Message:
split up ermyth into ermyth-modules, libermyth (currently just ermyth-util) and ermyth-core

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.11 * $Id: flatfile.C,v 1.10 2007-09-16 18:54:42 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.11 #include <libermyth.h>
19     #include <util/string.h>
20 pippijn 1.4 #include <ermyth/database.h>
21 pippijn 1.1 #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 pippijn 1.11 static char const rcsid[] = "$Id: flatfile.C,v 1.10 2007-09-16 18:54:42 pippijn Exp $";
31 pippijn 1.1
32     /* database versions */
33 pippijn 1.4 #define DB_SHRIKE 1
34     #define DB_ATHEME 2
35 pippijn 1.1
36 pippijn 1.4 namespace database
37 pippijn 1.1 {
38 pippijn 1.4 /* flatfile state */
39     unsigned int muout = 0, mcout = 0, caout = 0, kout = 0;
40    
41     struct flatfile : handler
42 pippijn 1.1 {
43 pippijn 1.4 virtual void save ();
44     virtual void load ();
45     };
46    
47     struct flatfile_save_myusers_cb
48 pippijn 1.1 {
49 pippijn 1.4 flatfile_save_myusers_cb (FILE *file)
50     : f (file)
51 pippijn 1.1 {
52     }
53 pippijn 1.4
54 pippijn 1.8 void operator () (myuser_t::pair_type &it)
55 pippijn 1.1 {
56 pippijn 1.4 myuser_t *mu = it.second;
57 pippijn 1.8 metadata::map_type::iterator mdit, mdet;
58 pippijn 1.4 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 pippijn 1.1
77 pippijn 1.4 for (mdit = mu->mdmap.begin (), mdet = mu->mdmap.end (); mdit != mdet; ++mdit)
78 pippijn 1.1 {
79 pippijn 1.8 metadata *md = mdit->second;
80 pippijn 1.4 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 pippijn 1.8 fprintf (f, "ME %s %s %lu %u %s\n", mu->name, mz->sender, mz->sent, mz->status, mz->text);
87 pippijn 1.4 }
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 pippijn 1.8 {
94     fprintf (f, "AC %s %s\n", mu->name, (char *) tn->data);
95     }
96 pippijn 1.1
97 pippijn 1.4 LIST_FOREACH (tn, mu->nicks.head)
98 pippijn 1.8 {
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 pippijn 1.1 }
104 pippijn 1.8
105     private:
106 pippijn 1.4 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 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.11 str.add (static_cast<char *> (i->data), strlen (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 pippijn 1.11 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 pippijn 1.4 slog (LG_DEBUG, "flatfile::save(): saving klines");
259    
260 pippijn 1.9 for (klit = kline_t::list.begin (), klet = kline_t::list.end (); klit != klet; ++klit)
261 pippijn 1.4 {
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 pippijn 1.1 {
301 pippijn 1.4 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 pippijn 1.6 /* We need to know the flags before we myuser_t::create,
381 pippijn 1.4 * so we need a few temporary places to put stuff.
382     */
383     unsigned int registered, lastlogin;
384     char *failnum, *lastfailaddr, *lastfailtime;
385    
386 pippijn 1.5 if ((mu = myuser_t::find (s)))
387 pippijn 1.4 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 pippijn 1.6 mu = myuser_t::create (muname, mupass, muemail, atol (strtok (NULL, " ")));
402 pippijn 1.4
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 pippijn 1.5 mu = myuser_t::find (strtok (NULL, " "));
437 pippijn 1.4 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 pippijn 1.5 mu = myuser_t::find (user);
472 pippijn 1.4
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 pippijn 1.5 mu = myuser_t::find (user);
491 pippijn 1.4
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 pippijn 1.5 mu->access_add (mask);
499 pippijn 1.4 }
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 pippijn 1.5 mu = myuser_t::find (user);
513 pippijn 1.4 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 pippijn 1.9 mn = mynick_t::create (mu, nick);
520 pippijn 1.4 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 pippijn 1.5 mu = myuser_t::find (user);
543     subscriptor = myuser_t::find (sub_user);
544 pippijn 1.4 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 pippijn 1.5 mu = myuser_t::find (user);
571 pippijn 1.4
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 pippijn 1.7 if ((mc = mychan_t::find (s)))
588 pippijn 1.4 continue;
589    
590     mcin++;
591    
592     mcname = s;
593     /* unused */
594     mcpass = strtok (NULL, " ");
595    
596 pippijn 1.7 mc = mychan_t::create (mcname);
597 pippijn 1.4
598 pippijn 1.5 founder = myuser_t::find (strtok (NULL, " "));
599 pippijn 1.4
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 pippijn 1.5 mu = myuser_t::find (name);
636 pippijn 1.4 if (mu != NULL)
637     mu->add_metadata (property, value);
638     }
639     else if (*type == 'C')
640     {
641 pippijn 1.7 mc = mychan_t::find (name);
642 pippijn 1.4 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 pippijn 1.7 ca = chanacs_find_by_mask (mychan_t::find (name), mask, CA_NONE);
655 pippijn 1.4 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 pippijn 1.7 mc = mychan_t::find (chan);
674 pippijn 1.4
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 pippijn 1.7 mc = mychan_t::find (chan);
693 pippijn 1.4
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 pippijn 1.7 mc = mychan_t::find (cachan);
711 pippijn 1.5 mu = myuser_t::find (causer);
712 pippijn 1.4
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 pippijn 1.9 k = kline_t::create (user, host, reason, duration);
833 pippijn 1.4 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 pippijn 1.1 }
866 pippijn 1.4 } // namespace database
867 pippijn 1.1
868 pippijn 1.4 #define FACREG_TYPE database::flatfile
869     #define FACREG_TYPE_NAME "flatfile"
870     #define FACREG_INTERFACE_TYPE database::handler
871     #include <ermyth/factory_reg.h>