diff options
| author | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
|---|---|---|
| committer | svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b <svn svn@31f1291d-b8d6-0310-a050-a5561fc1590b@5417fbe8-f217-4b02-8779-1006273d7864> | 2004-03-28 21:59:56 +0000 |
| commit | 55bf4dbcabf378e9472b7d31d6edf87f6ac853e9 (patch) | |
| tree | 7a9454ea6b8750256e242cf6d5fba3ca7a4b5044 /nickserv.c | |
Initial Anope Import
git-svn-id: svn://svn.anope.org/anope/trunk@1 31f1291d-b8d6-0310-a050-a5561fc1590b
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'nickserv.c')
| -rw-r--r-- | nickserv.c | 4010 |
1 files changed, 4010 insertions, 0 deletions
diff --git a/nickserv.c b/nickserv.c new file mode 100644 index 000000000..f6365ab93 --- /dev/null +++ b/nickserv.c @@ -0,0 +1,4010 @@ +/* NickServ functions. + * + * (C) 2003 Anope Team + * Contact us at info@anope.org + * + * Please read COPYING and README for furhter details. + * + * Based on the original code of Epona by Lara. + * Based on the original code of Services by Andy Church. + * + * $Id: nickserv.c,v 1.93 2004/03/13 03:25:59 dane Exp $ + * + */ + +#include "services.h" +#include "pseudo.h" + +/*************************************************************************/ + +#define HASH(nick) ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31)) + +NickAlias *nalists[1024]; +NickCore *nclists[1024]; +NickRequest *nrlists[1024]; + +static int guestnum; /* Current guest number */ + +#define TO_COLLIDE 0 /* Collide the user with this nick */ +#define TO_RELEASE 1 /* Release a collided nick */ + +/*************************************************************************/ + +extern char *getvHost(char *nick); + +static int is_on_access(User * u, NickCore * nc); +static void alpha_insert_alias(NickAlias * na); +static void insert_core(NickCore * nc); +static void insert_requestnick(NickRequest * nr); +static NickAlias *makenick(const char *nick); +static NickRequest *makerequest(const char *nick); +static NickAlias *makealias(const char *nick, NickCore * nc); +static void change_core_display(NickCore * nc, char *newdisplay); +static int group_identified(User * u, NickCore * nc); + +static void collide(NickAlias * na, int from_timeout); +static void release(NickAlias * na, int from_timeout); +static void add_ns_timeout(NickAlias * na, int type, time_t delay); +static void del_ns_timeout(NickAlias * na, int type); +int delnickrequest(NickRequest * nr); +NickRequest *findrequestnick(const char *nick); +static int do_sendregmail(User * u, NickRequest * nr); +static int do_setmodes(User * u); + +static int do_help(User * u); +static int do_register(User * u); +static int do_confirm(User * u); +static int do_group(User * u); +static int do_nickupdate(User * u); +static int do_identify(User * u); +static int do_logout(User * u); +static int do_drop(User * u); +static int do_set(User * u); +static int do_set_display(User * u, NickCore * nc, char *param); +static int do_set_password(User * u, NickCore * nc, char *param); +static int do_set_language(User * u, NickCore * nc, char *param); +static int do_set_url(User * u, NickCore * nc, char *param); +static int do_set_email(User * u, NickCore * nc, char *param); +static int do_set_greet(User * u, NickCore * nc, char *param); +static int do_set_icq(User * u, NickCore * nc, char *param); +static int do_set_kill(User * u, NickCore * nc, char *param); +static int do_set_secure(User * u, NickCore * nc, char *param); +static int do_set_private(User * u, NickCore * nc, char *param); +static int do_set_msg(User * u, NickCore * nc, char *param); +static int do_set_hide(User * u, NickCore * nc, char *param); +static int do_set_noexpire(User * u, NickAlias * nc, char *param); +static int do_access(User * u); +static int do_info(User * u); +static int do_list(User * u); +static int do_alist(User * u); +static int do_glist(User * u); +static int do_recover(User * u); +static int do_release(User * u); +static int do_ghost(User * u); +static int do_status(User * u); +static int do_getpass(User * u); +static int do_getemail(User * u); +static int do_sendpass(User * u); +static int do_forbid(User * u); +static int do_resend(User * u); + +/* Obsolete commands */ +static int do_link(User * u); +static int do_unlink(User * u); +static int do_listlinks(User * u); + + +/*************************************************************************/ +/* *INDENT-OFF* */ +void moduleAddNickServCmds(void) { + Command *c; + c = createCommand("HELP", do_help, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("REGISTER", do_register, NULL, NICK_HELP_REGISTER, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("RESEND", do_resend, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("CONFIRM", do_confirm, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("GROUP", do_group, NULL, NICK_HELP_GROUP, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("UPDATE", do_nickupdate, NULL, NICK_HELP_UPDATE, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("ID", do_identify, NULL, NICK_HELP_IDENTIFY, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("IDENTIFY", do_identify, NULL, NICK_HELP_IDENTIFY, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SIDENTIFY",do_identify, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("LOGOUT", do_logout, NULL, -1,NICK_HELP_LOGOUT, NICK_SERVADMIN_HELP_LOGOUT,NICK_SERVADMIN_HELP_LOGOUT, NICK_SERVADMIN_HELP_LOGOUT); addCoreCommand(NICKSERV,c); + c = createCommand("DROP", do_drop, NULL, -1,NICK_HELP_DROP, NICK_SERVADMIN_HELP_DROP,NICK_SERVADMIN_HELP_DROP, NICK_SERVADMIN_HELP_DROP); addCoreCommand(NICKSERV,c); + c = createCommand("LINK", do_link, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("UNLINK", do_unlink, NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("LISTLINKS",do_listlinks,NULL, -1, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("ACCESS", do_access, NULL, NICK_HELP_ACCESS, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET", do_set, NULL, NICK_HELP_SET,-1, NICK_SERVADMIN_HELP_SET,NICK_SERVADMIN_HELP_SET, NICK_SERVADMIN_HELP_SET); addCoreCommand(NICKSERV,c); + c = createCommand("SET DISPLAY", NULL, NULL, NICK_HELP_SET_DISPLAY, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET PASSWORD", NULL, NULL, NICK_HELP_SET_PASSWORD, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET URL", NULL, NULL, NICK_HELP_SET_URL, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET EMAIL", NULL, NULL, NICK_HELP_SET_EMAIL, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET ICQ", NULL, NULL, NICK_HELP_SET_ICQ, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET GREET", NULL, NULL, NICK_HELP_SET_GREET, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET KILL", NULL, NULL, NICK_HELP_SET_KILL, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET SECURE", NULL, NULL, NICK_HELP_SET_SECURE, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET PRIVATE", NULL, NULL, NICK_HELP_SET_PRIVATE, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET MSG", NULL, NULL, NICK_HELP_SET_MSG, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET HIDE", NULL, NULL, NICK_HELP_SET_HIDE, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SET NOEXPIRE", NULL, NULL, -1, -1,NICK_SERVADMIN_HELP_SET_NOEXPIRE,NICK_SERVADMIN_HELP_SET_NOEXPIRE,NICK_SERVADMIN_HELP_SET_NOEXPIRE); addCoreCommand(NICKSERV,c); + c = createCommand("RECOVER", do_recover, NULL, NICK_HELP_RECOVER, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("RELEASE", do_release, NULL, NICK_HELP_RELEASE, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("GHOST", do_ghost, NULL, NICK_HELP_GHOST, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("INFO", do_info, NULL, NICK_HELP_INFO,-1, NICK_HELP_INFO, NICK_SERVADMIN_HELP_INFO,NICK_SERVADMIN_HELP_INFO); addCoreCommand(NICKSERV,c); + c = createCommand("LIST", do_list, NULL, -1,NICK_HELP_LIST, NICK_SERVADMIN_HELP_LIST,NICK_SERVADMIN_HELP_LIST, NICK_SERVADMIN_HELP_LIST); addCoreCommand(NICKSERV,c); + c = createCommand("ALIST", do_alist, NULL, -1,NICK_HELP_ALIST, NICK_SERVADMIN_HELP_ALIST,NICK_SERVADMIN_HELP_ALIST, NICK_SERVADMIN_HELP_ALIST); addCoreCommand(NICKSERV,c); + c = createCommand("GLIST", do_glist, NULL, -1,NICK_HELP_GLIST, NICK_SERVADMIN_HELP_GLIST,NICK_SERVADMIN_HELP_GLIST, NICK_SERVADMIN_HELP_GLIST); addCoreCommand(NICKSERV,c); + c = createCommand("STATUS", do_status, NULL, NICK_HELP_STATUS, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("SENDPASS", do_sendpass, NULL, NICK_HELP_SENDPASS, -1,-1,-1,-1); addCoreCommand(NICKSERV,c); + c = createCommand("GETPASS", do_getpass, is_services_admin, -1,-1, NICK_SERVADMIN_HELP_GETPASS,NICK_SERVADMIN_HELP_GETPASS, NICK_SERVADMIN_HELP_GETPASS); addCoreCommand(NICKSERV,c); + c = createCommand("GETEMAIL", do_getemail, is_services_admin, -1,-1, NICK_SERVADMIN_HELP_GETEMAIL,NICK_SERVADMIN_HELP_GETEMAIL, NICK_SERVADMIN_HELP_GETEMAIL); addCoreCommand(NICKSERV,c); + c = createCommand("FORBID", do_forbid, is_services_admin, -1,-1, NICK_SERVADMIN_HELP_FORBID,NICK_SERVADMIN_HELP_FORBID, NICK_SERVADMIN_HELP_FORBID); addCoreCommand(NICKSERV,c); +} +/* *INDENT-ON* */ +/*************************************************************************/ +/*************************************************************************/ + +/* Display total number of registered nicks and info about each; or, if + * a specific nick is given, display information about that nick (like + * /msg NickServ INFO <nick>). If count_only != 0, then only display the + * number of registered nicks (the nick parameter is ignored). + */ + +void listnicks(int count_only, const char *nick) +{ + int count = 0; + NickAlias *na; + int i; + char *end; + + if (count_only) { + + for (i = 0; i < 1024; i++) { + for (na = nalists[i]; na; na = na->next) + count++; + } + printf("%d nicknames registered.\n", count); + + } else if (nick) { + + struct tm *tm; + char buf[512]; + static const char commastr[] = ", "; + int need_comma = 0; + + if (!(na = findnick(nick))) { + printf("%s not registered.\n", nick); + return; + } else if (na->status & NS_VERBOTEN) { + printf("%s is FORBIDden.\n", nick); + return; + } + printf("%s is %s\n", nick, na->last_realname); + printf("Last seen address: %s\n", na->last_usermask); + tm = localtime(&na->time_registered); + strftime(buf, sizeof(buf), + getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm); + printf(" Time registered: %s\n", buf); + tm = localtime(&na->last_seen); + strftime(buf, sizeof(buf), + getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm); + printf(" Last seen time: %s\n", buf); + if (na->nc->url) + printf(" URL: %s\n", na->nc->url); + if (na->nc->email) + printf(" E-mail address: %s\n", na->nc->email); + if (na->nc->icq) + printf(" ICQ #: %d\n", na->nc->icq); + if (na->nc->greet) + printf(" Greet: %s\n", na->nc->greet); + *buf = 0; + end = buf; + if (na->nc->flags & NI_KILLPROTECT) { + end += + snprintf(end, sizeof(buf) - (end - buf), + "Kill protection"); + need_comma = 1; + } + if (na->nc->flags & NI_SECURE) { + end += snprintf(buf, sizeof(buf) - (end - buf), "%sSecurity", + need_comma ? commastr : ""); + need_comma = 1; + } + if (na->nc->flags & NI_PRIVATE) { + end += snprintf(buf, sizeof(buf) - (end - buf), "%sPrivate", + need_comma ? commastr : ""); + need_comma = 1; + } + if (na->status & NS_NO_EXPIRE) { + end += snprintf(buf, sizeof(buf) - (end - buf), "%sNo Expire", + need_comma ? commastr : ""); + need_comma = 1; + } + printf(" Options: %s\n", *buf ? buf : "None"); + + } else { + + for (i = 0; i < 1024; i++) { + for (na = nalists[i]; na; na = na->next) { + printf(" %s %-20s %s\n", + na->status & NS_NO_EXPIRE ? "!" : " ", + na->nick, na->status & NS_VERBOTEN ? + "Disallowed (FORBID)" : na->last_usermask); + count++; + } + } + printf("%d nicknames registered.\n", count); + + } +} + +/*************************************************************************/ + +/* Return information on memory use. Assumes pointers are valid. */ + +void get_aliases_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + int i; + NickAlias *na; + + for (i = 0; i < 1024; i++) { + for (na = nalists[i]; na; na = na->next) { + count++; + mem += sizeof(*na); + if (na->nick) + mem += strlen(na->nick) + 1; + if (na->last_usermask) + mem += strlen(na->last_usermask) + 1; + if (na->last_realname) + mem += strlen(na->last_realname) + 1; + if (na->last_quit) + mem += strlen(na->last_quit) + 1; + } + } + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ + +/* Return information on memory use. Assumes pointers are valid. */ + +void get_core_stats(long *nrec, long *memuse) +{ + long count = 0, mem = 0; + int i, j; + NickCore *nc; + char **accptr; + + for (i = 0; i < 1024; i++) { + for (nc = nclists[i]; nc; nc = nc->next) { + count++; + mem += sizeof(*nc); + + if (nc->display) + mem += strlen(nc->display) + 1; + if (nc->pass) + mem += strlen(nc->pass) + 1; + + if (nc->url) + mem += strlen(nc->url) + 1; + if (nc->email) + mem += strlen(nc->email) + 1; + if (nc->greet) + mem += strlen(nc->greet) + 1; + + mem += sizeof(char *) * nc->accesscount; + for (accptr = nc->access, j = 0; j < nc->accesscount; + accptr++, j++) { + if (*accptr) + mem += strlen(*accptr) + 1; + } + + mem += nc->memos.memocount * sizeof(Memo); + for (j = 0; j < nc->memos.memocount; j++) { + if (nc->memos.memos[j].text) + mem += strlen(nc->memos.memos[j].text) + 1; + } + + mem += sizeof(void *) * nc->aliases.count; + } + } + *nrec = count; + *memuse = mem; +} + +/*************************************************************************/ +/*************************************************************************/ + +/* NickServ initialization. */ + +void ns_init(void) +{ + moduleAddNickServCmds(); + guestnum = time(NULL); + while (guestnum > 9999999) + guestnum -= 10000000; +} + +/*************************************************************************/ + +/* Main NickServ routine. */ + +void nickserv(User * u, char *buf) +{ + char *cmd, *s; + + cmd = strtok(buf, " "); + + if (!cmd) { + return; + } else if (stricmp(cmd, "\1PING") == 0) { + if (!(s = strtok(NULL, ""))) + s = "\1"; + notice(s_NickServ, u->nick, "\1PING %s", s); + } else if (skeleton) { + notice_lang(s_NickServ, u, SERVICE_OFFLINE, s_NickServ); + } else { + mod_run_cmd(s_NickServ, u, NICKSERV, cmd); + } + +} + +/*************************************************************************/ + +/* Load/save data files. */ + + +#define SAFE(x) do { \ + if ((x) < 0) { \ + if (!forceload) \ + fatal("Read error on %s", NickDBName); \ + failed = 1; \ + break; \ + } \ +} while (0) + +/* Loads NickServ database versions 5 to 11 (<= 4 is not supported) */ + +void load_old_ns_dbase(void) +{ + dbFILE *f; + int ver, i, j, c; + NickAlias *na, *na2, *next; + NickCore *nc; + int failed = 0; + + int16 tmp16; + int32 tmp32; + + char bufn[NICKMAX], bufp[PASSMAX]; + char *email, *greet, *url, *forbidby, *forbidreason; + uint32 icq; + + if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION))) + return; + + ver = get_file_version(f); + if (ver <= 4) { + fatal("Unsupported version number (%d) on %s", ver, NickDBName); + close_db(f); + return; + } + + for (i = 0; i < 256 && !failed; i++) { + while ((c = getc_db(f)) == 1) { + if (c != 1) + fatal("Invalid format in %s", NickDBName); + + na = scalloc(sizeof(NickAlias), 1); + + SAFE(read_buffer(bufn, f)); + na->nick = sstrdup(bufn); + SAFE(read_buffer(bufp, f)); /* Will be used later if needed */ + + SAFE(read_string(&url, f)); + SAFE(read_string(&email, f)); + if (ver >= 10) + SAFE(read_int32(&icq, f)); + else + icq = 0; + if (ver >= 9) + SAFE(read_string(&greet, f)); + else + greet = NULL; + + SAFE(read_string(&na->last_usermask, f)); + SAFE(read_string(&na->last_realname, f)); + SAFE(read_string(&na->last_quit, f)); + + SAFE(read_int32(&tmp32, f)); + na->time_registered = tmp32; + SAFE(read_int32(&tmp32, f)); + na->last_seen = tmp32; + + SAFE(read_int16(&na->status, f)); + na->status &= ~NS_TEMPORARY; +#ifdef USE_ENCRYPTION + if (!(na->status & (NS_OLD_ENCRYPTEDPW | NS_VERBOTEN))) { + if (debug) + alog("debug: %s: encrypting password for `%s' on load", + s_NickServ, na->nick); + if (encrypt_in_place(bufp, PASSMAX) < 0) + fatal("%s: Can't encrypt `%s' nickname password!", + s_NickServ, na->nick); + na->status |= NS_OLD_ENCRYPTEDPW; + } +#else + if (na->status & NS_OLD_ENCRYPTEDPW) { + /* Bail: it makes no sense to continue with encrypted + * passwords, since we won't be able to verify them */ + fatal + ("%s: load database: password for %s encrypted but encryption disabled, aborting", + s_NickServ, na->nick); + } +#endif + if (ver >= 9) { + SAFE(read_string(&forbidby, f)); + SAFE(read_string(&forbidreason, f)); + /* Cleanup */ + if (forbidby && *forbidby == '@') { + free(forbidby); + forbidby = NULL; + } + if (forbidreason && *forbidreason == 0) { + free(forbidreason); + forbidreason = NULL; + } + } else { + forbidby = NULL; + forbidreason = NULL; + } + + if (na->status & NS_VERBOTEN) { + if (na->last_usermask) + free(na->last_usermask); + if (na->last_realname) + free(na->last_realname); + + na->last_usermask = forbidby; + na->last_realname = forbidreason; + } else { + if (!na->last_usermask) + na->last_usermask = sstrdup(""); + if (!na->last_realname) + na->last_realname = sstrdup(""); + } + + /* Store the reference for later resolving */ + SAFE(read_string((char **) &na->nc, f)); + SAFE(read_int16(&tmp16, f)); /* Was linkcount */ + + if (na->nc) { + SAFE(read_int16(&tmp16, f)); /* Was channelcount */ + } else { + /* This nick was a master nick, so it also has all the + * core info! =) + */ + nc = scalloc(1, sizeof(NickCore)); + slist_init(&nc->aliases); + + /* The initial display is what used to be the master nick */ + nc->display = sstrdup(na->nick); + + /* We grabbed info before; fill the appropriate fields now */ + if (*bufp) + nc->pass = sstrdup(bufp); + else + nc->pass = NULL; /* Which may be the case for forbidden nicks .. */ + + nc->email = email; + nc->greet = greet; + nc->icq = icq; + nc->url = url; + + /* We check whether the e-mail is valid because it was not tested + * in older versions. + */ + if (ver <= 10 && nc->email && !MailValidate(nc->email)) { + free(nc->email); + nc->email = NULL; + } + + SAFE(read_int32(&nc->flags, f)); + if (!NSAllowKillImmed) + nc->flags &= ~NI_KILL_IMMED; + + /* Status flags cleanup */ + if (na->status & NS_OLD_ENCRYPTEDPW) { + nc->flags |= NI_ENCRYPTEDPW; + na->status &= ~NS_OLD_ENCRYPTEDPW; + } + + /* Add services opers and admins to the appropriate list, but + only if the database version is equal to or more than 10. */ + if (ver >= 10) { + if (nc->flags & NI_SERVICES_ADMIN) + slist_add(&servadmins, nc); + if (nc->flags & NI_SERVICES_OPER) + slist_add(&servopers, nc); + } + + /* Add the Services root flag if needed. */ + if (nc) + for (j = 0; j < RootNumber; j++) + if (!stricmp(ServicesRoots[j], na->nick)) + nc->flags |= NI_SERVICES_ROOT; + + SAFE(read_int16(&nc->accesscount, f)); + if (nc->accesscount) { + char **access; + access = scalloc(sizeof(char *) * nc->accesscount, 1); + nc->access = access; + for (j = 0; j < nc->accesscount; j++, access++) + SAFE(read_string(access, f)); + } + + SAFE(read_int16(&nc->memos.memocount, f)); + SAFE(read_int16(&nc->memos.memomax, f)); + if (nc->memos.memocount) { + Memo *memos; + memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1); + nc->memos.memos = memos; + + for (j = 0; j < nc->memos.memocount; j++, memos++) { + SAFE(read_int32(&memos->number, f)); + SAFE(read_int16(&memos->flags, f)); + SAFE(read_int32(&tmp32, f)); + memos->time = tmp32; + SAFE(read_buffer(memos->sender, f)); + SAFE(read_string(&memos->text, f)); + } + } + + /* We read the channel count, but don't take care of it. + load_cs_dbase will regenerate it correctly. */ + SAFE(read_int16(&tmp16, f)); + SAFE(read_int16(&nc->channelmax, f)); + if (ver == 5) + nc->channelmax = CSMaxReg; + + SAFE(read_int16(&nc->language, f)); + + if (ver >= 11 && ver < 13) { + char *s; + + SAFE(read_int16(&tmp16, f)); + SAFE(read_int32(&tmp32, f)); + SAFE(read_int16(&tmp16, f)); + SAFE(read_string(&s, f)); + } + + /* Set us as being a master nick; fill the nc field also. + The NS_MASTER flag will not be cleared in this function. */ + na->status |= NS_MASTER; + na->nc = nc; + slist_add(&nc->aliases, na); + + /* Insert our new core in the core list */ + insert_core(nc); + } + + alpha_insert_alias(na); + + } /* while (getc_db(f) != 0) */ + } /* for (i) */ + + /* Now resolve what were called links */ + for (i = 0; i < 1024; i++) { + for (na = nalists[i]; na; na = next) { + next = na->next; + + /* Master nicks are already resolved */ + if (na->status & NS_MASTER) + continue; + + na2 = na; + /* While the reference resolves and it's not a master nick */ + while ((na2 = findnick((char *) na2->nc)) + && !(na2->status & NS_MASTER)); + + /* It didn't resolve. This is problematic since there is no core. :/ + We delete the nick. */ + if (!na2) { + alog("%s: while loading database: %s was linked to inexistant %s", s_NickServ, na->nick, (char *) na->nc); + delnick(na); + continue; + } + + /* OK we have information on the core. We mark the current alias + as a master nick because it now contains a valid core. */ + na->nc = na2->nc; + na->status |= NS_MASTER; + slist_add(&na->nc->aliases, na); + } + } + + close_db(f); +} + +void load_ns_req_db(void) +{ + dbFILE *f; + int i, c, ver; + NickRequest *nr; + int32 tmp32; + int failed = 0; + + if (!(f = open_db(s_NickServ, PreNickDBName, "r", PRE_NICK_VERSION))) + return; + ver = get_file_version(f); + for (i = 0; i < 1024 && !failed; i++) { + while ((c = getc_db(f)) == 1) { + if (c != 1) + fatal("Invalid format in %s", PreNickDBName); + nr = scalloc(1, sizeof(NickRequest)); + SAFE(read_string(&nr->nick, f)); + SAFE(read_string(&nr->passcode, f)); + SAFE(read_string(&nr->password, f)); + SAFE(read_string(&nr->email, f)); + SAFE(read_int32(&tmp32, f)); + nr->requested = tmp32; + insert_requestnick(nr); + } + } + close_db(f); +} + +void load_ns_dbase(void) +{ + dbFILE *f; + int ver, i, j, c; + NickAlias *na, **nalast, *naprev; + NickCore *nc, **nclast, *ncprev; + int failed = 0; + int16 tmp16; + int32 tmp32; + char *s; + + if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION))) + return; + + ver = get_file_version(f); + + if (ver <= 11) { + close_db(f); + load_old_ns_dbase(); + return; + } + + /* First we load nick cores */ + for (i = 0; i < 1024 && !failed; i++) { + nclast = &nclists[i]; + ncprev = NULL; + + while ((c = getc_db(f)) == 1) { + if (c != 1) + fatal("Invalid format in %s", NickDBName); + + nc = scalloc(1, sizeof(NickCore)); + *nclast = nc; + nclast = &nc->next; + nc->prev = ncprev; + ncprev = nc; + + slist_init(&nc->aliases); + + SAFE(read_string(&nc->display, f)); + SAFE(read_string(&nc->pass, f)); + + SAFE(read_string(&nc->email, f)); + SAFE(read_string(&nc->greet, f)); + SAFE(read_int32(&nc->icq, f)); + SAFE(read_string(&nc->url, f)); + + SAFE(read_int32(&nc->flags, f)); + if (!NSAllowKillImmed) + nc->flags &= ~NI_KILL_IMMED; +#ifdef USE_ENCRYPTION + if (nc->pass && !(nc->flags & NI_ENCRYPTEDPW)) { + if (debug) + alog("debug: %s: encrypting password for `%s' on load", + s_NickServ, nc->display); + if (encrypt_in_place(nc->pass, PASSMAX) < 0) + fatal("%s: Can't encrypt `%s' nickname password!", + s_NickServ, nc->display); + nc->flags |= NI_ENCRYPTEDPW; + } +#else + if (nc->flags & NI_ENCRYPTEDPW) { + /* Bail: it makes no sense to continue with encrypted + * passwords, since we won't be able to verify them */ + fatal + ("%s: load database: password for %s encrypted but encryption disabled, aborting", + s_NickServ, nc->display); + } +#endif + SAFE(read_int16(&nc->language, f)); + + /* Add services opers and admins to the appropriate list, but + only if the database version is more than 10. */ + if (nc->flags & NI_SERVICES_ADMIN) + slist_add(&servadmins, nc); + if (nc->flags & NI_SERVICES_OPER) + slist_add(&servopers, nc); + + SAFE(read_int16(&nc->accesscount, f)); + if (nc->accesscount) { + char **access; + access = scalloc(sizeof(char *) * nc->accesscount, 1); + nc->access = access; + for (j = 0; j < nc->accesscount; j++, access++) + SAFE(read_string(access, f)); + } + + SAFE(read_int16(&nc->memos.memocount, f)); + SAFE(read_int16(&nc->memos.memomax, f)); + if (nc->memos.memocount) { + Memo *memos; + memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1); + nc->memos.memos = memos; + for (j = 0; j < nc->memos.memocount; j++, memos++) { + SAFE(read_int32(&memos->number, f)); + SAFE(read_int16(&memos->flags, f)); + SAFE(read_int32(&tmp32, f)); + memos->time = tmp32; + SAFE(read_buffer(memos->sender, f)); + SAFE(read_string(&memos->text, f)); + } + } + + SAFE(read_int16(&nc->channelcount, f)); + SAFE(read_int16(&tmp16, f)); + nc->channelmax = CSMaxReg; + + if (ver < 13) { + /* Used to be dead authentication system */ + SAFE(read_int16(&tmp16, f)); + SAFE(read_int32(&tmp32, f)); + SAFE(read_int16(&tmp16, f)); + SAFE(read_string(&s, f)); + } + + } /* while (getc_db(f) != 0) */ + *nclast = NULL; + } /* for (i) */ + + for (i = 0; i < 1024 && !failed; i++) { + nalast = &nalists[i]; + naprev = NULL; + while ((c = getc_db(f)) == 1) { + if (c != 1) + fatal("Invalid format in %s", NickDBName); + + na = scalloc(1, sizeof(NickAlias)); + + SAFE(read_string(&na->nick, f)); + + SAFE(read_string(&na->last_usermask, f)); + SAFE(read_string(&na->last_realname, f)); + SAFE(read_string(&na->last_quit, f)); + + SAFE(read_int32(&tmp32, f)); + na->time_registered = tmp32; + SAFE(read_int32(&tmp32, f)); + na->last_seen = tmp32; + SAFE(read_int16(&na->status, f)); + na->status &= ~NS_TEMPORARY; + + SAFE(read_string(&s, f)); + na->nc = findcore(s); + free(s); + + slist_add(&na->nc->aliases, na); + + if (!(na->status & NS_VERBOTEN)) { + if (!na->last_usermask) + na->last_usermask = sstrdup(""); + if (!na->last_realname) + na->last_realname = sstrdup(""); + } + + na->nc->flags &= ~NI_SERVICES_ROOT; + + *nalast = na; + nalast = &na->next; + na->prev = naprev; + naprev = na; + + } /* while (getc_db(f) != 0) */ + + *nalast = NULL; + } /* for (i) */ + + close_db(f); + + for (i = 0; i < 1024; i++) { + NickAlias *next; + + for (na = nalists[i]; na; na = next) { + next = na->next; + /* We check for coreless nicks (although it should never happen) */ + if (!na->nc) { + alog("%s: while loading database: %s has no core! We delete it.", s_NickServ, na->nick); + delnick(na); + continue; + } + + /* Add the Services root flag if needed. */ + for (j = 0; j < RootNumber; j++) + if (!stricmp(ServicesRoots[j], na->nick)) + na->nc->flags |= NI_SERVICES_ROOT; + } + } +} + +#undef SAFE + +/*************************************************************************/ + +#define SAFE(x) do { \ + if ((x) < 0) { \ + restore_db(f); \ + log_perror("Write error on %s", NickDBName); \ + if (time(NULL) - lastwarn > WarningTimeout) { \ + wallops(NULL, "Write error on %s: %s", NickDBName, \ + strerror(errno)); \ + lastwarn = time(NULL); \ + } \ + return; \ + } \ +} while (0) + + + +void save_ns_dbase(void) +{ + dbFILE *f; + int i, j; + NickAlias *na; + NickCore *nc; + char **access; + Memo *memos; + static time_t lastwarn = 0; + + if (!(f = open_db(s_NickServ, NickDBName, "w", NICK_VERSION))) + return; + + for (i = 0; i < 1024; i++) { + for (nc = nclists[i]; nc; nc = nc->next) { + SAFE(write_int8(1, f)); + + SAFE(write_string(nc->display, f)); + SAFE(write_string(nc->pass, f)); + + SAFE(write_string(nc->email, f)); + SAFE(write_string(nc->greet, f)); + SAFE(write_int32(nc->icq, f)); + SAFE(write_string(nc->url, f)); + + SAFE(write_int32(nc->flags, f)); + SAFE(write_int16(nc->language, f)); + + SAFE(write_int16(nc->accesscount, f)); + for (j = 0, access = nc->access; j < nc->accesscount; + j++, access++) + SAFE(write_string(*access, f)); + + SAFE(write_int16(nc->memos.memocount, f)); + SAFE(write_int16(nc->memos.memomax, f)); + memos = nc->memos.memos; + for (j = 0; j < nc->memos.memocount; j++, memos++) { + SAFE(write_int32(memos->number, f)); + SAFE(write_int16(memos->flags, f)); + SAFE(write_int32(memos->time, f)); + SAFE(write_buffer(memos->sender, f)); + SAFE(write_string(memos->text, f)); + } + + SAFE(write_int16(nc->channelcount, f)); + SAFE(write_int16(nc->channelmax, f)); + + } /* for (nc) */ + + SAFE(write_int8(0, f)); + + } /* for (i) */ + + for (i = 0; i < 1024; i++) { + for (na = nalists[i]; na; na = na->next) { + SAFE(write_int8(1, f)); + + SAFE(write_string(na->nick, f)); + + SAFE(write_string(na->last_usermask, f)); + SAFE(write_string(na->last_realname, f)); + SAFE(write_string(na->last_quit, f)); + + SAFE(write_int32(na->time_registered, f)); + SAFE(write_int32(na->last_seen, f)); + + SAFE(write_int16(na->status, f)); + + SAFE(write_string(na->nc->display, f)); + + } /* for (na) */ + SAFE(write_int8(0, f)); + } /* for (i) */ + + close_db(f); + +} + +void save_ns_req_dbase(void) +{ + dbFILE *f; + int i; + NickRequest *nr; + static time_t lastwarn = 0; + + if (!(f = open_db(s_NickServ, PreNickDBName, "w", PRE_NICK_VERSION))) + return; + + for (i = 0; i < 1024; i++) { + for (nr = nrlists[i]; nr; nr = nr->next) { + SAFE(write_int8(1, f)) |
