a66c91dd29e38f1e0739ba2d6ea43b41c36a4467
[srvx.git] / src / mod-hostserv.c
1 /* mod-hostserv.c - HostServ module for srvx
2  * Copyright 2003-2004 Martijn Smit and srvx Development Team
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 "managers"
44 #define KEY_FAKEHOST "fakehost"
45 #define KEY_ASSIGNMENTS "assignments"
46
47 static const struct message_entry msgtab[] = {
48     { "HSMSG_ASSIGNED_FAKEHOSTS", "Assigned Fakehosts for User $b%s$b:" },
49     { "HSMSG_ASSIGNED_FAKEHOST", "  $b%s.%s$b" },
50     { "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE", "  $b%s.%s$b (active)" },
51     { "HSMSG_ASSIGN_HOWTO", "Use $bassign xxx.yyy$b to activate one of the listed fakehosts or $bassign *$b to use the default fakehost." },
52     { "HSMSG_ASSIGNED_NONE", "  None." },
53     { "HSMSG_MANAGED_FAKEHOSTS", "Fakehosts managed by User $b%s$b:" },
54     { "HSMSG_MANAGED_TOPLEVEL", "  $b*.%s$b   fakehosts: %d   assignments: %d" },
55     { "HSMSG_MANAGED_FAKEHOST", "  $b%s.%s$b   assignments: %d" },
56     { "HSMSG_MANAGE_HOWTO", "Use $bview xxx.yyy$b to view more information about a fakehost group." },
57     { "HSMSG_UNKNOWN_FAKEHOST", "Fakehost $b%s.%s$b is unknown or you have no access to manage it." },
58     { "HSMSG_TOPLEVEL_FAKEHOSTS", "Fakehosts in group $b*.%s$b:" },
59     { "HSMSG_TOPLEVEL_FAKEHOST", "  $b%s.%s$b   assignments: %d   managers: %d" },
60     { "HSMSG_MANAGERS_TOPLEVEL", "Managers of group $b*.%s$b:" },
61     { "HSMSG_MANAGERS_FAKEHOST", "Managers of group $b%s.%s$b:" },
62     { "HSMSG_MANAGERS_MANAGERS", "  %s" },
63     { "HSMSG_FAKEHOST_ASSIGNMENTS", "Assignments in group $b%s.%s$b:" },
64     { "HSMSG_FAKEHOST_ASSIGNMENT", "  $b%s$b (%s.%s.%s)" },
65     { "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE", "  $b%s$b (%s.%s.%s)   active" },
66     { "HSMSG_MANAGER_ALREADY", "$b%s$b is already a manager of %s.%s" },
67     { "HSMSG_MANAGER_ADDED", "$b%s$b is now a manager of %s.%s" },
68     { "HSMSG_MANAGER_NOT", "$b%s$b is not a manager of %s.%s" },
69     
70     { NULL, NULL }
71 };
72
73 static struct {
74     const char *nick;
75     const char *modes;
76     int toplevel_access;
77 } hostserv_conf;
78
79 const char *hostserv_module_deps[] = { NULL };
80 struct userNode *hostserv;
81 struct helpfile *hostserv_helpfile;
82 static struct module *hostserv_module;
83 static struct service *hostserv_service;
84 static dict_t hostserv_func_dict;
85 static int shutting_down;
86 static FILE *reqlog_f;
87 static struct log_type *HS_LOG;
88 static struct hs_toplevel *toplevels = NULL;
89 static struct hs_user *hostserv_users = NULL;
90
91 /* FAKEHOST STRUCTS */
92 struct hs_toplevel {
93     char *fakehost;
94     struct hs_manager *managers;
95     struct hs_secondlevel *secondlevel;
96     struct hs_toplevel *next;
97 };
98
99 struct hs_secondlevel {
100     struct hs_toplevel *toplevel;
101     char *fakehost;
102     struct hs_manager *managers;
103     struct hs_assignment *assignments;
104     struct hs_secondlevel *next;
105 };
106
107 struct hs_assignment {
108     struct hs_secondlevel *secondlevel;
109     struct hs_user *user;
110     int active;
111     struct hs_assignment *next;
112     struct hs_assignment *unext; /* for hs_user */
113 };
114
115 struct hs_manager {
116     char type;
117     void *object;
118     struct hs_user *user;
119     struct hs_manager *next;
120     struct hs_manager *unext; /* for hs_user */
121 };
122
123 struct hs_user {
124     struct handle_info *hi;
125     struct hs_assignment *assignments;
126     struct hs_manager *managements;
127     struct hs_user *next;
128 };
129
130 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
131 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
132 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
133 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
134 static void hs_del_user(struct hs_user *user);
135
136 static void hs_free_all() {
137     struct hs_toplevel *tlfh, *next_tlfh;
138     struct hs_secondlevel *slfh, *next_slfh;
139     struct hs_assignment *assng, *next_assng;
140     struct hs_manager *manager, *next_manager;
141     struct hs_user *user, *next_user;
142     for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
143         next_tlfh = tlfh->next;
144         for(manager = tlfh->managers; manager; manager = next_manager) {
145             next_manager = manager->next;
146             free(manager);
147         }
148         for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
149             next_slfh = slfh->next;
150             for(manager = tlfh->managers; manager; manager = next_manager) {
151                 next_manager = manager->next;
152                 free(manager);
153             }
154             for(assng = slfh->assignments; assng; assng = next_assng) {
155                 next_assng = assng->next;
156                 free(assng);
157             }
158             free(slfh->fakehost);
159             free(slfh);
160         }
161         free(tlfh->fakehost);
162         free(tlfh);
163     }
164     for(user = hostserv_users; user; user = next_user) {
165         next_user = user->next;
166         free(user);
167     }
168     toplevels = NULL;
169     hostserv_users = NULL;
170 }
171
172 static struct hs_toplevel *hs_add_toplevel(char *name) {
173     struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
174     tlfh->fakehost = strdup(name);
175     tlfh->next = toplevels;
176     toplevels = tlfh;
177     return tlfh;
178 }
179
180 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
181     //unassign all assignments
182     struct hs_secondlevel *slfh, *next_slfh;
183     struct hs_manager *manager, *next_manager;
184     for(manager = tlfh->managers; manager; manager = next_manager) {
185         next_manager = manager->next;
186         hs_del_manager(manager, 0);
187     }
188     for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
189         next_slfh = slfh->next;
190         hs_del_secondlevel(slfh, 0);
191     }
192     free(tlfh->fakehost);
193     free(tlfh);
194 }
195
196 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, char *name) {
197     struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
198     slfh->toplevel = tlfh;
199     slfh->fakehost = strdup(name);
200     slfh->next = tlfh->secondlevel;
201     tlfh->secondlevel = slfh;
202     return slfh;
203 }
204
205 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
206     if(remove_from_tlfh) {
207         struct hs_secondlevel *cslfh, *prev_slfh = NULL;
208         for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
209             if(cslfh == slfh) {
210                 if(prev_slfh)
211                     prev_slfh->next = slfh->next;
212                 else
213                     slfh->toplevel->secondlevel = slfh->next;
214                 break;
215             } else
216                 prev_slfh = cslfh;
217         }
218     }
219     struct hs_assignment *assng, *next_assng;
220     struct hs_manager *manager, *next_manager;
221     for(manager = slfh->managers; manager; manager = next_manager) {
222         next_manager = manager->next;
223         hs_del_manager(manager, 0);
224     }
225     for(assng = slfh->assignments; assng; assng = next_assng) {
226         next_assng = assng->next;
227         hs_del_assignment(assng, 0);
228     }
229     free(slfh->fakehost);
230     free(slfh);
231 }
232
233 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
234     struct hs_manager *manager = calloc(1, sizeof(*manager));
235     manager->user = user;
236     manager->type = 1;
237     manager->object = tlfh;
238     manager->unext = user->managements;
239     user->managements = manager;
240     manager->next = tlfh->managers;
241     tlfh->managers = manager;
242     return manager;
243 }
244
245 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
246     struct hs_manager *manager = calloc(1, sizeof(*manager));
247     manager->user = user;
248     manager->type = 2;
249     manager->object = slfh;
250     manager->unext = user->managements;
251     user->managements = manager;
252     manager->next = slfh->managers;
253     slfh->managers = manager;
254     return manager;
255 }
256
257 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
258     struct hs_manager *cmanager, *prev_manager = NULL;
259     if(remove_from_object) {
260         if(manager->type == 1) {
261             struct hs_toplevel *tlfh = manager->object;
262             for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
263                 if(cmanager == manager) {
264                     if(prev_manager)
265                         prev_manager->next = manager->next;
266                     else
267                         tlfh->managers = manager->next;
268                     break;
269                 } else
270                     prev_manager = cmanager;
271             }
272         } else if(manager->type == 2) {
273             struct hs_secondlevel *slfh = manager->object;
274             for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
275                 if(cmanager == manager) {
276                     if(prev_manager)
277                         prev_manager->next = manager->next;
278                     else
279                         slfh->managers = manager->next;
280                     break;
281                 } else
282                     prev_manager = cmanager;
283             }
284         }
285         prev_manager = NULL;
286     }
287     if(remove_from_object != 2) {
288         for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
289             if(cmanager == manager) {
290                 if(prev_manager)
291                     prev_manager->unext = manager->unext;
292                 else
293                     manager->user->managements = manager->unext;
294                 break;
295             } else
296                 prev_manager = cmanager;
297         }
298         if(manager->user->managements == NULL && manager->user->assignments == NULL)
299             hs_del_user(manager->user);
300     }
301     free(manager);
302 }
303
304 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
305     struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
306     assignment->secondlevel = slfh;
307     assignment->user = user;
308     if(user->assignments == NULL)
309         assignment->active = 1;
310     assignment->next = slfh->assignments;
311     slfh->assignments = assignment;
312     assignment->unext = user->assignments;
313     user->assignments = assignment;
314     if(assignment->active) {
315         /* use this assignment */
316     }
317     return assignment;
318 }
319
320 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
321     struct hs_assignment *cassignment, *prev_assignment = NULL;
322     if(remove_from_slfh) {
323         for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
324             if(cassignment == assignment) {
325                 if(prev_assignment)
326                     prev_assignment->next = assignment->next;
327                 else
328                     assignment->secondlevel->assignments = assignment->next;
329                 break;
330             } else
331                 prev_assignment = cassignment;
332         }
333         prev_assignment = NULL;
334     }
335     if(remove_from_slfh != 2) {
336         for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
337             if(cassignment == assignment) {
338                 if(prev_assignment)
339                     prev_assignment->unext = assignment->unext;
340                 else
341                     assignment->user->assignments = assignment->unext;
342                 break;
343             } else
344                 prev_assignment = cassignment;
345         }
346         if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
347             hs_del_user(assignment->user);
348         if(assignment->active) {
349             /* use other assignment */
350         }
351     }
352     free(assignment);
353 }
354
355 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
356     struct hs_user *cuser;
357     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
358         if(cuser->hi == hi)
359             return cuser;
360     }
361     if(create) {
362         cuser = calloc(1, sizeof(*cuser));
363         cuser->hi = hi;
364         cuser->next = hostserv_users;
365         hostserv_users = cuser;
366         return cuser;
367     } else
368         return NULL;
369 }
370
371 static void hs_del_user(struct hs_user *user) {
372     if(user->managements) {
373         struct hs_manager *manager, *next_manager;
374         for(manager = user->managements; manager; manager = next_manager) {
375             next_manager = manager->unext;
376             hs_del_manager(manager, 2);
377         }
378     }
379     if(user->assignments) {
380         struct hs_assignment *assng, *next_assng;
381         for(assng = user->assignments; assng; assng = next_assng) {
382             next_assng = assng->unext;
383             hs_del_assignment(assng, 2);
384         }
385     }
386     struct hs_user *cuser, *prev_user = NULL;
387     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
388         if(cuser == user) {
389             if(prev_user)
390                 prev_user->next = user->next;
391             else
392                 hostserv_users = user->next;
393             break;
394         } else
395             prev_user = cuser;
396     }
397     free(user);
398 }
399
400 /* END OF MANAGEMENT FUNCTIONS */
401
402 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_secondlevel *slfh) {
403     tlfh = NULL;
404         if(!hi) 
405         return 0;
406     if(hi->opserv_level >= hostserv_conf.toplevel_access) 
407         return 1;
408     struct hs_user *user = hs_get_user(hi, 0);
409     if(!user)
410         return 0;
411     struct hs_manager *manager;
412     if(slfh) {
413         for(manager = user->managements; manager; manager = manager->next) {
414             if(manager->type == 2 && manager->object == slfh) 
415                 return 1;
416         }
417     }
418     for(manager = user->managements; manager; manager = manager->next) {
419         if(manager->type == 1 && manager->object == slfh) 
420             return 1;
421     }
422     return 0;
423 }
424
425
426 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
427     reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
428     struct hs_secondlevel *slfh;
429     if(!tlfh->secondlevel)
430         reply("HSMSG_ASSIGNED_NONE");
431     else
432     for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
433         struct hs_manager *cmanager;
434         int managers = 0;
435         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
436             managers++;
437         struct hs_assignment *assignment;
438         int assignments = 0;
439         for(assignment = slfh->assignments; assignment; assignment = assignment->next)
440             assignments++;
441         reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
442     }
443     reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
444     struct hs_manager *cmanager;
445     if(!tlfh->managers)
446         reply("HSMSG_ASSIGNED_NONE");
447     else {
448         char managerBuf[351];
449         int managerPos = 0;
450         for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
451             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
452                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
453                 managerPos = 0;
454             }
455             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
456         }
457         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
458     }
459 }
460
461 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
462     reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
463     struct hs_assignment *assignment;
464     for(assignment = slfh->assignments; assignment; assignment = assignment->next) {
465         reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
466     }
467     reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
468     struct hs_manager *cmanager;
469     if(!slfh->managers)
470         reply("HSMSG_ASSIGNED_NONE");
471     else {
472         char managerBuf[351];
473         int managerPos = 0;
474         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
475             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
476                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
477                 managerPos = 0;
478             }
479             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
480         }
481         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
482     }
483 }
484
485
486 static MODCMD_FUNC(cmd_view) {
487     struct handle_info *hi;
488     if(argc >= 2 && !strchr(argv[1], '.')) {
489         if (!(hi = modcmd_get_handle_info(user, argv[1])))
490             return 0;
491     } else if(argc >= 2) {
492         if (!(hi = user->handle_info)) {
493             reply("NSMSG_MUST_AUTH");
494             return 0;
495         }
496         char *slfh_name = argv[1];
497         char *tlfh_name = strchr(argv[1], '.');
498         *tlfh_name = '\0';
499         tlfh_name++;
500         if(strchr(tlfh_name, '.')) {
501             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
502             return 0;
503         }
504         struct hs_toplevel *tlfh;
505         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
506             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
507         }
508         if(!tlfh) {
509             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
510             return 0;
511         }
512         if(!irccasecmp(slfh_name, "*")) {
513             if(!check_management_access(hi, tlfh, NULL)) {
514                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
515                 return 0;
516             }
517             cmd_view_toplevel_information(user, cmd, tlfh);
518             return 1;
519         } else {
520             struct hs_secondlevel *slfh;
521             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
522                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
523             }
524             if(!slfh || !check_management_access(hi, tlfh, slfh)) {
525                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
526                 return 0;
527             }
528             cmd_view_secondlevel_information(user, cmd, slfh);
529             return 1;
530         }
531     } else {
532         if (!(hi = user->handle_info)) {
533             reply("NSMSG_MUST_AUTH");
534             return 0;
535         }
536     }
537     struct hs_user *huser = hs_get_user(hi, 0);
538     reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
539     int assigncount = 0;
540     if(huser) {
541         struct hs_assignment *assignment;
542         for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
543             reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
544             assigncount++;
545         }
546         if(assigncount && huser->hi == user->handle_info)
547             reply("HSMSG_ASSIGN_HOWTO");
548     }
549     if(!assigncount)
550         reply("HSMSG_ASSIGNED_NONE");
551     if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
552         struct hs_toplevel *tlfh;
553         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
554             struct hs_secondlevel *slfh;
555             struct hs_assignment *assignment;
556             int slfhs = 0, assignments = 0;
557             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
558                 slfhs++;
559                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
560                     assignments++;
561             }
562             reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
563         }
564         reply("HSMSG_MANAGE_HOWTO");
565     } else if(huser && huser->managements) {
566         reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
567         struct hs_manager *manager;
568         for(manager = huser->managements; manager; manager = manager->next) {
569             if(manager->type == 1) {
570                 struct hs_toplevel *tlfh = manager->object;
571                 struct hs_secondlevel *slfh;
572                 struct hs_assignment *assignment;
573                 int slfhs = 0, assignments = 0;
574                 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
575                     slfhs++;
576                     for(assignment = slfh->assignments; assignment; assignment = assignment->next)
577                         assignments++;
578                 }
579                 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
580             }
581         }
582         for(manager = huser->managements; manager; manager = manager->next) {
583             if(manager->type == 2) {
584                 struct hs_secondlevel *slfh = manager->object;
585                 struct hs_toplevel *tlfh = slfh->toplevel;
586                 //check if the user is already a manager of the tlfh
587                 struct hs_manager *cmanager;
588                 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
589                     if(cmanager->user == huser) break;
590                 }
591                 if(cmanager) continue;
592                 struct hs_assignment *assignment;
593                 int assignments = 0;
594                 for(assignment = slfh->assignments; assignment; assignment = assignment->next)
595                     assignments++;
596                 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
597             }
598         }
599         if(huser->hi == user->handle_info)
600             reply("HSMSG_MANAGE_HOWTO");
601     }
602     return 1;
603 }
604
605 static MODCMD_FUNC(cmd_addmanager) {
606     struct handle_info *hi;
607     char *fakehost;
608     if(argc >= 2) {
609             if(!strchr(argv[1], '.')) {
610                 if (!(hi = modcmd_get_handle_info(user, argv[1])))
611                     return 0;
612                 fakehost = argv[2];
613             } else {
614                 if (!(hi = modcmd_get_handle_info(user, argv[2])))
615                     return 0;
616                 fakehost = argv[1];
617             }
618             char *slfh_name = fakehost;
619             char *tlfh_name = strchr(fakehost, '.');
620             *tlfh_name = '\0';
621             tlfh_name++;
622             if(strchr(tlfh_name, '.')) {
623                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
624                 return 0;
625             }
626             struct hs_toplevel *tlfh;
627             struct hs_secondlevel *slfh = NULL;
628             for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
629                 if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
630             }
631             if(!tlfh) {
632                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
633                 return 0;
634             }
635             if(!irccasecmp(slfh_name, "*")) {
636                 if(!check_management_access(user->handle_info, tlfh, NULL)) {
637                     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
638                     return 0;
639                 }
640             } else {
641                 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
642                     if(!irccasecmp(slfh->fakehost, slfh_name)) break;
643                 }
644                 if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
645                     reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
646                     return 0;
647                 }
648             }
649             struct hs_user *huser = hs_get_user(hi, 1);
650             struct hs_manager *manager;
651             if(slfh) {
652                 for(manager = huser->managements; manager; manager = manager->next) {
653                     if(manager->type == 2 && manager->object == slfh) {
654                         reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
655                         return 0;
656                     }
657                 }
658             }
659             for(manager = huser->managements; manager; manager = manager->next) {
660                 if(manager->type == 1 && manager->object == tlfh) {
661                     reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
662                     return 0;
663                 }
664             }
665             if(slfh)
666                 hs_add_manager_secondlevel(slfh, huser);
667             else
668                 hs_add_manager_toplevel(tlfh, huser);
669             reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
670     }
671 }
672
673 static MODCMD_FUNC(cmd_delmanager) {
674     struct handle_info *hi;
675     char *fakehost;
676     if(!strchr(argv[1], '.')) {
677         if (!(hi = modcmd_get_handle_info(user, argv[1])))
678             return 0;
679         fakehost = argv[2];
680     } else {
681         if (!(hi = modcmd_get_handle_info(user, argv[2])))
682             return 0;
683         fakehost = argv[1];
684     }
685     char *slfh_name = fakehost;
686     char *tlfh_name = strchr(fakehost, '.');
687     *tlfh_name = '\0';
688     tlfh_name++;
689     if(strchr(tlfh_name, '.')) {
690         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
691         return 0;
692     }
693     struct hs_toplevel *tlfh;
694     struct hs_secondlevel *slfh = NULL;
695     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
696         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
697     }
698     if(!tlfh) {
699         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
700         return 0;
701     }
702     if(!irccasecmp(slfh_name, "*")) {
703         if(!check_management_access(user->handle_info, tlfh, NULL)) {
704             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
705             return 0;
706         }
707     } else {
708         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
709             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
710         }
711         if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
712             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
713             return 0;
714         }
715     }
716     struct hs_user *huser = hs_get_user(hi, 0);
717     struct hs_manager *manager;
718     if(!huser) {
719         reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
720         return 0;
721     }
722     if(slfh) {
723         for(manager = huser->managements; manager; manager = manager->next) {
724             if(manager->type == 2 && manager->object == slfh) 
725                 break;
726         }
727         if(!manager) {
728             reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
729             return 0;
730         }
731     } else {
732         for(manager = huser->managements; manager; manager = manager->next) {
733             if(manager->type == 1 && manager->object == tlfh) 
734                 break;
735         }
736         if(!manager) {
737             reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
738             return 0;
739         }
740     }
741     hs_del_manager(manager, 1);
742     reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
743 }
744
745 static int hostserv_saxdb_read(struct dict *conf_db) {
746         return 1;
747 }
748
749 static int hostserv_saxdb_write(struct saxdb_context *ctx) {
750         
751         return 0;
752 }
753
754 static void hostserv_conf_read(void)
755 {
756     dict_t conf_node;
757     const char *str;
758
759     str = "modules/hostserv";
760     if (!(conf_node = conf_get_data(str, RECDB_OBJECT))) {
761         log_module(HS_LOG, LOG_ERROR, "config node `%s' is missing or has wrong type.", str);
762         return;
763     }
764
765     str = database_get_data(conf_node, "nick", RECDB_QSTRING);
766     if(hostserv_conf.nick && strcmp(hostserv_conf.nick, str)) {
767         //nick changed
768     }
769     hostserv_conf.nick = str;
770     
771     str = database_get_data(conf_node, "modes", RECDB_QSTRING);
772     hostserv_conf.modes = (str ? str : NULL);
773     
774     /*str = database_get_data(conf_node, "description", RECDB_QSTRING);
775     hostserv_conf.description = (str ? str : NULL);*/
776 }
777
778 static void hostserv_db_cleanup(void) {
779     shutting_down=1;
780     close_helpfile(hostserv_helpfile);
781     dict_delete(hostserv_func_dict);
782
783     if (reqlog_f)
784         fclose(reqlog_f);
785 }
786
787 /* to be continued - some day in the future - maybe? */
788 int hostserv_init() {
789         HS_LOG = log_register_type("HostServ", "file:hostserv.log");
790         hostserv_func_dict = dict_new();
791         /*dict_set_free_data(hosts, delete_memo_account);*/
792         /*reg_auth_func(hostserv_check_messages);
793         reg_handle_rename_func(hostserv_rename_account);
794         reg_unreg_func(hostserv_unreg_account);*/
795         conf_register_reload(hostserv_conf_read);
796         reg_exit_func(hostserv_db_cleanup);
797         saxdb_register("HostServ", hostserv_saxdb_read, hostserv_saxdb_write);
798         hostserv_module = module_register("HostServ", HS_LOG, "mod-hostserv.help", NULL);
799         modcmd_register(hostserv_module, "view", cmd_view, 3, MODCMD_REQUIRE_AUTHED, NULL);
800         modcmd_register(hostserv_module, "addmanager", cmd_addmanager, 1, MODCMD_REQUIRE_AUTHED, NULL);
801         modcmd_register(hostserv_module, "delmanager", cmd_delmanager, 2, MODCMD_REQUIRE_AUTHED, NULL);
802         message_register_table(msgtab);
803         return 1;
804 }
805
806 int hostserv_finalize(void) {
807     return 1;
808 }