/* HostServ functions * * (C) 2003-2009 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. * * Based on the original code of Epona by Lara. * Based on the original code of Services by Andy Church. * * $Id$ * */ /*************************************************************************/ #include "services.h" #include "pseudo.h" #define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31)) void load_hs_dbase(dbFILE * f); HostCore *head = NULL; /* head of the HostCore list */ E int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask, char *creator, time_t time); E void moduleAddHostServCmds(); /*************************************************************************/ void moduleAddHostServCmds() { ModuleManager::LoadModuleList(HostServCoreNumber, HostServCoreModules); } /*************************************************************************/ /** * Return information on memory use. * Assumes pointers are valid. **/ void get_hostserv_stats(long *nrec, long *memuse) { long count = 0, mem = 0; HostCore *hc; for (hc = head; hc; hc = hc->next) { count++; mem += sizeof(*hc); if (hc->nick) mem += strlen(hc->nick) + 1; if (hc->vIdent) mem += strlen(hc->vIdent) + 1; if (hc->vHost) mem += strlen(hc->vHost) + 1; if (hc->creator) mem += strlen(hc->creator) + 1; } *nrec = count; *memuse = mem; } /*************************************************************************/ /** * HostServ initialization. * @return void */ void hostserv_init() { if (s_HostServ) { moduleAddHostServCmds(); } } /*************************************************************************/ /** * Main HostServ routine. * @param u User Struct * @param buf Buffer holding the message * @return void */ void hostserv(User * u, char *buf) { const char *cmd, *s; cmd = strtok(buf, " "); if (!cmd) { return; } else if (stricmp(cmd, "\1PING") == 0) { if (!(s = strtok(NULL, ""))) { s = ""; } ircdproto->SendCTCP(findbot(s_HostServ), u->nick, "PING %s", s); } else { if (ircd->vhost) { mod_run_cmd(s_HostServ, u, HOSTSERV, cmd); } else { notice_lang(s_HostServ, u, SERVICE_OFFLINE, s_HostServ); } } } /*************************************************************************/ /* Start of Linked List routines */ /*************************************************************************/ HostCore *hostCoreListHead() { return head; } /** * Create HostCore list member * @param next HostCore next slot * @param nick Nick to add * @param vIdent Virtual Ident * @param vHost Virtual Host * @param creator Person whom set the vhost * @param time Time the vhost was Set * @return HostCore */ HostCore *createHostCorelist(HostCore * next, const char *nick, char *vIdent, char *vHost, const char *creator, int32 tmp_time) { next = new HostCore; if (next == NULL) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to create the vHost LL, problems i sense.."); } else { next->nick = new char[strlen(nick) + 1]; next->vHost = new char[strlen(vHost) + 1]; next->creator = new char[strlen(creator) + 1]; if (vIdent) next->vIdent = new char[strlen(vIdent) + 1]; if ((next->nick == NULL) || (next->vHost == NULL) || (next->creator == NULL)) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to create the vHost LL, problems i sense.."); return NULL; } strcpy(next->nick, nick); strcpy(next->vHost, vHost); strcpy(next->creator, creator); if (vIdent) { if ((next->vIdent == NULL)) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to create the vHost LL, problems i sense.."); return NULL; } strcpy(next->vIdent, vIdent); } else { next->vIdent = NULL; } next->time = tmp_time; next->next = NULL; return next; } return NULL; } /*************************************************************************/ /** * Returns either NULL for the head, or the location of the *PREVIOUS* * record, this is where we need to insert etc.. * @param head HostCore head * @param nick Nick to find * @param found If found * @return HostCore */ HostCore *findHostCore(HostCore * phead, const char *nick, bool* found) { HostCore *previous, *current; *found = false; current = phead; previous = current; if (!nick) { return NULL; } FOREACH_MOD(I_OnFindHostCore, OnFindHostCore(nick)); while (current != NULL) { if (stricmp(nick, current->nick) == 0) { *found = true; break; } else if (stricmp(nick, current->nick) < 0) { /* we know were not gonna find it now.... */ break; } else { previous = current; current = current->next; } } if (current == phead) { return NULL; } else { return previous; } } /*************************************************************************/ HostCore *insertHostCore(HostCore * phead, HostCore * prev, const char *nick, char *vIdent, char *vHost, const char *creator, int32 tmp_time) { HostCore *newCore, *tmp; if (!nick || !vHost || !creator) { return NULL; } newCore = new HostCore; if (newCore == NULL) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to insert into the vHost LL, problems i sense.."); return NULL; } else { newCore->nick = new char[strlen(nick) + 1]; newCore->vHost = new char[strlen(vHost) + 1]; newCore->creator = new char[strlen(creator) + 1]; if (vIdent) newCore->vIdent = new char[strlen(vIdent) + 1]; if ((newCore->nick == NULL) || (newCore->vHost == NULL) || (newCore->creator == NULL)) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to create the vHost LL, problems i sense.."); return NULL; } strcpy(newCore->nick, nick); strcpy(newCore->vHost, vHost); strcpy(newCore->creator, creator); if (vIdent) { if ((newCore->vIdent == NULL)) { ircdproto->SendGlobops(s_HostServ, "Unable to allocate memory to create the vHost LL, problems i sense.."); return NULL; } strcpy(newCore->vIdent, vIdent); } else { newCore->vIdent = NULL; } newCore->time = tmp_time; if (prev == NULL) { tmp = phead; phead = newCore; newCore->next = tmp; } else { tmp = prev->next; prev->next = newCore; newCore->next = tmp; } } FOREACH_MOD(I_OnInsertHostCore, OnInsertHostCore(newCore)); return phead; } /*************************************************************************/ HostCore *deleteHostCore(HostCore * phead, HostCore * prev) { HostCore *tmp; if (prev == NULL) { tmp = phead; phead = phead->next; } else { tmp = prev->next; prev->next = tmp->next; } FOREACH_MOD(I_OnDeleteHostCore, OnDeleteHostCore(tmp)); delete [] tmp->vHost; delete [] tmp->nick; delete [] tmp->creator; if (tmp->vIdent) { delete [] tmp->vIdent; } delete tmp; return phead; } /*************************************************************************/ void addHostCore(const char *nick, char *vIdent, char *vhost, const char *creator, int32 tmp_time) { HostCore *tmp; bool found = false; if (head == NULL) { head = createHostCorelist(head, nick, vIdent, vhost, creator, tmp_time); } else { tmp = findHostCore(head, nick, &found); if (!found) { head = insertHostCore(head, tmp, nick, vIdent, vhost, creator, tmp_time); } else { head = deleteHostCore(head, tmp); /* delete the old entry */ addHostCore(nick, vIdent, vhost, creator, tmp_time); /* recursive call to add new entry */ } } } /*************************************************************************/ char *getvHost(char *nick) { HostCore *tmp; bool found = false; tmp = findHostCore(head, nick, &found); if (found) { if (tmp == NULL) return head->vHost; else return tmp->next->vHost; } return NULL; } /*************************************************************************/ char *getvIdent(char *nick) { HostCore *tmp; bool found = false; tmp = findHostCore(head, nick, &found); if (found) { if (tmp == NULL) return head->vIdent; else return tmp->next->vIdent; } return NULL; } /*************************************************************************/ void delHostCore(const char *nick) { HostCore *tmp; bool found = false; tmp = findHostCore(head, nick, &found); if (found) { head = deleteHostCore(head, tmp); } } /*************************************************************************/ /* End of Linked List routines */ /*************************************************************************/ /*************************************************************************/ /* Start of Load/Save routines */ /*************************************************************************/ #define SAFE(x) do { \ if ((x) < 0) { \ if (!forceload) \ fatal("Read error on %s", HostDBName); \ failed = 1; \ break; \ } \ } while (0) void load_hs_dbase() { dbFILE *f; int ver; if (!(f = open_db(s_HostServ, HostDBName, "r", HOST_VERSION))) { return; } ver = get_file_version(f); if (ver != 3) { close_db(f); fatal("DB %s is too old", HostDBName); return; } load_hs_dbase(f); close_db(f); } void load_hs_dbase(dbFILE * f) { int c; int failed = 0; char *nick; char *vHost; char *creator; char *vIdent; uint32 time; while (!failed && (c = getc_db(f)) == 1) { if (c == 1) { SAFE(read_string(&nick, f)); SAFE(read_string(&vIdent, f)); SAFE(read_string(&vHost, f)); SAFE(read_string(&creator, f)); SAFE(read_int32(&time, f)); // Older Anope could save an empty vident when importing from MySQL, so trap that here. if (vIdent && !strcmp(vIdent, "")) { delete [] vIdent; vIdent = NULL; } addHostCore(nick, vIdent, vHost, creator, time); /* could get a speed increase by not searching the list */ delete [] nick; /* as we know the db is in alphabetical order... */ delete [] vHost; delete [] creator; if (vIdent) delete [] vIdent; } else { fatal("Invalid format in %s %d", HostDBName, c); } } } #undef SAFE /*************************************************************************/ #define SAFE(x) do { \ if ((x) < 0) { \ restore_db(f); \ log_perror("Write error on %s", HostDBName); \ if (time(NULL) - lastwarn > WarningTimeout) { \ ircdproto->SendGlobops(NULL, "Write error on %s: %s", HostDBName, \ strerror(errno)); \ lastwarn = time(NULL); \ } \ return; \ } \ } while (0) void save_hs_dbase() { dbFILE *f; static time_t lastwarn = 0; HostCore *current; if (!(f = open_db(s_HostServ, HostDBName, "w", HOST_VERSION))) return; current = head; while (current != NULL) { SAFE(write_int8(1, f)); SAFE(write_string(current->nick, f)); SAFE(write_string(current->vIdent, f)); SAFE(write_string(current->vHost, f)); SAFE(write_string(current->creator, f)); SAFE(write_int32(current->time, f)); current = current->next; } SAFE(write_int8(0, f)); close_db(f); } #undef SAFE /*************************************************************************/ /* End of Load/Save Functions */ /*************************************************************************/ /*************************************************************************/ /* Start of Generic Functions */ /*************************************************************************/ int do_hs_sync(NickCore * nc, char *vIdent, char *hostmask, char *creator, time_t time) { int i; NickAlias *na; for (i = 0; i < nc->aliases.count; i++) { na = static_cast(nc->aliases.list[i]); addHostCore(na->nick, vIdent, hostmask, creator, time); } return MOD_CONT; } /*************************************************************************/ int do_on_id(User * u) { /* we've assumed that the user exists etc.. */ char *vHost; /* as were only gonna call this from nsid routine */ char *vIdent; vHost = getvHost(u->nick); vIdent = getvIdent(u->nick); if (vHost != NULL) { if (vIdent) { notice_lang(s_HostServ, u, HOST_IDENT_ACTIVATED, vIdent, vHost); } else { notice_lang(s_HostServ, u, HOST_ACTIVATED, vHost); } ircdproto->SendVhost(u->nick, vIdent, vHost); if (ircd->vhost) { if (u->vhost) delete [] u->vhost; u->vhost = sstrdup(vHost); } if (ircd->vident) { if (vIdent) u->SetVIdent(vIdent); } set_lastmask(u); } return MOD_CONT; } /*************************************************************************/ /* * Sets the last_usermak properly. Using virtual ident and/or host */ void set_lastmask(User * u) { NickAlias *na = findnick(u->nick); if (na->last_usermask) delete [] na->last_usermask; na->last_usermask = new char[u->GetIdent().length() + u->GetDisplayedHost().length() + 2]; sprintf(na->last_usermask, "%s@%s", u->GetIdent().c_str(), u->GetDisplayedHost().c_str()); }