nickserv.c

Go to the documentation of this file.
00001 
00002 /* NickServ functions.
00003  *
00004  * (C) 2003-2013 Anope Team
00005  * Contact us at team@anope.org
00006  *
00007  * Please read COPYING and README for further details.
00008  *
00009  * Based on the original code of Epona by Lara.
00010  * Based on the original code of Services by Andy Church. 
00011  * 
00012  *
00013  */
00014 
00015 #include "services.h"
00016 #include "pseudo.h"
00017 
00018 /*************************************************************************/
00019 
00020 #define HASH(nick)      ((tolower((nick)[0])&31)<<5 | (tolower((nick)[1])&31))
00021 
00022 NickAlias *nalists[1024];
00023 NickCore *nclists[1024];
00024 NickRequest *nrlists[1024];
00025 
00026 unsigned int guestnum;          /* Current guest number */
00027 
00028 #define TO_COLLIDE   0          /* Collide the user with this nick */
00029 #define TO_RELEASE   1          /* Release a collided nick */
00030 
00031 /*************************************************************************/
00032 
00033 static void add_ns_timeout(NickAlias * na, int type, time_t delay);
00034 
00035 /*************************************************************************/
00036 /* *INDENT-OFF* */
00037 void moduleAddNickServCmds(void) {
00038     modules_core_init(NickServCoreNumber, NickServCoreModules);
00039 }
00040 /* *INDENT-ON* */
00041 /*************************************************************************/
00042 
00043 /* Display total number of registered nicks and info about each; or, if
00044  * a specific nick is given, display information about that nick (like
00045  * /msg NickServ INFO <nick>).  If count_only != 0, then only display the
00046  * number of registered nicks (the nick parameter is ignored).
00047  */
00048 
00049 void listnicks(int count_only, const char *nick)
00050 {
00051     int count = 0;
00052     NickAlias *na;
00053     int i;
00054     char *end;
00055 
00056     if (count_only) {
00057 
00058         for (i = 0; i < 1024; i++) {
00059             for (na = nalists[i]; na; na = na->next)
00060                 count++;
00061         }
00062         printf("%d nicknames registered.\n", count);
00063 
00064     } else if (nick) {
00065 
00066         struct tm *tm;
00067         char buf[512];
00068         static const char commastr[] = ", ";
00069         int need_comma = 0;
00070 
00071         if (!(na = findnick(nick))) {
00072             printf("%s not registered.\n", nick);
00073             return;
00074         } else if (na->status & NS_VERBOTEN) {
00075             printf("%s is FORBIDden.\n", nick);
00076             return;
00077         }
00078         printf("%s is %s\n", nick, na->last_realname);
00079         printf("Last seen address: %s\n", na->last_usermask);
00080         tm = localtime(&na->time_registered);
00081         strftime(buf, sizeof(buf),
00082                  getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00083         printf("  Time registered: %s\n", buf);
00084         tm = localtime(&na->last_seen);
00085         strftime(buf, sizeof(buf),
00086                  getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00087         printf("   Last seen time: %s\n", buf);
00088         if (na->nc->url)
00089             printf("              URL: %s\n", na->nc->url);
00090         if (na->nc->email)
00091             printf("   E-mail address: %s\n", na->nc->email);
00092         if (na->nc->icq)
00093             printf("            ICQ #: %d\n", na->nc->icq);
00094         if (na->nc->greet)
00095             printf("            Greet: %s\n", na->nc->greet);
00096         *buf = 0;
00097         end = buf;
00098         if (na->nc->flags & NI_KILLPROTECT) {
00099             end +=
00100                 snprintf(end, sizeof(buf) - (end - buf),
00101                          "Kill protection");
00102             need_comma = 1;
00103         }
00104         if (na->nc->flags & NI_SECURE) {
00105             end += snprintf(end, sizeof(buf) - (end - buf), "%sSecurity",
00106                             need_comma ? commastr : "");
00107             need_comma = 1;
00108         }
00109         if (na->nc->flags & NI_PRIVATE) {
00110             end += snprintf(end, sizeof(buf) - (end - buf), "%sPrivate",
00111                             need_comma ? commastr : "");
00112             need_comma = 1;
00113         }
00114         if (na->status & NS_NO_EXPIRE) {
00115             end += snprintf(end, sizeof(buf) - (end - buf), "%sNo Expire",
00116                             need_comma ? commastr : "");
00117             need_comma = 1;
00118         }
00119         printf("          Options: %s\n", *buf ? buf : "None");
00120 
00121         if (na->nc->flags & NI_SUSPENDED) {
00122             if (na->last_quit) {
00123                 printf
00124                     ("This nickname is currently suspended, reason: %s\n",
00125                      na->last_quit);
00126             } else {
00127                 printf("This nickname is currently suspended.\n");
00128             }
00129         }
00130 
00131 
00132     } else {
00133 
00134         for (i = 0; i < 1024; i++) {
00135             for (na = nalists[i]; na; na = na->next) {
00136                 printf("    %s %-20s  %s\n",
00137                        na->status & NS_NO_EXPIRE ? "!" : " ",
00138                        na->nick, na->status & NS_VERBOTEN ?
00139                        "Disallowed (FORBID)" : (na->nc->
00140                                                 flags & NI_SUSPENDED ?
00141                                                 "Disallowed (SUSPENDED)" :
00142                                                 na->last_usermask));
00143                 count++;
00144             }
00145         }
00146         printf("%d nicknames registered.\n", count);
00147 
00148     }
00149 }
00150 
00151 /*************************************************************************/
00152 
00153 /* Return information on memory use.  Assumes pointers are valid. */
00154 
00155 void get_aliases_stats(long *nrec, long *memuse)
00156 {
00157     long count = 0, mem = 0;
00158     int i;
00159     NickAlias *na;
00160 
00161     for (i = 0; i < 1024; i++) {
00162         for (na = nalists[i]; na; na = na->next) {
00163             count++;
00164             mem += sizeof(*na);
00165             if (na->nick)
00166                 mem += strlen(na->nick) + 1;
00167             if (na->last_usermask)
00168                 mem += strlen(na->last_usermask) + 1;
00169             if (na->last_realname)
00170                 mem += strlen(na->last_realname) + 1;
00171             if (na->last_quit)
00172                 mem += strlen(na->last_quit) + 1;
00173         }
00174     }
00175     *nrec = count;
00176     *memuse = mem;
00177 }
00178 
00179 /*************************************************************************/
00180 
00181 /* Return information on memory use.  Assumes pointers are valid. */
00182 
00183 void get_core_stats(long *nrec, long *memuse)
00184 {
00185     long count = 0, mem = 0;
00186     int i, j;
00187     NickCore *nc;
00188     char **accptr;
00189 
00190     for (i = 0; i < 1024; i++) {
00191         for (nc = nclists[i]; nc; nc = nc->next) {
00192             count++;
00193             mem += sizeof(*nc);
00194 
00195             if (nc->display)
00196                 mem += strlen(nc->display) + 1;
00197             if (nc->pass)
00198                 mem += strlen(nc->pass) + 1;
00199 
00200             if (nc->url)
00201                 mem += strlen(nc->url) + 1;
00202             if (nc->email)
00203                 mem += strlen(nc->email) + 1;
00204             if (nc->greet)
00205                 mem += strlen(nc->greet) + 1;
00206 
00207             mem += sizeof(char *) * nc->accesscount;
00208             for (accptr = nc->access, j = 0; j < nc->accesscount;
00209                  accptr++, j++) {
00210                 if (*accptr)
00211                     mem += strlen(*accptr) + 1;
00212             }
00213 
00214             mem += nc->memos.memocount * sizeof(Memo);
00215             for (j = 0; j < nc->memos.memocount; j++) {
00216                 if (nc->memos.memos[j].text)
00217                     mem += strlen(nc->memos.memos[j].text) + 1;
00218             }
00219 
00220             mem += sizeof(void *) * nc->aliases.count;
00221         }
00222     }
00223     *nrec = count;
00224     *memuse = mem;
00225 }
00226 
00227 /*************************************************************************/
00228 /*************************************************************************/
00229 
00230 /* NickServ initialization. */
00231 
00232 void ns_init(void)
00233 {
00234     moduleAddNickServCmds();
00235     guestnum = time(NULL);
00236     while (guestnum > 9999999)
00237         guestnum -= 10000000;
00238 }
00239 
00240 /*************************************************************************/
00241 
00242 /* Main NickServ routine. */
00243 
00244 void nickserv(User * u, char *buf)
00245 {
00246     char *cmd, *s;
00247 
00248     cmd = strtok(buf, " ");
00249 
00250     if (!cmd) {
00251         return;
00252     } else if (stricmp(cmd, "\1PING") == 0) {
00253         if (!(s = strtok(NULL, ""))) {
00254             s = "";
00255         }
00256         anope_cmd_ctcp(s_NickServ, u->nick, "PING %s", s);
00257     } else if (skeleton) {
00258         notice_lang(s_NickServ, u, SERVICE_OFFLINE, s_NickServ);
00259     } else {
00260         mod_run_cmd(s_NickServ, u, NICKSERV, cmd);
00261     }
00262 
00263 }
00264 
00265 /*************************************************************************/
00266 
00267 /* Load/save data files. */
00268 
00269 
00270 #define SAFE(x) do {                                    \
00271     if ((x) < 0) {                                      \
00272         if (!forceload)                                 \
00273             fatal("Read error on %s", NickDBName);      \
00274         failed = 1;                                     \
00275         break;                                          \
00276     }                                                   \
00277 } while (0)
00278 
00279 /* Loads NickServ database versions 5 to 11 (<= 4 is not supported) */
00280 
00281 void load_old_ns_dbase(void)
00282 {
00283     dbFILE *f;
00284     int ver, i, j, c;
00285     NickAlias *na, *na2, *next;
00286     NickCore *nc;
00287     int failed = 0;
00288 
00289     uint16 tmp16;
00290     uint32 tmp32;
00291 
00292     char bufn[NICKMAX], bufp[PASSMAX];
00293     char *email, *greet, *url, *forbidby, *forbidreason;
00294     uint32 icq;
00295 
00296     if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION)))
00297         return;
00298 
00299     ver = get_file_version(f);
00300     if (ver <= 4) {
00301         fatal("Unsupported version number (%d) on %s", ver, NickDBName);
00302         close_db(f);
00303         return;
00304     }
00305 
00306     for (i = 0; i < 256 && !failed; i++) {
00307         while ((c = getc_db(f)) == 1) {
00308             if (c != 1)
00309                 fatal("Invalid format in %s", NickDBName);
00310 
00311             na = scalloc(sizeof(NickAlias), 1);
00312 
00313             SAFE(read_buffer(bufn, f));
00314             na->nick = sstrdup(bufn);
00315             SAFE(read_buffer(bufp, f)); /* Will be used later if needed */
00316 
00317             SAFE(read_string(&url, f));
00318             SAFE(read_string(&email, f));
00319             if (ver >= 10)
00320                 SAFE(read_int32(&icq, f));
00321             else
00322                 icq = 0;
00323             if (ver >= 9)
00324                 SAFE(read_string(&greet, f));
00325             else
00326                 greet = NULL;
00327 
00328             SAFE(read_string(&na->last_usermask, f));
00329             SAFE(read_string(&na->last_realname, f));
00330             SAFE(read_string(&na->last_quit, f));
00331 
00332             SAFE(read_int32(&tmp32, f));
00333             na->time_registered = tmp32;
00334             SAFE(read_int32(&tmp32, f));
00335             na->last_seen = tmp32;
00336 
00337             SAFE(read_int16(&na->status, f));
00338             na->status &= ~NS_TEMPORARY;
00339 
00340             if (ver >= 9) {
00341                 SAFE(read_string(&forbidby, f));
00342                 SAFE(read_string(&forbidreason, f));
00343                 /* Cleanup */
00344                 if (forbidby && *forbidby == '@') {
00345                     free(forbidby);
00346                     forbidby = NULL;
00347                 }
00348                 if (forbidreason && *forbidreason == 0) {
00349                     free(forbidreason);
00350                     forbidreason = NULL;
00351                 }
00352             } else {
00353                 forbidby = NULL;
00354                 forbidreason = NULL;
00355             }
00356 
00357             if (na->status & NS_VERBOTEN) {
00358                 if (na->last_usermask)
00359                     free(na->last_usermask);
00360                 if (na->last_realname)
00361                     free(na->last_realname);
00362 
00363                 na->last_usermask = forbidby;
00364                 na->last_realname = forbidreason;
00365             } else {
00366                 if (!na->last_usermask)
00367                     na->last_usermask = sstrdup("");
00368                 if (!na->last_realname)
00369                     na->last_realname = sstrdup("");
00370             }
00371 
00372             /* Store the reference for later resolving */
00373             SAFE(read_string((char **) &na->nc, f));
00374             SAFE(read_int16(&tmp16, f));        /* Was linkcount */
00375 
00376             if (na->nc) {
00377                 SAFE(read_int16(&tmp16, f));    /* Was channelcount */
00378             } else {
00379                 /* This nick was a master nick, so it also has all the
00380                  * core info! =)
00381                  */
00382                 nc = scalloc(1, sizeof(NickCore));
00383                 slist_init(&nc->aliases);
00384 
00385                 /* The initial display is what used to be the master nick */
00386                 nc->display = sstrdup(na->nick);
00387 
00388                 /* We grabbed info before; fill the appropriate fields now */
00389                 if (*bufp)
00390                     memcpy(nc->pass, bufp, PASSMAX);
00391                 else
00392                     memset(nc->pass, 0, PASSMAX);       /* Which may be the case for forbidden nicks .. */
00393 
00394                 nc->email = email;
00395                 nc->greet = greet;
00396                 nc->icq = icq;
00397                 nc->url = url;
00398 
00399                 /* We check whether the e-mail is valid because it was not tested
00400                  * in older versions.
00401                  */
00402                 if (ver <= 10 && nc->email && !MailValidate(nc->email)) {
00403                     free(nc->email);
00404                     nc->email = NULL;
00405                 }
00406 
00407                 SAFE(read_int32(&nc->flags, f));
00408                 if (!NSAllowKillImmed)
00409                     nc->flags &= ~NI_KILL_IMMED;
00410 
00411                 /* Status flags cleanup */
00412                 if (na->status & NS_OLD_ENCRYPTEDPW) {
00413                     nc->flags |= NI_ENCRYPTEDPW;
00414                     na->status &= ~NS_OLD_ENCRYPTEDPW;
00415                 }
00416 
00417                 /* Add services opers and admins to the appropriate list, but
00418                    only if the database version is equal to or more than 10. */
00419                 if (ver >= 10) {
00420                     if (nc->flags & NI_SERVICES_ADMIN)
00421                         slist_add(&servadmins, nc);
00422                     if (nc->flags & NI_SERVICES_OPER)
00423                         slist_add(&servopers, nc);
00424                 }
00425 
00426                 /* Add the Services root flag if needed. */
00427                 if (nc)
00428                     for (j = 0; j < RootNumber; j++)
00429                         if (!stricmp(ServicesRoots[j], na->nick))
00430                             nc->flags |= NI_SERVICES_ROOT;
00431 
00432                 SAFE(read_int16(&nc->accesscount, f));
00433                 if (nc->accesscount) {
00434                     char **access;
00435                     access = scalloc(sizeof(char *) * nc->accesscount, 1);
00436                     nc->access = access;
00437                     for (j = 0; j < nc->accesscount; j++, access++)
00438                         SAFE(read_string(access, f));
00439                 }
00440 
00441                 SAFE(read_int16(&tmp16, f));
00442                 nc->memos.memocount = (int16) tmp16;
00443                 SAFE(read_int16(&tmp16, f));
00444                 nc->memos.memomax = (int16) tmp16;
00445                 if (nc->memos.memocount) {
00446                     Memo *memos;
00447                     memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1);
00448                     nc->memos.memos = memos;
00449 
00450                     for (j = 0; j < nc->memos.memocount; j++, memos++) {
00451                         SAFE(read_int32(&memos->number, f));
00452                         SAFE(read_int16(&memos->flags, f));
00453                         SAFE(read_int32(&tmp32, f));
00454                         memos->time = tmp32;
00455                         SAFE(read_buffer(memos->sender, f));
00456                         SAFE(read_string(&memos->text, f));
00457                         memos->moduleData = NULL;
00458                     }
00459                 }
00460 
00461                 /* We read the channel count, but don't take care of it.
00462                    load_cs_dbase will regenerate it correctly. */
00463                 SAFE(read_int16(&tmp16, f));
00464                 SAFE(read_int16(&nc->channelmax, f));
00465                 if (ver == 5)
00466                     nc->channelmax = CSMaxReg;
00467 
00468                 SAFE(read_int16(&nc->language, f));
00469 
00470                 if (ver >= 11 && ver < 13) {
00471                     char *s;
00472 
00473                     SAFE(read_int16(&tmp16, f));
00474                     SAFE(read_int32(&tmp32, f));
00475                     SAFE(read_int16(&tmp16, f));
00476                     SAFE(read_string(&s, f));
00477                 }
00478 
00479                 /* Set us as being a master nick; fill the nc field also.
00480                    The NS_MASTER flag will not be cleared in this function. */
00481                 na->status |= NS_MASTER;
00482                 na->nc = nc;
00483                 slist_add(&nc->aliases, na);
00484 
00485                 /* Insert our new core in the core list */
00486                 insert_core(nc);
00487             }
00488 
00489             alpha_insert_alias(na);
00490 
00491         }                       /* while (getc_db(f) != 0) */
00492     }                           /* for (i) */
00493 
00494     /* Now resolve what were called links */
00495     for (i = 0; i < 1024; i++) {
00496         for (na = nalists[i]; na; na = next) {
00497             next = na->next;
00498 
00499             /* Master nicks are already resolved */
00500             if (na->status & NS_MASTER)
00501                 continue;
00502 
00503             na2 = na;
00504             /* While the reference resolves and it's not a master nick */
00505             while ((na2 = findnick((char *) na2->nc))
00506                    && !(na2->status & NS_MASTER));
00507 
00508             /* It didn't resolve. This is problematic since there is no core. :/
00509                We delete the nick. */
00510             if (!na2) {
00511                 alog("%s: while loading database: %s was linked to inexistant %s", s_NickServ, na->nick, (char *) na->nc);
00512                 delnick(na);
00513                 continue;
00514             }
00515 
00516             /* OK we have information on the core. We mark the current alias
00517                as a master nick because it now contains a valid core. */
00518             na->nc = na2->nc;
00519             na->status |= NS_MASTER;
00520             slist_add(&na->nc->aliases, na);
00521         }
00522     }
00523 
00524     close_db(f);
00525 }
00526 
00527 void load_ns_req_db(void)
00528 {
00529     dbFILE *f;
00530     int i, c, ver;
00531     NickRequest *nr;
00532     uint32 tmp32;
00533     int failed = 0, len;
00534     char *pass;
00535 
00536     if (!(f = open_db(s_NickServ, PreNickDBName, "r", PRE_NICK_VERSION)))
00537         return;
00538     ver = get_file_version(f);
00539     for (i = 0; i < 1024 && !failed; i++) {
00540         while ((c = getc_db(f)) == 1) {
00541             if (c != 1)
00542                 fatal("Invalid format in %s", PreNickDBName);
00543             nr = scalloc(1, sizeof(NickRequest));
00544             SAFE(read_string(&nr->nick, f));
00545             SAFE(read_string(&nr->passcode, f));
00546             if (ver < 2) {
00547                 SAFE(read_string(&pass, f));
00548                 len = strlen(pass);
00549                 enc_encrypt(pass, len, nr->password, PASSMAX);
00550                 memset(pass, 0, len);
00551                 free(pass);
00552             } else
00553                 SAFE(read_buffer(nr->password, f));
00554             SAFE(read_string(&nr->email, f));
00555             SAFE(read_int32(&tmp32, f));
00556             nr->requested = tmp32;
00557             insert_requestnick(nr);
00558         }
00559     }
00560     close_db(f);
00561 }
00562 
00563 void load_ns_dbase(void)
00564 {
00565     dbFILE *f;
00566     int ver, i, j, c;
00567     NickAlias *na, **nalast, *naprev;
00568     NickCore *nc, **nclast, *ncprev;
00569     int failed = 0;
00570     uint16 tmp16;
00571     uint32 tmp32;
00572     char *s, *pass;
00573 
00574     if (!(f = open_db(s_NickServ, NickDBName, "r", NICK_VERSION)))
00575         return;
00576 
00577     ver = get_file_version(f);
00578 
00579     if (ver <= 11) {
00580         close_db(f);
00581         load_old_ns_dbase();
00582         return;
00583     }
00584 
00585     /* First we load nick cores */
00586     for (i = 0; i < 1024 && !failed; i++) {
00587         nclast = &nclists[i];
00588         ncprev = NULL;
00589 
00590         while ((c = getc_db(f)) == 1) {
00591             if (c != 1)
00592                 fatal("Invalid format in %s", NickDBName);
00593 
00594             nc = scalloc(1, sizeof(NickCore));
00595             *nclast = nc;
00596             nclast = &nc->next;
00597             nc->prev = ncprev;
00598             ncprev = nc;
00599 
00600             slist_init(&nc->aliases);
00601 
00602             SAFE(read_string(&nc->display, f));
00603             if (ver < 14) {
00604                 SAFE(read_string(&pass, f));
00605                 if (pass) {
00606                     memset(nc->pass, 0, PASSMAX);
00607                     memcpy(nc->pass, pass, strlen(pass));
00608                 } else
00609                     memset(nc->pass, 0, PASSMAX);
00610             } else
00611                 SAFE(read_buffer(nc->pass, f));
00612 
00613             SAFE(read_string(&nc->email, f));
00614             SAFE(read_string(&nc->greet, f));
00615             SAFE(read_int32(&nc->icq, f));
00616             SAFE(read_string(&nc->url, f));
00617 
00618             SAFE(read_int32(&nc->flags, f));
00619             if (!NSAllowKillImmed)
00620                 nc->flags &= ~NI_KILL_IMMED;
00621             SAFE(read_int16(&nc->language, f));
00622 
00623             /* Add services opers and admins to the appropriate list, but
00624                only if the database version is more than 10. */
00625             if (nc->flags & NI_SERVICES_ADMIN)
00626                 slist_add(&servadmins, nc);
00627             if (nc->flags & NI_SERVICES_OPER)
00628                 slist_add(&servopers, nc);
00629 
00630             SAFE(read_int16(&nc->accesscount, f));
00631             if (nc->accesscount) {
00632                 char **access;
00633                 access = scalloc(sizeof(char *) * nc->accesscount, 1);
00634                 nc->access = access;
00635                 for (j = 0; j < nc->accesscount; j++, access++)
00636                     SAFE(read_string(access, f));
00637             }
00638 
00639             SAFE(read_int16(&tmp16, f));
00640             nc->memos.memocount = (int16) tmp16;
00641             SAFE(read_int16(&tmp16, f));
00642             nc->memos.memomax = (int16) tmp16;
00643             if (nc->memos.memocount) {
00644                 Memo *memos;
00645                 memos = scalloc(sizeof(Memo) * nc->memos.memocount, 1);
00646                 nc->memos.memos = memos;
00647                 for (j = 0; j < nc->memos.memocount; j++, memos++) {
00648                     SAFE(read_int32(&memos->number, f));
00649                     SAFE(read_int16(&memos->flags, f));
00650                     SAFE(read_int32(&tmp32, f));
00651                     memos->time = tmp32;
00652                     SAFE(read_buffer(memos->sender, f));
00653                     SAFE(read_string(&memos->text, f));
00654                     memos->moduleData = NULL;
00655                 }
00656             }
00657 
00658             SAFE(read_int16(&nc->channelcount, f));
00659             SAFE(read_int16(&tmp16, f));
00660             nc->channelmax = CSMaxReg;
00661 
00662             if (ver < 13) {
00663                 /* Used to be dead authentication system */
00664                 SAFE(read_int16(&tmp16, f));
00665                 SAFE(read_int32(&tmp32, f));
00666                 SAFE(read_int16(&tmp16, f));
00667                 SAFE(read_string(&s, f));
00668             }
00669 
00670         }                       /* while (getc_db(f) != 0) */
00671         *nclast = NULL;
00672     }                           /* for (i) */
00673 
00674     for (i = 0; i < 1024 && !failed; i++) {
00675         nalast = &nalists[i];
00676         naprev = NULL;
00677         while ((c = getc_db(f)) == 1) {
00678             if (c != 1)
00679                 fatal("Invalid format in %s", NickDBName);
00680 
00681             na = scalloc(1, sizeof(NickAlias));
00682 
00683             SAFE(read_string(&na->nick, f));
00684 
00685             SAFE(read_string(&na->last_usermask, f));
00686             SAFE(read_string(&na->last_realname, f));
00687             SAFE(read_string(&na->last_quit, f));
00688 
00689             SAFE(read_int32(&tmp32, f));
00690             na->time_registered = tmp32;
00691             SAFE(read_int32(&tmp32, f));
00692             na->last_seen = tmp32;
00693             SAFE(read_int16(&na->status, f));
00694             na->status &= ~NS_TEMPORARY;
00695 
00696             SAFE(read_string(&s, f));
00697             na->nc = findcore(s);
00698             free(s);
00699 
00700             slist_add(&na->nc->aliases, na);
00701 
00702             if (!(na->status & NS_VERBOTEN)) {
00703                 if (!na->last_usermask)
00704                     na->last_usermask = sstrdup("");
00705                 if (!na->last_realname)
00706                     na->last_realname = sstrdup("");
00707             }
00708 
00709             na->nc->flags &= ~NI_SERVICES_ROOT;
00710 
00711             *nalast = na;
00712             nalast = &na->next;
00713             na->prev = naprev;
00714             naprev = na;
00715 
00716         }                       /* while (getc_db(f) != 0) */
00717 
00718         *nalast = NULL;
00719     }                           /* for (i) */
00720 
00721     close_db(f);
00722 
00723     for (i = 0; i < 1024; i++) {
00724         NickAlias *next;
00725 
00726         for (na = nalists[i]; na; na = next) {
00727             next = na->next;
00728             /* We check for coreless nicks (although it should never happen) */
00729             if (!na->nc) {
00730                 alog("%s: while loading database: %s has no core! We delete it.", s_NickServ, na->nick);
00731                 delnick(na);
00732                 continue;
00733             }
00734 
00735             /* Add the Services root flag if needed. */
00736             for (j = 0; j < RootNumber; j++)
00737                 if (!stricmp(ServicesRoots[j], na->nick))
00738                     na->nc->flags |= NI_SERVICES_ROOT;
00739         }
00740     }
00741 }
00742 
00743 #undef SAFE
00744 
00745 /*************************************************************************/
00746 
00747 #define SAFE(x) do {                                            \
00748     if ((x) < 0) {                                              \
00749         restore_db(f);                                          \
00750         log_perror("Write error on %s", NickDBName);            \
00751         if (time(NULL) - lastwarn > WarningTimeout) {           \
00752             anope_cmd_global(NULL, "Write error on %s: %s", NickDBName, \
00753                         strerror(errno));                       \
00754             lastwarn = time(NULL);                              \
00755         }                                                       \
00756         return;                                                 \
00757     }                                                           \
00758 } while (0)
00759 
00760 
00761 
00762 void save_ns_dbase(void)
00763 {
00764     dbFILE *f;
00765     int i, j;
00766     NickAlias *na;
00767     NickCore *nc;
00768     char **access;
00769     Memo *memos;
00770     static time_t lastwarn = 0;
00771 
00772     if (!(f = open_db(s_NickServ, NickDBName, "w", NICK_VERSION)))
00773         return;
00774 
00775     for (i = 0; i < 1024; i++) {
00776         for (nc = nclists[i]; nc; nc = nc->next) {
00777             SAFE(write_int8(1, f));
00778 
00779             SAFE(write_string(nc->display, f));
00780             SAFE(write_buffer(nc->pass, f));
00781 
00782             SAFE(write_string(nc->email, f));
00783             SAFE(write_string(nc->greet, f));
00784             SAFE(write_int32(nc->icq, f));
00785             SAFE(write_string(nc->url, f));
00786 
00787             SAFE(write_int32(nc->flags, f));
00788             SAFE(write_int16(nc->language, f));
00789 
00790             SAFE(write_int16(nc->accesscount, f));
00791             for (j = 0, access = nc->access; j < nc->accesscount;
00792                  j++, access++)
00793                 SAFE(write_string(*access, f));
00794 
00795             SAFE(write_int16(nc->memos.memocount, f));
00796             SAFE(write_int16(nc->memos.memomax, f));
00797             memos = nc->memos.memos;
00798             for (j = 0; j < nc->memos.memocount; j++, memos++) {
00799                 SAFE(write_int32(memos->number, f));
00800                 SAFE(write_int16(memos->flags, f));
00801                 SAFE(write_int32(memos->time, f));
00802                 SAFE(write_buffer(memos->sender, f));
00803                 SAFE(write_string(memos->text, f));
00804             }
00805 
00806             SAFE(write_int16(nc->channelcount, f));
00807             SAFE(write_int16(nc->channelmax, f));
00808 
00809         }                       /* for (nc) */
00810 
00811         SAFE(write_int8(0, f));
00812 
00813     }                           /* for (i) */
00814 
00815     for (i = 0; i < 1024; i++) {
00816         for (na = nalists[i]; na; na = na->next) {
00817             SAFE(write_int8(1, f));
00818 
00819             SAFE(write_string(na->nick, f));
00820 
00821             SAFE(write_string(na->last_usermask, f));
00822             SAFE(write_string(na->last_realname, f));
00823             SAFE(write_string(na->last_quit, f));
00824 
00825             SAFE(write_int32(na->time_registered, f));
00826             SAFE(write_int32(na->last_seen, f));
00827 
00828             SAFE(write_int16(na->status, f));
00829 
00830             SAFE(write_string(na->nc->display, f));
00831 
00832         }                       /* for (na) */
00833         SAFE(write_int8(0, f));
00834     }                           /* for (i) */
00835 
00836     close_db(f);
00837 
00838 }
00839 
00840 void save_ns_req_dbase(void)
00841 {
00842     dbFILE *f;
00843     int i;
00844     NickRequest *nr;
00845     static time_t lastwarn = 0;
00846 
00847     if (!(f = open_db(s_NickServ, PreNickDBName, "w", PRE_NICK_VERSION)))
00848         return;
00849 
00850     for (i = 0; i < 1024; i++) {
00851         for (nr = nrlists[i]; nr; nr = nr->next) {
00852             SAFE(write_int8(1, f));
00853             SAFE(write_string(nr->nick, f));
00854             SAFE(write_string(nr->passcode, f));
00855             SAFE(write_buffer(nr->password, f));
00856             SAFE(write_string(nr->email, f));
00857             SAFE(write_int32(nr->requested, f));
00858             SAFE(write_int8(0, f));
00859         }
00860     }
00861     close_db(f);
00862 
00863 }
00864 
00865 #undef SAFE
00866 
00867 void save_ns_rdb_dbase(void)
00868 {
00869 #ifdef USE_RDB
00870     int i;
00871     NickAlias *na;
00872     NickCore *nc;
00873 
00874     if (!rdb_open())
00875         return;
00876 
00877     if (rdb_tag_table("anope_ns_core") == 0) {
00878         alog("Unable to tag 'anope_ns_core' - NickServ RDB save failed.");
00879         rdb_close();
00880         return;
00881     }
00882     if (rdb_tag_table("anope_ns_alias") == 0) {
00883         alog("Unable to tag 'anope_ns_alias' - NickServ RDB save failed.");
00884         rdb_close();
00885         return;
00886     }
00887     if (rdb_tag_table("anope_ns_access") == 0) {
00888         alog("Unable to tag 'anope_ns_access' - NickServ RDB save failed.");
00889         rdb_close();
00890         return;
00891     }
00892     if (rdb_tag_table_where("anope_ms_info", "serv='NICK'") == 0) {
00893         alog("Unable to tag 'anope_ms_info' - NickServ RDB save failed.");
00894         rdb_close();
00895         return;
00896     }
00897 
00898     for (i = 0; i < 1024; i++) {
00899         for (nc = nclists[i]; nc; nc = nc->next) {
00900             if (rdb_save_ns_core(nc) == 0) {
00901                 alog("Unable to save NickCore for '%s' - NickServ RDB save failed.", nc->display);
00902                 rdb_close();
00903                 return;
00904             }
00905         }                       /* for (nc) */
00906     }                           /* for (i) */
00907 
00908     for (i = 0; i < 1024; i++) {
00909         for (na = nalists[i]; na; na = na->next) {
00910             if (rdb_save_ns_alias(na) == 0) {
00911                 alog("Unable to save NickAlias for '%s' - NickServ RDB save failed.", na->nick);
00912                 rdb_close();
00913                 return;
00914             }
00915         }                       /* for (na) */
00916     }                           /* for (i) */
00917 
00918     if (rdb_clean_table("anope_ns_core") == 0) {
00919         alog("Unable to clean table 'anope_ns_core' - NickServ RDB save failed.");
00920         rdb_close();
00921         return;
00922     }
00923     if (rdb_clean_table("anope_ns_alias") == 0) {
00924         alog("Unable to clean table 'anope_ns_alias' - NickServ RDB save failed.");
00925         rdb_close();
00926         return;
00927     }
00928     if (rdb_clean_table("anope_ns_access") == 0) {
00929         alog("Unable to clean table 'anope_ns_access' - NickServ RDB save failed.");
00930         rdb_close();
00931         return;
00932     }
00933     if (rdb_clean_table_where("anope_ms_info", "serv='NICK'") == 0)
00934         alog("Unable to clean table 'anope_ms_info' - NickServ RDB save failed.");
00935 
00936     rdb_close();
00937 #endif
00938 }
00939 
00940 void save_ns_req_rdb_dbase(void)
00941 {
00942 #ifdef USE_RDB
00943     int i;
00944     NickRequest *nr;
00945 
00946     if (!rdb_open())
00947         return;
00948 
00949     if (rdb_tag_table("anope_ns_request") == 0) {
00950         alog("Unable to tag table 'anope_ns_request' - NickServ Request RDB save failed.");
00951         rdb_close();
00952         return;
00953     }
00954 
00955     for (i = 0; i < 1024; i++) {
00956         for (nr = nrlists[i]; nr; nr = nr->next) {
00957             if (rdb_save_ns_req(nr) == 0) {
00958                 /* Something went wrong - abort saving */
00959                 alog("Unable to save NickRequest (nick '%s') - NickServ Request RDB save failed.", nr->nick);
00960                 rdb_close();
00961                 return;
00962             }
00963         }
00964     }
00965 
00966     if (rdb_clean_table("anope_ns_request") == 0)
00967         alog("Unable to clean table 'anope_ns_request' - NickServ Request RDB save failed.");
00968 
00969     rdb_close();
00970 #endif
00971 
00972 }
00973 
00974 /*************************************************************************/
00975 
00976 /* Check whether a user is on the access list of the nick they're using If
00977  * not, send warnings as appropriate.  If so (and not NI_SECURE), update
00978  * last seen info.
00979  * Return 1 if the user is valid and recognized, 0 otherwise (note
00980  * that this means an NI_SECURE nick will return 0 from here).
00981  * If the user's nick is not registered, 0 is returned.
00982  */
00983 
00984 int validate_user(User * u)
00985 {
00986     NickAlias *na;
00987     NickRequest *nr;
00988 
00989     int on_access;
00990 
00991     if ((nr = findrequestnick(u->nick))) {
00992         notice_lang(s_NickServ, u, NICK_IS_PREREG);
00993     }
00994 
00995     if (!(na = u->na))
00996         return 0;
00997 
00998     if (na->status & NS_VERBOTEN) {
00999         notice_lang(s_NickServ, u, NICK_MAY_NOT_BE_USED);
01000         collide(na, 0);
01001         return 0;
01002     }
01003 
01004     if (na->nc->flags & NI_SUSPENDED) {
01005         notice_lang(s_NickServ, u, NICK_X_SUSPENDED, u->nick);
01006         collide(na, 0);
01007         return 0;
01008     }
01009 
01010     if (na->status & NS_IDENTIFIED)
01011         return 1;
01012 
01013     on_access = is_on_access(u, na->nc);
01014     if (on_access)
01015         na->status |= NS_ON_ACCESS;
01016 
01017     if (!(na->nc->flags & NI_SECURE) && on_access) {
01018         na->status |= NS_RECOGNIZED;
01019         na->last_seen = time(NULL);
01020         if (na->last_usermask)
01021             free(na->last_usermask);
01022         na->last_usermask =
01023             scalloc(strlen(common_get_vident(u)) +
01024                     strlen(common_get_vhost(u)) + 2, 1);
01025         sprintf(na->last_usermask, "%s@%s", common_get_vident(u),
01026                 common_get_vhost(u));
01027         if (na->last_realname)
01028             free(na->last_realname);
01029         na->last_realname = sstrdup(u->realname);
01030         return 1;
01031     }
01032 
01033     if (on_access || !(na->nc->flags & NI_KILL_IMMED)) {
01034         if (na->nc->flags & NI_SECURE)
01035             notice_lang(s_NickServ, u, NICK_IS_SECURE, s_NickServ);
01036         else
01037             notice_lang(s_NickServ, u, NICK_IS_REGISTERED, s_NickServ);
01038     }
01039 
01040     if ((na->nc->flags & NI_KILLPROTECT) && !on_access) {
01041         if (na->nc->flags & NI_KILL_IMMED) {
01042             notice_lang(s_NickServ, u, FORCENICKCHANGE_NOW);
01043             collide(na, 0);
01044         } else if (na->nc->flags & NI_KILL_QUICK) {
01045             notice_lang(s_NickServ, u, FORCENICKCHANGE_IN_20_SECONDS);
01046             add_ns_timeout(na, TO_COLLIDE, 20);
01047         } else {
01048             notice_lang(s_NickServ, u, FORCENICKCHANGE_IN_1_MINUTE);
01049             add_ns_timeout(na, TO_COLLIDE, 60);
01050         }
01051     }
01052 
01053     return 0;
01054 }
01055 
01056 /*************************************************************************/
01057 
01058 /* Cancel validation flags for a nick (i.e. when the user with that nick
01059  * signs off or changes nicks).  Also cancels any impending collide. */
01060 
01061 void cancel_user(User * u)
01062 {
01063     NickAlias *na = u->na;
01064 
01065     if (na) {
01066         if (na->status & NS_GUESTED) {
01067             if (ircd->svshold) {
01068                 if (UseSVSHOLD) {
01069                     anope_cmd_svshold(na->nick);
01070                 } else {
01071                     if (ircd->svsnick) {
01072                         anope_cmd_guest_nick(u->nick, NSEnforcerUser,
01073                                              NSEnforcerHost,
01074                                              "Services Enforcer", "+");
01075                         add_ns_timeout(na, TO_RELEASE, NSReleaseTimeout);
01076                     } else {
01077                         anope_cmd_svskill(s_NickServ, u->nick,
01078                                           "Killing to enforce nick");
01079                     }
01080                 }
01081             } else {
01082                 if (ircd->svsnick) {
01083                     anope_cmd_guest_nick(u->nick, NSEnforcerUser,
01084                                          NSEnforcerHost,
01085                                          "Services Enforcer", "+");
01086                     add_ns_timeout(na, TO_RELEASE, NSReleaseTimeout);
01087                 } else {
01088                     anope_cmd_svskill(s_NickServ, u->nick,
01089                                       "Killing to enforce nick");
01090                 }
01091             }
01092             na->status &= ~NS_TEMPORARY;
01093             na->status |= NS_KILL_HELD;
01094         } else {
01095             na->status &= ~NS_TEMPORARY;
01096         }
01097         del_ns_timeout(na, TO_COLLIDE);
01098     }
01099 }
01100 
01101 /*************************************************************************/
01102 
01103 /* Return whether a user has identified for their nickname. */
01104 
01105 int nick_identified(User * u)
01106 {
01107     if (u) {
01108         if (u->na) {
01109             if (u->na->status) {
01110                 return (u->na->status & NS_IDENTIFIED);
01111             } else {
01112                 return 0;
01113             }
01114         } else {
01115             return 0;
01116         }
01117     }
01118     return 0;
01119 }
01120 
01121 /*************************************************************************/
01122 
01123 /* Return whether a user is recognized for their nickname. */
01124 
01125 int nick_recognized(User * u)
01126 {
01127     if (u) {
01128         if (u->na) {
01129             if (u->na->status) {
01130                 return (u->na->status & (NS_IDENTIFIED | NS_RECOGNIZED));
01131             } else {
01132                 return 0;
01133             }
01134         } else {
01135             return 0;
01136         }
01137     }
01138     return 0;
01139 }
01140 
01141 /*************************************************************************/
01142 
01143 /* Returns whether a user is identified AND in the group nc */
01144 
01145 int group_identified(User * u, NickCore * nc)
01146 {
01147     return nick_identified(u) && u->na->nc == nc;
01148 }
01149 
01150 /*************************************************************************/
01151 
01152 /* Remove all nicks which have expired.  Also update last-seen time for all
01153  * nicks.
01154  */
01155 
01156 void expire_nicks()
01157 {
01158     int i;
01159     NickAlias *na, *next;
01160     time_t now = time(NULL);
01161     char *tmpnick;
01162 
01163     for (i = 0; i < 1024; i++) {
01164         for (na = nalists[i]; na; na = next) {
01165             next = na->next;
01166 
01167             if (na->u
01168                 && ((na->nc->flags & NI_SECURE) ? nick_identified(na->u) :
01169                     nick_recognized(na->u))) {
01170                 if (debug >= 2)
01171                     alog("debug: NickServ: updating last seen time for %s",
01172                          na->nick);
01173                 na->last_seen = now;
01174                 continue;
01175             }
01176 
01177             if (NSExpire && now - na->last_seen >= NSExpire
01178                 && !(na->status & (NS_VERBOTEN | NS_NO_EXPIRE))
01179                 && !(na->nc->flags & (NI_SUSPENDED))) {
01180                 alog("Expiring nickname %s (group: %s) (e-mail: %s)",
01181                      na->nick, na->nc->display,
01182                      (na->nc->email ? na->nc->email : "none"));
01183                 tmpnick = sstrdup(na->nick);
01184                 delnick(na);
01185                 send_event(EVENT_NICK_EXPIRE, 1, tmpnick);
01186                 free(tmpnick);
01187             }
01188         }
01189     }
01190 }
01191 
01192 void expire_requests()
01193 {
01194     int i;
01195     NickRequest *nr, *next;
01196     time_t now = time(NULL);
01197     for (i = 0; i < 1024; i++) {
01198         for (nr = nrlists[i]; nr; nr = next) {
01199             next = nr->next;
01200             if (NSRExpire && now - nr->requested >= NSRExpire) {
01201                 alog("Request for nick %s expiring", nr->nick);
01202                 delnickrequest(nr);
01203             }
01204         }
01205     }
01206 }
01207 
01208 /*************************************************************************/
01209 /*************************************************************************/
01210 /* Return the NickRequest structire for the given nick, or NULL */
01211 
01212 NickRequest *findrequestnick(const char *nick)
01213 {
01214     NickRequest *nr;
01215 
01216     if (!*nick || !nick) {
01217         if (debug) {
01218             alog("debug: findrequestnick() called with NULL values");
01219         }
01220         return NULL;
01221     }
01222 
01223     for (nr = nrlists[HASH(nick)]; nr; nr = nr->next) {
01224         if (stricmp(nr->nick, nick) == 0)
01225             return nr;
01226     }
01227     return NULL;
01228 }
01229 
01230 /* Return the NickAlias structure for the given nick, or NULL if the nick
01231  * isn't registered. */
01232 
01233 NickAlias *findnick(const char *nick)
01234 {
01235     NickAlias *na;
01236 
01237     if (!nick || !*nick) {
01238         if (debug) {
01239             alog("debug: findnick() called with NULL values");
01240         }
01241         return NULL;
01242     }
01243 
01244     for (na = nalists[HASH(nick)]; na; na = na->next) {
01245         if (stricmp(na->nick, nick) == 0)
01246             return na;
01247     }
01248 
01249     return NULL;
01250 }
01251 
01252 /*************************************************************************/
01253 
01254 /* Return the NickCore structure for the given nick, or NULL if the core
01255  * doesn't exist. */
01256 
01257 NickCore *findcore(const char *nick)
01258 {
01259     NickCore *nc;
01260 
01261     if (!nick || !*nick) {
01262         if (debug) {
01263             alog("debug: findcore() called with NULL values");
01264         }
01265         return NULL;
01266     }
01267 
01268     for (nc = nclists[HASH(nick)]; nc; nc = nc->next) {
01269         if (stricmp(nc->display, nick) == 0)
01270             return nc;
01271     }
01272 
01273     return NULL;
01274 }
01275 
01276 /*************************************************************************/
01277 /*********************** NickServ private routines ***********************/
01278 /*************************************************************************/
01279 
01280 /* Is the given user's address on the given nick's access list?  Return 1
01281  * if so, 0 if not. */
01282 
01283 int is_on_access(User * u, NickCore * nc)
01284 {
01285     int i;
01286     char *buf, *buf2 = NULL, *buf3 = NULL;
01287 
01288     if (nc->accesscount == 0)
01289         return 0;
01290 
01291     buf = scalloc(strlen(u->username) + strlen(u->host) + 2, 1);
01292     sprintf(buf, "%s@%s", u->username, u->host);
01293     if (ircd->vhost) {
01294         if (u->vhost) {
01295             buf2 = scalloc(strlen(u->vident) + strlen(u->vhost) + 2, 1);
01296             sprintf(buf2, "%s@%s", u->vident, u->vhost);
01297         }
01298         if (u->chost)
01299         {
01300             buf3 = scalloc(strlen(u->username) + strlen(u->chost) + 2, 1);
01301             sprintf(buf3, "%s@%s", u->username, u->chost);
01302         }
01303     }
01304 
01305     for (i = 0; i < nc->accesscount; i++) {
01306           if (match_wild_nocase(nc->access[i], buf) || (buf2 && match_wild_nocase(nc->access[i], buf2)) || (buf3 && match_wild_nocase(nc->access[i], buf3)))
01307           {
01308             free(buf);
01309             if (ircd->vhost) {
01310                 if (u->vhost) {
01311                     free(buf2);
01312                 }
01313                 if (u->chost)
01314                   free(buf3);
01315             }
01316             return 1;
01317         }
01318     }
01319     free(buf);
01320     if (buf2)
01321         free(buf2);
01322     if (buf3)
01323         free(buf3);
01324     
01325     return 0;
01326 }
01327 
01328 /*************************************************************************/
01329 
01330 /* Insert a nick alias alphabetically into the database. */
01331 
01332 void alpha_insert_alias(NickAlias * na)
01333 {
01334     NickAlias *ptr, *prev;
01335     char *nick;
01336     int index;
01337 
01338     if (!na) {
01339         if (debug) {
01340             alog("debug: alpha_insert_alias called with NULL values");
01341         }
01342         return;
01343     }
01344 
01345     nick = na->nick;
01346     index = HASH(nick);
01347 
01348     for (prev = NULL, ptr = nalists[index];
01349          ptr && stricmp(ptr->nick, nick) < 0; prev = ptr, ptr = ptr->next);
01350     na->prev = prev;
01351     na->next = ptr;
01352     if (!prev)
01353         nalists[index] = na;
01354     else
01355         prev->next = na;
01356     if (ptr)
01357         ptr->prev = na;
01358 }
01359 
01360 /*************************************************************************/
01361 
01362 /* Insert a nick core into the database. */
01363 
01364 void insert_core(NickCore * nc)
01365 {
01366     int index;
01367 
01368     if (!nc) {
01369         if (debug) {
01370             alog("debug: insert_core called with NULL values");
01371         }
01372         return;
01373     }
01374 
01375     index = HASH(nc->display);
01376 
01377     nc->prev = NULL;
01378     nc->next = nclists[index];
01379     if (nc->next)
01380         nc->next->prev = nc;
01381     nclists[index] = nc;
01382 }
01383 
01384 /*************************************************************************/
01385 void insert_requestnick(NickRequest * nr)
01386 {
01387     int index;
01388     if (!nr) {
01389         if (debug) {
01390             alog("debug: insert_requestnick called with NULL values");
01391         }
01392         return;
01393     }
01394 
01395     index = HASH(nr->nick);
01396 
01397     nr->prev = NULL;
01398     nr->next = nrlists[index];
01399     if (nr->next)
01400         nr->next->prev = nr;
01401     nrlists[index] = nr;
01402 }
01403 
01404 /*************************************************************************/
01405 
01406 /* Sets nc->display to newdisplay. If newdisplay is NULL, it will change
01407  * it to the first alias in the list.
01408  */
01409 
01410 void change_core_display(NickCore * nc, char *newdisplay)
01411 {
01412     if (!newdisplay) {
01413         NickAlias *na;
01414 
01415         if (nc->aliases.count <= 0)
01416             return;
01417 
01418         na = nc->aliases.list[0];
01419         newdisplay = na->nick;
01420     }
01421 
01422     /* Log ... */
01423     alog("%s: changing %s nickname group display to %s", s_NickServ,
01424          nc->display, newdisplay);
01425     send_event(EVENT_CORE_NEWDISPLAY, 2, nc->display, newdisplay);
01426 
01427 #ifdef USE_RDB
01428     /* Reflect this change in the database right away. This
01429      * ensures that we know how to deal with this "new" nick
01430      * on the next /OS UPDATE might need it on /NS DROP too...
01431      */
01432     if (rdb_open()) {
01433         if (rdb_ns_set_display(newdisplay, nc->display) == 0) {
01434             alog("Unable to update display for %s - Nick Display RDB update failed.", nc->display);
01435         }
01436         rdb_close();
01437     }
01438 #endif
01439 
01440     /* Remove the core from the list */
01441     if (nc->next)
01442         nc->next->prev = nc->prev;
01443     if (nc->prev)
01444         nc->prev->next = nc->next;
01445     else
01446         nclists[HASH(nc->display)] = nc->next;
01447 
01448     free(nc->display);
01449     nc->display = sstrdup(newdisplay);
01450     insert_core(nc);
01451 
01452 }
01453 
01454 /*************************************************************************/
01455 
01456 /* Deletes the core. This must be called only when there is no more
01457  * aliases for it, because no cleanup is done.
01458  * This function removes all references to the core as well.
01459  */
01460 
01461 static int delcore(NickCore * nc)
01462 {
01463     int i;
01464 #ifdef USE_RDB
01465     static char clause[128];
01466     char *q_display;
01467 #endif
01468 
01469     /* Inform everyone we will be deleted.. 
01470      * Some modules may link to the core and should be told when we
01471      * are no longer around.. ~ Viper */
01472     send_event(EVENT_CORE_DROPPED, 1, nc->display);
01473     /* (Hopefully complete) cleanup */
01474     cs_remove_nick(nc);
01475     os_remove_nick(nc);
01476 
01477     /* Remove the core from the list */
01478     if (nc->next)
01479         nc->next->prev = nc->prev;
01480     if (nc->prev)
01481         nc->prev->next = nc->next;
01482     else
01483         nclists[HASH(nc->display)] = nc->next;
01484 
01485     /* Log .. */
01486     alog("%s: deleting nickname group %s", s_NickServ, nc->display);
01487 
01488 #ifdef USE_RDB
01489     /* Reflect this change in the database right away. */
01490     if (rdb_open()) {
01491         q_display = rdb_quote(nc->display);
01492         snprintf(clause, sizeof(clause), "display='%s'", q_display);
01493         if (rdb_scrub_table("anope_ns_access", clause) == 0)
01494             alog("Unable to scrub table 'anope_ns_access' - RDB update failed.");
01495         else if (rdb_scrub_table("anope_ns_core", clause) == 0)
01496             alog("Unable to scrub table 'anope_ns_core' - RDB update failed.");
01497         else if (rdb_scrub_table("anope_cs_access", clause) == 0)
01498             alog("Unable to scrub table 'anope_cs_access' - RDB update failed.");
01499         else {
01500             /* I'm unsure how to clean up the OS ADMIN/OPER list on the db */
01501             /* I wish the "display" primary key would be the same on all tables */
01502             snprintf(clause, sizeof(clause),
01503                      "receiver='%s' AND serv='NICK'", q_display);
01504             if (rdb_scrub_table("anope_ms_info", clause) == 0)
01505                 alog("Unable to scrub table 'anope_ms_info' - RDB update failed.");
01506         }
01507         rdb_close();
01508         free(q_display);
01509     }
01510 #endif
01511 
01512     /* Now we can safely free it. */
01513     free(nc->display);
01514 
01515     if (nc->email)
01516         free(nc->email);
01517     if (nc->greet)
01518         free(nc->greet);
01519     if (nc->url)
01520         free(nc->url);
01521 
01522     if (nc->access) {
01523         for (i = 0; i < nc->accesscount; i++) {
01524             if (nc->access[i])
01525                 free(nc->access[i]);
01526         }
01527         free(nc->access);
01528     }
01529 
01530     if (nc->memos.memos) {
01531         for (i = 0; i < nc->memos.memocount; i++) {
01532             if (nc->memos.memos[i].text)
01533                 free(nc->memos.memos[i].text);
01534             moduleCleanStruct(&nc->memos.memos[i].moduleData);
01535         }
01536         free(nc->memos.memos);
01537     }
01538 
01539     moduleCleanStruct(&nc->moduleData);
01540 
01541     free(nc);
01542 
01543     return 1;
01544 }
01545 
01546 
01547 /*************************************************************************/
01548 int delnickrequest(NickRequest * nr)
01549 {
01550     if (nr) {
01551         if (nr->next)
01552             nr->next->prev = nr->prev;
01553         if (nr->prev)
01554             nr->prev->next = nr->next;
01555         else
01556             nrlists[HASH(nr->nick)] = nr->next;
01557 
01558         if (nr->nick)
01559             free(nr->nick);
01560         if (nr->passcode)
01561             free(nr->passcode);
01562         if (nr->email)
01563             free(nr->email);
01564         free(nr);
01565     }
01566 
01567     return 0;
01568 }
01569 
01570 /*************************************************************************/
01571 
01572 /* Deletes an alias. The core will also be deleted if it has no more
01573  * nicks attached to it. Easy but powerful.
01574  * Well, we must also take care that the nick being deleted is not
01575  * the core display, and if so, change it to the next alias in the list,
01576  * otherwise weird things will happen.
01577  * Returns 1 on success, 0 otherwise.
01578  */
01579 
01580 int delnick(NickAlias * na)
01581 {
01582 #ifdef USE_RDB
01583     static char clause[128];
01584     char *q_nick;
01585 #endif
01586     /* First thing to do: remove any timeout belonging to the nick we're deleting */
01587     clean_ns_timeouts(na);
01588 
01589     /* Second thing to do: look for an user using the alias
01590      * being deleted, and make appropriate changes */
01591 
01592     if (na->u) {
01593         na->u->na = NULL;
01594 
01595         if (ircd->modeonunreg)
01596             common_svsmode(na->u, ircd->modeonunreg, "1");
01597 
01598     }
01599 
01600     delHostCore(na->nick);      /* delete any vHost's for this nick */
01601 
01602     /* Accept nicks that have no core, because of database load functions */
01603     if (na->nc) {
01604         /* Next: see if our core is still useful. */
01605         slist_remove(&na->nc->aliases, na);
01606         if (na->nc->aliases.count == 0) {
01607             if (!delcore(na->nc))
01608                 return 0;
01609             na->nc = NULL;
01610         } else {
01611             /* Display updating stuff */
01612             if (!stricmp(na->nick, na->nc->display))
01613                 change_core_display(na->nc, NULL);
01614         }
01615     }
01616 
01617     /* Remove us from the aliases list */
01618     if (na->next)
01619         na->next->prev = na->prev;
01620     if (na->prev)
01621         na->prev->next = na->next;
01622     else
01623         nalists[HASH(na->nick)] = na->next;
01624 
01625 #ifdef USE_RDB
01626     /* Reflect this change in the database right away. */
01627     if (rdb_open()) {
01628         q_nick = rdb_quote(na->nick);
01629         snprintf(clause, sizeof(clause), "nick='%s'", q_nick);
01630         if (rdb_scrub_table("anope_ns_alias", clause) == 0)
01631             alog("Unable to scrub table 'anope_ns_alias' - RDB update failed");
01632         rdb_close();
01633         free(q_nick);
01634     }
01635 #endif
01636 
01637     free(na->nick);
01638     if (na->last_usermask)
01639         free(na->last_usermask);
01640     if (na->last_realname)
01641         free(na->last_realname);
01642     if (na->last_quit)
01643         free(na->last_quit);
01644 
01645     moduleCleanStruct(&na->moduleData);
01646 
01647     free(na);
01648 
01649 
01650     return 1;
01651 }
01652 
01653 /*************************************************************************/
01654 /*************************************************************************/
01655 
01656 /* Collide a nick.
01657  *
01658  * When connected to a network using DALnet servers, version 4.4.15 and above,
01659  * Services is now able to force a nick change instead of killing the user.
01660  * The new nick takes the form "Guest######". If a nick change is forced, we
01661  * do not introduce the enforcer nick until the user's nick actually changes.
01662  * This is watched for and done in cancel_user(). -TheShadow
01663  */
01664 
01665 void collide(NickAlias * na, int from_timeout)
01666 {
01667     char guestnick[NICKMAX];
01668 
01669     if (!from_timeout)
01670         del_ns_timeout(na, TO_COLLIDE);
01671 
01672     /* Old system was unsure since there can be more than one collide
01673      * per second. So let use another safer method.
01674      *          --lara
01675      */
01676     /* So you should check the length of NSGuestNickPrefix, eh Lara?
01677      *          --Certus
01678      */
01679 
01680     if (ircd->svsnick) {
01681         /* We need to make sure the guestnick is free -- heinz */
01682         do {
01683             snprintf(guestnick, sizeof(guestnick), "%s%d",
01684                      NSGuestNickPrefix, getrandom16());
01685         } while (finduser(guestnick));
01686         notice_lang(s_NickServ, na->u, FORCENICKCHANGE_CHANGING,
01687                     guestnick);
01688         anope_cmd_svsnick(na->nick, guestnick, time(NULL));
01689         na->status |= NS_GUESTED;
01690     } else {
01691         kill_user(s_NickServ, na->nick, "Services nickname-enforcer kill");
01692     }
01693 }
01694 
01695 /*************************************************************************/
01696 
01697 /* Release hold on a nick. */
01698 
01699 void release(NickAlias * na, int from_timeout)
01700 {
01701     if (!from_timeout)
01702         del_ns_timeout(na, TO_RELEASE);
01703     if (ircd->svshold) {
01704         if (UseSVSHOLD) {
01705             anope_cmd_release_svshold(na->nick);
01706         } else {
01707             anope_cmd_quit(na->nick, NULL);
01708         }
01709     } else {
01710         anope_cmd_quit(na->nick, NULL);
01711     }
01712     na->status &= ~NS_KILL_HELD;
01713 }
01714 
01715 /*************************************************************************/
01716 /*************************************************************************/
01717 
01718 static struct my_timeout {
01719     struct my_timeout *next, *prev;
01720     NickAlias *na;
01721     Timeout *to;
01722     int type;
01723 } *my_timeouts;
01724 
01725 /*************************************************************************/
01726 
01727 /* Remove a collide/release timeout from our private list. */
01728 
01729 static void rem_ns_timeout(NickAlias * na, int type)
01730 {
01731     struct my_timeout *t, *t2;
01732 
01733     t = my_timeouts;
01734     while (t) {
01735         if (t->na == na && t->type == type) {
01736             t2 = t->next;
01737             if (t->next)
01738                 t->next->prev = t->prev;
01739             if (t->prev)
01740                 t->prev->next = t->next;
01741             else
01742                 my_timeouts = t->next;
01743             free(t);
01744             t = t2;
01745         } else {
01746             t = t->next;
01747         }
01748     }
01749 }
01750 
01751 /*************************************************************************/
01752 
01753 /* Collide a nick on timeout. */
01754 
01755 static void timeout_collide(Timeout * t)
01756 {
01757     NickAlias *na = t->data;
01758 
01759     rem_ns_timeout(na, TO_COLLIDE);
01760     /* If they identified or don't exist anymore, don't kill them. */
01761     if ((na->status & NS_IDENTIFIED) || !na->u
01762         || na->u->my_signon > t->settime)
01763         return;
01764     /* The RELEASE timeout will always add to the beginning of the
01765      * list, so we won't see it.  Which is fine because it can't be
01766      * triggered yet anyway. */
01767     collide(na, 1);
01768 }
01769 
01770 /*************************************************************************/
01771 
01772 /* Release a nick on timeout. */
01773 
01774 static void timeout_release(Timeout * t)
01775 {
01776     NickAlias *na = t->data;
01777 
01778     rem_ns_timeout(na, TO_RELEASE);
01779     release(na, 1);
01780 }
01781 
01782 /*************************************************************************/
01783 
01784 /* Add a collide/release timeout. */
01785 
01786 static void add_ns_timeout(NickAlias * na, int type, time_t delay)
01787 {
01788     Timeout *to;
01789     struct my_timeout *t;
01790     void (*timeout_routine) (Timeout *);
01791 
01792     if (type == TO_COLLIDE)
01793         timeout_routine = timeout_collide;
01794     else if (type == TO_RELEASE)
01795         timeout_routine = timeout_release;
01796     else {
01797         alog("NickServ: unknown timeout type %d! na=0x%p (%s), delay=%ld",
01798              type, (void *) na, na->nick, (long int) delay);
01799         return;
01800     }
01801 
01802     to = add_timeout(delay, timeout_routine, 0);
01803     to->data = na;
01804 
01805     t = scalloc(sizeof(struct my_timeout), 1);
01806     t->na = na;
01807     t->to = to;
01808     t->type = type;
01809 
01810     t->prev = NULL;
01811     t->next = my_timeouts;
01812     my_timeouts = t;
01813     /* Andy Church should stop coding while being drunk.
01814      * Here's the two lines he forgot that produced the timed_update evil bug
01815      * and a *big* memory leak.
01816      */
01817     if (t->next)
01818         t->next->prev = t;
01819 }
01820 
01821 /*************************************************************************/
01822 
01823 /* Delete a collide/release timeout. */
01824 
01825 void del_ns_timeout(NickAlias * na, int type)
01826 {
01827     struct my_timeout *t, *t2;
01828 
01829     t = my_timeouts;
01830     while (t) {
01831         if (t->na == na && t->type == type) {
01832             t2 = t->next;
01833             if (t->next)
01834                 t->next->prev = t->prev;
01835             if (t->prev)
01836                 t->prev->next = t->next;
01837             else
01838                 my_timeouts = t->next;
01839             del_timeout(t->to);
01840             free(t);
01841             t = t2;
01842         } else {
01843             t = t->next;
01844         }
01845     }
01846 }
01847 
01848 /*************************************************************************/
01849 
01850 /* Deletes all timeouts belonging to a given nick.
01851  * This should only be called before nick deletion.
01852  */
01853 
01854 void clean_ns_timeouts(NickAlias * na)
01855 {
01856     struct my_timeout *t, *next;
01857 
01858     for (t = my_timeouts; t; t = next) {
01859         next = t->next;
01860         if (t->na == na) {
01861             if (debug)
01862                 alog("debug: %s deleting timeout type %d from %s",
01863                      s_NickServ, t->type, t->na->nick);
01864             /* If the timeout has the TO_RELEASE type, we should release the user */
01865             if (t->type == TO_RELEASE)
01866                 release(na, 1);
01867             if (t->next)
01868                 t->next->prev = t->prev;
01869             if (t->prev)
01870                 t->prev->next = t->next;
01871             else
01872                 my_timeouts = t->next;
01873             del_timeout(t->to);
01874             free(t);
01875         }
01876     }
01877 }
01878 
01879 /*************************************************************************/
01880 /*********************** NickServ command routines ***********************/
01881 /*************************************************************************/
01882 
01883 
01884 /* We don't use this function but we keep it for module coders -certus */
01885 int should_mode_change(int16 status, int16 mode)
01886 {
01887     switch (mode) {
01888     case CUS_OP:
01889         if (status & CUS_OP) {
01890             return 0;
01891         }
01892         break;
01893     case CUS_VOICE:
01894         if (status & CUS_OP) {
01895             return 0;
01896         }
01897         if (status & CUS_HALFOP) {
01898             return 0;
01899         }
01900         if (status & CUS_VOICE) {
01901             return 0;
01902         }
01903         return 1;
01904         break;
01905     case CUS_HALFOP:
01906         if (status & CUS_OP) {
01907             return 0;
01908         }
01909         if (status & CUS_HALFOP) {
01910             return 0;
01911         }
01912         return 1;
01913         break;
01914     case CUS_OWNER:
01915         if (ircd->owner) {
01916             if (status & CUS_OWNER) {
01917                 return 0;
01918             }
01919         }
01920         break;
01921     case CUS_PROTECT:
01922         if (ircd->protect) {
01923             if (status & CUS_PROTECT) {
01924                 return 0;
01925             }
01926         }
01927         break;
01928     }
01929     return 1;
01930 }
01931 
01932 /*************************************************************************/
01933 
01934 int do_setmodes(User * u)
01935 {
01936     struct u_chanlist *uc;
01937     Channel *c;
01938 
01939     /* Walk users current channels */
01940     for (uc = u->chans; uc; uc = uc->next) {
01941         if ((c = uc->chan))
01942             chan_set_correct_modes(u, c, 1);
01943     }
01944     return MOD_CONT;
01945 }
01946 
01947 /*************************************************************************/
01948 /*               
01949  * Nick tracking
01950  */
01951 
01956 void nsStartNickTracking(User * u)
01957 {
01958     NickCore *nc;
01959 
01960     /* We only track identified users */
01961     if (nick_identified(u)) {
01962         nc = u->na->nc;
01963 
01964         /* Release memory if needed */
01965         if (u->nickTrack)
01966             free(u->nickTrack);
01967 
01968         /* Copy the nick core displayed nick to
01969            the user structure for further checks */
01970         u->nickTrack = sstrdup(nc->display);
01971     }
01972 }
01973 
01978 void nsStopNickTracking(User * u)
01979 {
01980     /* Simple enough. If its there, release it */
01981     if (u->nickTrack) {
01982         free(u->nickTrack);
01983         u->nickTrack = NULL;
01984     }
01985 }
01986 
01992 int nsCheckNickTracking(User * u)
01993 {
01994     NickCore *nc;
01995     NickAlias *na;
01996     char *nick;
01997 
01998     /* No nick alias or nick return false by default */
01999     if ((!(na = u->na)) || (!(nick = na->nick))) {
02000         return 0;
02001     }
02002 
02003     /* nick is forbidden best return 0 */
02004     if (na->status & NS_VERBOTEN) {
02005         return 0;
02006     }
02007 
02008     /* Get the core for the requested nick */
02009     nc = na->nc;
02010 
02011     /* If the core and the tracking displayed nick are there,
02012      * and they match, return true
02013      */
02014     if (nc && u->nickTrack && (strcmp(nc->display, u->nickTrack) == 0))
02015         return 1;
02016     else
02017         return 0;
02018 }