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