chanserv.c

Go to the documentation of this file.
00001 /* ChanServ functions.
00002  *
00003  * (C) 2003-2007 Anope Team
00004  * Contact us at info@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church. 
00010  * 
00011  * $Id: chanserv.c 1322 2007-12-28 19:12:02Z geniusdex $ 
00012  *
00013  */
00014 
00015 /*************************************************************************/
00016 
00017 #include "services.h"
00018 #include "pseudo.h"
00019 
00020 /*************************************************************************/
00021 /* *INDENT-OFF* */
00022 
00023 ChannelInfo *chanlists[256];
00024 
00025 static int def_levels[][2] = {
00026     { CA_AUTOOP,                     5 },
00027     { CA_AUTOVOICE,                  3 },
00028     { CA_AUTODEOP,                  -1 },
00029     { CA_NOJOIN,                    -2 },
00030     { CA_INVITE,                     5 },
00031     { CA_AKICK,                     10 },
00032     { CA_SET,           ACCESS_INVALID },
00033     { CA_CLEAR,         ACCESS_INVALID },
00034     { CA_UNBAN,                      5 },
00035     { CA_OPDEOP,                     5 },
00036     { CA_ACCESS_LIST,                1 },
00037     { CA_ACCESS_CHANGE,             10 },
00038     { CA_MEMO,                      10 },
00039     { CA_ASSIGN,        ACCESS_INVALID },
00040     { CA_BADWORDS,                  10 },
00041     { CA_NOKICK,                     1 },
00042     { CA_FANTASIA,                   3 },
00043     { CA_SAY,                        5 },
00044     { CA_GREET,                      5 },
00045     { CA_VOICEME,                    3 },
00046     { CA_VOICE,                      5 },
00047     { CA_GETKEY,                     5 },
00048     { CA_AUTOHALFOP,                 4 },
00049     { CA_AUTOPROTECT,               10 },
00050     { CA_OPDEOPME,                   5 },
00051     { CA_HALFOPME,                   4 },
00052     { CA_HALFOP,                     5 },
00053     { CA_PROTECTME,                 10 },
00054     { CA_PROTECT,       ACCESS_INVALID },
00055     { CA_KICKME,                     5 },
00056     { CA_KICK,                       5 },
00057     { CA_SIGNKICK,      ACCESS_INVALID },
00058     { CA_BANME,                      5 },
00059     { CA_BAN,                        5 },
00060     { CA_TOPIC,         ACCESS_INVALID },
00061     { CA_INFO,          ACCESS_INVALID },
00062     { -1 }
00063 };
00064 
00065 
00066 LevelInfo levelinfo[] = {
00067     { CA_AUTODEOP,      "AUTODEOP",     CHAN_LEVEL_AUTODEOP },
00068     { CA_AUTOHALFOP,    "AUTOHALFOP",   CHAN_LEVEL_AUTOHALFOP },
00069     { CA_AUTOOP,        "AUTOOP",       CHAN_LEVEL_AUTOOP },
00070     { CA_AUTOPROTECT,   "",  CHAN_LEVEL_AUTOPROTECT },
00071     { CA_AUTOVOICE,     "AUTOVOICE",    CHAN_LEVEL_AUTOVOICE },
00072     { CA_NOJOIN,        "NOJOIN",       CHAN_LEVEL_NOJOIN },
00073     { CA_SIGNKICK,      "SIGNKICK",     CHAN_LEVEL_SIGNKICK },
00074     { CA_ACCESS_LIST,   "ACC-LIST",     CHAN_LEVEL_ACCESS_LIST },
00075     { CA_ACCESS_CHANGE, "ACC-CHANGE",   CHAN_LEVEL_ACCESS_CHANGE },
00076     { CA_AKICK,         "AKICK",        CHAN_LEVEL_AKICK },
00077     { CA_SET,           "SET",          CHAN_LEVEL_SET },
00078     { CA_BAN,           "BAN",          CHAN_LEVEL_BAN },
00079     { CA_BANME,         "BANME",        CHAN_LEVEL_BANME },
00080     { CA_CLEAR,         "CLEAR",        CHAN_LEVEL_CLEAR },
00081     { CA_GETKEY,        "GETKEY",       CHAN_LEVEL_GETKEY },
00082     { CA_HALFOP,        "HALFOP",       CHAN_LEVEL_HALFOP },
00083     { CA_HALFOPME,      "HALFOPME",     CHAN_LEVEL_HALFOPME },
00084     { CA_INFO,          "INFO",         CHAN_LEVEL_INFO },
00085     { CA_KICK,          "KICK",         CHAN_LEVEL_KICK },
00086     { CA_KICKME,        "KICKME",       CHAN_LEVEL_KICKME },
00087     { CA_INVITE,        "INVITE",       CHAN_LEVEL_INVITE },
00088     { CA_OPDEOP,        "OPDEOP",       CHAN_LEVEL_OPDEOP },
00089     { CA_OPDEOPME,      "OPDEOPME",     CHAN_LEVEL_OPDEOPME },
00090     { CA_PROTECT,       "",      CHAN_LEVEL_PROTECT },
00091     { CA_PROTECTME,     "",    CHAN_LEVEL_PROTECTME },
00092     { CA_TOPIC,         "TOPIC",        CHAN_LEVEL_TOPIC },
00093     { CA_UNBAN,         "UNBAN",        CHAN_LEVEL_UNBAN },
00094     { CA_VOICE,         "VOICE",        CHAN_LEVEL_VOICE },
00095     { CA_VOICEME,       "VOICEME",      CHAN_LEVEL_VOICEME },
00096     { CA_MEMO,          "MEMO",         CHAN_LEVEL_MEMO },
00097     { CA_ASSIGN,        "ASSIGN",       CHAN_LEVEL_ASSIGN },
00098     { CA_BADWORDS,      "BADWORDS",     CHAN_LEVEL_BADWORDS },
00099     { CA_FANTASIA,      "FANTASIA",     CHAN_LEVEL_FANTASIA },
00100     { CA_GREET,     "GREET",        CHAN_LEVEL_GREET },
00101     { CA_NOKICK,        "NOKICK",       CHAN_LEVEL_NOKICK },
00102     { CA_SAY,       "SAY",      CHAN_LEVEL_SAY },
00103         { -1 }
00104 };
00105 int levelinfo_maxwidth = 0;
00106 
00107 CSModeUtil csmodeutils[] = {
00108     { "DEOP",      "deop",     "-o", CI_OPNOTICE, CA_OPDEOP,  CA_OPDEOPME },
00109     { "OP",        "op",       "+o", CI_OPNOTICE, CA_OPDEOP,  CA_OPDEOPME },
00110     { "DEVOICE",   "devoice",  "-v", 0,           CA_VOICE,   CA_VOICEME  },
00111     { "VOICE",     "voice",    "+v", 0,           CA_VOICE,   CA_VOICEME  },
00112     { "DEHALFOP",  "dehalfop", "-h", 0,           CA_HALFOP,  CA_HALFOPME },
00113     { "HALFOP",    "halfop",   "+h", 0,           CA_HALFOP,  CA_HALFOPME },
00114     { "DEPROTECT", "",         "",   0,           CA_PROTECT, CA_PROTECTME },
00115     { "PROTECT",   "",         "",   0,           CA_PROTECT, CA_PROTECTME },
00116     { NULL }
00117 };
00118 
00119 /*************************************************************************/
00120 
00121 void moduleAddChanServCmds(void) {
00122     modules_core_init(ChanServCoreNumber, ChanServCoreModules);
00123 }
00124 
00125 /* *INDENT-ON* */
00126 /*************************************************************************/
00127 /*************************************************************************/
00128 
00129 /* Returns modes for mlock in a nice way. */
00130 
00131 char *get_mlock_modes(ChannelInfo * ci, int complete)
00132 {
00133     static char res[BUFSIZE];
00134 
00135     char *end = res;
00136 
00137     if (ci->mlock_on || ci->mlock_off) {
00138         int n = 0;
00139         CBModeInfo *cbmi = cbmodeinfos;
00140 
00141         if (ci->mlock_on) {
00142             *end++ = '+';
00143             n++;
00144 
00145             do {
00146                 if (ci->mlock_on & cbmi->flag)
00147                     *end++ = cbmi->mode;
00148             } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
00149 
00150             cbmi = cbmodeinfos;
00151         }
00152 
00153         if (ci->mlock_off) {
00154             *end++ = '-';
00155             n++;
00156 
00157             do {
00158                 if (ci->mlock_off & cbmi->flag)
00159                     *end++ = cbmi->mode;
00160             } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
00161 
00162             cbmi = cbmodeinfos;
00163         }
00164 
00165         if (ci->mlock_on && complete) {
00166             do {
00167                 if (cbmi->csgetvalue && (ci->mlock_on & cbmi->flag)) {
00168                     char *value = cbmi->csgetvalue(ci);
00169 
00170                     if (value) {
00171                         *end++ = ' ';
00172                         while (*value)
00173                             *end++ = *value++;
00174                     }
00175                 }
00176             } while ((++cbmi)->flag != 0 && ++n < sizeof(res) - 1);
00177         }
00178     }
00179 
00180     *end = 0;
00181 
00182     return res;
00183 }
00184 
00185 /* Display total number of registered channels and info about each; or, if
00186  * a specific channel is given, display information about that channel
00187  * (like /msg ChanServ INFO <channel>).  If count_only != 0, then only
00188  * display the number of registered channels (the channel parameter is
00189  * ignored).
00190  */
00191 
00192 void listchans(int count_only, const char *chan)
00193 {
00194     int count = 0;
00195     ChannelInfo *ci;
00196     int i;
00197 
00198     if (count_only) {
00199 
00200         for (i = 0; i < 256; i++) {
00201             for (ci = chanlists[i]; ci; ci = ci->next)
00202                 count++;
00203         }
00204         printf("%d channels registered.\n", count);
00205 
00206     } else if (chan) {
00207 
00208         struct tm *tm;
00209         char buf[BUFSIZE];
00210 
00211         if (!(ci = cs_findchan(chan))) {
00212             printf("Channel %s not registered.\n", chan);
00213             return;
00214         }
00215         if (ci->flags & CI_VERBOTEN) {
00216             printf("Channel %s is FORBIDden.\n", ci->name);
00217         } else {
00218             printf("Information about channel %s:\n", ci->name);
00219             printf("        Founder: %s\n", ci->founder->display);
00220             printf("    Description: %s\n", ci->desc);
00221             tm = localtime(&ci->time_registered);
00222             strftime(buf, sizeof(buf),
00223                      getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00224             printf("     Registered: %s\n", buf);
00225             tm = localtime(&ci->last_used);
00226             strftime(buf, sizeof(buf),
00227                      getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00228             printf("      Last used: %s\n", buf);
00229             if (ci->last_topic) {
00230                 printf("     Last topic: %s\n", ci->last_topic);
00231                 printf("   Topic set by: %s\n", ci->last_topic_setter);
00232             }
00233             if (ci->url)
00234                 printf("            URL: %s\n", ci->url);
00235             if (ci->email)
00236                 printf(" E-mail address: %s\n", ci->email);
00237             printf("        Options: ");
00238             if (!ci->flags) {
00239                 printf("None\n");
00240             } else {
00241                 int need_comma = 0;
00242                 static const char commastr[] = ", ";
00243                 if (ci->flags & CI_PRIVATE) {
00244                     printf("Private");
00245                     need_comma = 1;
00246                 }
00247                 if (ci->flags & CI_KEEPTOPIC) {
00248                     printf("%sTopic Retention",
00249                            need_comma ? commastr : "");
00250                     need_comma = 1;
00251                 }
00252                 if (ci->flags & CI_TOPICLOCK) {
00253                     printf("%sTopic Lock", need_comma ? commastr : "");
00254                     need_comma = 1;
00255                 }
00256                 if (ci->flags & CI_SECUREOPS) {
00257                     printf("%sSecure Ops", need_comma ? commastr : "");
00258                     need_comma = 1;
00259                 }
00260                 if (ci->flags & CI_RESTRICTED) {
00261                     printf("%sRestricted Access",
00262                            need_comma ? commastr : "");
00263                     need_comma = 1;
00264                 }
00265                 if (ci->flags & CI_SECURE) {
00266                     printf("%sSecure", need_comma ? commastr : "");
00267                     need_comma = 1;
00268                 }
00269                 if (ci->flags & CI_NO_EXPIRE) {
00270                     printf("%sNo Expire", need_comma ? commastr : "");
00271                     need_comma = 1;
00272                 }
00273                 printf("\n");
00274             }
00275             if (ci->mlock_on || ci->mlock_off)
00276                 printf("      Mode lock: %s\n", get_mlock_modes(ci, 1));
00277         }
00278 
00279     } else {
00280 
00281         for (i = 0; i < 256; i++) {
00282             for (ci = chanlists[i]; ci; ci = ci->next) {
00283                 printf("  %s %-20s  %s\n",
00284                        ci->flags & CI_NO_EXPIRE ? "!" : " ", ci->name,
00285                        ci->
00286                        flags & CI_VERBOTEN ? "Disallowed (FORBID)" : ci->
00287                        desc);
00288                 count++;
00289             }
00290         }
00291         printf("%d channels registered.\n", count);
00292 
00293     }
00294 }
00295 
00296 /*************************************************************************/
00297 
00298 /* Return information on memory use.  Assumes pointers are valid. */
00299 
00300 void get_chanserv_stats(long *nrec, long *memuse)
00301 {
00302     long count = 0, mem = 0;
00303     int i, j;
00304     ChannelInfo *ci;
00305 
00306     for (i = 0; i < 256; i++) {
00307         for (ci = chanlists[i]; ci; ci = ci->next) {
00308             count++;
00309             mem += sizeof(*ci);
00310             if (ci->desc)
00311                 mem += strlen(ci->desc) + 1;
00312             if (ci->url)
00313                 mem += strlen(ci->url) + 1;
00314             if (ci->email)
00315                 mem += strlen(ci->email) + 1;
00316             mem += ci->accesscount * sizeof(ChanAccess);
00317             mem += ci->akickcount * sizeof(AutoKick);
00318             for (j = 0; j < ci->akickcount; j++) {
00319                 if (!(ci->akick[j].flags & AK_ISNICK)
00320                     && ci->akick[j].u.mask)
00321                     mem += strlen(ci->akick[j].u.mask) + 1;
00322                 if (ci->akick[j].reason)
00323                     mem += strlen(ci->akick[j].reason) + 1;
00324                 if (ci->akick[j].creator)
00325                     mem += strlen(ci->akick[j].creator) + 1;
00326             }
00327             if (ci->mlock_key)
00328                 mem += strlen(ci->mlock_key) + 1;
00329             if (ircd->fmode) {
00330                 if (ci->mlock_flood)
00331                     mem += strlen(ci->mlock_flood) + 1;
00332             }
00333             if (ircd->Lmode) {
00334                 if (ci->mlock_redirect)
00335                     mem += strlen(ci->mlock_redirect) + 1;
00336             }
00337             if (ci->last_topic)
00338                 mem += strlen(ci->last_topic) + 1;
00339             if (ci->entry_message)
00340                 mem += strlen(ci->entry_message) + 1;
00341             if (ci->forbidby)
00342                 mem += strlen(ci->forbidby) + 1;
00343             if (ci->forbidreason)
00344                 mem += strlen(ci->forbidreason) + 1;
00345             if (ci->levels)
00346                 mem += sizeof(*ci->levels) * CA_SIZE;
00347             mem += ci->memos.memocount * sizeof(Memo);
00348             for (j = 0; j < ci->memos.memocount; j++) {
00349                 if (ci->memos.memos[j].text)
00350                     mem += strlen(ci->memos.memos[j].text) + 1;
00351             }
00352             if (ci->ttb)
00353                 mem += sizeof(*ci->ttb) * TTB_SIZE;
00354             mem += ci->bwcount * sizeof(BadWord);
00355             for (j = 0; j < ci->bwcount; j++)
00356                 if (ci->badwords[j].word)
00357                     mem += strlen(ci->badwords[j].word) + 1;
00358         }
00359     }
00360     *nrec = count;
00361     *memuse = mem;
00362 }
00363 
00364 /*************************************************************************/
00365 /*************************************************************************/
00366 
00367 /* ChanServ initialization. */
00368 
00369 void cs_init(void)
00370 {
00371     moduleAddChanServCmds();
00372 }
00373 
00374 /*************************************************************************/
00375 
00376 /* Main ChanServ routine. */
00377 
00378 void chanserv(User * u, char *buf)
00379 {
00380     char *cmd, *s;
00381 
00382     cmd = strtok(buf, " ");
00383 
00384     if (!cmd) {
00385         return;
00386     } else if (stricmp(cmd, "\1PING") == 0) {
00387         if (!(s = strtok(NULL, ""))) {
00388             s = "";
00389         }
00390         anope_cmd_ctcp(s_ChanServ, u->nick, "PING %s", s);
00391     } else if (skeleton) {
00392         notice_lang(s_ChanServ, u, SERVICE_OFFLINE, s_ChanServ);
00393     } else {
00394         mod_run_cmd(s_ChanServ, u, CHANSERV, cmd);
00395     }
00396 }
00397 
00398 /*************************************************************************/
00399 
00400 /* Load/save data files. */
00401 
00402 
00403 #define SAFE(x) do {                    \
00404     if ((x) < 0) {                  \
00405     if (!forceload)                 \
00406         fatal("Read error on %s", ChanDBName);  \
00407     failed = 1;                 \
00408     break;                      \
00409     }                           \
00410 } while (0)
00411 
00412 void load_cs_dbase(void)
00413 {
00414     dbFILE *f;
00415     int ver, i, j, c;
00416     ChannelInfo *ci, **last, *prev;
00417     int failed = 0;
00418 
00419     if (!(f = open_db(s_ChanServ, ChanDBName, "r", CHAN_VERSION)))
00420         return;
00421 
00422     ver = get_file_version(f);
00423 
00424     for (i = 0; i < 256 && !failed; i++) {
00425         uint16 tmp16;
00426         uint32 tmp32;
00427         int n_levels;
00428         char *s;
00429         NickAlias *na;
00430 
00431         last = &chanlists[i];
00432         prev = NULL;
00433         while ((c = getc_db(f)) != 0) {
00434             if (c != 1)
00435                 fatal("Invalid format in %s", ChanDBName);
00436             ci = scalloc(sizeof(ChannelInfo), 1);
00437             *last = ci;
00438             last = &ci->next;
00439             ci->prev = prev;
00440             prev = ci;
00441             SAFE(read_buffer(ci->name, f));
00442             SAFE(read_string(&s, f));
00443             if (s) {
00444                 if (ver >= 13)
00445                     ci->founder = findcore(s);
00446                 else {
00447                     na = findnick(s);
00448                     if (na)
00449                         ci->founder = na->nc;
00450                     else
00451                         ci->founder = NULL;
00452                 }
00453                 free(s);
00454             } else
00455                 ci->founder = NULL;
00456             if (ver >= 7) {
00457                 SAFE(read_string(&s, f));
00458                 if (s) {
00459                     if (ver >= 13)
00460                         ci->successor = findcore(s);
00461                     else {
00462                         na = findnick(s);
00463                         if (na)
00464                             ci->successor = na->nc;
00465                         else
00466                             ci->successor = NULL;
00467                     }
00468                     free(s);
00469                 } else
00470                     ci->successor = NULL;
00471             } else {
00472                 ci->successor = NULL;
00473             }
00474             SAFE(read_buffer(ci->founderpass, f));
00475             SAFE(read_string(&ci->desc, f));
00476             if (!ci->desc)
00477                 ci->desc = sstrdup("");
00478             SAFE(read_string(&ci->url, f));
00479             SAFE(read_string(&ci->email, f));
00480             SAFE(read_int32(&tmp32, f));
00481             ci->time_registered = tmp32;
00482             SAFE(read_int32(&tmp32, f));
00483             ci->last_used = tmp32;
00484             SAFE(read_string(&ci->last_topic, f));
00485             SAFE(read_buffer(ci->last_topic_setter, f));
00486             SAFE(read_int32(&tmp32, f));
00487             ci->last_topic_time = tmp32;
00488             SAFE(read_int32(&ci->flags, f));
00489 
00490             /* Leaveops cleanup */
00491             if (ver <= 13 && (ci->flags & 0x00000020))
00492                 ci->flags &= ~0x00000020;
00493             /* Temporary flags cleanup */
00494             ci->flags &= ~CI_INHABIT;
00495 
00496             if (ver >= 9) {
00497                 SAFE(read_string(&ci->forbidby, f));
00498                 SAFE(read_string(&ci->forbidreason, f));
00499             } else {
00500                 ci->forbidreason = NULL;
00501                 ci->forbidby = NULL;
00502             }
00503             if (ver >= 9)
00504                 SAFE(read_int16(&tmp16, f));
00505             else
00506                 tmp16 = CSDefBantype;
00507             ci->bantype = tmp16;
00508             SAFE(read_int16(&tmp16, f));
00509             n_levels = tmp16;
00510             ci->levels = scalloc(2 * CA_SIZE, 1);
00511             reset_levels(ci);
00512             for (j = 0; j < n_levels; j++) {
00513                 SAFE(read_int16(&tmp16, f));
00514                 if (j < CA_SIZE)
00515                     ci->levels[j] = (int16) tmp16;
00516             }
00517             /* To avoid levels list silly hacks */
00518             if (ver < 10)
00519                 ci->levels[CA_OPDEOPME] = ci->levels[CA_OPDEOP];
00520             if (ver < 11) {
00521                 ci->levels[CA_KICKME] = ci->levels[CA_OPDEOP];
00522                 ci->levels[CA_KICK] = ci->levels[CA_OPDEOP];
00523             }
00524             if (ver < 15) {
00525 
00526                 /* Old Ultimate levels import */
00527                 /* We now conveniently use PROTECT internals for Ultimate's ADMIN support - ShadowMaster */
00528                 /* Doh, must of course be done before we change the values were trying to import - ShadowMaster */
00529                 ci->levels[CA_AUTOPROTECT] = ci->levels[32];
00530                 ci->levels[CA_PROTECTME] = ci->levels[33];
00531                 ci->levels[CA_PROTECT] = ci->levels[34];
00532 
00533                 ci->levels[CA_BANME] = ci->levels[CA_OPDEOP];
00534                 ci->levels[CA_BAN] = ci->levels[CA_OPDEOP];
00535                 ci->levels[CA_TOPIC] = ACCESS_INVALID;
00536 
00537 
00538             }
00539 
00540             SAFE(read_int16(&ci->accesscount, f));
00541             if (ci->accesscount) {
00542                 ci->access = scalloc(ci->accesscount, sizeof(ChanAccess));
00543                 for (j = 0; j < ci->accesscount; j++) {
00544                     SAFE(read_int16(&ci->access[j].in_use, f));
00545                     if (ci->access[j].in_use) {
00546                         SAFE(read_int16(&tmp16, f));
00547                         ci->access[j].level = (int16) tmp16;
00548                         SAFE(read_string(&s, f));
00549                         if (s) {
00550                             if (ver >= 13)
00551                                 ci->access[j].nc = findcore(s);
00552                             else {
00553                                 na = findnick(s);
00554                                 if (na)
00555                                     ci->access[j].nc = na->nc;
00556                                 else
00557                                     ci->access[j].nc = NULL;
00558                             }
00559                             free(s);
00560                         }
00561                         if (ci->access[j].nc == NULL)
00562                             ci->access[j].in_use = 0;
00563                         if (ver >= 11) {
00564                             SAFE(read_int32(&tmp32, f));
00565                             ci->access[j].last_seen = tmp32;
00566                         } else {
00567                             ci->access[j].last_seen = 0;        /* Means we have never seen the user */
00568                         }
00569                     }
00570                 }
00571             } else {
00572                 ci->access = NULL;
00573             }
00574 
00575             SAFE(read_int16(&ci->akickcount, f));
00576             if (ci->akickcount) {
00577                 ci->akick = scalloc(ci->akickcount, sizeof(AutoKick));
00578                 for (j = 0; j < ci->akickcount; j++) {
00579                     if (ver >= 15) {
00580                         SAFE(read_int16(&ci->akick[j].flags, f));
00581                     } else {
00582                         SAFE(read_int16(&tmp16, f));
00583                         if (tmp16)
00584                             ci->akick[j].flags |= AK_USED;
00585                     }
00586                     if (ci->akick[j].flags & AK_USED) {
00587                         if (ver < 15) {
00588                             SAFE(read_int16(&tmp16, f));
00589                             if (tmp16)
00590                                 ci->akick[j].flags |= AK_ISNICK;
00591                         }
00592                         SAFE(read_string(&s, f));
00593                         if (ci->akick[j].flags & AK_ISNICK) {
00594                             if (ver >= 13) {
00595                                 ci->akick[j].u.nc = findcore(s);
00596                             } else {
00597                                 na = findnick(s);
00598                                 if (na)
00599                                     ci->akick[j].u.nc = na->nc;
00600                                 else
00601                                     ci->akick[j].u.nc = NULL;
00602                             }
00603                             if (!ci->akick[j].u.nc)
00604                                 ci->akick[j].flags &= ~AK_USED;
00605                             free(s);
00606                         } else {
00607                             ci->akick[j].u.mask = s;
00608                         }
00609                         SAFE(read_string(&s, f));
00610                         if (ci->akick[j].flags & AK_USED)
00611                             ci->akick[j].reason = s;
00612                         else if (s)
00613                             free(s);
00614                         if (ver >= 9) {
00615                             SAFE(read_string(&s, f));
00616                             if (ci->akick[j].flags & AK_USED) {
00617                                 ci->akick[j].creator = s;
00618                             } else if (s) {
00619                                 free(s);
00620                             }
00621                             SAFE(read_int32(&tmp32, f));
00622                             if (ci->akick[j].flags & AK_USED)
00623                                 ci->akick[j].addtime = tmp32;
00624                         } else {
00625                             ci->akick[j].creator = NULL;
00626                             ci->akick[j].addtime = 0;
00627                         }
00628                     }
00629 
00630                     /* Bugfix */
00631                     if ((ver == 15) && ci->akick[j].flags > 8) {
00632                         ci->akick[j].flags = 0;
00633                         ci->akick[j].u.nc = NULL;
00634                         ci->akick[j].u.nc = NULL;
00635                         ci->akick[j].addtime = 0;
00636                         ci->akick[j].creator = NULL;
00637                         ci->akick[j].reason = NULL;
00638                     }
00639                 }
00640             } else {
00641                 ci->akick = NULL;
00642             }
00643 
00644             if (ver >= 10) {
00645                 SAFE(read_int32(&ci->mlock_on, f));
00646                 SAFE(read_int32(&ci->mlock_off, f));
00647             } else {
00648                 SAFE(read_int16(&tmp16, f));
00649                 ci->mlock_on = tmp16;
00650                 SAFE(read_int16(&tmp16, f));
00651                 ci->mlock_off = tmp16;
00652             }
00653             SAFE(read_int32(&ci->mlock_limit, f));
00654             SAFE(read_string(&ci->mlock_key, f));
00655             if (ver >= 10) {
00656                 if (ircd->fmode) {
00657                     SAFE(read_string(&ci->mlock_flood, f));
00658                 } else {
00659                     SAFE(read_string(&s, f));
00660                     if (s)
00661                         free(s);
00662                 }
00663                 if (ircd->Lmode) {
00664                     SAFE(read_string(&ci->mlock_redirect, f));
00665                 } else {
00666                     SAFE(read_string(&s, f));
00667                     if (s)
00668                         free(s);
00669                 }
00670             }
00671 
00672             SAFE(read_int16(&tmp16, f));
00673             ci->memos.memocount = (int16) tmp16;
00674             SAFE(read_int16(&tmp16, f));
00675             ci->memos.memomax = (int16) tmp16;
00676             if (ci->memos.memocount) {
00677                 Memo *memos;
00678                 memos = scalloc(sizeof(Memo) * ci->memos.memocount, 1);
00679                 ci->memos.memos = memos;
00680                 for (j = 0; j < ci->memos.memocount; j++, memos++) {
00681                     SAFE(read_int32(&memos->number, f));
00682                     SAFE(read_int16(&memos->flags, f));
00683                     SAFE(read_int32(&tmp32, f));
00684                     memos->time = tmp32;
00685                     SAFE(read_buffer(memos->sender, f));
00686                     SAFE(read_string(&memos->text, f));
00687                     memos->moduleData = NULL;
00688                 }
00689             }
00690 
00691             SAFE(read_string(&ci->entry_message, f));
00692 
00693             ci->c = NULL;
00694 
00695             /* Some cleanup */
00696             if (ver <= 11) {
00697                 /* Cleanup: Founder must be != than successor */
00698                 if (!(ci->flags & CI_VERBOTEN)
00699                     && ci->successor == ci->founder) {
00700                     alog("Warning: founder and successor of %s are equal. Cleaning up.", ci->name);
00701                     ci->successor = NULL;
00702                 }
00703             }
00704 
00705             /* BotServ options */
00706 
00707             if (ver >= 8) {
00708                 int n_ttb;
00709 
00710                 SAFE(read_string(&s, f));
00711                 if (s) {
00712                     ci->bi = findbot(s);
00713                     free(s);
00714                 } else
00715                     ci->bi = NULL;
00716 
00717                 SAFE(read_int32(&tmp32, f));
00718                 ci->botflags = tmp32;
00719                 SAFE(read_int16(&tmp16, f));
00720                 n_ttb = tmp16;
00721                 ci->ttb = scalloc(2 * TTB_SIZE, 1);
00722                 for (j = 0; j < n_ttb; j++) {
00723                     SAFE(read_int16(&tmp16, f));
00724                     if (j < TTB_SIZE)
00725                         ci->ttb[j] = (int16) tmp16;
00726                 }
00727                 for (j = n_ttb; j < TTB_SIZE; j++)
00728                     ci->ttb[j] = 0;
00729                 SAFE(read_int16(&tmp16, f));
00730                 ci->capsmin = tmp16;
00731                 SAFE(read_int16(&tmp16, f));
00732                 ci->capspercent = tmp16;
00733                 SAFE(read_int16(&tmp16, f));
00734                 ci->floodlines = tmp16;
00735                 SAFE(read_int16(&tmp16, f));
00736                 ci->floodsecs = tmp16;
00737                 SAFE(read_int16(&tmp16, f));
00738                 ci->repeattimes = tmp16;
00739 
00740                 SAFE(read_int16(&ci->bwcount, f));
00741                 if (ci->bwcount) {
00742                     ci->badwords = scalloc(ci->bwcount, sizeof(BadWord));
00743                     for (j = 0; j < ci->bwcount; j++) {
00744                         SAFE(read_int16(&ci->badwords[j].in_use, f));
00745                         if (ci->badwords[j].in_use) {
00746                             SAFE(read_string(&ci->badwords[j].word, f));
00747                             SAFE(read_int16(&ci->badwords[j].type, f));
00748                         }
00749                     }
00750                 } else {
00751                     ci->badwords = NULL;
00752                 }
00753             } else {
00754                 ci->bi = NULL;
00755                 ci->botflags = 0;
00756                 ci->ttb = scalloc(2 * TTB_SIZE, 1);
00757                 for (j = 0; j < TTB_SIZE; j++)
00758                     ci->ttb[j] = 0;
00759                 ci->bwcount = 0;
00760                 ci->badwords = NULL;
00761             }
00762 
00763         }                       /* while (getc_db(f) != 0) */
00764 
00765         *last = NULL;
00766 
00767     }                           /* for (i) */
00768 
00769     close_db(f);
00770 
00771     /* Check for non-forbidden channels with no founder.
00772        Makes also other essential tasks. */
00773     for (i = 0; i < 256; i++) {
00774         ChannelInfo *next;
00775         for (ci = chanlists[i]; ci; ci = next) {
00776             next = ci->next;
00777             if (!(ci->flags & CI_VERBOTEN) && !ci->founder) {
00778                 alog("%s: database load: Deleting founderless channel %s",
00779                      s_ChanServ, ci->name);
00780                 delchan(ci);
00781                 continue;
00782             }
00783             if (ver < 13) {
00784                 ChanAccess *access, *access2;
00785                 AutoKick *akick, *akick2;
00786                 int k;
00787 
00788                 if (ci->flags & CI_VERBOTEN)
00789                     continue;
00790                 /* Need to regenerate the channel count for the founder */
00791                 ci->founder->channelcount++;
00792                 /* Check for eventual double entries in access/akick lists. */
00793                 for (j = 0, access = ci->access; j < ci->accesscount;
00794                      j++, access++) {
00795                     if (!access->in_use)
00796                         continue;
00797                     for (k = 0, access2 = ci->access; k < j;
00798                          k++, access2++) {
00799                         if (access2->in_use && access2->nc == access->nc) {
00800                             alog("%s: deleting %s channel access entry of %s because it is already in the list (this is OK).", s_ChanServ, access->nc->display, ci->name);
00801                             memset(access, 0, sizeof(ChanAccess));
00802                             break;
00803                         }
00804                     }
00805                 }
00806                 for (j = 0, akick = ci->akick; j < ci->akickcount;
00807                      j++, akick++) {
00808                     if (!(akick->flags & AK_USED)
00809                         || !(akick->flags & AK_ISNICK))
00810                         continue;
00811                     for (k = 0, akick2 = ci->akick; k < j; k++, akick2++) {
00812                         if ((akick2->flags & AK_USED)
00813                             && (akick2->flags & AK_ISNICK)
00814                             && akick2->u.nc == akick->u.nc) {
00815                             alog("%s: deleting %s channel akick entry of %s because it is already in the list (this is OK).", s_ChanServ, akick->u.nc->display, ci->name);
00816                             if (akick->reason)
00817                                 free(akick->reason);
00818                             if (akick->creator)
00819                                 free(akick->creator);
00820                             memset(akick, 0, sizeof(AutoKick));
00821                             break;
00822                         }
00823                     }
00824                 }
00825             }
00826         }
00827     }
00828 }
00829 
00830 #undef SAFE
00831 
00832 /*************************************************************************/
00833 
00834 #define SAFE(x) do {                        \
00835     if ((x) < 0) {                      \
00836     restore_db(f);                      \
00837     log_perror("Write error on %s", ChanDBName);        \
00838     if (time(NULL) - lastwarn > WarningTimeout) {       \
00839         anope_cmd_global(NULL, "Write error on %s: %s", ChanDBName, \
00840             strerror(errno));           \
00841         lastwarn = time(NULL);              \
00842     }                           \
00843     return;                         \
00844     }                               \
00845 } while (0)
00846 
00847 void save_cs_dbase(void)
00848 {
00849     dbFILE *f;
00850     int i, j;
00851     ChannelInfo *ci;
00852     Memo *memos;
00853     static time_t lastwarn = 0;
00854 
00855     if (!(f = open_db(s_ChanServ, ChanDBName, "w", CHAN_VERSION)))
00856         return;
00857 
00858     for (i = 0; i < 256; i++) {
00859         int16 tmp16;
00860 
00861         for (ci = chanlists[i]; ci; ci = ci->next) {
00862             SAFE(write_int8(1, f));
00863             SAFE(write_buffer(ci->name, f));
00864             if (ci->founder)
00865                 SAFE(write_string(ci->founder->display, f));
00866             else
00867                 SAFE(write_string(NULL, f));
00868             if (ci->successor)
00869                 SAFE(write_string(ci->successor->display, f));
00870             else
00871                 SAFE(write_string(NULL, f));
00872             SAFE(write_buffer(ci->founde