fixed hs_del_toplevel and assignment removal && codestyle
[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         if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
456             hs_del_user(assignment->user);
457         
458         if(assignment->active) {
459             struct handle_info *hi;
460             
461             hi = assignment->user->hi;
462             hi->fakehost = NULL;
463             apply_fakehost(hi, NULL);
464         }
465     }
466     free(assignment);
467 }
468
469 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
470     struct hs_user *cuser;
471     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
472         if(cuser->hi == hi)
473             return cuser;
474     }
475     if(create) {
476         cuser = calloc(1, sizeof(*cuser));
477         cuser->hi = hi;
478         cuser->next = hostserv_users;
479         hostserv_users = cuser;
480         return cuser;
481     } else
482         return NULL;
483 }
484
485 static void hs_del_user(struct hs_user *user) {
486     if(user->managements) {
487         struct hs_manager *manager, *next_manager;
488         for(manager = user->managements; manager; manager = next_manager) {
489             next_manager = manager->unext;
490             hs_del_manager(manager, 2);
491         }
492     }
493     if(user->assignments) {
494         struct hs_assignment *assng, *next_assng;
495         for(assng = user->assignments; assng; assng = next_assng) {
496             next_assng = assng->unext;
497             hs_del_assignment(assng, 2);
498         }
499     }
500     struct hs_user *cuser, *prev_user = NULL;
501     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
502         if(cuser == user) {
503             if(prev_user)
504                 prev_user->next = user->next;
505             else
506                 hostserv_users = user->next;
507             break;
508         } else
509             prev_user = cuser;
510     }
511     free(user);
512 }
513
514 /* END OF MANAGEMENT FUNCTIONS */
515
516 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_secondlevel *slfh) {
517     if(!hi) 
518         return 0;
519     if(hi->opserv_level >= hostserv_conf.toplevel_access) 
520         return 1;
521     struct hs_user *user = hs_get_user(hi, 0);
522     if(!user)
523         return 0;
524     struct hs_manager *manager;
525     if(slfh) {
526         for(manager = user->managements; manager; manager = manager->next) {
527             if(manager->type == 2 && manager->object == slfh) 
528                 return 1;
529         }
530     }
531     if(tlfh) {
532         for(manager = user->managements; manager; manager = manager->next) {
533             if(manager->type == 1 && manager->object == tlfh) 
534                 return 1;
535         }
536     }
537     return 0;
538 }
539
540
541 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
542     reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
543     struct hs_secondlevel *slfh;
544     if(!tlfh->secondlevel)
545         reply("HSMSG_ASSIGNED_NONE");
546     else
547     for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
548         struct hs_manager *cmanager;
549         int managers = 0;
550         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
551             managers++;
552         struct hs_assignment *assignment;
553         int assignments = 0;
554         for(assignment = slfh->assignments; assignment; assignment = assignment->next)
555             assignments++;
556         reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
557     }
558     reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
559     struct hs_manager *cmanager;
560     if(!tlfh->managers)
561         reply("HSMSG_ASSIGNED_NONE");
562     else {
563         char managerBuf[351];
564         int managerPos = 0;
565         for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
566             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
567                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
568                 managerPos = 0;
569             }
570             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
571         }
572         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
573     }
574 }
575
576 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
577     reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
578     struct hs_assignment *assignment;
579     for(assignment = slfh->assignments; assignment; assignment = assignment->next) {
580         reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
581     }
582     reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
583     struct hs_manager *cmanager;
584     if(!slfh->managers)
585         reply("HSMSG_ASSIGNED_NONE");
586     else {
587         char managerBuf[351];
588         int managerPos = 0;
589         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
590             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
591                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
592                 managerPos = 0;
593             }
594             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
595         }
596         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
597     }
598 }
599
600 static MODCMD_FUNC(cmd_addhost) {
601     struct handle_info *hi;
602     if (!(hi = user->handle_info)) {
603         reply("NSMSG_MUST_AUTH");
604         return 0;
605     }
606     char *slfh_name = argv[1];
607     char *tlfh_name = strchr(argv[1], '.');
608     if(!tlfh_name) {
609         reply("HSMSG_TOPLEVEL_INVALID", slfh_name);
610         return 0;
611     }
612     *tlfh_name = '\0';
613     tlfh_name++;
614     if(strchr(tlfh_name, '.')) {
615         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
616         return 0;
617     }
618     if(!irccasecmp(slfh_name, "*")) {
619         if(hi->opserv_level >= hostserv_conf.toplevel_access) {
620             struct hs_toplevel *tlfh;
621             for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
622                 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
623             }
624             if(tlfh) {
625                 reply("HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
626                 return 0;
627             }
628             hs_add_toplevel(tlfh_name);
629             reply("HSMSG_FAKEHOST_TOPLEVEL_ADDED", tlfh_name);
630             return 1;
631         }
632         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
633         return 0;
634     } else {
635         struct hs_secondlevel *slfh;
636         struct hs_toplevel *tlfh;
637         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
638             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
639         }
640         if(!tlfh) {
641             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
642             return 0;
643         }
644         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
645             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
646         }
647         if(slfh) {
648             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
649             return 0;
650         }
651         if(!check_management_access(hi, tlfh, NULL)) {
652             reply("HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", slfh_name, tlfh_name);
653             return 0;
654         }
655         hs_add_secondlevel(tlfh, slfh_name);
656         reply("HSMSG_FAKEHOST_SECONDLEVEL_ADDED", slfh_name, tlfh_name);
657     }
658     return 0;
659 }
660
661 static MODCMD_FUNC(cmd_delhost) {
662     struct handle_info *hi;
663     if (!(hi = user->handle_info)) {
664         reply("NSMSG_MUST_AUTH");
665         return 0;
666     }
667     char *slfh_name = argv[1];
668     char *tlfh_name = strchr(argv[1], '.');
669     *tlfh_name = '\0';
670     tlfh_name++;
671     if(strchr(tlfh_name, '.')) {
672         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
673         return 0;
674     }
675     struct hs_toplevel *tlfh;
676     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
677         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
678     }
679     if(!tlfh) {
680         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
681         return 0;
682     }
683     if(!irccasecmp(slfh_name, "*")) {
684         if(hi->opserv_level < hostserv_conf.toplevel_access) {
685             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
686             return 0;
687         }
688         hs_del_toplevel(tlfh);
689         reply("HSMSG_FAKEHOST_TOPLEVEL_DELETED", tlfh_name);
690         return 1;
691     } else {
692         struct hs_secondlevel *slfh;
693         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
694             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
695         }
696         if(!slfh || !check_management_access(hi, tlfh, NULL)) {
697             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
698             return 0;
699         }
700         hs_del_secondlevel(slfh, 1);
701         reply("HSMSG_FAKEHOST_SECONDLEVEL_DELETED", slfh_name, tlfh_name);
702     }
703     return 0;
704 }
705
706 static MODCMD_FUNC(cmd_view) {
707     struct handle_info *hi;
708     if(argc >= 2 && !strchr(argv[1], '.')) {
709         if (!(hi = modcmd_get_handle_info(user, argv[1])))
710             return 0;
711     } else if(argc >= 2) {
712         if (!(hi = user->handle_info)) {
713             reply("NSMSG_MUST_AUTH");
714             return 0;
715         }
716         char *slfh_name = argv[1];
717         char *tlfh_name = strchr(argv[1], '.');
718         *tlfh_name = '\0';
719         tlfh_name++;
720         if(strchr(tlfh_name, '.')) {
721             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
722             return 0;
723         }
724         struct hs_toplevel *tlfh;
725         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
726             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
727         }
728         if(!tlfh) {
729             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
730             return 0;
731         }
732         if(!irccasecmp(slfh_name, "*")) {
733             if(!check_management_access(hi, tlfh, NULL)) {
734                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
735                 return 0;
736             }
737             cmd_view_toplevel_information(user, cmd, tlfh);
738             return 1;
739         } else {
740             struct hs_secondlevel *slfh;
741             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
742                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
743             }
744             if(!slfh || !check_management_access(hi, tlfh, slfh)) {
745                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
746                 return 0;
747             }
748             cmd_view_secondlevel_information(user, cmd, slfh);
749             return 1;
750         }
751     } else {
752         if (!(hi = user->handle_info)) {
753             reply("NSMSG_MUST_AUTH");
754             return 0;
755         }
756     }
757     struct hs_user *huser = hs_get_user(hi, 0);
758     reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
759     int assigncount = 0;
760     if(huser) {
761         struct hs_assignment *assignment;
762         for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
763             reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
764             assigncount++;
765         }
766         if(assigncount && huser->hi == user->handle_info)
767             reply("HSMSG_ASSIGN_HOWTO");
768     }
769     if(!assigncount)
770         reply("HSMSG_ASSIGNED_NONE");
771     if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
772         struct hs_toplevel *tlfh;
773         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
774             struct hs_secondlevel *slfh;
775             struct hs_assignment *assignment;
776             int slfhs = 0, assignments = 0;
777             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
778                 slfhs++;
779                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
780                     assignments++;
781             }
782             reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
783         }
784         reply("HSMSG_MANAGE_HOWTO");
785     } else if(huser && huser->managements) {
786         reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
787         struct hs_manager *manager;
788         for(manager = huser->managements; manager; manager = manager->unext) {
789             if(manager->type == 1) {
790                 struct hs_toplevel *tlfh = manager->object;
791                 struct hs_secondlevel *slfh;
792                 struct hs_assignment *assignment;
793                 int slfhs = 0, assignments = 0;
794                 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
795                     slfhs++;
796                     for(assignment = slfh->assignments; assignment; assignment = assignment->next)
797                         assignments++;
798                 }
799                 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
800             }
801         }
802         for(manager = huser->managements; manager; manager = manager->next) {
803             if(manager->type == 2) {
804                 struct hs_secondlevel *slfh = manager->object;
805                 struct hs_toplevel *tlfh = slfh->toplevel;
806                 //check if the user is already a manager of the tlfh
807                 struct hs_manager *cmanager;
808                 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
809                     if(cmanager->user == huser) break;
810                 }
811                 if(cmanager) continue;
812                 struct hs_assignment *assignment;
813                 int assignments = 0;
814                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
815                     assignments++;
816                 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
817             }
818         }
819         if(huser->hi == user->handle_info)
820             reply("HSMSG_MANAGE_HOWTO");
821     }
822     return 1;
823 }
824
825 static MODCMD_FUNC(cmd_addmanager) {
826     struct handle_info *hi;
827     char *fakehost;
828     if(argc >= 3) {
829         if(!strchr(argv[1], '.')) {
830             if (!(hi = modcmd_get_handle_info(user, argv[1])))
831                 return 0;
832             fakehost = argv[2];
833         } else {
834             if (!(hi = modcmd_get_handle_info(user, argv[2])))
835                 return 0;
836             fakehost = argv[1];
837         }
838         char *slfh_name = fakehost;
839         char *tlfh_name = strchr(fakehost, '.');
840         *tlfh_name = '\0';
841         tlfh_name++;
842         if(strchr(tlfh_name, '.')) {
843             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
844             return 0;
845         }
846         struct hs_toplevel *tlfh;
847         struct hs_secondlevel *slfh = NULL;
848         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
849             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
850         }
851         if(!tlfh) {
852             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
853             return 0;
854         }
855         if(!irccasecmp(slfh_name, "*")) {
856             if(!check_management_access(user->handle_info, tlfh, NULL)) {
857                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
858                 return 0;
859             }
860         } else {
861             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
862                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
863             }
864             if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
865                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
866                 return 0;
867             }
868         }
869         struct hs_user *huser = hs_get_user(hi, 1);
870         struct hs_manager *manager;
871         if(slfh) {
872             for(manager = huser->managements; manager; manager = manager->next) {
873                 if(manager->type == 2 && manager->object == slfh) {
874                     reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
875                     return 0;
876                 }
877             }
878         }
879         for(manager = huser->managements; manager; manager = manager->next) {
880             if(manager->type == 1 && manager->object == tlfh) {
881                 reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
882                 return 0;
883             }
884         }
885         if(slfh)
886             hs_add_manager_secondlevel(slfh, huser);
887         else
888             hs_add_manager_toplevel(tlfh, huser);
889         reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
890         return 1;
891     }
892     return 0;
893 }
894
895 static MODCMD_FUNC(cmd_delmanager) {
896     struct handle_info *hi;
897     char *fakehost;
898     if(!strchr(argv[1], '.')) {
899         if (!(hi = modcmd_get_handle_info(user, argv[1])))
900             return 0;
901         fakehost = argv[2];
902     } else {
903         if (!(hi = modcmd_get_handle_info(user, argv[2])))
904             return 0;
905         fakehost = argv[1];
906     }
907     if(!fakehost) {
908         reply("HSMSG_ASSIGNED_NONE");
909         return 0;
910     }
911     char *slfh_name = fakehost;
912     char *tlfh_name = strchr(fakehost, '.');
913     if(tlfh_name) {
914         *tlfh_name = '\0';
915     } else {
916         reply("HSMSG_ASSIGNED_NONE");
917         return 0;
918     }
919     tlfh_name++;
920     if(strchr(tlfh_name, '.')) {
921         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
922         return 0;
923     }
924     struct hs_toplevel *tlfh;
925     struct hs_secondlevel *slfh = NULL;
926     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
927         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
928     }
929     if(!tlfh) {
930         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
931         return 0;
932     }
933     if(!irccasecmp(slfh_name, "*")) {
934         if(!check_management_access(user->handle_info, tlfh, NULL)) {
935             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
936             return 0;
937         }
938     } else {
939         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
940             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
941         }
942         if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
943             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
944             return 0;
945         }
946     }
947     struct hs_user *huser = hs_get_user(hi, 0);
948     struct hs_manager *manager;
949     if(!huser) {
950         reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
951         return 0;
952     }
953     if(slfh) {
954         for(manager = huser->managements; manager; manager = manager->next) {
955             if(manager->type == 2 && manager->object == slfh) 
956                 break;
957         }
958         if(!manager) {
959             reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
960             return 0;
961         }
962     } else {
963         for(manager = huser->managements; manager; manager = manager->next) {
964             if(manager->type == 1 && manager->object == tlfh) 
965                 break;
966         }
967         if(!manager) {
968             reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
969             return 0;
970         }
971     }
972     hs_del_manager(manager, 1);
973     reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
974     return 1;
975 }
976
977 static MODCMD_FUNC(cmd_set) {
978     struct handle_info *hi;
979     struct hs_user *hs_user;
980     struct hs_assignment *assignment;
981     struct hs_assignment *assgn;
982     struct hs_toplevel *tlfh;
983     struct hs_secondlevel *slfh;
984     char *fakehost;
985     
986     if (!(hi = user->handle_info)) {
987         reply("NSMSG_MUST_AUTH");
988         return 0;
989     }
990     hs_user = hs_get_user(hi, 0);
991     if(!strcmp(argv[1], "*")) {
992         hi->fakehost = NULL;
993         apply_fakehost(hi, NULL);
994         if(hs_user->assignments) {
995             for(assgn = hs_user->assignments; assgn; assgn = assgn->unext) {
996                 assgn->active = 0;
997             }
998         }
999         return 1;
1000     } else {
1001         if(!strchr(argv[1], '.')) {
1002             return 0;
1003         }
1004         fakehost = argv[1];
1005         char *slfh_name = fakehost;
1006         char *tlfh_name = strchr(fakehost, '.');
1007         *tlfh_name = '\0';
1008         tlfh_name++;
1009         if(strchr(tlfh_name, '.')) {
1010             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1011             return 0;
1012         }
1013         for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1014             slfh = assignment->secondlevel;
1015             tlfh = slfh->toplevel;
1016             if(!irccasecmp(slfh_name, slfh->fakehost)) {
1017                 if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
1018                     activateAssignment(assignment);
1019                     reply("HSMSG_FAKEHOST_SET_SUCCESS", slfh->fakehost, tlfh->fakehost);
1020                     return 1;
1021                 }
1022             }
1023         }
1024         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1025         return 0;
1026     }
1027 }
1028
1029 static MODCMD_FUNC(cmd_assign) {
1030     struct handle_info *hi;
1031     struct handle_info *hiuser;
1032     char *fakehost;
1033     if(!strchr(argv[1], '.')) {
1034         if (!(hi = modcmd_get_handle_info(user, argv[1])))
1035             return 0;
1036         fakehost = argv[2];
1037     } else {
1038         if (!(hi = modcmd_get_handle_info(user, argv[2])))
1039             return 0;
1040         fakehost = argv[1];
1041     }
1042     if (!(hiuser = user->handle_info)) {
1043         reply("NSMSG_MUST_AUTH");
1044         return 0;
1045     }
1046     if(!fakehost) {
1047         reply("HSMSG_ASSIGNED_NONE");
1048         return 0;
1049     }
1050     char *slfh_name = fakehost;
1051     char *tlfh_name = strchr(fakehost, '.');
1052     if(tlfh_name) {
1053         *tlfh_name = '\0';
1054     } else {
1055         reply("HSMSG_ASSIGNED_NONE");
1056         return 0;
1057     }
1058     tlfh_name++;
1059     if(strchr(tlfh_name, '.')) {
1060         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1061         return 0;
1062     }
1063     struct hs_toplevel *tlfh;;
1064     struct hs_secondlevel *slfh;
1065     struct hs_user *hs_user = hs_get_user(hi, 1);
1066     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1067         if(!irccasecmp(tlfh_name, tlfh->fakehost)) {
1068             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1069                 if(!irccasecmp(slfh_name, slfh->fakehost)) {
1070                     if(check_management_access(hiuser, tlfh, slfh)) {
1071                         hs_add_assignment(slfh, hs_user);
1072                         reply("HSMSG_FAKEHOST_ASSIGN_SUCCESS", slfh_name, tlfh_name);
1073                         return 1;
1074                     }
1075                     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1076                     return 0;
1077                 }
1078             }
1079         }
1080     }
1081     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1082     return 0;
1083 }
1084
1085 static MODCMD_FUNC(cmd_revoke) {
1086     struct handle_info *hi;
1087     struct handle_info *hiuser;
1088     char *fakehost;
1089     if(!strchr(argv[1], '.')) {
1090         if (!(hi = modcmd_get_handle_info(user, argv[1])))
1091             return 0;
1092         fakehost = argv[2];
1093     } else {
1094         if (!(hi = modcmd_get_handle_info(user, argv[2])))
1095             return 0;
1096         fakehost = argv[1];
1097     }
1098     if (!(hiuser = user->handle_info)) {
1099         reply("NSMSG_MUST_AUTH");
1100         return 0;
1101     }
1102     if(!fakehost) {
1103         reply("HSMSG_ASSIGNED_NONE");
1104         return 0;
1105     }
1106     char *slfh_name = fakehost;
1107     char *tlfh_name = strchr(fakehost, '.');
1108     if(tlfh_name) {
1109         *tlfh_name = '\0';
1110     } else {
1111         reply("HSMSG_ASSIGNED_NONE");
1112         return 0;
1113     }
1114     tlfh_name++;
1115     if(strchr(tlfh_name, '.')) {
1116         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1117         return 0;
1118     }
1119     struct hs_assignment *assignment;
1120     struct hs_user *hs_user = hs_get_user(hi, 0);
1121     for(assignment = hs_user->assignments; assignment; assignment = assignment->unext) {
1122         if(!irccasecmp(slfh_name, assignment->secondlevel->fakehost)) {
1123             if(!irccasecmp(tlfh_name, assignment->secondlevel->toplevel->fakehost)) {
1124                 if(check_management_access(hi, assignment->secondlevel->toplevel, assignment->secondlevel)) {
1125                     hs_del_assignment(assignment, 1);
1126                     reply("HSMSG_FAKEHOST_REVOKE_SUCCESS", slfh_name, tlfh_name);
1127                     return 1;
1128                 }
1129                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1130                 return 0;
1131             }
1132         }
1133     }
1134     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
1135     return 0;
1136 }
1137
1138 static void hostserv_conf_read(void)
1139 {
1140     dict_t conf_node;
1141     const char *str;
1142
1143     str = "modules/hostserv";
1144     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1145         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1146         return;
1147     }
1148
1149     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1150     if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
1151         //nick changed
1152     }
1153     hostserv_conf.nick = str;
1154     
1155     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1156     hostserv_conf.modes = (str ? str : NULL);
1157     
1158     str = database_get_data(conf_node, "toplevel_access", RECDB_QSTRING);
1159     unsigned int toplevel_access = atoi(str);
1160     hostserv_conf.toplevel_access = (toplevel_access ? toplevel_access : 600);
1161     
1162     /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
1163     hostserv_conf.description = (str ? str : NULL);*/
1164     str = database_get_data(conf_node, KEY_TITLEHOST_SUFFIX, RECDB_QSTRING);
1165     title_suffix = str ? str : "example.net";
1166 }
1167
1168 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra));
1169 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra));
1170
1171 static int hostserv_saxdb_read_toplevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1172     struct record_data *rd = data;
1173     struct hs_toplevel *tlfh;
1174     struct hs_manager *managerTL;
1175     struct hs_user *user;
1176     struct dict *object;
1177
1178      if (rd->type == RECDB_OBJECT) {
1179         dict_t db = GET_RECORD_OBJECT(rd);
1180         dict_iterator_t it;
1181         
1182         tlfh = hs_add_toplevel(name);
1183         
1184         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1185             for (it = dict_first(object); it; it = iter_next(it)) {
1186                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1187                 //rd = iter_data(it);
1188                 /* nothing in here, yet */
1189                 managerTL = hs_add_manager_toplevel(tlfh, user);
1190                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1191                     managerTL->active = 1;
1192                 else
1193                     managerTL->active = 0;
1194             }
1195         }
1196         
1197         if ((object = database_get_data(db, KEY_SECONDLEVEL, RECDB_OBJECT)))
1198             dict_foreach(object, hostserv_saxdb_read_secondlevel, tlfh);
1199     }
1200     return 0;
1201 }
1202
1203 static int hostserv_saxdb_read_secondlevel(const char *name, void *data, UNUSED_ARG(void *extra)) {
1204     struct record_data *rd = data;
1205     struct hs_toplevel *tlfh = extra;
1206     struct hs_secondlevel *slfh;
1207     struct hs_manager *managerSL;
1208     struct hs_user *user;
1209     struct dict *object;
1210
1211     if (rd->type == RECDB_OBJECT) {
1212         dict_t db = GET_RECORD_OBJECT(rd);
1213         dict_iterator_t it;
1214         
1215         slfh = hs_add_secondlevel(tlfh, name);
1216         
1217         if ((object = database_get_data(db, KEY_MANAGERS, RECDB_OBJECT))) {
1218             for (it = dict_first(object); it; it = iter_next(it)) {
1219                 user = hs_get_user(get_handle_info(iter_key(it)), 1);
1220                 //rd = iter_data(it);
1221                 /* nothing in here, yet */
1222                 managerSL = hs_add_manager_secondlevel(slfh, user);
1223                 if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1224                     managerSL->active = 1;
1225                 else
1226                     managerSL->active = 0;
1227             }
1228         }
1229         
1230         if ((object = database_get_data(db, KEY_ASSIGNMENTS, RECDB_OBJECT)))
1231             dict_foreach(object, hostserv_saxdb_read_assignments, slfh);
1232     }
1233     return 0;
1234 }
1235
1236 static int hostserv_saxdb_read_assignments(const char *name, void *data, UNUSED_ARG(void *extra)) {
1237     struct record_data *rd = data;
1238     struct hs_secondlevel *slfh = extra;
1239     struct hs_user *user;
1240     struct hs_assignment *assng;
1241     
1242     if (rd->type == RECDB_OBJECT) {
1243         dict_t db = GET_RECORD_OBJECT(rd);
1244         
1245         user = hs_get_user(get_handle_info(name), 1);
1246         assng = hs_add_assignment(slfh, user);
1247         
1248         if (database_get_data(db, KEY_ACTIVE, RECDB_QSTRING))
1249             assng->active = 1;
1250         else
1251             assng->active = 0;
1252     }
1253     
1254     return 0;
1255 }
1256
1257 static int
1258 hostserv_saxdb_read(struct dict *db)
1259 {
1260     struct dict *object;
1261
1262     if ((object = database_get_data(db, KEY_TOPLEVEL, RECDB_OBJECT)))
1263         dict_foreach(object, hostserv_saxdb_read_toplevel, NULL);
1264
1265     return 1;
1266 }
1267
1268 static int
1269 hostserv_saxdb_write(struct saxdb_context *ctx)
1270 {
1271     struct hs_toplevel *tlfh;
1272     struct hs_secondlevel *slfh;
1273     struct hs_assignment *assng;
1274     struct hs_manager *manager;
1275
1276     saxdb_start_record(ctx, KEY_TOPLEVEL, 1);
1277     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
1278         saxdb_start_record(ctx, tlfh->fakehost, 1);
1279         
1280         saxdb_start_record(ctx, KEY_MANAGERS, 1);
1281         for(manager = tlfh->managers; manager; manager = manager->next) {
1282             saxdb_start_record(ctx, manager->user->hi->handle, 0);
1283             //additional manager information?
1284             if(manager->active)
1285                 saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1286             saxdb_end_record(ctx);
1287         }
1288         saxdb_end_record(ctx);
1289         
1290         saxdb_start_record(ctx, KEY_SECONDLEVEL, 1);
1291         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
1292             saxdb_start_record(ctx, slfh->fakehost, 1);
1293             
1294             saxdb_start_record(ctx, KEY_MANAGERS, 1);
1295             for(manager = slfh->managers; manager; manager = manager->next) {
1296                 saxdb_start_record(ctx, manager->user->hi->handle, 0);
1297                 //additional manager information?
1298                 if(manager->active)
1299                     saxdb_write_int(ctx, KEY_ACTIVE, manager->active);
1300                 saxdb_end_record(ctx);
1301             }
1302             saxdb_end_record(ctx);
1303             
1304             saxdb_start_record(ctx, KEY_ASSIGNMENTS, 1);
1305             for(assng = slfh->assignments; assng; assng = assng->next) {
1306                 saxdb_start_record(ctx, assng->user->hi->handle, 0);
1307                 //additional assignment information?
1308                 if(assng->active)
1309                     saxdb_write_int(ctx, KEY_ACTIVE, assng->active);
1310                 saxdb_end_record(ctx);
1311             }
1312             saxdb_end_record(ctx);
1313             
1314             saxdb_end_record(ctx);
1315         }
1316         saxdb_end_record(ctx);
1317         
1318         saxdb_end_record(ctx);
1319     }
1320     saxdb_end_record(ctx);
1321     
1322     return 0;
1323 }
1324
1325
1326 static void hostserv_db_cleanup(void) {
1327     hs_free_all();
1328 }
1329
1330 int hostserv_init() {
1331     HS_LOG = log_register_type("HostServ", "file:hostserv.log");
1332     
1333     const char *nick, *modes;
1334     if((nick = conf_get_data("modules/hostserv/nick", RECDB_QSTRING))) {
1335         modes = conf_get_data("modules/hostserv/modes", RECDB_QSTRING);
1336         hostserv = AddLocalUser(nick, nick, NULL, "Host Service", modes);
1337         hostserv_service = service_register(hostserv);
1338         hostserv_service->trigger = '*';
1339     }
1340         
1341     conf_register_reload(hostserv_conf_read);
1342     reg_exit_func(hostserv_db_cleanup);
1343     saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
1344     hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
1345     modcmd_register(hostserv_module, "view", cmd_view, 0, MODCMD_REQUIRE_AUTHED, NULL);
1346     modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1347     modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 3, MODCMD_REQUIRE_AUTHED, NULL);
1348     modcmd_register(hostserv_module, "set", cmd_set, 2, MODCMD_REQUIRE_AUTHED, NULL);
1349     modcmd_register(hostserv_module, "assign", cmd_assign, 3, MODCMD_REQUIRE_AUTHED, NULL);
1350     modcmd_register(hostserv_module, "revoke", cmd_revoke, 3, MODCMD_REQUIRE_AUTHED, NULL);
1351     modcmd_register(hostserv_module, "addhost", cmd_addhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1352     modcmd_register(hostserv_module, "delhost", cmd_delhost, 2, MODCMD_REQUIRE_AUTHED, NULL);
1353     message_register_table(msgtab);
1354     return 1;
1355 }
1356
1357 int hostserv_finalize(void) {
1358     dict_t conf_node;
1359     const char *str;
1360
1361     str = "modules/hostserv";
1362     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
1363         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
1364         return 0;
1365     }
1366
1367     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
1368     if (str) hostserv_conf.nick = str;
1369     
1370     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
1371     if (str) hostserv_conf.modes = str; 
1372     return 1;
1373 }