6dd35d020070c448ec15a6329465f3e9f551f279
[srvx.git] / src / mod-hostserv.c
1 /* mod-watchdog.c - Watchdog module for srvx
2  * Copyright 2003-2004 Martijn Smit and srvx Development Team
3  *
4  * This file is part of srvx.
5  *
6  * srvx is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with srvx; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
19  */
20
21 /* Adds new section to srvx.conf:
22  * "modules" {
23  *     "hostserv" {
24  *         "nick" "HostServ";
25  *         "modes" "+iok";
26            "toplevel_access" "600";
27  *     };
28  *  };
29  *
30  */
31
32 #include "chanserv.h"
33 #include "opserv.h"
34 #include "nickserv.h"
35 #include "conf.h"
36 #include "modcmd.h"
37 #include "saxdb.h"
38 #include "timeq.h"
39 #include "gline.h"
40
41 #define KEY_TOPLEVEL "toplevel"
42 #define KEY_SECONDLEVEL "secondlevel"
43 #define KEY_MANAGERS "managers"
44 #define KEY_FAKEHOST "fakehost"
45 #define KEY_ASSIGNMENTS "assignments"
46
47
48
49 static const struct message_entry msgtab[] = {
50     { "HSMSG_ASSIGNED_FAKEHOSTS", "Assigned Fakehosts for User $b%s$b:" },
51     { "HSMSG_ASSIGNED_FAKEHOST", "  $b%s.%s$b" },
52     { "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE", "  $b%s.%s$b (active)" },
53     { "HSMSG_ASSIGN_HOWTO", "Use $bassign xxx.yyy$b to activate one of the listed fakehosts or $bassign *$b to use the default fakehost." },
54     { "HSMSG_ASSIGNED_NONE", "  None." },
55     { "HSMSG_MANAGED_FAKEHOSTS", "Fakehosts managed by User $b%s$b:" },
56     { "HSMSG_MANAGED_TOPLEVEL", "  $b*.%s$b   fakehosts: %d   assignments: %d" },
57     { "HSMSG_MANAGED_FAKEHOST", "  $b%s.%s$b   assignments: %d" },
58     { "HSMSG_MANAGE_HOWTO", "Use $bview xxx.yyy$b to view more information about a fakehost group." },
59     { "HSMSG_UNKNOWN_FAKEHOST", "Fakehost $b%s.%s$b is unknown or you have no access to manage it." },
60     { "HSMSG_TOPLEVEL_FAKEHOSTS", "Fakehosts in group $b*.%s$b:" },
61     { "HSMSG_TOPLEVEL_FAKEHOST", "  $b%s.%s$b   assignments: %d   managers: %d" },
62     { "HSMSG_MANAGERS_TOPLEVEL", "Managers of group $b*.%s$b:" },
63     { "HSMSG_MANAGERS_FAKEHOST", "Managers of group $b%s.%s$b:" },
64     { "HSMSG_MANAGERS_MANAGERS", "  %s" },
65     { "HSMSG_FAKEHOST_ASSIGNMENTS", "Assignments in group $b%s.%s$b:" },
66     { "HSMSG_FAKEHOST_ASSIGNMENT", "  $b%s$b (%s.%s.%s)" },
67     { "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE", "  $b%s$b (%s.%s.%s)   active" },
68     { "HSMSG_MANAGER_ALREADY", "$b%s$b is already a manager of %s.%s" },
69     { "HSMSG_MANAGER_ADDED", "$b%s$b is now a manager of %s.%s" },
70     { "HSMSG_MANAGER_NOT", "$b%s$b is not a manager of %s.%s" },
71     
72     { NULL, NULL }
73 };
74
75 static struct {
76     const char *nick;
77     const char *modes;
78     int toplevel_access;
79 } hostserv_conf;
80
81 const char *hostserv_module_deps[] = { NULL };
82 struct userNode *hostserv;
83 static struct module *hostserv_module;
84 static struct service *hostserv_service;
85 static struct log_type *MS_LOG;
86 static struct hs_toplevel *toplevels = NULL;
87 static struct hs_user *hostserv_users = NULL;
88
89 /* FAKEHOST STRUCTS */
90 struct hs_toplevel {
91     char *fakehost;
92     struct hs_manager *managers;
93     struct hs_secondlevel *secondlevel;
94     struct hs_toplevel *next;
95 };
96
97 struct hs_secondlevel {
98     struct hs_toplevel *toplevel;
99     char *fakehost;
100     struct hs_manager *managers;
101     struct hs_assignment *assignment;
102     struct hs_secondlevel *next;
103 };
104
105 struct hs_assignment {
106     struct hs_secondlevel *secondlevel;
107     struct hs_user *user;
108     int active;
109     struct hs_assignment *next;
110     struct hs_assignment *unext; /* for hs_user */
111 };
112
113 struct hs_manager {
114     char type;
115     void *object;
116     struct hs_user *user;
117     struct hs_manager *next;
118     struct hs_manager *unext; /* for hs_user */
119 };
120
121 struct hs_user {
122     struct handle_info *hi;
123     struct hs_assignment *assignments;
124     struct hs_manager *managements;
125     struct hs_user *next;
126 };
127
128 /* MANAGEMENT FUNCTIONS for FAKEHOST STRUCTS */
129 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh);
130 static void hs_del_manager(struct hs_manager *manager, int remove_from_object);
131 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh);
132 static void hs_del_user(struct hs_user *user);
133
134 static void hs_free_all() {
135     struct hs_toplevel *tlfh, *next_tlfh;
136     struct hs_secondlevel *slfh, *next_slfh;
137     struct hs_assignment *assng, *next_assng;
138     struct hs_manager *manager, *next_manager;
139     struct hs_user *user, *next_user;
140     for(tlfh = toplevels; tlfh; tlfh = next_tlfh) {
141         next_tlfh = tlfh->next;
142         for(manager = tlfh->managers; manager; manager = next_manager) {
143             next_manager = manager->next;
144             free(manager);
145         }
146         for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
147             next_slfh = slfh->next;
148             for(manager = tlfh->managers; manager; manager = next_manager) {
149                 next_manager = manager->next;
150                 free(manager);
151             }
152             for(assng = slfh->assignments; assng; assng = next_assng) {
153                 next_assng = assng->next;
154                 free(assng);
155             }
156             free(slfh->fakehost);
157             free(slfh);
158         }
159         free(tlfh->fakehost);
160         free(tlfh);
161     }
162     for(user = hostserv_users; user; user = next_user) {
163         next_user = user->next;
164         free(user);
165     }
166     toplevels = NULL;
167     hostserv_users = NULL;
168 }
169
170 static struct hs_toplevel *hs_add_toplevel(char *name) {
171     struct hs_toplevel *tlfh = calloc(1, sizeof(*tlfh));
172     tlfh->fakehost = strdup(name);
173     tlfh->next = toplevels;
174     toplevels = tlfh;
175     return tlfh;
176 }
177
178 static void hs_del_toplevel(struct hs_toplevel *tlfh) {
179     //unassign all assignments
180     struct hs_secondlevel *slfh, *next_slfh;
181     struct hs_manager *manager, *next_manager;
182     for(manager = tlfh->managers; manager; manager = next_manager) {
183         next_manager = manager->next;
184         hs_del_manager(manager, 0);
185     }
186     for(slfh = tlfh->secondlevel; slfh; slfh = next_slfh) {
187         next_slfh = slfh->next;
188         hs_del_secondlevel(slfh, 0);
189     }
190     free(tlfh->fakehost);
191     free(tlfh);
192 }
193
194 static struct hs_secondlevel *hs_add_secondlevel(struct hs_toplevel *tlfh, char *name) {
195     struct hs_secondlevel *slfh = calloc(1, sizeof(*slfh));
196     slfh->toplevel = tlfh;
197     slfh->fakehost = strdup(name);
198     slfh->next = tlfh->secondlevel;
199     tlfh->secondlevel = slfh;
200     return slfh;
201 }
202
203 static void hs_del_secondlevel(struct hs_secondlevel *slfh, int remove_from_tlfh) {
204     if(remove_from_tlfh) {
205         struct hs_secondlevel *cslfh, *prev_slfh = NULL;
206         for(cslfh = slfh->toplevel->secondlevel; cslfh; cslfh = cslfh->next) {
207             if(cslfh == slfh) {
208                 if(prev_slfh)
209                     prev_slfh->next = slfh->next;
210                 else
211                     slfh->toplevel->secondlevel = slfh->next;
212                 break;
213             } else
214                 prev_slfh = cslfh;
215         }
216     }
217     struct hs_assignment *assng, *next_assng;
218     struct hs_manager *manager, *next_manager;
219     for(manager = slfh->managers; manager; manager = next_manager) {
220         next_manager = manager->next;
221         hs_del_manager(manager, 0);
222     }
223     for(assng = slfh->assignments; assng; assng = next_assng) {
224         next_assng = assng->next;
225         hs_del_assignment(assng, 0);
226     }
227     free(slfh->fakehost);
228     free(slfh);
229 }
230
231 static struct hs_manager *hs_add_manager_toplevel(struct hs_toplevel *tlfh, struct hs_user *user) {
232     struct hs_manager *manager = calloc(1, sizeof(*manager));
233     manager->user = user;
234     manager->type = 1;
235     manager->object = tlfh;
236     manager->unext = user->managements;
237     user->managements = manager;
238     manager->next = tlfh->managers;
239     tlfh->managers = manager;
240     return manager;
241 }
242
243 static struct hs_manager *hs_add_manager_secondlevel(struct hs_secondlevel *slfh, struct hs_user *user) {
244     struct hs_manager *manager = calloc(1, sizeof(*manager));
245     manager->user = user;
246     manager->type = 2;
247     manager->object = slfh;
248     manager->unext = user->managements;
249     user->managements = manager;
250     manager->next = slfh->managers;
251     slfh->managers = manager;
252     return manager;
253 }
254
255 static void hs_del_manager(struct hs_manager *manager, int remove_from_object) {
256     struct hs_manager *cmanager, *prev_manager = NULL;
257     if(remove_from_object) {
258         if(manager->type == 1) {
259             struct hs_toplevel *tlfh = manager->object;
260             for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
261                 if(cmanager = manager) {
262                     if(prev_manager)
263                         prev_manager->next = manager->next;
264                     else
265                         tlfh->managers = manager->next;
266                     break;
267                 } else
268                     prev_manager = cmanager;
269             }
270         } else if(manager->type == 2) {
271             struct hs_secondlevel *slfh = manager->object;
272             for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
273                 if(cmanager = manager) {
274                     if(prev_manager)
275                         prev_manager->next = manager->next;
276                     else
277                         slfh->managers = manager->next;
278                     break;
279                 } else
280                     prev_manager = cmanager;
281             }
282         }
283         prev_manager = NULL;
284     }
285     if(remove_from_object != 2) {
286         for(cmanager = manager->user->managements; cmanager; cmanager = cmanager->unext) {
287             if(cmanager == manager) {
288                 if(prev_manager)
289                     prev_manager->unext = manager->unext;
290                 else
291                     manager->user->managements = manager->unext;
292                 break;
293             } else
294                 prev_manager = cmanager;
295         }
296         if(manager->user->managements == NULL && manager->user->assignments == NULL)
297             hs_del_user(manager->user);
298     }
299     free(manager);
300 }
301
302 static struct hs_assignment *hs_add_assignment(struct hs_secondlevel *slfh, struct hs_user *user) {
303     struct hs_assignment *assignment = calloc(1, sizeof(*assignment));
304     assignment->secondlevel = slfh;
305     assignment->user = user;
306     if(user->assignments == NULL)
307         assignment->active = 1;
308     assignment->next = slfh->assignments;
309     slfh->assignments = assignment;
310     assignment->unext = user->assignments;
311     user->assignments = assignment;
312     if(assignment->active) {
313         /* use this assignment */
314     }
315     return assignment;
316 }
317
318 static void hs_del_assignment(struct hs_assignment *assignment, int remove_from_slfh) {
319     struct hs_assignment *cassignment, *prev_assignment = NULL;
320     if(remove_from_slfh) {
321         for(cassignment = assignment->secondlevel->assignments; cassignment; cassignment = cassignment->next) {
322             if(cassignment == assignment) {
323                 if(prev_assignment)
324                     prev_assignment->next = assignment->next;
325                 else
326                     assignment->secondlevel->assignments = assignment->next;
327                 break;
328             } else
329                 prev_assignment = cassignment;
330         }
331         prev_assignment = NULL;
332     }
333     if(remove_from_slfh != 2) {
334         for(cassignment = assignment->user->assignments; cassignment; cassignment = cassignment->unext) {
335             if(cassignment == assignment) {
336                 if(prev_assignment)
337                     prev_assignment->unext = assignment->unext;
338                 else
339                     assignment->user->assignments = assignment->unext;
340                 break;
341             } else
342                 prev_assignment = cassignment;
343         }
344         if(assignment->user->managements == NULL && assignment->user->assignments == NULL)
345             hs_del_user(assignment->user);
346         if(assignment->active) {
347             /* use other assignment */
348         }
349     }
350     free(assignment);
351 }
352
353 static struct hs_user *hs_get_user(struct handle_info *hi, int create) {
354     struct hs_user *cuser;
355     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
356         if(cuser->hi == hi)
357             return cuser;
358     }
359     if(create) {
360         cuser = calloc(1, sizeof(*cuser));
361         cuser->hi = hi;
362         cuser->next = hostserv_users;
363         hostserv_users = cuser;
364         return cuser;
365     } else
366         return NULL;
367 }
368
369 static void hs_del_user(struct hs_user *user) {
370     if(user->managements) {
371         struct hs_manager *manager, *next_manager;
372         for(manager = user->managements; manager; manager = next_manager) {
373             next_manager = manager->unext;
374             hs_del_manager(manager, 2);
375         }
376     }
377     if(user->assignments) {
378         struct hs_assignment *assng, *next_assng;
379         for(assng = user->assignments; assng; assng = next_assng) {
380             next_assng = assng->unext;
381             hs_del_assignment(assng, 2);
382         }
383     }
384     struct hs_user *cuser, *prev_user = NULL;
385     for(cuser = hostserv_users; cuser; cuser = cuser->next) {
386         if(cuser == user) {
387             if(prev_user)
388                 prev_user->next = user->next;
389             else
390                 hostserv_users = user->next;
391             break;
392         } else
393             prev_user = cuser;
394     }
395     free(user);
396 }
397
398 /* END OF MANAGEMENT FUNCTIONS */
399
400 static int check_management_access(struct handle_info *hi, struct hs_toplevel *tlfh, struct hs_toplevel *slfh) {
401     if(!hi) 
402         return 0;
403     if(hi->opserv_level >= hostserv_conf.toplevel_access) 
404         return 1;
405     struct hs_user *user = hs_get_user(hi, 0);
406     if(!user)
407         return 0;
408     struct hs_manager *manager;
409     if(slfh) {
410         for(manager = huser->managements; manager; manager = manager->next) {
411             if(manager->type == 2 && manager->object == slfh) 
412                 return 1;
413         }
414     }
415     for(manager = huser->managements; manager; manager = manager->next) {
416         if(manager->type == 1 && manager->object == tlfh) 
417             return 1;
418     }
419     return 0;
420 }
421
422
423 static void cmd_view_toplevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_toplevel *tlfh) {
424     reply("HSMSG_TOPLEVEL_FAKEHOSTS", tlfh->fakehost);
425     struct hs_secondlevel *slfh;
426     if(!tlfh->secondlevel)
427         reply("HSMSG_ASSIGNED_NONE");
428     else
429     for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
430         struct hs_manager *cmanager;
431         int managers = 0;
432         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next)
433             managers++;
434         struct hs_assignment *assignment;
435         int assignments = 0;
436         for(assignment = slfh->assignment; assignment; assignment = assignment->next)
437             assignments++;
438         reply("HSMSG_TOPLEVEL_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments, managers);
439     }
440     reply("HSMSG_MANAGERS_TOPLEVEL", tlfh->fakehost);
441     struct hs_manager *cmanager;
442     if(!tlfh->managers)
443         reply("HSMSG_ASSIGNED_NONE");
444     else {
445         char managerBuf[351];
446         int managerPos = 0;
447         for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
448             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
449                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
450                 managerPos = 0;
451             }
452             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
453         }
454         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
455     }
456 }
457
458 static void cmd_view_secondlevel_information(UNUSED_ARG(struct userNode *user), UNUSED_ARG(struct svccmd *cmd), struct hs_secondlevel *slfh) {
459     reply("HSMSG_FAKEHOST_ASSIGNMENTS", slfh->fakehost, slfh->toplevel->fakehost);
460     struct hs_assignment *assignment;
461     for(assignment = slfh->assignment; assignment; assignment = assignment->next) {
462         reply((assignment->active ? "HSMSG_FAKEHOST_ASSIGNMENT_ACTIVE" : "HSMSG_FAKEHOST_ASSIGNMENT"), assignment->user->hi->handle, assignment->user->hi->handle, slfh->fakehost, slfh->toplevel->fakehost);
463     }
464     reply("HSMSG_MANAGERS_FAKEHOST", slfh->fakehost, slfh->toplevel->fakehost);
465     struct hs_manager *cmanager;
466     if(!tlfh->managers)
467         reply("HSMSG_ASSIGNED_NONE");
468     else {
469         char managerBuf[351];
470         int managerPos = 0;
471         for(cmanager = slfh->managers; cmanager; cmanager = cmanager->next) {
472             if(managerPos + strlen(cmanager->user->hi->handle) + 2 >= 350) {
473                 reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
474                 managerPos = 0;
475             }
476             managerPos += sprintf(managerBuf + managerPos, (managerPos ? ", %s" : "%s"), cmanager->user->hi->handle);
477         }
478         reply("HSMSG_MANAGERS_MANAGERS", managerBuf);
479     }
480 }
481
482
483 static MODCMD_FUNC(cmd_view) {
484     struct handle_info *hi;
485     if(argc >= 2 && !strchr(argv[1], '.')) {
486         if (!(hi = modcmd_get_handle_info(user, argv[1])))
487             return 0
488     } else if(argc >= 2) {
489         if (!(hi = user->handle_info)) {
490             reply("NSMSG_MUST_AUTH");
491             return 0;
492         }
493         char *slfh_name = argv[1];
494         char *tlfh_name = strchr(argv[1], '.');
495         *tlfh_name = '\0';
496         tlfh_name++;
497         if(strchr(tlfh_name, '.')) {
498             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
499             return 0;
500         }
501         struct hs_toplevel *tlfh;
502         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
503             if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
504         }
505         if(!tlfh) {
506             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
507             return 0;
508         }
509         if(!irccasecmp(slfh_name, "*")) {
510             if(!check_management_access(hi, tlfh, NULL)) {
511                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
512                 return 0;
513             }
514             cmd_view_toplevel_information(user, cmd, tlfh);
515             return 1;
516         } else {
517             struct hs_secondlevel *slfh;
518             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
519                 if(!irccasecmp(slfh->fakehost, slfh_name)) break;
520             }
521             if(!slfh || !check_management_access(hi, tlfh, slfh)) {
522                 reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
523                 return 0;
524             }
525             cmd_view_secondlevel_information(user, cmd, slfh);
526             return 1;
527         }
528     } else {
529         if (!(hi = user->handle_info)) {
530             reply("NSMSG_MUST_AUTH");
531             return 0;
532         }
533     }
534     struct hs_user *huser = hs_get_user(hi, 0);
535     reply("HSMSG_ASSIGNED_FAKEHOSTS", hi->handle);
536     int assigncount = 0;
537     if(huser) {
538         struct hs_assignment *assignment;
539         for(assignment = huser->assignments; assignment; assignment = assignment->unext) {
540             reply((assignment->active ? "HSMSG_ASSIGNED_FAKEHOST_ACTTIVE" : "HSMSG_ASSIGNED_FAKEHOST"), assignment->secondlevel->fakehost, assignment->secondlevel->toplevel->fakehost);
541             assigncount++;
542         }
543         if(assigncount && huser->hi == user->handle_info)
544             reply("HSMSG_ASSIGN_HOWTO");
545     }
546     if(!assigncount)
547         reply("HSMSG_ASSIGNED_NONE");
548     if(user->handle_info == hi && hi->opserv_level >= hostserv_conf.toplevel_access) {
549         struct hs_toplevel *tlfh;
550         for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
551             struct hs_secondlevel *slfh;
552             struct hs_assignment *assignment;
553             int slfhs = 0, assignments = 0;
554             for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
555                 slfhs++;
556                 for(assignment = slfh->assignment; assignment; assignment = assignment->next)
557                     assignments++;
558             }
559             reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
560         }
561         reply("HSMSG_MANAGE_HOWTO");
562     } else if(huser && huser->managements) {
563         reply("HSMSG_MANAGED_FAKEHOSTS", hi->handle);
564         struct hs_manager *manager;
565         for(manager = huser->managements; manager; manager = manager->next) {
566             if(manager->type == 1) {
567                 struct hs_toplevel *tlfh = manager->object;
568                 struct hs_secondlevel *slfh;
569                 struct hs_assignment *assignment;
570                 int slfhs = 0, assignments = 0;
571                 for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
572                     slfhs++;
573                     for(assignment = slfh->assignment; assignment; assignment = assignment->next)
574                         assignments++;
575                 }
576                 reply("HSMSG_MANAGED_TOPLEVEL", tlfh->fakehost, slfhs, assignments);
577             }
578         }
579         for(manager = huser->managements; manager; manager = manager->next) {
580             if(manager->type == 2) {
581                 struct hs_secondlevel *slfh = manager->object;
582                 struct hs_toplevel *tlfh = slfh->toplevel;
583                 //check if the user is already a manager of the tlfh
584                 struct hs_manager *cmanager;
585                 for(cmanager = tlfh->managers; cmanager; cmanager = cmanager->next) {
586                     if(cmanager->user == huser) break;
587                 }
588                 if(cmanager) continue;
589                 struct hs_assignment *assignment;
590                 int assignments = 0;
591                 for(assignment = slfh->assignment; assignment; assignment = assignment->next)
592                     assignments++;
593                 reply("HSMSG_MANAGED_FAKEHOST", slfh->fakehost, tlfh->fakehost, assignments);
594             }
595         }
596         if(huser->hi == user->handle_info)
597             reply("HSMSG_MANAGE_HOWTO");
598     }
599     return 1;
600 }
601
602 static MODCMD_FUNC(cmd_addmanager) {
603     struct handle_info *hi;
604     char *fakehost;
605     if(!strchr(argv[1], '.')) {
606         if (!(hi = modcmd_get_handle_info(user, argv[1])))
607             return 0
608         fakehost = argv[2];
609     } else {
610         if (!(hi = modcmd_get_handle_info(user, argv[2])))
611             return 0
612         fakehost = argv[1];
613     }
614     char *slfh_name = fakehost;
615     char *tlfh_name = strchr(fakehost, '.');
616     *tlfh_name = '\0';
617     tlfh_name++;
618     if(strchr(tlfh_name, '.')) {
619         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
620         return 0;
621     }
622     struct hs_toplevel *tlfh;
623     struct hs_secondlevel *slfh = NULL;
624     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
625         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
626     }
627     if(!tlfh) {
628         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
629         return 0;
630     }
631     if(!irccasecmp(slfh_name, "*")) {
632         if(!check_management_access(user->handle_info, tlfh, NULL)) {
633             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
634             return 0;
635         }
636     } else {
637         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
638             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
639         }
640         if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
641             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
642             return 0;
643         }
644     }
645     struct hs_user *huser = hs_get_user(hi, 1);
646     struct hs_manager *manager;
647     if(slfh) {
648         for(manager = huser->managements; manager; manager = manager->next) {
649             if(manager->type == 2 && manager->object == slfh) {
650                 reply("HSMSG_MANAGER_ALREADY", hi->handle, slfh_name, tlfh_name);
651                 return 0;
652             }
653         }
654     }
655     for(manager = huser->managements; manager; manager = manager->next) {
656         if(manager->type == 1 && manager->object == tlfh) {
657             reply("HSMSG_MANAGER_ALREADY", hi->handle, "*", tlfh_name);
658             return 0;
659         }
660     }
661     if(slfh)
662         hs_add_manager_secondlevel(slfh, huser);
663     else
664         hs_add_manager_toplevel(tlfh, huser);
665     reply("HSMSG_MANAGER_ADDED", hi->handle, slfh_name, tlfh_name);
666 }
667
668 static MODCMD_FUNC(cmd_delmanager) {
669     struct handle_info *hi;
670     char *fakehost;
671     if(!strchr(argv[1], '.')) {
672         if (!(hi = modcmd_get_handle_info(user, argv[1])))
673             return 0
674         fakehost = argv[2];
675     } else {
676         if (!(hi = modcmd_get_handle_info(user, argv[2])))
677             return 0
678         fakehost = argv[1];
679     }
680     char *slfh_name = fakehost;
681     char *tlfh_name = strchr(fakehost, '.');
682     *tlfh_name = '\0';
683     tlfh_name++;
684     if(strchr(tlfh_name, '.')) {
685         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
686         return 0;
687     }
688     struct hs_toplevel *tlfh;
689     struct hs_secondlevel *slfh = NULL;
690     for(tlfh = toplevels; tlfh; tlfh = tlfh->next) {
691         if(!irccasecmp(tlfh->fakehost, tlfh_name)) break;
692     }
693     if(!tlfh) {
694         reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
695         return 0;
696     }
697     if(!irccasecmp(slfh_name, "*")) {
698         if(!check_management_access(user->handle_info, tlfh, NULL)) {
699             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
700             return 0;
701         }
702     } else {
703         for(slfh = tlfh->secondlevel; slfh; slfh = slfh->next) {
704             if(!irccasecmp(slfh->fakehost, slfh_name)) break;
705         }
706         if(!slfh || !check_management_access(user->handle_info, tlfh, slfh)) {
707             reply("HSMSG_UNKNOWN_FAKEHOST", slfh_name, tlfh_name);
708             return 0;
709         }
710     }
711     struct hs_user *huser = hs_get_user(hi, 0);
712     struct hs_manager *manager;
713     if(!huser) {
714         reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
715         return 0;
716     }
717     if(slfh) {
718         for(manager = huser->managements; manager; manager = manager->next) {
719             if(manager->type == 2 && manager->object == slfh) 
720                 break;
721         }
722         if(!manager) {
723             reply("HSMSG_MANAGER_NOT", hi->handle, slfh_name, tlfh_name);
724             return 0;
725         }
726     } else {
727         for(manager = huser->managements; manager; manager = manager->next) {
728             if(manager->type == 1 && manager->object == tlfh) 
729                 break;
730         }
731         if(!manager) {
732             reply("HSMSG_MANAGER_NOT", hi->handle, "*", tlfh_name);
733             return 0;
734         }
735     }
736     hs_del_manager(manager, 1);
737     reply("HSMSG_MANAGER_DELETED", hi->handle, slfh_name, tlfh_name);
738 }
739
740
741
742
743
744
745
746 /* to be continued - some day in the future - maybe? */
747
748