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