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