fixed some compiler warnings and prevent duplicate assignments
[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_ASSIGNED", "Group $b%s.%s$b is already assigned to the user." },
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 0;
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_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                     if(hs_get_assignment(slfh, hs_user)) {
1038                         reply("HSMSG_FAKEHOST_ASSIGNED", slfh_name, tlfh_name);
1039                         return 0;
1040                     }
1041                     hs_add_assignment(slfh, hs_user);
1042                     reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
1043                     return 1;
1044                 }
1045             }
1046         }
1047     }
1048     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1049     return 0;
1050 }
1051
1052 static MODCMD_FUNC(cmd_unassign) {
1053     struct handle_info *hi;
1054     char *fakehost;
1055     if(!strchr(argv[1], '.')) {
1056         if (!(hi = modcmd_get_handle_info(user, argv[1])))
1057             return 0;
1058         fakehost = argv[2];
1059     } else {
1060         if (!(hi = modcmd_get_handle_info(user, argv[2])))
1061             return 0;
1062         fakehost = argv[1];
1063     }
1064     if (!user->handle_info) {
1065         reply("NSMSG_MUST_AUTH");
1066         return 0;
1067     }
1068     char *slfh_name = fakehost;
1069     char *tlfh_name = strchr(fakehost, '.');
1070     if(tlfh_name) {
1071         *tlfh_name = '\0';
1072     } else {
1073         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, "");
1074         return 0;
1075     }
1076     tlfh_name++;
1077     if(strchr(tlfh_name, '.')) {
1078         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1079         return 0;
1080     }
1081     struct hs_assignment *assignment;
1082     struct hs_user *hs_user = hs_get_user(hi, 0);
1083     if(!hs_user) {
1084         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1085         return 0;
1086     }
1087     for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1088         if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
1089             if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
1090                 if(!check_management_access(user->handle_info, assignment->secondlevel->toplevel, assignment->secondlevel)) {
1091                     reply("HSMSG_ACCESS_DENIED");
1092                     return 0;
1093                 }
1094                 hs_del_assignment(assignment, 1);
1095                 reply("HSMSG_FAKEHOST_UNASSIGN_SUCCESS", slfh_name, tlfh_name);
1096                 return 1;
1097             }
1098         }
1099     }
1100     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1101     return 0;
1102 }
1103
1104 static void hostserv_conf_read(void) {
1105     dict_t conf_node;
1106     const char *str;
1107
1108     str = "modules/hostserv";
1109     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1110         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1111         return;
1112     }
1113
1114     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1115     if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
1116         //nick changed
1117     }
1118     hostserv_conf.nick = str;
1119     
1120     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1121     hostserv_conf.modes = (str ? str : NULL);
1122     
1123     str = database_get_data(conf_node, "toplevel_access", RECDB_QSTRING);
1124     unsigned int toplevel_access = atoi(str);
1125     hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
1126     
1127     str = database_get_data(conf_node, "fallback_other_assignment", RECDB_QSTRING);
1128     hostserv_conf.fallback_other_assignment = (atoi(str) ? 1 : 0);
1129     
1130     str = database_get_data(conf_node, "manager_can_del_toplevel", RECDB_QSTRING);
1131     hostserv_conf.manager_can_del_toplevel = (atoi(str) ? 1 : 0);
1132     
1133     str = database_get_data(conf_node, "manager_can_del_secondlevel", RECDB_QSTRING);
1134     hostserv_conf.manager_can_del_secondlevel = (atoi(str) ? 1 : 0);
1135     
1136     /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
1137     hostserv_conf.description = (str ? str : NULL);*/
1138 }
1139
1140 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));
1141 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra));
1142
1143 static int hostserv_saxdb_read_toplevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1144     struct record_data *rd = data;
1145     struct hs_toplevel *tlfh;
1146     struct hs_manager *managerTL;
1147     struct hs_user *user;
1148     struct dict *object;
1149
1150      if (rd->type == RECDB_OBJECT) {
1151         dict_t db = GET_RECORD_OBJECT(rd);
1152         dict_iterator_t it;
1153         
1154         tlfh = hs_add_toplevel(name);
1155         
1156         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1157             for (it = dict_first(object); it; it = iter_next(it)) {
1158                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1159                 //rd = iter_data(it);
1160                 /* nothing in here, yet */
1161                 managerTL = hs_add_manager_toplevel(tlfh, user);
1162                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1163                     managerTL->active = 1;
1164                 else
1165                     managerTL->active = 0;
1166             }
1167         }
1168         
1169         if ((object = database_get_data(db, KEY_SECONDLEVEL, RECDB_OBJECT)))
1170             dict_foreach(object, hostserv_saxdb_read_secondlevel, tlfh);
1171     }
1172     return 0;
1173 }
1174
1175 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1176     struct record_data *rd = data;
1177     struct hs_toplevel *tlfh = extra;
1178     struct hs_secondlevel *slfh;
1179     struct hs_manager *managerSL;
1180     struct hs_user *user;
1181     struct dict *object;
1182
1183     if (rd->type == RECDB_OBJECT) {
1184         dict_t db = GET_RECORD_OBJECT(rd);
1185         dict_iterator_t it;
1186         
1187         slfh = hs_add_secondlevel(tlfh, name);
1188         
1189         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1190             for (it = dict_first(object); it; it = iter_next(it)) {
1191                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1192                 //rd = iter_data(it);
1193                 /* nothing in here, yet */
1194                 managerSL = hs_add_manager_secondlevel(slfh, user);
1195                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1196                     managerSL->active = 1;
1197                 else
1198                     managerSL->active = 0;
1199             }
1200         }
1201         
1202         if ((object = database_get_data(db, KEY_ASSIGNMENTS, RECDB_OBJECT)))
1203             dict_foreach(object, hostserv_saxdb_read_assignments, slfh);
1204     }
1205     return 0;
1206 }
1207
1208 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra)) {
1209     struct record_data *rd = data;
1210     struct hs_secondlevel *slfh = extra;
1211     struct hs_user *user;
1212     struct hs_assignment *assng;
1213     
1214     if (rd->type == RECDB_OBJECT) {
1215         dict_t db = GET_RECORD_OBJECT(rd);
1216         
1217         user = hs_get_user(get_handle_info(name), 1);
1218         assng = hs_add_assignment(slfh, user);
1219         
1220         if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1221             assng->active = 1;
1222         else
1223             assng->active = 0;
1224     }
1225     
1226     return 0;
1227 }
1228
1229 static int
1230 hostserv_saxdb_read(struct dict *db)
1231 {
1232     struct dict *object;
1233
1234     if ((object = database_get_data(db, KEY_TOPLEVEL, RECDB_OBJECT)))
1235         dict_foreach(object, hostserv_saxdb_read_toplevel, NULL);
1236
1237     return 1;
1238 }
1239
1240 static int
1241 hostserv_saxdb_write(struct saxdb_context *ctx)
1242 {
1243     struct hs_toplevel *tlfh;
1244     struct hs_secondlevel *slfh;
1245     struct hs_assignment *assng;
1246     struct hs_manager *manager;
1247
1248     saxdb_start_record(ctx, KEY_TOPLEVEL, 1);
1249     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1250         saxdb_start_record(ctx, tlfh->fakehost, 1);
1251         
1252         saxdb_start_record(ctx, KEY_MANAGERS, 1);
1253         for(manager = tlfh->managers; manager; manager = manager->next) {
1254             saxdb_start_record(ctx, manager->user->hi->handle, 0);
1255             //additional manager information?
1256             if(manager->active)
1257                 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1258             saxdb_end_record(ctx);
1259         }
1260         saxdb_end_record(ctx);
1261         
1262         saxdb_start_record(ctx, KEY_SECONDLEVEL, 1);
1263         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1264             saxdb_start_record(ctx, slfh->fakehost, 1);
1265             
1266             saxdb_start_record(ctx, KEY_MANAGERS, 1);
1267             for(manager = slfh->managers; manager; manager = manager->next) {
1268                 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1269                 //additional manager information?
1270                 if(manager->active)
1271                     saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1272                 saxdb_end_record(ctx);
1273             }
1274             saxdb_end_record(ctx);
1275             
1276             saxdb_start_record(ctx, KEY_ASSIGNMENTS, 1);
1277             for(assng = slfh->assignments; assng; assng = assng->next) {
1278                 saxdb_start_record(ctx, assng->user->hi->handle, 0);
1279                 //additional assignment information?
1280                 if(assng->active)
1281                     saxdb_write_int(ctx, KEY_ACTIVE, assng->active);
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         saxdb_end_record(ctx);
1291     }
1292     saxdb_end_record(ctx);
1293     
1294     return 0;
1295 }
1296
1297
1298 static void hostserv_db_cleanup(void) {
1299     hs_free_all();
1300 }
1301
1302 int hostserv_init() {
1303     HS_LOG = log_register_type("HostServ", "file:hostserv.log");
1304     
1305     const char *nick, *modes;
1306     if((nick = conf_get_data("modules/hostserv/nick", RECDB_QSTRING))) {
1307         modes = conf_get_data("modules/hostserv/modes", RECDB_QSTRING);
1308         hostserv = AddLocalUser(nick, nick, NULL, "Host Service", modes);
1309         hostserv_service = service_register(hostserv);
1310         hostserv_service->trigger = '*';
1311     }
1312         
1313     conf_register_reload(hostserv_conf_read);
1314     reg_exit_func(hostserv_db_cleanup);
1315     saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
1316     hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
1317     modcmd_register(hostserv_module, "view", cmd_view, 0, MODCMD_REQUIRE_AUTHED, NULL);
1318     modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1319     modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1320     modcmd_register(hostserv_module, "set", cmd_set, 2, MODCMD_REQUIRE_AUTHED, NULL);
1321     modcmd_register(hostserv_module, "assign", cmd_assign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1322     modcmd_register(hostserv_module, "unassign", cmd_unassign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1323     modcmd_register(hostserv_module, "addhost", cmd_addhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1324     modcmd_register(hostserv_module, "delhost", cmd_delhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1325     message_register_table(msgtab);
1326     return 1;
1327 }
1328
1329 int hostserv_finalize(void) {
1330     dict_t conf_node;
1331     const char *str;
1332
1333     str = "modules/hostserv";
1334     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1335         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1336         return 0;
1337     }
1338
1339     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1340     if (str) hostserv_conf.nick = str;
1341     
1342     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1343     if (str) hostserv_conf.modes = str; 
1344     return 1;
1345 }