fixed hostserv codestyle and some (undetected) bugs
[srvx.git] / src / mod-hostserv.c
1 /* mod-hostserv.c - HostServ module for srvx
2  * Copyright 2012-2013 pk910, Stricted, NurPech
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 /* Adds new section to srvx.conf:
22  * "modules" {
23  *     "hostserv" {
24  *         "nick" "HostServ";
25  *         "modes" "+iok";
26            "toplevel_access" "600";
27  *     };
28  *  };
29  *
30  * After you started srvx make the bot active:
31  /msg opserv bind hostserv * hostserv.*
32  /msg opserv bind hostserv help *modcmd.help
33  */
34
35 #include "chanserv.h"
36 #include "opserv.h"
37 #include "nickserv.h"
38 #include "conf.h"
39 #include "modcmd.h"
40 #include "saxdb.h"
41 #include "timeq.h"
42 #include "gline.h"
43
44 #define KEY_TOPLEVEL "TopLevel"
45 #define KEY_SECONDLEVEL "SecondLevel"
46 #define KEY_MANAGERS "Manager"
47 #define KEY_ASSIGNMENTS "Assignments"
48 #define KEY_ACTIVE "active"
49
50 static const struct message_entry msgtab[] = {
51     { "HSMSG_ACCESS_DENIED", "Access denied." },
52     { "HSMSG_ASSIGNED_FAKEHOSTS", "Assigned Fakehosts for User $b%s$b:" },
53     { "HSMSG_ASSIGNED_FAKEHOST", "  $b%s.%s$b" },
54     { "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE", "  $b%s.%s$b (active)" },
55     { "HSMSG_ASSIGNED_FAKEHOST_NOT_ACTIVE", "Fakehost $b%s.%s.$b is not active." },
56     { "HSMSG_ASSIGN_HOWTO", "Use $bset xxx.yyy$b to activate one of the listed fakehosts or $bset *$b to use the default fakehost." },
57     { "HSMSG_ASSIGNED_NONE", "  None." },
58     { "HSMSG_MANAGED_FAKEHOSTS", "Fakehosts managed by User $b%s$b:" },
59     { "HSMSG_MANAGED_TOPLEVEL", "  $b*.%s$b   fakehosts: %d   assignments: %d" },
60     { "HSMSG_MANAGED_TOPLEVEL_OWN", "  $b*.%s$b   fakehosts: %d   assignments: %d   (active)" },
61     { "HSMSG_MANAGED_FAKEHOST", "  $b%s.%s$b   assignments: %d" },
62     { "HSMSG_MANAGE_HOWTO", "Use $bview xxx.yyy$b to view more information about a fakehost group." },
63     { "HSMSG_UNKNOWN_FAKEHOST", "Fakehost $b%s.%s$b is unknown or you have no access to manage it." },
64     { "HSMSG_TOPLEVEL_FAKEHOSTS", "Fakehosts in group $b*.%s$b:" },
65     { "HSMSG_TOPLEVEL_FAKEHOST", "  $b%s.%s$b   assignments: %d   managers: %d" },
66     { "HSMSG_TOPLEVEL_INVALID", "The name of the group you entered is invalid ($b%s$b)" },
67     { "HSMSG_MANAGERS_TOPLEVEL", "Managers of group $b*.%s$b:" },
68     { "HSMSG_MANAGERS_FAKEHOST", "Managers of group $b%s.%s$b:" },
69     { "HSMSG_MANAGERS_MANAGERS", "  %s" },
70     { "HSMSG_FAKEHOST_ASSIGNMENTS", "Assignments in group $b%s.%s$b:" },
71     { "HSMSG_FAKEHOST_ASSIGNMENT", "  $b%s$b (%s.%s.%s)" },
72     { "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE", "  $b%s$b (%s.%s.%s)   active" },
73     { "HSMSG_FAKEHOST_SET_SUCCESS", "$b%s.%s$b where set successfully." },
74     { "HSMSG_FAKEHOST_TOPLEVEL_ADDED", "Group $b%s$b successfully added." },
75     { "HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", "Group $b%s$b already exists." },
76     { "HSMSG_FAKEHOST_TOPLEVEL_DELETED", "Group $b%s$b successfully deleted." },
77     { "HSMSG_FAKEHOST_SECONDLEVEL_ADDED", "Group $b%s.%s$b successfully added." },
78     { "HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", "Group $b%s.%s$b already exists." },
79     { "HSMSG_FAKEHOST_SECONDLEVEL_DELETED", "Group $b%s.%s$b successfully deleted." },
80     { "HSMSG_MANAGER_ALREADY", "$b%s$b is already a manager of %s.%s" },
81     { "HSMSG_MANAGER_ADDED", "$b%s$b is now a manager of %s.%s" },
82     { "HSMSG_MANAGER_NOT", "$b%s$b is not a manager of %s.%s" },
83     { "HSMSG_MANAGER_DELETED", "$b%s$b is no longer a manager of %s.%s" },
84     { "HSMSG_FAKEHOST_ASSIGN_SUCCESS", "Group $b%s.%s$b was assigned successfully." },
85     { "HSMSG_FAKEHOST_UNASSIGN_SUCCESS", "Group $b%s.%s$b was unassigned successfully." },
86     
87     { NULL, NULL }
88 };
89
90 static struct {
91     const char *nick;
92     const char *modes;
93     int toplevel_access;
94     int fallback_other_assignment : 1;
95     int manager_can_del_toplevel : 1;
96     int manager_can_del_secondlevel : 1;
97 } hostserv_conf;
98
99 const char *hostserv_module_deps[] = { NULL };
100 struct userNode *hostserv;
101 struct helpfile *hostserv_helpfile;
102 static struct module *hostserv_module;
103 static struct service *hostserv_service;
104 static struct log_type *HS_LOG;
105 static struct hs_toplevel *toplevels = NULL;
106 static struct hs_user *hostserv_users = NULL;
107
108 /* FAKEHOST STRUCTS */
109 struct hs_toplevel {
110     char *fakehost;
111     struct hs_manager *managers;
112     struct hs_secondlevel *secondlevel;
113     struct hs_toplevel *next;
114 };
115
116 struct hs_secondlevel {
117     struct hs_toplevel *toplevel;
118     char *fakehost;
119     struct hs_manager *managers;
120     struct hs_assignment *assignments;
121     struct hs_secondlevel *next;
122 };
123
124 struct hs_assignment {
125     struct hs_secondlevel *secondlevel;
126     struct hs_user *user;
127     int active;
128     struct hs_assignment *next;
129     struct hs_assignment *unext; /* for hs_user */
130 };
131
132 struct hs_manager {
133     char type;
134     void *object;
135     int active;
136     struct hs_user *user;
137     struct hs_manager *next;
138     struct hs_manager *unext; /* for hs_user */
139 };
140
141 struct hs_user {
142     struct handle_info *hi;
143     struct hs_assignment *assignments;
144     struct hs_manager *managements;
145     struct hs_user *next;
146 };
147
148 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
149 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
150 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
151 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
152 static void hs_del_user(struct hs_user *user);
153
154 static void hs_free_all() {
155     struct hs_toplevel *tlfh, *next_tlfh;
156     struct hs_secondlevel *slfh, *next_slfh;
157     struct hs_assignment *assng, *next_assng;
158     struct hs_manager *manager, *next_manager;
159     struct hs_user *user, *next_user;
160     for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
161         next_tlfh = tlfh->next;
162         for(manager = tlfh->managers; manager; manager = next_manager) {
163             next_manager = manager->next;
164             free(manager);
165         }
166         for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
167             next_slfh = slfh->next;
168             for(manager = tlfh->managers; manager; manager = next_manager) {
169                 next_manager = manager->next;
170                 free(manager);
171             }
172             for(assng = slfh->assignments; assng; assng = next_assng) {
173                 next_assng = assng->next;
174                 free(assng);
175             }
176             free(slfh->fakehost);
177             free(slfh);
178         }
179         free(tlfh->fakehost);
180         free(tlfh);
181     }
182     for(user = hostserv_users; user; user = next_user) {
183         next_user = user->next;
184         free(user);
185     }
186     toplevels = NULL;
187     hostserv_users = NULL;
188 }
189
190 static struct hs_toplevel *hs_add_toplevel(const char *name) {
191     struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
192     tlfh->fakehost = strdup(name);
193     tlfh->next = toplevels;
194     toplevels = tlfh;
195     return tlfh;
196 }
197
198 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
199     //unassign all assignments
200     struct hs_secondlevel *slfh, *next_slfh;
201     struct hs_manager *manager, *next_manager;
202     for(manager = tlfh->managers; manager; manager = next_manager) {
203         next_manager = manager->next;
204         hs_del_manager(manager, 0);
205     }
206     for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
207         next_slfh = slfh->next;
208         hs_del_secondlevel(slfh, 0);
209     }
210     
211     struct hs_toplevel *ctlfh, *last_tlfh = NULL;
212     for(ctlfh = toplevels; ctlfh; ctlfh = ctlfh->next) {
213         if(ctlfh == tlfh) {
214             if(last_tlfh)
215                 last_tlfh->next = ctlfh->next;
216             else
217                 toplevels = ctlfh->next;
218         } else
219             last_tlfh = ctlfh;
220     }
221     free(tlfh->fakehost);
222     free(tlfh);
223 }
224
225 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, const char *name) {
226     struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
227     slfh->toplevel = tlfh;
228     slfh->fakehost = strdup(name);
229     slfh->next = tlfh->secondlevel;
230     tlfh->secondlevel = slfh;
231     return slfh;
232 }
233
234 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
235     if(remove_from_tlfh) {
236         struct hs_secondlevel *cslfh, *prev_slfh = NULL;
237         for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
238             if(cslfh == slfh) {
239                 if(prev_slfh)
240                     prev_slfh->next = slfh->next;
241                 else
242                     slfh->toplevel->secondlevel = slfh->next;
243                 break;
244             } else
245                 prev_slfh = cslfh;
246         }
247     }
248     struct hs_assignment *assng, *next_assng;
249     struct hs_manager *manager, *next_manager;
250     for(manager = slfh->managers; manager; manager = next_manager) {
251         next_manager = manager->next;
252         hs_del_manager(manager, 0);
253     }
254     for(assng = slfh->assignments; assng; assng = next_assng) {
255         next_assng = assng->next;
256         hs_del_assignment(assng, 0);
257     }
258     free(slfh->fakehost);
259     free(slfh);
260 }
261
262 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
263     struct hs_manager *manager = calloc(1, sizeof(*manager));
264     manager->user = user;
265     manager->type = 1;
266     manager->object = tlfh;
267     manager->unext = user->managements;
268     user->managements = manager;
269     manager->next = tlfh->managers;
270     tlfh->managers = manager;
271     return manager;
272 }
273
274 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
275     struct hs_manager *manager = calloc(1, sizeof(*manager));
276     manager->user = user;
277     manager->type = 2;
278     manager->object = slfh;
279     manager->unext = user->managements;
280     user->managements = manager;
281     manager->next = slfh->managers;
282     slfh->managers = manager;
283     return manager;
284 }
285
286 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
287     struct hs_manager *cmanager, *prev_manager = NULL;
288     if(remove_from_object) {
289         if(manager->type == 1) {
290             struct hs_toplevel *tlfh = manager->object;
291             for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
292                 if(cmanager == manager) {
293                     if(prev_manager)
294                         prev_manager->next = manager->next;
295                     else
296                         tlfh->managers = manager->next;
297                     break;
298                 } else
299                     prev_manager = cmanager;
300             }
301         } else if(manager->type == 2) {
302             struct hs_secondlevel *slfh = manager->object;
303             for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
304                 if(cmanager == manager) {
305                     if(prev_manager)
306                         prev_manager->next = manager->next;
307                     else
308                         slfh->managers = manager->next;
309                     break;
310                 } else
311                     prev_manager = cmanager;
312             }
313         }
314         prev_manager = NULL;
315     }
316     if(remove_from_object != 2) {
317         for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
318             if(cmanager == manager) {
319                 if(prev_manager)
320                     prev_manager->unext = manager->unext;
321                 else
322                     manager->user->managements = manager->unext;
323                 break;
324             } else
325                 prev_manager = cmanager;
326         }
327         if(manager->user->managements == NULL && manager->user->assignments == NULL)
328             hs_del_user(manager->user);
329     }
330     free(manager);
331 }
332
333 static void hs_activate_assignment(struct hs_user *user, struct hs_assignment *assignment) {
334     struct hs_toplevel *tlfh;
335     struct hs_secondlevel *slfh;
336     struct hs_assignment *assgn;
337     char fakehost[HOSTLEN];
338     
339     assert((!assignment || (assignment->user == user)));
340     
341     if(user->assignments) {
342         for(assgn = assignment->user->assignments; assgn; assgn = assgn->unext)
343             assgn->active = 0;
344     }
345     
346     if(user->hi->fakehost) {
347         free(user->hi->fakehost);
348         user->hi->fakehost = NULL;
349     }
350     
351     if(assignment) {
352         slfh = assignment->secondlevel;
353         tlfh = slfh->toplevel;
354         snprintf(fakehost, sizeof(fakehost), "$.%s.%s", slfh->fakehost, tlfh->fakehost);
355         user->hi->fakehost = strdup(fakehost);
356         assignment->active = 1;
357     }
358     
359     apply_fakehost(assignment->user->hi, NULL);
360 }
361
362 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
363     struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
364     assignment->secondlevel = slfh;
365     assignment->user = user;
366     if(user->assignments == NULL)
367         assignment->active = 1;
368     assignment->next = slfh->assignments;
369     slfh->assignments = assignment;
370     assignment->unext = user->assignments;
371     user->assignments = assignment;
372     if(assignment->active) {
373         hs_activate_assignment(user, assignment);
374     }
375     return assignment;
376 }
377
378 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
379     struct hs_assignment *cassignment, *prev_assignment = NULL;
380     if(remove_from_slfh) {
381         for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
382             if(cassignment == assignment) {
383                 if(prev_assignment)
384                     prev_assignment->next = assignment->next;
385                 else
386                     assignment->secondlevel->assignments = assignment->next;
387                 break;
388             } else
389                 prev_assignment = cassignment;
390         }
391         prev_assignment = NULL;
392     }
393     if(remove_from_slfh != 2) {
394         prev_assignment = NULL;
395         for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
396             if(cassignment == assignment) {
397                 if(prev_assignment)
398                     prev_assignment->unext = assignment->unext;
399                 else
400                     assignment->user->assignments = assignment->unext;
401                 break;
402             } else
403                 prev_assignment = cassignment;
404         }
405         
406         if(assignment->active) {
407             /* use another assignment - or fall back to default user host? */
408             cassignment = NULL;
409             if(hostserv_conf.fallback_other_assignment && assignment->user->assignments) {
410                 /* try to find another assignment from same slfh first */
411                 for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
412                     if(cassignment != assignment && cassignment->user == assignment->user)
413                         break;
414                 }
415                 /* use another tlfh assignment */
416                 if(!cassignment)
417                     cassignment = assignment->user->assignments;
418             }
419             hs_activate_assignment(assignment->user, cassignment);
420         }
421         
422         if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
423             hs_del_user(assignment->user);
424     }
425     free(assignment);
426 }
427
428 static struct hs_assignment *hs_get_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
429     struct hs_assignment *cassignment;
430     for(cassignment = slfh->assignments; cassignment; cassignment = cassignment->next) {
431         if(cassignment->user == user)
432             return cassignment;
433     }
434     return NULL;
435 }
436
437 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
438     struct hs_user *cuser;
439     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
440         if(cuser->hi == hi)
441             return cuser;
442     }
443     if(create) {
444         cuser = calloc(1, sizeof(*cuser));
445         cuser->hi = hi;
446         cuser->next = hostserv_users;
447         hostserv_users = cuser;
448         return cuser;
449     } else
450         return NULL;
451 }
452
453 static void hs_del_user(struct hs_user *user) {
454     if(user->managements) {
455         struct hs_manager *manager, *next_manager;
456         for(manager = user->managements; manager; manager = next_manager) {
457             next_manager = manager->unext;
458             hs_del_manager(manager, 2);
459         }
460     }
461     if(user->assignments) {
462         struct hs_assignment *assng, *next_assng;
463         for(assng = user->assignments; assng; assng = next_assng) {
464             next_assng = assng->unext;
465             hs_del_assignment(assng, 2);
466         }
467     }
468     struct hs_user *cuser, *prev_user = NULL;
469     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
470         if(cuser == user) {
471             if(prev_user)
472                 prev_user->next = user->next;
473             else
474                 hostserv_users = user->next;
475             break;
476         } else
477             prev_user = cuser;
478     }
479     free(user);
480 }
481
482 /* END OF MANAGEMENT FUNCTIONS */
483
484 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_secondlevel *slfh) {
485     if(!hi) 
486         return 0;
487     if(hi->opserv_level >= hostserv_conf.toplevel_access) 
488         return 1;
489     struct hs_user *user = hs_get_user(hi, 0);
490     if(!user)
491         return 0;
492     struct hs_manager *manager;
493     if(slfh) {
494         for(manager = user->managements; manager; manager = manager->next) {
495             if(manager->type == 2 && manager->object == slfh) 
496                 return 1;
497         }
498     }
499     if(tlfh) {
500         for(manager = user->managements; manager; manager = manager->next) {
501             if(manager->type == 1 && manager->object == tlfh) 
502                 return 1;
503         }
504     }
505     return 0;
506 }
507
508
509 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
510     reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
511     struct hs_secondlevel *slfh;
512     if(!tlfh->secondlevel)
513         reply("HSMSG_ASSIGNED_NONE");
514     else
515     for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
516         struct hs_manager *cmanager;
517         int managers = 0;
518         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
519             managers++;
520         struct hs_assignment *assignment;
521         int assignments = 0;
522         for(assignment = slfh->assignments; assignment; assignment = assignment->next)
523             assignments++;
524         reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
525     }
526     reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
527     struct hs_manager *cmanager;
528     if(!tlfh->managers)
529         reply("HSMSG_ASSIGNED_NONE");
530     else {
531         char managerBuf[351];
532         int managerPos = 0;
533         for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
534             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
535                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
536                 managerPos = 0;
537             }
538             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
539         }
540         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
541     }
542 }
543
544 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
545     reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
546     struct hs_assignment *assignment;
547     for(assignment = slfh->assignments; assignment; assignment = assignment->next) {
548         reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
549     }
550     reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
551     struct hs_manager *cmanager;
552     if(!slfh->managers)
553         reply("HSMSG_ASSIGNED_NONE");
554     else {
555         char managerBuf[351];
556         int managerPos = 0;
557         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
558             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
559                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
560                 managerPos = 0;
561             }
562             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
563         }
564         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
565     }
566 }
567
568 static MODCMD_FUNC(cmd_view) {
569     struct handle_info *hi;
570     if(argc >= 2 && !strchr(argv[1], '.')) {
571         if (!(hi = modcmd_get_handle_info(user, argv[1])))
572             return 0;
573     } else if(argc >= 2) {
574         if (!(hi = user->handle_info)) {
575             reply("NSMSG_MUST_AUTH");
576             return 0;
577         }
578         char *slfh_name = argv[1];
579         char *tlfh_name = strchr(argv[1], '.');
580         *tlfh_name = '\0';
581         tlfh_name++;
582         if(strchr(tlfh_name, '.')) {
583             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
584             return 0;
585         }
586         struct hs_toplevel *tlfh;
587         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
588             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
589         }
590         if(!tlfh) {
591             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
592             return 0;
593         }
594         if(!irccasecmp(slfh_name, "*")) {
595             if(!check_management_access(hi, tlfh, NULL)) {
596                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
597                 return 0;
598             }
599             cmd_view_toplevel_information(user, cmd, tlfh);
600             return 1;
601         } else {
602             struct hs_secondlevel *slfh;
603             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
604                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
605             }
606             if(!slfh || !check_management_access(hi, tlfh, slfh)) {
607                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
608                 return 0;
609             }
610             cmd_view_secondlevel_information(user, cmd, slfh);
611             return 1;
612         }
613     } else {
614         if (!(hi = user->handle_info)) {
615             reply("NSMSG_MUST_AUTH");
616             return 0;
617         }
618     }
619     struct hs_user *huser = hs_get_user(hi, 0);
620     reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
621     int assigncount = 0;
622     if(huser) {
623         struct hs_assignment *assignment;
624         for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
625             reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
626             assigncount++;
627         }
628         if(assigncount && huser->hi == user->handle_info)
629             reply("HSMSG_ASSIGN_HOWTO");
630     }
631     if(!assigncount)
632         reply("HSMSG_ASSIGNED_NONE");
633     if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
634         struct hs_toplevel *tlfh;
635         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
636             struct hs_secondlevel *slfh;
637             struct hs_assignment *assignment;
638             int slfhs = 0, assignments = 0;
639             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
640                 slfhs++;
641                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
642                     assignments++;
643             }
644             reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
645         }
646         reply("HSMSG_MANAGE_HOWTO");
647     } else if(huser && huser->managements) {
648         reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
649         struct hs_manager *manager;
650         for(manager = huser->managements; manager; manager = manager->unext) {
651             if(manager->type == 1) {
652                 struct hs_toplevel *tlfh = manager->object;
653                 struct hs_secondlevel *slfh;
654                 struct hs_assignment *assignment;
655                 int slfhs = 0, assignments = 0;
656                 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
657                     slfhs++;
658                     for(assignment = slfh->assignments; assignment; assignment = assignment->next)
659                         assignments++;
660                 }
661                 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
662             }
663         }
664         for(manager = huser->managements; manager; manager = manager->next) {
665             if(manager->type == 2) {
666                 struct hs_secondlevel *slfh = manager->object;
667                 struct hs_toplevel *tlfh = slfh->toplevel;
668                 //check if the user is already a manager of the tlfh
669                 struct hs_manager *cmanager;
670                 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
671                     if(cmanager->user == huser) break;
672                 }
673                 if(cmanager) continue;
674                 struct hs_assignment *assignment;
675                 int assignments = 0;
676                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
677                     assignments++;
678                 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
679             }
680         }
681         if(huser->hi == user->handle_info)
682             reply("HSMSG_MANAGE_HOWTO");
683     }
684     return 1;
685 }
686
687 static MODCMD_FUNC(cmd_addhost) {
688     struct handle_info *hi;
689     struct hs_toplevel *tlfh;
690     struct hs_secondlevel *slfh;
691     if (!(hi = user->handle_info)) {
692         reply("NSMSG_MUST_AUTH");
693         return 0;
694     }
695     char *slfh_name = argv[1];
696     char *tlfh_name = strchr(argv[1], '.');
697     if(!tlfh_name) {
698         reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
699         return 0;
700     }
701     *tlfh_name = '\0';
702     tlfh_name++;
703     if(strchr(tlfh_name, '.')) {
704         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
705         return 0;
706     }
707     if(!irccasecmp(slfh_name, "*")) {
708         if(!check_management_access(hi, NULL, NULL)) {
709             reply("HSMSG_ACCESS_DENIED");
710             return NULL;
711         }
712         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
713             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
714         }
715         if(tlfh) {
716             reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
717             return 0;
718         }
719         hs_add_toplevel(tlfh_name);
720         reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
721     } else {
722         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
723             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
724         }
725         if(!tlfh) {
726             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
727             return 0;
728         }
729         if(!check_management_access(hi, tlfh, NULL)) {
730             reply("HSMSG_ACCESS_DENIED");
731             return 0;
732         }
733         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
734             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
735         }
736         if(slfh) {
737             reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
738             return 0;
739         }
740         hs_add_secondlevel(tlfh, slfh_name);
741         reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
742     }
743     return 1;
744 }
745
746 static MODCMD_FUNC(cmd_delhost) {
747     struct handle_info *hi;
748     if (!(hi = user->handle_info)) {
749         reply("NSMSG_MUST_AUTH");
750         return 0;
751     }
752     char *slfh_name = argv[1];
753     char *tlfh_name = strchr(argv[1], '.');
754     *tlfh_name = '\0';
755     tlfh_name++;
756     if(strchr(tlfh_name, '.')) {
757         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
758         return 0;
759     }
760     struct hs_toplevel *tlfh;
761     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
762         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
763     }
764     if(!tlfh) {
765         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
766         return 0;
767     }
768     if(!irccasecmp(slfh_name, "*")) {
769         if(!check_management_access(hi, (hostserv_conf.manager_can_del_toplevel ? tlfh : NULL), NULL)) { /* manager access is enough to delete whole toplevel? */
770             reply("HSMSG_ACCESS_DENIED");
771             return 0;
772         }
773         hs_del_toplevel(tlfh);
774         reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
775     } else {
776         struct hs_secondlevel *slfh;
777         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
778             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
779         }
780         if(!slfh) {
781             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
782             return 0;
783         }
784         if(!check_management_access(hi, tlfh, (hostserv_conf.manager_can_del_secondlevel ? slfh : NULL))) {
785             reply("HSMSG_ACCESS_DENIED");
786             return 0;
787         }
788         hs_del_secondlevel(slfh, 1);
789         reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
790     }
791     return 1;
792 }
793
794 static MODCMD_FUNC(cmd_addmanager) {
795     struct handle_info *hi;
796     char *fakehost;
797     if(argc >= 3) {
798         if(!strchr(argv[1], '.')) {
799             if (!(hi = modcmd_get_handle_info(user, argv[1])))
800                 return 0;
801             fakehost = argv[2];
802         } else {
803             if (!(hi = modcmd_get_handle_info(user, argv[2])))
804                 return 0;
805             fakehost = argv[1];
806         }
807         char *slfh_name = fakehost;
808         char *tlfh_name = strchr(fakehost, '.');
809         *tlfh_name = '\0';
810         tlfh_name++;
811         if(strchr(tlfh_name, '.')) {
812             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
813             return 0;
814         }
815         struct hs_toplevel *tlfh;
816         struct hs_secondlevel *slfh = NULL;
817         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
818             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
819         }
820         if(!tlfh) {
821             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
822             return 0;
823         }
824         if(!irccasecmp(slfh_name, "*")) {
825             if(!check_management_access(user->handle_info, tlfh, NULL)) {
826                 reply("HSMSG_ACCESS_DENIED");
827                 return 0;
828             }
829         } else {
830             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
831                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
832             }
833             if(!slfh) {
834                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
835                 return 0;
836             }
837             if(!check_management_access(user->handle_info, tlfh, slfh)) {
838                 reply("HSMSG_ACCESS_DENIED");
839                 return 0;
840             }
841         }
842         struct hs_user *huser = hs_get_user(hi, 1);
843         struct hs_manager *manager;
844         if(slfh) {
845             for(manager = huser->managements; manager; manager = manager->next) {
846                 if(manager->type == 2 && manager->object == slfh) {
847                     reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
848                     return 0;
849                 }
850             }
851         }
852         for(manager = huser->managements; manager; manager = manager->next) {
853             if(manager->type == 1 && manager->object == tlfh) {
854                 reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
855                 return 0;
856             }
857         }
858         if(slfh)
859             hs_add_manager_secondlevel(slfh, huser);
860         else
861             hs_add_manager_toplevel(tlfh, huser);
862         reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
863         return 1;
864     }
865     return 0;
866 }
867
868 static MODCMD_FUNC(cmd_delmanager) {
869     struct handle_info *hi;
870     char *fakehost;
871     if(!strchr(argv[1], '.')) {
872         if (!(hi = modcmd_get_handle_info(user, argv[1])))
873             return 0;
874         fakehost = argv[2];
875     } else {
876         if (!(hi = modcmd_get_handle_info(user, argv[2])))
877             return 0;
878         fakehost = argv[1];
879     }
880     char *slfh_name = fakehost;
881     char *tlfh_name = strchr(fakehost, '.');
882     if(tlfh_name) {
883         *tlfh_name = '\0';
884     } else {
885         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
886         return 0;
887     }
888     tlfh_name++;
889     if(strchr(tlfh_name, '.')) {
890         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
891         return 0;
892     }
893     struct hs_toplevel *tlfh;
894     struct hs_secondlevel *slfh = NULL;
895     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
896         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
897     }
898     if(!tlfh) {
899         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
900         return 0;
901     }
902     if(!irccasecmp(slfh_name, "*")) {
903         if(!check_management_access(user->handle_info, tlfh, NULL)) {
904             reply("HSMSG_ACCESS_DENIED");
905             return 0;
906         }
907     } else {
908         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
909             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
910         }
911         if(!slfh) {
912             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
913             return 0;
914         }
915         if(!check_management_access(user->handle_info, tlfh, slfh)) {
916             reply("HSMSG_ACCESS_DENIED");
917             return 0;
918         }
919     }
920     struct hs_user *huser = hs_get_user(hi, 0);
921     struct hs_manager *manager;
922     if(!huser) {
923         reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
924         return 0;
925     }
926     if(slfh) {
927         for(manager = huser->managements; manager; manager = manager->next) {
928             if(manager->type == 2 && manager->object == slfh) 
929                 break;
930         }
931         if(!manager) {
932             reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
933             return 0;
934         }
935     } else {
936         for(manager = huser->managements; manager; manager = manager->next) {
937             if(manager->type == 1 && manager->object == tlfh) 
938                 break;
939         }
940         if(!manager) {
941             reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
942             return 0;
943         }
944     }
945     hs_del_manager(manager, 1);
946     reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
947     return 1;
948 }
949
950 static MODCMD_FUNC(cmd_set) {
951     struct handle_info *hi;
952     struct hs_user *hs_user;
953     struct hs_assignment *assignment;
954     struct hs_assignment *assgn;
955     struct hs_toplevel *tlfh;
956     struct hs_secondlevel *slfh;
957     char *fakehost;
958     
959     if (!(hi = user->handle_info)) {
960         reply("NSMSG_MUST_AUTH");
961         return 0;
962     }
963     hs_user = hs_get_user(hi, 0);
964     if(!hs_user)
965         return 0; //nothing to do here
966     if(!strcmp(argv[1], "*")) {
967         hs_activate_assignment(hs_user, NULL);
968         return 1;
969     } else {
970         if(!strchr(argv[1], '.')) {
971             
972         }
973         fakehost = argv[1];
974         char *slfh_name = fakehost;
975         char *tlfh_name = strchr(fakehost, '.');
976         if(tlfh_name) {
977             *tlfh_name = '\0';
978             tlfh_name++;
979         }
980         if(!tlfh_name || strchr(tlfh_name, '.')) {
981             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, (tlfh_name ? tlfh_name : ""));
982             return 0;
983         }
984         for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
985             slfh = assignment->secondlevel;
986             tlfh = slfh->toplevel;
987             if(!irccasecmp(tlfh_name, tlfh->fakehost) && !irccasecmp(slfh_name, slfh->fakehost)) {
988                 hs_activate_assignment(hs_user, assignment);
989                 reply("HSMSG_FAKEHOST_SET_SUCCESS", slfh->fakehost, tlfh->fakehost);
990                 return 1;
991             }
992         }
993         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
994         return 0;
995     }
996 }
997
998 static MODCMD_FUNC(cmd_assign) {
999     struct handle_info *hi;
1000     char *fakehost;
1001     if(!strchr(argv[1], '.')) {
1002         if (!(hi = modcmd_get_handle_info(user, argv[1])))
1003             return 0;
1004         fakehost = argv[2];
1005     } else {
1006         if (!(hi = modcmd_get_handle_info(user, argv[2])))
1007             return 0;
1008         fakehost = argv[1];
1009     }
1010     if (!user->handle_info) {
1011         reply("NSMSG_MUST_AUTH");
1012         return 0;
1013     }
1014     char *slfh_name = fakehost;
1015     char *tlfh_name = strchr(fakehost, '.');
1016     if(tlfh_name) {
1017         *tlfh_name = '\0';
1018     } else {
1019         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1020         return 0;
1021     }
1022     tlfh_name++;
1023     if(strchr(tlfh_name, '.')) {
1024         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1025         return 0;
1026     }
1027     struct hs_toplevel *tlfh;
1028     struct hs_secondlevel *slfh;
1029     struct hs_user *hs_user = hs_get_user(hi, 1);
1030     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1031         if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
1032             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1033                 if(!irccasecmp(slfh_name, slfh->fakehost)) {
1034                     if(!check_management_access(user->handle_info, tlfh, slfh)) {
1035                         reply("HSMSG_ACCESS_DENIED");
1036                         return 0;
1037                     }
1038                     hs_add_assignment(slfh, hs_user);
1039                     reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
1040                     return 1;
1041                 }
1042             }
1043         }
1044     }
1045     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1046     return 0;
1047 }
1048
1049 static MODCMD_FUNC(cmd_unassign) {
1050     struct handle_info *hi;
1051     char *fakehost;
1052     if(!strchr(argv[1], '.')) {
1053         if (!(hi = modcmd_get_handle_info(user, argv[1])))
1054             return 0;
1055         fakehost = argv[2];
1056     } else {
1057         if (!(hi = modcmd_get_handle_info(user, argv[2])))
1058             return 0;
1059         fakehost = argv[1];
1060     }
1061     if (!user->handle_info) {
1062         reply("NSMSG_MUST_AUTH");
1063         return 0;
1064     }
1065     char *slfh_name = fakehost;
1066     char *tlfh_name = strchr(fakehost, '.');
1067     if(tlfh_name) {
1068         *tlfh_name = '\0';
1069     } else {
1070         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1071         return 0;
1072     }
1073     tlfh_name++;
1074     if(strchr(tlfh_name, '.')) {
1075         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1076         return 0;
1077     }
1078     struct hs_assignment *assignment;
1079     struct hs_user *hs_user = hs_get_user(hi, 0);
1080     if(!hs_user) {
1081         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1082         return 0;
1083     }
1084     for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1085         if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
1086             if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
1087                 if(!check_management_access(user->handle_info, assignment->secondlevel->toplevel, assignment->secondlevel)) {
1088                     reply("HSMSG_ACCESS_DENIED");
1089                     return 0;
1090                 }
1091                 hs_del_assignment(assignment, 1);
1092                 reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
1093                 return 1;
1094             }
1095         }
1096     }
1097     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1098     return 0;
1099 }
1100
1101 static void hostserv_conf_read(void) {
1102     dict_t conf_node;
1103     const char *str;
1104
1105     str = "modules/hostserv";
1106     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1107         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1108         return;
1109     }
1110
1111     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1112     if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
1113         //nick changed
1114     }
1115     hostserv_conf.nick = str;
1116     
1117     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1118     hostserv_conf.modes = (str ? str : NULL);
1119     
1120     str = database_get_data(conf_node, "toplevel_access", RECDB_QSTRING);
1121     unsigned int toplevel_access = atoi(str);
1122     hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
1123     
1124     str = database_get_data(conf_node, "fallback_other_assignment", RECDB_QSTRING);
1125     hostserv_conf.fallback_other_assignment = (atoi(str) ? 1 : 0);
1126     
1127     str = database_get_data(conf_node, "manager_can_del_toplevel", RECDB_QSTRING);
1128     hostserv_conf.manager_can_del_toplevel = (atoi(str) ? 1 : 0);
1129     
1130     str = database_get_data(conf_node, "manager_can_del_secondlevel", RECDB_QSTRING);
1131     hostserv_conf.manager_can_del_secondlevel = (atoi(str) ? 1 : 0);
1132     
1133     /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
1134     hostserv_conf.description = (str ? str : NULL);*/
1135 }
1136
1137 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));
1138 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra));
1139
1140 static int hostserv_saxdb_read_toplevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1141     struct record_data *rd = data;
1142     struct hs_toplevel *tlfh;
1143     struct hs_manager *managerTL;
1144     struct hs_user *user;
1145     struct dict *object;
1146
1147      if (rd->type == RECDB_OBJECT) {
1148         dict_t db = GET_RECORD_OBJECT(rd);
1149         dict_iterator_t it;
1150         
1151         tlfh = hs_add_toplevel(name);
1152         
1153         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1154             for (it = dict_first(object); it; it = iter_next(it)) {
1155                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1156                 //rd = iter_data(it);
1157                 /* nothing in here, yet */
1158                 managerTL = hs_add_manager_toplevel(tlfh, user);
1159                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1160                     managerTL->active = 1;
1161                 else
1162                     managerTL->active = 0;
1163             }
1164         }
1165         
1166         if ((object = database_get_data(db, KEY_SECONDLEVEL, RECDB_OBJECT)))
1167             dict_foreach(object, hostserv_saxdb_read_secondlevel, tlfh);
1168     }
1169     return 0;
1170 }
1171
1172 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1173     struct record_data *rd = data;
1174     struct hs_toplevel *tlfh = extra;
1175     struct hs_secondlevel *slfh;
1176     struct hs_manager *managerSL;
1177     struct hs_user *user;
1178     struct dict *object;
1179
1180     if (rd->type == RECDB_OBJECT) {
1181         dict_t db = GET_RECORD_OBJECT(rd);
1182         dict_iterator_t it;
1183         
1184         slfh = hs_add_secondlevel(tlfh, name);
1185         
1186         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1187             for (it = dict_first(object); it; it = iter_next(it)) {
1188                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1189                 //rd = iter_data(it);
1190                 /* nothing in here, yet */
1191                 managerSL = hs_add_manager_secondlevel(slfh, user);
1192                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1193                     managerSL->active = 1;
1194                 else
1195                     managerSL->active = 0;
1196             }
1197         }
1198         
1199         if ((object = database_get_data(db, KEY_ASSIGNMENTS, RECDB_OBJECT)))
1200             dict_foreach(object, hostserv_saxdb_read_assignments, slfh);
1201     }
1202     return 0;
1203 }
1204
1205 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra)) {
1206     struct record_data *rd = data;
1207     struct hs_secondlevel *slfh = extra;
1208     struct hs_user *user;
1209     struct hs_assignment *assng;
1210     
1211     if (rd->type == RECDB_OBJECT) {
1212         dict_t db = GET_RECORD_OBJECT(rd);
1213         
1214         user = hs_get_user(get_handle_info(name), 1);
1215         assng = hs_add_assignment(slfh, user);
1216         
1217         if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1218             assng->active = 1;
1219         else
1220             assng->active = 0;
1221     }
1222     
1223     return 0;
1224 }
1225
1226 static int
1227 hostserv_saxdb_read(struct dict *db)
1228 {
1229     struct dict *object;
1230
1231     if ((object = database_get_data(db, KEY_TOPLEVEL, RECDB_OBJECT)))
1232         dict_foreach(object, hostserv_saxdb_read_toplevel, NULL);
1233
1234     return 1;
1235 }
1236
1237 static int
1238 hostserv_saxdb_write(struct saxdb_context *ctx)
1239 {
1240     struct hs_toplevel *tlfh;
1241     struct hs_secondlevel *slfh;
1242     struct hs_assignment *assng;
1243     struct hs_manager *manager;
1244
1245     saxdb_start_record(ctx, KEY_TOPLEVEL, 1);
1246     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1247         saxdb_start_record(ctx, tlfh->fakehost, 1);
1248         
1249         saxdb_start_record(ctx, KEY_MANAGERS, 1);
1250         for(manager = tlfh->managers; manager; manager = manager->next) {
1251             saxdb_start_record(ctx, manager->user->hi->handle, 0);
1252             //additional manager information?
1253             if(manager->active)
1254                 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1255             saxdb_end_record(ctx);
1256         }
1257         saxdb_end_record(ctx);
1258         
1259         saxdb_start_record(ctx, KEY_SECONDLEVEL, 1);
1260         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1261             saxdb_start_record(ctx, slfh->fakehost, 1);
1262             
1263             saxdb_start_record(ctx, KEY_MANAGERS, 1);
1264             for(manager = slfh->managers; manager; manager = manager->next) {
1265                 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1266                 //additional manager information?
1267                 if(manager->active)
1268                     saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1269                 saxdb_end_record(ctx);
1270             }
1271             saxdb_end_record(ctx);
1272             
1273             saxdb_start_record(ctx, KEY_ASSIGNMENTS, 1);
1274             for(assng = slfh->assignments; assng; assng = assng->next) {
1275                 saxdb_start_record(ctx, assng->user->hi->handle, 0);
1276                 //additional assignment information?
1277                 if(assng->active)
1278                     saxdb_write_int(ctx, KEY_ACTIVE, assng->active);
1279                 saxdb_end_record(ctx);
1280             }
1281             saxdb_end_record(ctx);
1282             
1283             saxdb_end_record(ctx);
1284         }
1285         saxdb_end_record(ctx);
1286         
1287         saxdb_end_record(ctx);
1288     }
1289     saxdb_end_record(ctx);
1290     
1291     return 0;
1292 }
1293
1294
1295 static void hostserv_db_cleanup(void) {
1296     hs_free_all();
1297 }
1298
1299 int hostserv_init() {
1300     HS_LOG = log_register_type("HostServ", "file:hostserv.log");
1301     
1302     const char *nick, *modes;
1303     if((nick = conf_get_data("modules/hostserv/nick", RECDB_QSTRING))) {
1304         modes = conf_get_data("modules/hostserv/modes", RECDB_QSTRING);
1305         hostserv = AddLocalUser(nick, nick, NULL, "Host Service", modes);
1306         hostserv_service = service_register(hostserv);
1307         hostserv_service->trigger = '*';
1308     }
1309         
1310     conf_register_reload(hostserv_conf_read);
1311     reg_exit_func(hostserv_db_cleanup);
1312     saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
1313     hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
1314     modcmd_register(hostserv_module, "view", cmd_view, 0, MODCMD_REQUIRE_AUTHED, NULL);
1315     modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1316     modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1317     modcmd_register(hostserv_module, "set", cmd_set, 2, MODCMD_REQUIRE_AUTHED, NULL);
1318     modcmd_register(hostserv_module, "assign", cmd_assign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1319     modcmd_register(hostserv_module, "unassign", cmd_unassign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1320     modcmd_register(hostserv_module, "addhost", cmd_addhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1321     modcmd_register(hostserv_module, "delhost", cmd_delhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1322     message_register_table(msgtab);
1323     return 1;
1324 }
1325
1326 int hostserv_finalize(void) {
1327     dict_t conf_node;
1328     const char *str;
1329
1330     str = "modules/hostserv";
1331     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1332         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1333         return 0;
1334     }
1335
1336     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1337     if (str) hostserv_conf.nick = str;
1338     
1339     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1340     if (str) hostserv_conf.modes = str; 
1341     return 1;
1342 }