d97ed83fceaaa304e84aa6f7e8257b32d753cadc
[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_TOPLEVEL_FAKEHOSTS", "Fakehosts in group $b*.%s$b:" },
62     { "HSMSG_TOPLEVEL_FAKEHOST", "  $b%s.%s$b   assignments: %d   managers: %d" },
63     { "HSMSG_TOPLEVEL_INVALID", "The name of the group you entered is invalid ($b%s$b)" },
64     { "HSMSG_MANAGERS_TOPLEVEL", "Managers of group $b*.%s$b:" },
65     { "HSMSG_MANAGERS_FAKEHOST", "Managers of group $b%s.%s$b:" },
66     { "HSMSG_MANAGERS_MANAGERS", "  %s" },
67     { "HSMSG_FAKEHOST_ASSIGNMENTS", "Assignments in group $b%s.%s$b:" },
68     { "HSMSG_FAKEHOST_ASSIGNMENT", "  $b%s$b (%s.%s.%s)" },
69     { "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE", "  $b%s$b (%s.%s.%s)   active" },
70     { "HSMSG_FAKEHOST_SET_SUCCESS", "$b%s.%s$b where set successfully." },
71     { "HSMSG_FAKEHOST_TOPLEVEL_ADDED", "Group $b%s$b successfully added." },
72     { "HSMSG_FAKEHOST_TOPLEVEL_ALREADY_EXISTS", "Group $b%s$b already exists." },
73     { "HSMSG_FAKEHOST_TOPLEVEL_DELETED", "Group $b%s$b successfully deleted." },
74     { "HSMSG_FAKEHOST_SECONDLEVEL_ADDED", "Group $b%s.%s$b successfully added." },
75     { "HSMSG_FAKEHOST_SECONDLEVEL_ALREADY_EXISTS", "Group $b%s.%s$b already exists." },
76     { "HSMSG_FAKEHOST_SECONDLEVEL_DELETED", "Group $b%s.%s$b successfully deleted." },
77     { "HSMSG_MANAGER_ALREADY", "$b%s$b is already a manager of %s.%s" },
78     { "HSMSG_MANAGER_ADDED", "$b%s$b is now a manager of %s.%s" },
79     { "HSMSG_MANAGER_NOT", "$b%s$b is not a manager of %s.%s" },
80     { "HSMSG_MANAGER_DELETED", "$b%s$b is no longer a manager of %s.%s" },
81     { "HSMSG_FAKEHOST_ASSIGN_SUCCESS", "Group $b%s.%s$b was assigned successfully." },
82     { "HSMSG_FAKEHOST_REVOKE_SUCCESS", "Group $b%s.%s$b was revoked successfully." },
83     
84     { NULL, NULL }
85 };
86
87 static struct {
88     const char *nick;
89     const char *modes;
90     int toplevel_access;
91 } hostserv_conf;
92
93 const char *hostserv_module_deps[] = { NULL };
94 struct userNode *hostserv;
95 struct helpfile *hostserv_helpfile;
96 static struct module *hostserv_module;
97 static struct service *hostserv_service;
98 static struct log_type *HS_LOG;
99 static struct hs_toplevel *toplevels = NULL;
100 static struct hs_user *hostserv_users = NULL;
101 const char *title_suffix = NULL;
102
103 /* FAKEHOST STRUCTS */
104 struct hs_toplevel {
105     char *fakehost;
106     struct hs_manager *managers;
107     struct hs_secondlevel *secondlevel;
108     struct hs_toplevel *next;
109 };
110
111 struct hs_secondlevel {
112     struct hs_toplevel *toplevel;
113     char *fakehost;
114     struct hs_manager *managers;
115     struct hs_assignment *assignments;
116     struct hs_secondlevel *next;
117 };
118
119 struct hs_assignment {
120     struct hs_secondlevel *secondlevel;
121     struct hs_user *user;
122     int active;
123     struct hs_assignment *next;
124     struct hs_assignment *unext; /* for hs_user */
125 };
126
127 struct hs_manager {
128     char type;
129     void *object;
130     int active;
131     struct hs_user *user;
132     struct hs_manager *next;
133     struct hs_manager *unext; /* for hs_user */
134 };
135
136 struct hs_user {
137     struct handle_info *hi;
138     struct hs_assignment *assignments;
139     struct hs_manager *managements;
140     struct hs_user *next;
141 };
142
143 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
144 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
145 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
146 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
147 static void hs_del_user(struct hs_user *user);
148
149 static void apply_fakehost(struct handle_info *handle, struct userNode *user);
150
151 static char *
152 generate_fakehost(struct handle_info *handle)
153 {
154     extern const char *hidden_host_suffix;
155     static char buffer[HOSTLEN+1];
156
157     if (!handle->fakehost) {
158         snprintf(buffer, sizeof(buffer), "%s.%s", handle->handle, hidden_host_suffix);
159         return buffer;
160     } else if (handle->fakehost[0] == '.') {
161         /* A leading dot indicates the stored value is actually a title. */
162         snprintf(buffer, sizeof(buffer), "%s.%s.%s", handle->handle, handle->fakehost+1, title_suffix);
163         return buffer;
164     } else if (handle->fakehost[0] == '$') {
165         /* A leading $ indicates the stored value begins with the user handle. */
166         snprintf(buffer, sizeof(buffer), "%s%s", handle->handle, handle->fakehost+1);
167         return buffer;
168     }
169     return handle->fakehost;
170 }
171
172 static char *
173 generate_fakeident(struct handle_info *handle, struct userNode *user)
174 {
175     static char buffer[USERLEN+1];
176
177     if (!handle->fakeident) {
178         if (!user)
179             return NULL;
180         safestrncpy(buffer, user->ident, sizeof(buffer));
181         return buffer;
182     }
183     return handle->fakeident;
184 }
185
186 static void
187 apply_fakehost(struct handle_info *handle, struct userNode *user)
188 {
189     struct userNode *target;
190     char *fakehost, *fakeident;
191
192     if (!handle->users)
193         return;
194
195     fakehost = generate_fakehost(handle);
196
197     if (user) {
198         fakeident = generate_fakeident(handle, user);
199         assign_fakehost(user, fakehost, fakeident, 0, 1);
200         return;
201     }
202
203     for (target = handle->users; target; target = target->next_authed) {
204         fakeident = generate_fakeident(handle, target);
205         assign_fakehost(target, fakehost, fakeident, 0, 1);
206     }
207     return;
208 }
209
210 static void hs_free_all() {
211     struct hs_toplevel *tlfh, *next_tlfh;
212     struct hs_secondlevel *slfh, *next_slfh;
213     struct hs_assignment *assng, *next_assng;
214     struct hs_manager *manager, *next_manager;
215     struct hs_user *user, *next_user;
216     for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
217         next_tlfh = tlfh->next;
218         for(manager = tlfh->managers; manager; manager = next_manager) {
219             next_manager = manager->next;
220             free(manager);
221         }
222         for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
223             next_slfh = slfh->next;
224             for(manager = tlfh->managers; manager; manager = next_manager) {
225                 next_manager = manager->next;
226                 free(manager);
227             }
228             for(assng = slfh->assignments; assng; assng = next_assng) {
229                 next_assng = assng->next;
230                 free(assng);
231             }
232             free(slfh->fakehost);
233             free(slfh);
234         }
235         free(tlfh->fakehost);
236         free(tlfh);
237     }
238     for(user = hostserv_users; user; user = next_user) {
239         next_user = user->next;
240         free(user);
241     }
242     toplevels = NULL;
243     hostserv_users = NULL;
244 }
245
246 static struct hs_toplevel *hs_add_toplevel(const char *name) {
247     struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
248     tlfh->fakehost = strdup(name);
249     tlfh->next = toplevels;
250     toplevels = tlfh;
251     return tlfh;
252 }
253
254 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
255     //unassign all assignments
256     struct hs_secondlevel *slfh, *next_slfh;
257     struct hs_manager *manager, *next_manager;
258     for(manager = tlfh->managers; manager; manager = next_manager) {
259         next_manager = manager->next;
260         hs_del_manager(manager, 0);
261     }
262     for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
263         next_slfh = slfh->next;
264         hs_del_secondlevel(slfh, 0);
265     }
266     
267     struct hs_toplevel *ctlfh, *last_tlfh = NULL;
268     for(ctlfh = toplevels; ctlfh; ctlfh = ctlfh->next) {
269         if(ctlfh == tlfh) {
270             if(last_tlfh)
271                 last_tlfh->next = ctlfh->next;
272             else
273                 toplevels = ctlfh->next;
274         } else
275             last_tlfh = ctlfh;
276     }
277     free(tlfh->fakehost);
278     free(tlfh);
279 }
280
281 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, const char *name) {
282     struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
283     slfh->toplevel = tlfh;
284     slfh->fakehost = strdup(name);
285     slfh->next = tlfh->secondlevel;
286     tlfh->secondlevel = slfh;
287     return slfh;
288 }
289
290 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
291     if(remove_from_tlfh) {
292         struct hs_secondlevel *cslfh, *prev_slfh = NULL;
293         for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
294             if(cslfh == slfh) {
295                 if(prev_slfh)
296                     prev_slfh->next = slfh->next;
297                 else
298                     slfh->toplevel->secondlevel = slfh->next;
299                 break;
300             } else
301                 prev_slfh = cslfh;
302         }
303     }
304     struct hs_assignment *assng, *next_assng;
305     struct hs_manager *manager, *next_manager;
306     for(manager = slfh->managers; manager; manager = next_manager) {
307         next_manager = manager->next;
308         hs_del_manager(manager, 0);
309     }
310     for(assng = slfh->assignments; assng; assng = next_assng) {
311         next_assng = assng->next;
312         hs_del_assignment(assng, 0);
313     }
314     free(slfh->fakehost);
315     free(slfh);
316 }
317
318 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
319     struct hs_manager *manager = calloc(1, sizeof(*manager));
320     manager->user = user;
321     manager->type = 1;
322     manager->object = tlfh;
323     manager->unext = user->managements;
324     user->managements = manager;
325     manager->next = tlfh->managers;
326     tlfh->managers = manager;
327     return manager;
328 }
329
330 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
331     struct hs_manager *manager = calloc(1, sizeof(*manager));
332     manager->user = user;
333     manager->type = 2;
334     manager->object = slfh;
335     manager->unext = user->managements;
336     user->managements = manager;
337     manager->next = slfh->managers;
338     slfh->managers = manager;
339     return manager;
340 }
341
342 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
343     struct hs_manager *cmanager, *prev_manager = NULL;
344     if(remove_from_object) {
345         if(manager->type == 1) {
346             struct hs_toplevel *tlfh = manager->object;
347             for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
348                 if(cmanager == manager) {
349                     if(prev_manager)
350                         prev_manager->next = manager->next;
351                     else
352                         tlfh->managers = manager->next;
353                     break;
354                 } else
355                     prev_manager = cmanager;
356             }
357         } else if(manager->type == 2) {
358             struct hs_secondlevel *slfh = manager->object;
359             for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
360                 if(cmanager == manager) {
361                     if(prev_manager)
362                         prev_manager->next = manager->next;
363                     else
364                         slfh->managers = manager->next;
365                     break;
366                 } else
367                     prev_manager = cmanager;
368             }
369         }
370         prev_manager = NULL;
371     }
372     if(remove_from_object != 2) {
373         for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
374             if(cmanager == manager) {
375                 if(prev_manager)
376                     prev_manager->unext = manager->unext;
377                 else
378                     manager->user->managements = manager->unext;
379                 break;
380             } else
381                 prev_manager = cmanager;
382         }
383         if(manager->user->managements == NULL && manager->user->assignments == NULL)
384             hs_del_user(manager->user);
385     }
386     free(manager);
387 }
388
389 static void activateAssignment(struct hs_assignment *assignment) {
390     struct hs_toplevel *tlfh;
391     struct hs_secondlevel *slfh;
392     struct hs_user *hs_user;
393     struct hs_assignment *assgn;
394     char fakehost[140];
395     char *prefix = "$";
396     
397     hs_user = assignment->user;
398     if(hs_user->assignments) {
399         for(assgn = hs_user->assignments; assgn; assgn = assgn->unext) {
400             assgn->active = 0;
401         }
402     }
403     slfh = assignment->secondlevel;
404     tlfh = slfh->toplevel;
405     sprintf(fakehost, "%s.%s.%s", prefix, slfh->fakehost, tlfh->fakehost);
406     hs_user->hi->fakehost = strdup(fakehost);
407     apply_fakehost(hs_user->hi, NULL);
408     assignment->active = 1;
409 }
410
411 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
412     struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
413     assignment->secondlevel = slfh;
414     assignment->user = user;
415     if(user->assignments == NULL)
416         assignment->active = 1;
417     assignment->next = slfh->assignments;
418     slfh->assignments = assignment;
419     assignment->unext = user->assignments;
420     user->assignments = assignment;
421     if(assignment->active) {
422         activateAssignment(assignment);
423     }
424     return assignment;
425 }
426
427 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
428     struct hs_assignment *cassignment, *prev_assignment = NULL;
429     if(remove_from_slfh) {
430         for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
431             if(cassignment == assignment) {
432                 if(prev_assignment)
433                     prev_assignment->next = assignment->next;
434                 else
435                     assignment->secondlevel->assignments = assignment->next;
436                 break;
437             } else
438                 prev_assignment = cassignment;
439         }
440         prev_assignment = NULL;
441     }
442     if(remove_from_slfh != 2) {
443         prev_assignment = NULL;
444         for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
445             if(cassignment == assignment) {
446                 if(prev_assignment)
447                     prev_assignment->unext = assignment->unext;
448                 else
449                     assignment->user->assignments = assignment->unext;
450                 break;
451             } else
452                 prev_assignment = cassignment;
453         }
454         
455         if(assignment->active) {
456             struct handle_info *hi;
457             
458             hi = assignment->user->hi;
459             hi->fakehost = NULL;
460             apply_fakehost(hi, NULL);
461         }
462         
463         if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
464             hs_del_user(assignment->user);
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(hiuser, 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 }