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