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