chanserv.c

Go to the documentation of this file.
00001 /* ChanServ functions.
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@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  *
00012  */
00013 
00014 /*************************************************************************/
00015 
00016 #include "services.h"
00017 #include "pseudo.h"
00018 
00019 /*************************************************************************/
00020 /* *INDENT-OFF* */
00021 
00022 ChannelInfo *chanlists[256];
00023 
00024 static int def_levels[][2] = {
00025     { CA_AUTOOP,                     5 },
00026     { CA_AUTOVOICE,                  3 },
00027     { CA_AUTODEOP,                  -1 },
00028     { CA_NOJOIN,                    -2 },
00029     { CA_INVITE,                     5 },
00030     { CA_AKICK,                     10 },
00031     { CA_SET,                   ACCESS_INVALID },
00032     { CA_CLEAR,                 ACCESS_INVALID },
00033     { CA_UNBAN,                      5 },
00034     { CA_OPDEOP,                     5 },
00035     { CA_ACCESS_LIST,                1 },
00036     { CA_ACCESS_CHANGE,             10 },
00037     { CA_MEMO,                      10 },
00038     { CA_ASSIGN,                ACCESS_INVALID },
00039     { CA_BADWORDS,                  10 },
00040     { CA_NOKICK,                     1 },
00041     { CA_FANTASIA,                               3 },
00042     { CA_SAY,                                    5 },
00043     { CA_GREET,                      5 },
00044     { CA_VOICEME,                                3 },
00045     { CA_VOICE,                                  5 },
00046     { CA_GETKEY,                     5 },
00047     { CA_AUTOHALFOP,                 4 },
00048     { CA_AUTOPROTECT,               10 },
00049     { CA_OPDEOPME,                   5 },
00050     { CA_HALFOPME,                   4 },
00051     { CA_HALFOP,                     5 },
00052     { CA_PROTECTME,                 10 },
00053     { CA_PROTECT,               ACCESS_INVALID },
00054     { CA_KICKME,                         5 },
00055     { CA_KICK,                       5 },
00056     { CA_SIGNKICK,              ACCESS_INVALID },
00057     { CA_BANME,                      5 },
00058     { CA_BAN,                        5 },
00059     { CA_TOPIC,         ACCESS_INVALID },
00060     { CA_INFO,          ACCESS_INVALID },
00061     { -1 }
00062 };
00063 
00064 
00065 LevelInfo levelinfo[] = {
00066         { CA_AUTODEOP,      "AUTODEOP",     CHAN_LEVEL_AUTODEOP },
00067         { CA_AUTOHALFOP,    "AUTOHALFOP",   CHAN_LEVEL_AUTOHALFOP },
00068         { CA_AUTOOP,        "AUTOOP",       CHAN_LEVEL_AUTOOP },
00069         { CA_AUTOPROTECT,   "",  CHAN_LEVEL_AUTOPROTECT },
00070         { CA_AUTOVOICE,     "AUTOVOICE",    CHAN_LEVEL_AUTOVOICE },
00071         { CA_NOJOIN,        "NOJOIN",       CHAN_LEVEL_NOJOIN },
00072         { CA_SIGNKICK,      "SIGNKICK",     CHAN_LEVEL_SIGNKICK },
00073         { CA_ACCESS_LIST,   "ACC-LIST",     CHAN_LEVEL_ACCESS_LIST },
00074         { CA_ACCESS_CHANGE, "ACC-CHANGE",   CHAN_LEVEL_ACCESS_CHANGE },
00075         { CA_AKICK,         "AKICK",        CHAN_LEVEL_AKICK },
00076         { CA_SET,           "SET",          CHAN_LEVEL_SET },
00077         { CA_BAN,           "BAN",          CHAN_LEVEL_BAN },
00078         { CA_BANME,         "BANME",        CHAN_LEVEL_BANME },
00079         { CA_CLEAR,         "CLEAR",        CHAN_LEVEL_CLEAR },
00080         { CA_GETKEY,        "GETKEY",       CHAN_LEVEL_GETKEY },
00081         { CA_HALFOP,        "HALFOP",       CHAN_LEVEL_HALFOP },
00082         { CA_HALFOPME,      "HALFOPME",     CHAN_LEVEL_HALFOPME },
00083         { CA_INFO,          "INFO",         CHAN_LEVEL_INFO },
00084         { CA_KICK,          "KICK",         CHAN_LEVEL_KICK },
00085         { CA_KICKME,        "KICKME",       CHAN_LEVEL_KICKME },
00086         { CA_INVITE,        "INVITE",       CHAN_LEVEL_INVITE },
00087         { CA_OPDEOP,        "OPDEOP",       CHAN_LEVEL_OPDEOP },
00088         { CA_OPDEOPME,      "OPDEOPME",     CHAN_LEVEL_OPDEOPME },
00089         { CA_PROTECT,       "",      CHAN_LEVEL_PROTECT },
00090         { CA_PROTECTME,     "",    CHAN_LEVEL_PROTECTME },
00091         { CA_TOPIC,         "TOPIC",        CHAN_LEVEL_TOPIC },
00092         { CA_UNBAN,         "UNBAN",        CHAN_LEVEL_UNBAN },
00093         { CA_VOICE,         "VOICE",        CHAN_LEVEL_VOICE },
00094         { CA_VOICEME,       "VOICEME",      CHAN_LEVEL_VOICEME },
00095         { CA_MEMO,          "MEMO",         CHAN_LEVEL_MEMO },
00096         { CA_ASSIGN,        "ASSIGN",       CHAN_LEVEL_ASSIGN },
00097         { CA_BADWORDS,      "BADWORDS",     CHAN_LEVEL_BADWORDS },
00098         { CA_FANTASIA,      "FANTASIA",     CHAN_LEVEL_FANTASIA },
00099         { CA_GREET,         "GREET",        CHAN_LEVEL_GREET },
00100         { CA_NOKICK,        "NOKICK",       CHAN_LEVEL_NOKICK },
00101         { CA_SAY,           "SAY",          CHAN_LEVEL_SAY },
00102         { -1 }
00103 };
00104 int levelinfo_maxwidth = 0;
00105 
00106 CSModeUtil csmodeutils[] = {
00107     { "DEOP",      "deop",     "-o", CI_OPNOTICE, CA_OPDEOP,  CA_OPDEOPME },
00108     { "OP",        "op",       "+o", CI_OPNOTICE, CA_OPDEOP,  CA_OPDEOPME },
00109     { "DEVOICE",   "devoice",  "-v", 0,           CA_VOICE,   CA_VOICEME  },
00110     { "VOICE",     "voice",    "+v", 0,           CA_VOICE,   CA_VOICEME  },
00111     { "DEHALFOP",  "dehalfop", "-h", 0,           CA_HALFOP,  CA_HALFOPME },
00112     { "HALFOP",    "halfop",   "+h", 0,           CA_HALFOP,  CA_HALFOPME },
00113     { "DEPROTECT", "",         "",   0,           CA_PROTECT, CA_PROTECTME },
00114     { "PROTECT",   "",         "",   0,           CA_PROTECT, CA_PROTECTME },
00115     { NULL }
00116 };
00117 
00118 /*************************************************************************/
00119 
00120 void moduleAddChanServCmds(void) {
00121     modules_core_init(ChanServCoreNumber, ChanServCoreModules);
00122 }
00123 
00124 /* *INDENT-ON* */
00125 /*************************************************************************/
00126 /*************************************************************************/
00127 
00128 /* Returns modes for mlock in a nice way. */
00129 
00130 char *get_mlock_modes(ChannelInfo * ci, int complete)
00131 {
00132     static char res[BUFSIZE];
00133 
00134     char *end = res;
00135 
00136     if (ci->mlock_on || ci->mlock_off) {
00137         int n = 0;
00138         CBModeInfo *cbmi = cbmodeinfos;
00139 
00140         if (ci->mlock_on) {
00141             *end++ = '+';
00142             n++;
00143 
00144             do {
00145                 if (ci->mlock_on & cbmi->flag)
00146                     *end++ = cbmi->mode;
00147             } while ((++cbmi)->mode != 0 && ++n < sizeof(res) - 1);
00148 
00149             cbmi = cbmodeinfos;
00150         }
00151 
00152         if (ci->mlock_off) {
00153             *end++ = '-';
00154             n++;
00155 
00156             do {
00157                 if (ci->mlock_off & cbmi->flag)
00158                     *end++ = cbmi->mode;
00159             } while ((++cbmi)->mode != 0 && ++n < sizeof(res) - 1);
00160 
00161             cbmi = cbmodeinfos;
00162         }
00163 
00164         if (ci->mlock_on && complete) {
00165             do {
00166                 if (cbmi->csgetvalue && (ci->mlock_on & cbmi->flag)) {
00167                     char *value = cbmi->csgetvalue(ci);
00168 
00169                     if (value) {
00170                         *end++ = ' ';
00171                         while (*value)
00172                             *end++ = *value++;
00173                     }
00174                 }
00175             } while ((++cbmi)->mode != 0 && ++n < sizeof(res) - 1);
00176         }
00177     }
00178 
00179     *end = 0;
00180 
00181     return res;
00182 }
00183 
00184 /* Display total number of registered channels and info about each; or, if
00185  * a specific channel is given, display information about that channel
00186  * (like /msg ChanServ INFO <channel>).  If count_only != 0, then only
00187  * display the number of registered channels (the channel parameter is
00188  * ignored).
00189  */
00190 
00191 void listchans(int count_only, const char *chan)
00192 {
00193     int count = 0;
00194     ChannelInfo *ci;
00195     int i;
00196 
00197     if (count_only) {
00198 
00199         for (i = 0; i < 256; i++) {
00200             for (ci = chanlists[i]; ci; ci = ci->next)
00201                 count++;
00202         }
00203         printf("%d channels registered.\n", count);
00204 
00205     } else if (chan) {
00206 
00207         struct tm *tm;
00208         char buf[BUFSIZE];
00209 
00210         if (!(ci = cs_findchan(chan))) {
00211             printf("Channel %s not registered.\n", chan);
00212             return;
00213         }
00214         if (ci->flags & CI_VERBOTEN) {
00215             printf("Channel %s is FORBIDden.\n", ci->name);
00216         } else {
00217             printf("Information about channel %s:\n", ci->name);
00218             printf("        Founder: %s\n", ci->founder->display);
00219             printf("    Description: %s\n", ci->desc);
00220             tm = localtime(&ci->time_registered);
00221             strftime(buf, sizeof(buf),
00222                      getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00223             printf("     Registered: %s\n", buf);
00224             tm = localtime(&ci->last_used);
00225             strftime(buf, sizeof(buf),
00226                      getstring(NULL, STRFTIME_DATE_TIME_FORMAT), tm);
00227             printf("      Last used: %s\n", buf);
00228             if (ci->last_topic) {
00229                 printf("     Last topic: %s\n", ci->last_topic);
00230                 printf("   Topic set by: %s\n", ci->last_topic_setter);
00231             }
00232             if (ci->url)
00233                 printf("            URL: %s\n", ci->url);
00234             if (ci->email)
00235                 printf(" E-mail address: %s\n", ci->email);
00236             printf("        Options: ");
00237             if (!ci->flags) {
00238                 printf("None\n");
00239             } else {
00240                 int need_comma = 0;
00241                 static const char commastr[] = ", ";
00242                 if (ci->flags & CI_PRIVATE) {
00243                     printf("Private");
00244                     need_comma = 1;
00245                 }
00246                 if (ci->flags & CI_KEEPTOPIC) {
00247                     printf("%sTopic Retention",
00248                            need_comma ? commastr : "");
00249                     need_comma = 1;
00250                 }
00251                 if (ci->flags & CI_TOPICLOCK) {
00252                     printf("%sTopic Lock", need_comma ? commastr : "");
00253                     need_comma = 1;
00254                 }
00255                 if (ci->flags & CI_SECUREOPS) {
00256                     printf("%sSecure Ops", need_comma ? commastr : "");
00257                     need_comma = 1;
00258                 }
00259                 if (ci->flags & CI_RESTRICTED) {
00260                     printf("%sRestricted Access",
00261                            need_comma ? commastr : "");
00262                     need_comma = 1;
00263                 }
00264                 if (ci->flags & CI_SECURE) {
00265                     printf("%sSecure", need_comma ? commastr : "");
00266                     need_comma = 1;
00267                 }
00268                 if (ci->flags & CI_NO_EXPIRE) {
00269                     printf("%sNo Expire", need_comma ? commastr : "");
00270                     need_comma = 1;
00271                 }
00272                 printf("\n");
00273             }
00274             if (ci->mlock_on || ci->mlock_off) {
00275                 printf("      Mode lock: %s\n", get_mlock_modes(ci, 1));
00276             }
00277             if (ci->flags & CI_SUSPENDED) {
00278                 printf
00279                     ("This nickname is currently suspended by %s, reason: %s\n",
00280                      ci->forbidby,
00281                      (ci->forbidreason ? ci->forbidreason : "No reason"));
00282             }
00283         }
00284 
00285     } else {
00286 
00287         for (i = 0; i < 256; i++) {
00288             for (ci = chanlists[i]; ci; ci = ci->next) {
00289                 printf("  %s %-20s  %s\n",
00290                        ci->flags & CI_NO_EXPIRE ? "!" : " ", ci->name,
00291                        ci->flags & CI_VERBOTEN ?
00292                        "Disallowed (FORBID)" : (ci->flags & CI_SUSPENDED ?
00293                                                 "Disallowed (SUSPENDED)" :
00294                                                 ci->desc));
00295                 count++;
00296             }
00297         }
00298         printf("%d channels registered.\n", count);
00299 
00300     }
00301 }
00302 
00303 /*************************************************************************/
00304 
00305 /* Return information on memory use.  Assumes pointers are valid. */
00306 
00307 void get_chanserv_stats(long *nrec, long *memuse)
00308 {
00309     long count = 0, mem = 0;
00310     int i, j;
00311     ChannelInfo *ci;
00312 
00313     for (i = 0; i < 256; i++) {
00314         for (ci = chanlists[i]; ci; ci = ci->next) {
00315             count++;
00316             mem += sizeof(*ci);
00317             if (ci->desc)
00318                 mem += strlen(ci->desc) + 1;
00319             if (ci->url)
00320                 mem += strlen(ci->url) + 1;
00321             if (ci->email)
00322                 mem += strlen(ci->email) + 1;
00323             mem += ci->accesscount * sizeof(ChanAccess);
00324             mem += ci->akickcount * sizeof(AutoKick);
00325             for (j = 0; j < ci->akickcount; j++) {
00326                 if (!(ci->akick[j].flags & AK_ISNICK)
00327                     && ci->akick[j].u.mask)
00328                     mem += strlen(ci->akick[j].u.mask) + 1;
00329                 if (ci->akick[j].reason)
00330                     mem += strlen(ci->akick[j].reason) + 1;
00331                 if (ci->akick[j].creator)
00332                     mem += strlen(ci->akick[j].creator) + 1;
00333             }
00334             if (ci->mlock_key)
00335                 mem += strlen(ci->mlock_key) + 1;
00336             if (ircd->fmode) {
00337                 if (ci->mlock_flood)
00338                     mem += strlen(ci->mlock_flood) + 1;
00339             }
00340             if (ircd->Lmode) {
00341                 if (ci->mlock_redirect)
00342                     mem += strlen(ci->mlock_redirect) + 1;
00343             }
00344             if (ircd->jmode) {
00345                 if (ci->mlock_throttle)
00346                     mem += strlen(ci->mlock_throttle) + 1;
00347             }
00348             if (ci->last_topic)
00349                 mem += strlen(ci->last_topic) + 1;
00350             if (ci->entry_message)
00351                 mem += strlen(ci->entry_message) + 1;
00352             if (ci->forbidby)
00353                 mem += strlen(ci->forbidby) + 1;
00354             if (ci->forbidreason)
00355                 mem += strlen(ci->forbidreason) + 1;
00356             if (ci->levels)
00357                 mem += sizeof(*ci->levels) * CA_SIZE;
00358             mem += ci->memos.memocount * sizeof(Memo);
00359             for (j = 0; j < ci->memos.memocount; j++) {
00360                 if (ci->memos.memos[j].text)
00361                     mem += strlen(ci->memos.memos[j].text) + 1;
00362             }
00363             if (ci->ttb)
00364                 mem += sizeof(*ci->ttb) * TTB_SIZE;
00365             mem += ci->bwcount * sizeof(BadWord);
00366             for (j = 0; j < ci->bwcount; j++)
00367                 if (ci->badwords[j].word)
00368                     mem += strlen(ci->badwords[j].word) + 1;
00369         }
00370     }
00371     *nrec = count;
00372     *memuse = mem;
00373 }
00374 
00375 /*************************************************************************/
00376 /*************************************************************************/
00377 
00378 /* ChanServ initialization. */
00379 
00380 void cs_init(void)
00381 {
00382     moduleAddChanServCmds();
00383 }
00384 
00385 /*************************************************************************/
00386 
00387 /* Main ChanServ routine. */
00388 
00389 void chanserv(User * u, char *buf)
00390 {
00391     char *cmd, *s;
00392 
00393     cmd = strtok(buf, " ");
00394 
00395     if (!cmd) {
00396         return;
00397     } else if (stricmp(cmd, "\1PING") == 0) {
00398         if (!(s = strtok(NULL, ""))) {
00399             s = "";
00400         }
00401         anope_cmd_ctcp(s_ChanServ, u->nick, "PING %s", s);
00402     } else if (skeleton) {
00403         notice_lang(s_ChanServ, u, SERVICE_OFFLINE, s_ChanServ);
00404     } else {
00405         mod_run_cmd(s_ChanServ, u, CHANSERV, cmd);
00406     }
00407 }
00408 
00409 /*************************************************************************/
00410 
00411 /* Load/save data files. */
00412 
00413 
00414 #define SAFE(x) do {                                    \
00415     if ((x) < 0) {                                      \
00416         if (!forceload)                                 \
00417             fatal("Read error on %s", ChanDBName);      \
00418         failed = 1;                                     \
00419         break;                                          \
00420     }                                                   \
00421 } while (0)
00422 
00423 void load_cs_dbase(void)
00424 {
00425     dbFILE *f;
00426     int ver, i, j, c;
00427     ChannelInfo *ci, **last, *prev;
00428     int failed = 0;
00429 
00430     if (!(f = open_db(s_ChanServ, ChanDBName, "r", CHAN_VERSION)))
00431         return;
00432 
00433     ver = get_file_version(f);
00434 
00435     for (i = 0; i < 256 && !failed; i++) {
00436         uint16 tmp16;
00437         uint32 tmp32;
00438         int n_levels;
00439         char *s;
00440         NickAlias *na;
00441 
00442         last = &chanlists[i];
00443         prev = NULL;
00444         while ((c = getc_db(f)) != 0) {
00445             if (c != 1)
00446                 fatal("Invalid format in %s", ChanDBName);
00447             ci = scalloc(sizeof(ChannelInfo), 1);
00448             *last = ci;
00449             last = &ci->next;
00450             ci->prev = prev;
00451             prev = ci;
00452             SAFE(read_buffer(ci->name, f));
00453             SAFE(read_string(&s, f));
00454             if (s) {
00455                 if (ver >= 13)
00456                     ci->founder = findcore(s);
00457                 else {
00458                     na = findnick(s);
00459                     if (na)
00460                         ci->founder = na->nc;
00461                     else
00462                         ci->founder = NULL;
00463                 }
00464                 free(s);
00465             } else
00466                 ci->founder = NULL;
00467             if (ver >= 7) {
00468                 SAFE(read_string(&s, f));
00469                 if (s) {
00470                     if (ver >= 13)
00471                         ci->successor = findcore(s);
00472                     else {
00473                         na = findnick(s);
00474                         if (na)
00475                             ci->successor = na->nc;
00476                         else
00477                             ci->successor = NULL;
00478                     }
00479                     free(s);
00480                 } else
00481                     ci->successor = NULL;
00482             } else {
00483                 ci->successor = NULL;
00484             }
00485             SAFE(read_buffer(ci->founderpass, f));
00486             SAFE(read_string(&ci->desc, f));
00487             if (!ci->desc)
00488                 ci->desc = sstrdup("");
00489             SAFE(read_string(&ci->url, f));
00490             SAFE(read_string(&ci->email, f));
00491             SAFE(read_int32(&tmp32, f));
00492             ci->time_registered = tmp32;
00493             SAFE(read_int32(&tmp32, f));
00494             ci->last_used = tmp32;
00495             SAFE(read_string(&ci->last_topic, f));
00496             SAFE(read_buffer(ci->last_topic_setter, f));
00497             SAFE(read_int32(&tmp32, f));
00498             ci->last_topic_time = tmp32;
00499             SAFE(read_int32(&ci->flags, f));
00500 
00501             /* Leaveops cleanup */
00502             if (ver <= 13 && (ci->flags & 0x00000020))
00503                 ci->flags &= ~0x00000020;
00504             /* Temporary flags cleanup */
00505             ci->flags &= ~CI_INHABIT;
00506 
00507             if (ver >= 9) {
00508                 SAFE(read_string(&ci->forbidby, f));
00509                 SAFE(read_string(&ci->forbidreason, f));
00510             } else {
00511                 ci->forbidreason = NULL;
00512                 ci->forbidby = NULL;
00513             }
00514             if (ver >= 9)
00515                 SAFE(read_int16(&tmp16, f));
00516             else
00517                 tmp16 = CSDefBantype;
00518             ci->bantype = tmp16;
00519             SAFE(read_int16(&tmp16, f));
00520             n_levels = tmp16;
00521             ci->levels = scalloc(2 * CA_SIZE, 1);
00522             reset_levels(ci);
00523             for (j = 0; j < n_levels; j++) {
00524                 SAFE(read_int16(&tmp16, f));
00525                 if (j < CA_SIZE)
00526                     ci->levels[j] = (int16) tmp16;
00527             }
00528             /* To avoid levels list silly hacks */
00529             if (ver < 10)
00530                 ci->levels[CA_OPDEOPME] = ci->levels[CA_OPDEOP];
00531             if (ver < 11) {
00532                 ci->levels[CA_KICKME] = ci->levels[CA_OPDEOP];
00533                 ci->levels[CA_KICK] = ci->levels[CA_OPDEOP];
00534             }
00535             if (ver < 15) {
00536 
00537                 /* Old Ultimate levels import */
00538                 /* We now conveniently use PROTECT internals for Ultimate's ADMIN support - ShadowMaster */
00539                 /* Doh, must of course be done before we change the values were trying to import - ShadowMaster */
00540                 ci->levels[CA_AUTOPROTECT] = ci->levels[32];
00541                 ci->levels[CA_PROTECTME] = ci->levels[33];
00542                 ci->levels[CA_PROTECT] = ci->levels[34];
00543 
00544                 ci->levels[CA_BANME] = ci->levels[CA_OPDEOP];
00545                 ci->levels[CA_BAN] = ci->levels[CA_OPDEOP];
00546                 ci->levels[CA_TOPIC] = ACCESS_INVALID;
00547 
00548 
00549             }
00550 
00551             SAFE(read_int16(&ci->accesscount, f));
00552             if (ci->accesscount) {
00553                 ci->access = scalloc(ci->accesscount, sizeof(ChanAccess));
00554                 for (j = 0; j < ci->accesscount; j++) {
00555                     SAFE(read_int16(&ci->access[j].in_use, f));
00556                     if (ci->access[j].in_use) {
00557                         SAFE(read_int16(&tmp16, f));
00558                         ci->access[j].level = (int16) tmp16;
00559                         SAFE(read_string(&s, f));
00560                         if (s) {
00561                             if (ver >= 13)
00562                                 ci->access[j].nc = findcore(s);
00563                             else {
00564                                 na = findnick(s);
00565                                 if (na)
00566                                     ci->access[j].nc = na->nc;
00567                                 else
00568                                     ci->access[j].nc = NULL;
00569                             }
00570                             free(s);
00571                         }
00572                         if (ci->access[j].nc == NULL)
00573                             ci->access[j].in_use = 0;
00574                         if (ver >= 11) {
00575                             SAFE(read_int32(&tmp32, f));
00576                             ci->access[j].last_seen = tmp32;
00577                         } else {
00578                             ci->access[j].last_seen = 0;        /* Means we have never seen the user */
00579                         }
00580                     }
00581                 }
00582             } else {
00583                 ci->access = NULL;
00584             }
00585 
00586             SAFE(read_int16(&ci->akickcount, f));
00587             if (ci->akickcount) {
00588                 ci->akick = scalloc(ci->akickcount, sizeof(AutoKick));
00589                 for (j = 0; j < ci->akickcount; j++) {
00590                     if (ver >= 15) {
00591                         SAFE(read_int16(&ci->akick[j].flags, f));
00592                     } else {
00593                         SAFE(read_int16(&tmp16, f));
00594                         if (tmp16)
00595                             ci->akick[j].flags |= AK_USED;
00596                     }
00597                     if (ci->akick[j].flags & AK_USED) {
00598                         if (ver < 15) {
00599                             SAFE(read_int16(&tmp16, f));
00600                             if (tmp16)
00601                                 ci->akick[j].flags |= AK_ISNICK;
00602                         }
00603                         SAFE(read_string(&s, f));
00604                         if (ci->akick[j].flags & AK_ISNICK) {
00605                             if (ver >= 13) {
00606                                 ci->akick[j].u.nc = findcore(s);
00607                             } else {
00608                                 na = findnick(s);
00609                                 if (na)
00610                                     ci->akick[j].u.nc = na->nc;
00611                                 else
00612                                     ci->akick[j].u.nc = NULL;
00613                             }
00614                             if (!ci->akick[j].u.nc)
00615                                 ci->akick[j].flags &= ~AK_USED;
00616                             free(s);
00617                         } else {
00618                             ci->akick[j].u.mask = s;
00619                         }
00620                         SAFE(read_string(&s, f));
00621                         if (ci->akick[j].flags & AK_USED)
00622                             ci->akick[j].reason = s;
00623                         else if (s)
00624                             free(s);
00625                         if (ver >= 9) {
00626                             SAFE(read_string(&s, f));
00627                             if (ci->akick[j].flags & AK_USED) {
00628                                 ci->akick[j].creator = s;
00629                             } else if (s) {
00630                                 free(s);
00631                             }
00632                             SAFE(read_int32(&tmp32, f));
00633                             if (ci->akick[j].flags & AK_USED)
00634                                 ci->akick[j].addtime = tmp32;
00635                         } else {
00636                             ci->akick[j].creator = NULL;
00637                             ci->akick[j].addtime = 0;
00638                         }
00639                     }
00640 
00641                     /* Bugfix */
00642                     if ((ver == 15) && ci->akick[j].flags > 8) {
00643                         ci->akick[j].flags = 0;
00644                         ci->akick[j].u.nc = NULL;
00645                         ci->akick[j].u.nc = NULL;
00646                         ci->akick[j].addtime = 0;
00647                         ci->akick[j].creator = NULL;
00648                         ci->akick[j].reason = NULL;
00649                     }
00650                 }
00651             } else {
00652                 ci->akick = NULL;
00653             }
00654 
00655             if (ver >= 10) {
00656                 SAFE(read_int32(&ci->mlock_on, f));
00657                 SAFE(read_int32(&ci->mlock_off, f));
00658             } else {
00659                 SAFE(read_int16(&tmp16, f));
00660                 ci->mlock_on = tmp16;
00661                 SAFE(read_int16(&tmp16, f));
00662                 ci->mlock_off = tmp16;
00663             }
00664             SAFE(read_int32(&ci->mlock_limit, f));
00665             SAFE(read_string(&ci->mlock_key, f));
00666             if (ver >= 10) {
00667                 SAFE(read_string(&ci->mlock_flood, f));
00668                 SAFE(read_string(&ci->mlock_redirect, f));
00669                 /* We added support for channelmode +j tracking,
00670                  * however unless for some other reason we need to
00671                  * change the DB format, it is being saved to DB. ~ Viper
00672                 SAFE(read_string(&ci->mlock_throttle, f));*/
00673             }
00674 
00675             SAFE(read_int16(&tmp16, f));
00676             ci->memos.memocount = (int16) tmp16;
00677             SAFE(read_int16(&tmp16, f));
00678             ci->memos.memomax = (int16) tmp16;
00679             if (ci->memos.memocount) {
00680                 Memo *memos;
00681                 memos = scalloc(sizeof(Memo) * ci->memos.memocount, 1);
00682                 ci->memos.memos = memos;
00683                 for (j = 0; j < ci->memos.memocount; j++, memos++) {
00684                     SAFE(read_int32(&memos->number, f));
00685                     SAFE(read_int16(&memos->flags, f));
00686                     SAFE(read_int32(&tmp32, f));
00687                     memos->time = tmp32;
00688                     SAFE(read_buffer(memos->sender, f));
00689                     SAFE(read_string(&memos->text, f));
00690                     memos->moduleData = NULL;
00691                 }
00692             }
00693 
00694             SAFE(read_string(&ci->entry_message, f));
00695 
00696             ci->c = NULL;
00697 
00698             /* Some cleanup */
00699             if (ver <= 11) {
00700                 /* Cleanup: Founder must be != than successor */
00701                 if (!(ci->flags & CI_VERBOTEN)
00702                     && ci->successor == ci->founder) {
00703                     alog("Warning: founder and successor of %s are equal. Cleaning up.", ci->name);
00704                     ci->successor = NULL;
00705                 }
00706             }
00707 
00708             /* BotServ options */
00709 
00710             if (ver >= 8) {
00711                 int n_ttb;
00712 
00713                 SAFE(read_string(&s, f));
00714                 if (s) {
00715                     ci->bi = findbot(s);
00716                     free(s);
00717                 } else
00718                     ci->bi = NULL;
00719 
00720                 SAFE(read_int32(&tmp32, f));
00721                 ci->botflags = tmp32;
00722                 SAFE(read_int16(&tmp16, f));
00723                 n_ttb = tmp16;
00724                 ci->ttb = scalloc(2 * TTB_SIZE, 1);
00725                 for (j = 0; j < n_ttb; j++) {
00726                     SAFE(read_int16(&tmp16, f));
00727                     if (j < TTB_SIZE)
00728                         ci->ttb[j] = (int16) tmp16;
00729                 }
00730                 for (j = n_ttb; j < TTB_SIZE; j++)
00731                     ci->ttb[j] = 0;
00732                 SAFE(read_int16(&tmp16, f));
00733                 ci->capsmin = tmp16;
00734                 SAFE(read_int16(&tmp16, f));
00735                 ci->capspercent = tmp16;
00736                 SAFE(read_int16(&tmp16, f));
00737                 ci->floodlines = tmp16;
00738                 SAFE(read_int16(&tmp16, f));
00739                 ci->floodsecs = tmp16;
00740                 SAFE(read_int16(&tmp16, f));
00741                 ci->repeattimes = tmp16;
00742 
00743                 SAFE(read_int16(&ci->bwcount, f));
00744                 if (ci->bwcount) {
00745                     ci->badwords = scalloc(ci->bwcount, sizeof(BadWord));
00746                     for (j = 0; j < ci->bwcount; j++) {
00747                         SAFE(read_int16(&ci->badwords[j].in_use, f));
00748                         if (ci->badwords[j].in_use) {
00749                             SAFE(read_string(&ci->badwords[j].word, f));
00750                             SAFE(read_int16(&ci->badwords[j].type, f));
00751                         }
00752                     }
00753                 } else {
00754                     ci->badwords = NULL;
00755                 }
00756             } else {
00757                 ci->bi = NULL;
00758                 ci->botflags = 0;
00759                 ci->ttb = scalloc(2 * TTB_SIZE, 1);
00760                 for (j = 0; j < TTB_SIZE; j++)
00761                     ci->ttb[j] = 0;
00762                 ci->bwcount = 0;
00763                 ci->badwords = NULL;
00764             }
00765 
00766         }                       /* while (getc_db(f) != 0) */
00767 
00768         *last = NULL;
00769 
00770     }                           /* for (i) */
00771 
00772     close_db(f);
00773 
00774     /* Check for non-forbidden channels with no founder.
00775        Makes also other essential tasks. */
00776     for (i = 0; i < 256; i++) {
00777         ChannelInfo *next;
00778         for (ci = chanlists[i]; ci; ci = next) {
00779             next = ci->next;
00780             if (!(ci->flags & CI_VERBOTEN) && !ci->founder) {
00781                 alog("%s: database load: Deleting founderless channel %s",
00782                      s_ChanServ, ci->name);
00783                 delchan(ci);
00784                 continue;
00785             }
00786             if (ver < 13) {
00787                 ChanAccess *access, *access2;
00788                 AutoKick *akick, *akick2;
00789                 int k;
00790 
00791                 if (ci->flags & CI_VERBOTEN)
00792                     continue;
00793                 /* Need to regenerate the channel count for the founder */
00794                 ci->founder->channelcount++;
00795                 /* Check for eventual double entries in access/akick lists. */
00796                 for (j = 0, access = ci->access; j < ci->accesscount;
00797                      j++, access++) {
00798                     if (!access->in_use)
00799                         continue;
00800                     for (k = 0, access2 = ci->access; k < j;
00801                          k++, access2++) {
00802                         if (access2->in_use && access2->nc == access->nc) {
00803                             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);
00804                             memset(access, 0, sizeof(ChanAccess));
00805                             break;
00806                         }
00807                     }
00808                 }
00809                 for (j = 0, akick = ci->akick; j < ci->akickcount;
00810                      j++, akick++) {
00811                     if (!(akick->flags & AK_USED)
00812                         || !(akick->flags & AK_ISNICK))
00813                         continue;
00814                     for (k = 0, akick2 = ci->akick; k < j; k++, akick2++) {
00815                         if ((akick2->flags & AK_USED)
00816                             && (akick2->flags & AK_ISNICK)
00817                             && akick2->u.nc == akick->u.nc) {
00818                             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);
00819                             if (akick->reason)
00820                                 free(akick->reason);
00821                             if (akick->creator)
00822                                 free(akick->creator);
00823                             memset(akick, 0, sizeof(AutoKick));
00824                             break;
00825                         }
00826                     }
00827                 }
00828             }
00829         }
00830     }
00831 }
00832 
00833 #undef SAFE
00834 
00835 /*************************************************************************/
00836 
00837 #define SAFE(x) do {                                            \
00838     if ((x) < 0) {                                              \
00839         restore_db(f);                                          \
00840         log_perror("Write error on %s", ChanDBName);            \
00841         if (time(NULL) - lastwarn > WarningTimeout) {           \
00842             anope_cmd_global(NULL, "Write error on %s: %s", ChanDBName, \
00843                         strerror(errno));                       \
00844             lastwarn = time(NULL);                              \
00845         }                                                       \
00846         return;                                                 \
00847     }                                                           \
00848 } while (0)
00849 
00850 void save_cs_dbase(void)
00851 {
00852     dbFILE *f;
00853     int i, j;
00854     ChannelInfo *ci;
00855     Memo *memos;
00856     static time_t lastwarn = 0;
00857 
00858     if (!(f = open_db(s_ChanServ, ChanDBName, "w", CHAN_VERSION)))
00859         return;
00860 
00861     for (i = 0; i < 256; i++) {
00862         int16 tmp16;
00863 
00864         for (ci = chanlists[i]; ci; ci = ci->next) {
00865             SAFE(write_int8(1, f));
00866             SAFE(write_buffer(ci->name, f));
00867             if (ci->founder)
00868                 SAFE(write_string(ci->founder->display, f));
00869             else
00870                 SAFE(write_string(NULL, f));
00871             if (ci->successor)
00872                 SAFE(write_string(ci->successor->display, f));
00873             else
00874                 SAFE(write_string(NULL, f));
00875             SAFE(write_buffer(ci->founderpass, f));
00876             SAFE(write_string(ci->desc, f));
00877             SAFE(write_string(ci->url, f));
00878             SAFE(write_string(ci->email, f));
00879             SAFE(write_int32(ci->time_registered, f));
00880             SAFE(write_int32(ci->last_used, f));
00881             SAFE(write_string(ci->last_topic, f));
00882             SAFE(write_buffer(ci->last_topic_setter, f));
00883             SAFE(write_int32(ci->last_topic_time, f));
00884             SAFE(write_int32(ci->flags, f));
00885             SAFE(write_string(ci->forbidby, f));
00886             SAFE(write_string(ci->forbidreason, f));
00887             SAFE(write_int16(ci->bantype, f));
00888 
00889             tmp16 = CA_SIZE;
00890             SAFE(write_int16(tmp16, f));
00891             for (j = 0; j < CA_SIZE; j++)
00892                 SAFE(write_int16(ci->levels[j], f));
00893 
00894             SAFE(write_int16(ci->accesscount, f));
00895             for (j = 0; j < ci->accesscount; j++) {
00896                 SAFE(write_int16(ci->access[j].in_use, f));
00897                 if (ci->access[j].in_use) {
00898                     SAFE(write_int16(ci->access[j].level, f));
00899                     SAFE(write_string(ci->access[j].nc->display, f));
00900                     SAFE(write_int32(ci->access[j].last_seen, f));
00901                 }
00902             }
00903 
00904             SAFE(write_int16(ci->akickcount, f));
00905             for (j = 0; j < ci->akickcount; j++) {
00906                 SAFE(write_int16(ci->akick[j].flags, f));
00907                 if (ci->akick[j].flags & AK_USED) {
00908                     if (ci->akick[j].flags & AK_ISNICK)
00909                         SAFE(write_string(ci->akick[j].u.nc->display, f));
00910                     else
00911                         SAFE(write_string(ci->akick[j].u.mask, f));
00912                     SAFE(write_string(ci->akick[j].reason, f));
00913                     SAFE(write_string(ci->akick[j].creator, f));
00914                     SAFE(write_int32(ci->akick[j].addtime, f));
00915                 }
00916             }
00917 
00918             SAFE(write_int32(ci->mlock_on, f));
00919             SAFE(write_int32(ci->mlock_off, f));
00920             SAFE(write_int32(ci->mlock_limit, f));
00921             SAFE(write_string(ci->mlock_key, f));
00922             SAFE(write_string(ci->mlock_flood, f));
00923             SAFE(write_string(ci->mlock_redirect, f));
00924             /* Current DB format does not hold +j yet..  ~ Viper
00925             SAFE(write_string(ci->mlock_throttle, f));*/
00926             SAFE(write_int16(ci->memos.memocount, f));
00927             SAFE(write_int16(ci->memos.memomax, f));
00928             memos = ci->memos.memos;
00929             for (j = 0; j < ci->memos.memocount; j++, memos++) {
00930                 SAFE(write_int32(memos->number, f));
00931                 SAFE(write_int16(memos->flags, f));
00932                 SAFE(write_int32(memos->time, f));
00933                 SAFE(write_buffer(memos->sender, f));
00934                 SAFE(write_string(memos->text, f));
00935             }
00936 
00937             SAFE(write_string(ci->entry_message, f));
00938 
00939             if (ci->bi)
00940                 SAFE(write_string(ci->bi->nick, f));
00941             else
00942                 SAFE(write_string(NULL, f));
00943 
00944             SAFE(write_int32(ci->botflags, f));
00945 
00946             tmp16 = TTB_SIZE;
00947             SAFE(write_int16(tmp16, f));
00948             for (j = 0; j < TTB_SIZE; j++)
00949                 SAFE(write_int16(ci->ttb[j], f));
00950 
00951             SAFE(write_int16(ci->capsmin, f));
00952             SAFE(write_int16(ci->capspercent, f));
00953             SAFE(write_int16(ci->floodlines, f));
00954             SAFE(write_int16(ci->floodsecs, f));
00955             SAFE(write_int16(ci->repeattimes, f));
00956 
00957             SAFE(write_int16(ci->bwcount, f));
00958             for (j = 0; j < ci->bwcount; j++) {
00959                 SAFE(write_int16(ci->badwords[j].in_use, f));
00960                 if (ci->badwords[j].in_use) {
00961                     SAFE(write_string(ci->badwords[j].word, f));
00962                     SAFE(write_int16(ci->badwords[j].type, f));
00963                 }
00964             }
00965         }                       /* for (chanlists[i]) */
00966 
00967         SAFE(write_int8(0, f));
00968 
00969     }                           /* for (i) */
00970 
00971     close_db(f);
00972 
00973 }
00974 
00975 #undef SAFE
00976 
00977 /*************************************************************************/
00978 
00979 void save_cs_rdb_dbase(void)
00980 {
00981 #ifdef USE_RDB
00982     int i;
00983     ChannelInfo *ci;
00984 
00985     if (!rdb_open())
00986         return;
00987 
00988     if (rdb_tag_table("anope_cs_info") == 0) {
00989         alog("Unable to tag table 'anope_cs_info' - ChanServ RDB save failed.");
00990         rdb_close();
00991         return;
00992     }
00993     if (rdb_tag_table("anope_cs_access") == 0) {
00994         alog("Unable to tag table 'anope_cs_access' - ChanServ RDB save failed.");
00995         rdb_close();
00996         return;
00997     }
00998     if (rdb_tag_table("anope_cs_levels") == 0) {
00999         alog("Unable to tag table 'anope_cs_levels' - ChanServ RDB save failed.");
01000         rdb_close();
01001         return;
01002     }
01003     if (rdb_tag_table("anope_cs_akicks") == 0) {
01004         alog("Unable to tag table 'anope_cs_akicks' - ChanServ RDB save failed.");
01005         rdb_close();
01006         return;
01007     }
01008     if (rdb_tag_table("anope_cs_badwords") == 0) {
01009         alog("Unable to tag table 'anope_cs_badwords' - ChanServ RDB save failed.");
01010         rdb_close();
01011         return;
01012     }
01013     if (rdb_tag_table("anope_cs_ttb") == 0) {
01014         alog("Unable to tag table 'anope_cs_ttb' - ChanServ RDB save failed.");
01015         rdb_close();
01016         return;
01017     }
01018     if (rdb_tag_table_where("anope_ms_info", "serv='CHAN'") == 0) {
01019         alog("Unable to tag table 'anope_ms_info' - ChanServ RDB save failed.");
01020         rdb_close();
01021         return;
01022     }
01023 
01024     for (i = 0; i < 256; i++) {
01025         for (ci = chanlists[i]; ci; ci = ci->next) {
01026             if (rdb_save_cs_info(ci) == 0) {
01027                 alog("Unable to save ChanInfo for %s - ChanServ RDB save failed.", ci->name);
01028                 rdb_close();
01029                 return;
01030             }
01031         }                       /* for (chanlists[i]) */
01032     }                           /* for (i) */
01033 
01034     if (rdb_clean_table("anope_cs_info") == 0) {
01035         alog("Unable to clean table 'anope_cs_info' - ChanServ RDB save failed.");
01036         rdb_close();
01037         return;
01038     }
01039     if (rdb_clean_table("anope_cs_access") == 0) {
01040         alog("Unable to clean table 'anope_cs_access' - ChanServ RDB save failed.");
01041         rdb_close();
01042         return;
01043     }
01044     if (rdb_clean_table("anope_cs_levels") == 0) {
01045         alog("Unable to clean table 'anope_cs_levels' - ChanServ RDB save failed.");
01046         rdb_close();
01047         return;
01048     }
01049     if (rdb_clean_table("anope_cs_akicks") == 0) {
01050         alog("Unable to clean table 'anope_cs_akicks' - ChanServ RDB save failed.");
01051         rdb_close();
01052         return;
01053     }
01054     if (rdb_clean_table("anope_cs_badwords") == 0) {
01055         alog("Unable to clean table 'anope_cs_badwords' - ChanServ RDB save failed.");
01056         rdb_close();
01057         return;
01058     }
01059     if (rdb_clean_table("anope_cs_ttb") == 0) {
01060         alog("Unable to clean table 'anope_cs_ttb' - ChanServ RDB save failed.");
01061         rdb_close();
01062         return;
01063     }
01064     if (rdb_clean_table_where("anope_ms_info", "serv='CHAN'") == 0)
01065         alog("Unable to clean table 'anope_ms_info' - ChanServ RDB save failed.");
01066 
01067     rdb_close();
01068 #endif
01069 }
01070 
01071 /*************************************************************************/
01072 
01073 /* Check the current modes on a channel; if they conflict with a mode lock,
01074  * fix them.
01075  *
01076  * Also check to make sure that every mode set or unset is allowed by the
01077  * defcon mlock settings. This is more important than any normal channel
01078  * mlock'd mode. --gdex (21-04-07)
01079  */
01080 
01081 void check_modes(Channel * c)
01082 {
01083     char modebuf[64], argbuf[BUFSIZE], *end = modebuf, *end2 = argbuf;
01084     uint32 modes = 0;
01085     ChannelInfo *ci;
01086     CBModeInfo *cbmi = NULL;
01087     CBMode *cbm = NULL;
01088     boolean DefConOn = DefConLevel != 5;
01089 
01090     if (!c) {
01091         if (debug) {
01092             alog("debug: check_modes called with NULL values");
01093         }
01094         return;
01095     }
01096 
01097     if (c->bouncy_modes)
01098         return;
01099 
01100     /* Check for mode bouncing */
01101     if (c->server_modecount >= 3 && c->chanserv_modecount >= 3) {
01102         anope_cmd_global(NULL,
01103                          "Warning: unable to set modes on channel %s.  "
01104                          "Are your servers' U:lines configured correctly?",
01105                          c->name);
01106         alog("%s: Bouncy modes on channel %s", s_ChanServ, c->name);
01107         c->bouncy_modes = 1;
01108         return;
01109     }
01110 
01111     if (c->chanserv_modetime != time(NULL)) {
01112         c->chanserv_modecount = 0;
01113         c->chanserv_modetime = time(NULL);
01114     }
01115     c->chanserv_modecount++;
01116 
01117     /* Check if the channel is registered; if not remove mode -r */
01118     if (!(ci = c->ci)) {
01119         if (ircd->regmode) {
01120             if (c->mode & ircd->regmode) {
01121                 c->mode &= ~ircd->regmode;
01122                 anope_cmd_mode(whosends(ci), c->name, "-r");
01123             }
01124         }
01125         /* Channels that are not regged also need the defcon modes.. ~ Viper */
01126         /* return; */
01127     }
01128 
01129     /* Initialize the modes-var to set all modes not set yet but which should
01130      * be set as by mlock and defcon.
01131      */
01132     if (ci) 
01133         modes = ~c->mode & ci->mlock_on;
01134     if (DefConOn && DefConModesSet)
01135         modes |= (~c->mode & DefConModesOn);
01136 
01137     /* Initialize the buffers */
01138     *end++ = '+';
01139     cbmi = cbmodeinfos;
01140 
01141     do {
01142         if (modes & cbmi->flag) {
01143             *end++ = cbmi->mode;
01144             c->mode |= cbmi->flag;
01145 
01146             /* Add the eventual parameter and modify the Channel structure */
01147             if (cbmi->getvalue && cbmi->csgetvalue) {
01148                 char *value;
01149                 /* Check if it's a defcon or mlock mode */
01150                 if (DefConOn && DefConModesOn & cbmi->flag)
01151                     value = cbmi->csgetvalue(&DefConModesCI);
01152                 else if (ci)
01153                     value = cbmi->csgetvalue(ci);
01154                 else {
01155                     value = NULL;
01156                     if (debug) 
01157                         alog ("Warning: setting modes with unknown origin.");
01158                 }
01159 
01160                 cbm = &cbmodes[(int) cbmi->mode];
01161                 cbm->setvalue(c, value);
01162 
01163                 if (value) {
01164                     *end2++ = ' ';
01165                     while (*value)
01166                         *end2++ = *value++;
01167                 }
01168             }
01169         } else if (cbmi->getvalue && cbmi->csgetvalue
01170                    && ((ci && (ci->mlock_on & cbmi->flag))
01171                        || (DefConOn && DefConModesOn & cbmi->flag))
01172                    && (c->mode & cbmi->flag)) {
01173             char *value = cbmi->getvalue(c);
01174             char *csvalue;
01175 
01176             /* Check if it's a defcon or mlock mode */
01177             if (DefConOn && DefConModesOn & cbmi->flag)
01178                 csvalue = cbmi->csgetvalue(&DefConModesCI);
01179             else if (ci)
01180                 csvalue = cbmi->csgetvalue(ci);
01181             else {
01182                 csvalue = NULL;
01183                 if (debug)
01184                     alog ("Warning: setting modes with unknown origin.");
01185             }
01186 
01187             /* Lock and actual values don't match, so fix the mode */
01188             if (value && csvalue && strcmp(value, csvalue)) {
01189                 *end++ = cbmi->mode;
01190 
01191                 cbm = &cbmodes[(int) cbmi->mode];
01192                 cbm->setvalue(c, csvalue);
01193 
01194                 *end2++ = ' ';
01195                 while (*csvalue)
01196                     *end2++ = *csvalue++;
01197             }
01198         }
01199     } while ((++cbmi)->mode != 0);
01200 
01201     if (*(end - 1) == '+')
01202         end--;
01203 
01204     modes = 0;
01205     if (ci) {
01206         modes = c->mode & ci->mlock_off;
01207         /* Make sure we don't remove a mode just set by defcon.. ~ Viper */
01208         if (DefConOn && DefConModesSet)
01209             modes &= ~(modes & DefConModesOn);
01210     }
01211     if (DefConOn && DefConModesSet)
01212         modes |= c->mode & DefConModesOff;
01213 
01214     if (modes) {
01215         *end++ = '-';
01216         cbmi = cbmodeinfos;
01217 
01218         do {
01219             if (modes & cbmi->flag) {
01220                 *end++ = cbmi->mode;
01221                 c->mode &= ~cbmi->flag;
01222 
01223                 /* Add the eventual parameter and clean up the Channel structure */
01224                 if (cbmi->getvalue) {
01225                     cbm = &cbmodes[(int) cbmi->mode];
01226 
01227                     if (!(cbm->flags & CBM_MINUS_NO_ARG)) {
01228                         char *value = cbmi->getvalue(c);
01229 
01230                         if (value) {
01231                             *end2++ = ' ';
01232                             while (*value)
01233                                 *end2++ = *value++;
01234                         }
01235                     }
01236 
01237                     cbm->setvalue(c, NULL);
01238                 }
01239             }
01240         } while ((++cbmi)->mode != 0);
01241     }
01242 
01243     if (end == modebuf)
01244         return;
01245 
01246     *end = 0;
01247     *end2 = 0;
01248 
01249     anope_cmd_mode((ci ? whosends(ci) : s_OperServ), c->name, "%s%s", modebuf,
01250                    (end2 == argbuf ? "" : argbuf));
01251 }
01252 
01253 /*************************************************************************/
01254 
01255 int check_valid_admin(User * user, Channel * chan, int servermode)
01256 {
01257     if (!chan || !chan->ci)
01258         return 1;
01259 
01260     if (!ircd->admin) {
01261         return 0;
01262     }
01263 
01264     /* They will be kicked; no need to deop, no need to update our internal struct too */
01265     if (chan->ci->flags & CI_VERBOTEN)
01266         return 0;
01267 
01268     if (servermode && !check_access(user, chan->ci, CA_AUTOPROTECT)) {
01269         notice_lang(s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
01270         anope_cmd_mode(whosends(chan->ci), chan->name, "%s %s",
01271                        ircd->adminunset, GET_USER(user));
01272         return 0;
01273     }
01274 
01275     if (check_access(user, chan->ci, CA_AUTODEOP)) {
01276         anope_cmd_mode(whosends(chan->ci), chan->name, "%s %s",
01277                        ircd->adminunset, GET_USER(user));
01278         return 0;
01279     }
01280 
01281     return 1;
01282 }
01283 
01284 /*************************************************************************/
01285 
01286 /* Check whether a user is allowed to be opped on a channel; if they
01287  * aren't, deop them.  If serverop is 1, the +o was done by a server.
01288  * Return 1 if the user is allowed to be opped, 0 otherwise. */
01289 
01290 int check_valid_op(User * user, Channel * chan, int servermode)
01291 {
01292     char *tmp;
01293     if (!chan || !chan->ci)
01294         return 1;
01295 
01296     /* They will be kicked; no need to deop, no need to update our internal struct too */
01297     if (chan->ci->flags & CI_VERBOTEN)
01298         return 0;
01299 
01300     if (servermode && !check_access(user, chan->ci, CA_AUTOOP)) {
01301         notice_lang(s_ChanServ, user, CHAN_IS_REGISTERED, s_ChanServ);
01302         if (ircd->halfop) {
01303             if (ircd->owner && ircd->protect) {
01304                 if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
01305                     tmp = stripModePrefix(ircd->ownerunset);
01306                     anope_cmd_mode(whosends(chan->ci), chan->name,
01307                                    "%so%s %s %s %s", ircd->adminunset,
01308                                    tmp, GET_USER(user),
01309                                    GET_USER(user), GET_USER(user));
01310                     free(tmp);
01311                 } else {
01312                     tmp = stripModePrefix(ircd->ownerunset);
01313                     anope_cmd_mode(whosends(chan->ci), chan->name,
01314                                    "%sho%s %s %s %s %s",
01315                                    ircd->adminunset, tmp,
01316                                    GET_USER(user), GET_USER(user), GET_USER(user),
01317                                    GET_USER(user));
01318                     free(tmp);
01319                 }
01320             } else if (!ircd->owner && ircd->protect) {
01321                 if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
01322                     anope_cmd_mode(whosends(chan->ci), chan->name,
01323                                    "%so %s %s", ircd->adminunset,
01324                                    GET_USER(user), GET_USER(user));
01325                 } else {
01326                     anope_cmd_mode(whosends(chan->ci), chan->name,
01327                                    "%soh %s %s %s", ircd->adminunset,
01328                                    GET_USER(user), GET_USER(user), GET_USER(user));
01329                 }
01330             } else {
01331                 if (check_access(user, chan->ci, CA_AUTOHALFOP)) {
01332                     anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
01333                                    GET_USER(user));
01334                 } else {
01335                     anope_cmd_mode(whosends(chan->ci), chan->name,
01336                                    "-ho %s %s", GET_USER(user), GET_USER(user));
01337                 }
01338             }
01339         } else {
01340             anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
01341                            GET_USER(user));
01342         }
01343         return 0;
01344     }
01345 
01346     if (check_access(user, chan->ci, CA_AUTODEOP)) {
01347         if (ircd->halfop) {
01348             if (ircd->owner && ircd->protect) {
01349                 tmp = stripModePrefix(ircd->ownerunset);
01350                 anope_cmd_mode(whosends(chan->ci), chan->name,
01351                                "%sho%s %s %s %s %s", ircd->adminunset,
01352                                tmp, GET_USER(user), GET_USER(user),
01353                                GET_USER(user), GET_USER(user));
01354                 free(tmp);
01355             } else {
01356                 anope_cmd_mode(whosends(chan->ci), chan->name, "-ho %s %s",
01357                                GET_USER(user), GET_USER(user));
01358             }
01359         } else {
01360             anope_cmd_mode(whosends(chan->ci), chan->name, "-o %s",
01361                            GET_USER(user));
01362         }
01363         return 0;
01364     }
01365 
01366     return 1;
01367 }
01368 
01369 /*************************************************************************/
01370 
01371 /* Check whether a user should be opped on a channel, and if so, do it.
01372  * Return 1 if the user was opped, 0 otherwise.  (Updates the channel's
01373  * last used time if the user was opped.) */
01374 
01375 int check_should_op(User * user, char *chan)
01376 {
01377     ChannelInfo *ci = cs_findchan(chan);
01378 
01379     if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
01380         return 0;
01381 
01382     if ((ci->flags & CI_SECURE) && !nick_identified(user))
01383         return 0;
01384 
01385     if (check_access(user, ci, CA_AUTOOP)) {
01386         anope_cmd_mode(whosends(ci), chan, "+o %s", GET_USER(user));
01387         return 1;
01388     }
01389 
01390     return 0;
01391 }
01392 
01393 /*************************************************************************/
01394 
01395 /* Check whether a user should be voiced on a channel, and if so, do it.
01396  * Return 1 if the user was voiced, 0 otherwise. */
01397 
01398 int check_should_voice(User * user, char *chan)
01399 {
01400     ChannelInfo *ci = cs_findchan(chan);
01401 
01402     if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
01403         return 0;
01404 
01405     if ((ci->flags & CI_SECURE) && !nick_identified(user))
01406         return 0;
01407 
01408     if (check_access(user, ci, CA_AUTOVOICE)) {
01409         anope_cmd_mode(whosends(ci), chan, "+v %s", GET_USER(user));
01410         return 1;
01411     }
01412 
01413     return 0;
01414 }
01415 
01416 /*************************************************************************/
01417 
01418 int check_should_halfop(User * user, char *chan)
01419 {
01420     ChannelInfo *ci = cs_findchan(chan);
01421 
01422     if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
01423         return 0;
01424 
01425     if (check_access(user, ci, CA_AUTOHALFOP)) {
01426         anope_cmd_mode(whosends(ci), chan, "+h %s", GET_USER(user));
01427         return 1;
01428     }
01429 
01430     return 0;
01431 }
01432 
01433 /*************************************************************************/
01434 
01435 int check_should_owner(User * user, char *chan)
01436 {
01437     char *tmp;
01438     ChannelInfo *ci = cs_findchan(chan);
01439 
01440     if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
01441         return 0;
01442 
01443     if (((ci->flags & CI_SECUREFOUNDER) && is_real_founder(user, ci))
01444         || (!(ci->flags & CI_SECUREFOUNDER) && is_founder(user, ci))) {
01445         tmp = stripModePrefix(ircd->ownerset);
01446         anope_cmd_mode(whosends(ci), chan, "+o%s %s %s", tmp, GET_USER(user),
01447                        GET_USER(user));
01448         free(tmp);
01449         return 1;
01450     }
01451 
01452     return 0;
01453 }
01454 
01455 /*************************************************************************/
01456 
01457 int check_should_protect(User * user, char *chan)
01458 {
01459     char *tmp;
01460     ChannelInfo *ci = cs_findchan(chan);
01461 
01462     if (!ci || (ci->flags & CI_VERBOTEN) || *chan == '+')
01463         return 0;
01464 
01465     if (check_access(user, ci, CA_AUTOPROTECT)) {
01466         tmp = stripModePrefix(ircd->adminset);
01467         anope_cmd_mode(whosends(ci), chan, "+o%s %s %s", tmp, GET_USER(user),
01468                        GET_USER(user));
01469         free(tmp);
01470         return 1;
01471     }
01472 
01473     return 0;
01474 }
01475 
01476 /*************************************************************************/
01477 
01478 /* Tiny helper routine to get ChanServ out of a channel after it went in. */
01479 
01480 static void timeout_leave(Timeout * to)
01481 {
01482     char *chan = to->data;
01483     ChannelInfo *ci = cs_findchan(chan);
01484 
01485     if (ci)                     /* Check cos the channel may be dropped in the meantime */
01486         ci->flags &= ~CI_INHABIT;
01487 
01488     anope_cmd_part(s_ChanServ, chan, NULL);
01489     free(to->data);
01490 }
01491 
01492 
01493 /* Check whether a user is permitted to be on a channel.  If so, return 0;
01494  * else, kickban the user with an appropriate message (could be either
01495  * AKICK or restricted access) and return 1.  Note that this is called
01496  * _before_ the user is added to internal channel lists (so do_kick() is
01497  * not called). The channel TS must be given for a new channel.
01498  */
01499 
01500 int check_kick(User * user, char *chan, time_t chants)
01501 {
01502     ChannelInfo *ci = cs_findchan(chan);
01503     Channel *c;
01504     AutoKick *akick;
01505     int i, set_modes = 0;
01506     NickCore *nc;
01507     char *av[4];
01508     int ac;
01509     char buf[BUFSIZE];
01510     char mask[BUFSIZE];
01511     const char *reason;
01512     Timeout *t;
01513 
01514     if (!ci)
01515         return 0;
01516 
01517     if (user->isSuperAdmin == 1)
01518         return 0;
01519 
01520     /* We don't enforce services restrictions on clients on ulined services 
01521      * as this will likely lead to kick/rejoin floods. ~ Viper */
01522     if (is_ulined(user->server->name)) {
01523         return 0;
01524     }
01525 
01526     if (ci->flags & CI_VERBOTEN) {
01527         get_idealban(ci, user, mask, sizeof(mask));
01528         reason =
01529             ci->forbidreason ? ci->forbidreason : getstring(user->na,
01530                                                             CHAN_MAY_NOT_BE_USED);
01531         set_modes = 1;
01532         goto kick;
01533     }
01534 
01535     if (ci->flags & CI_SUSPENDED) {
01536         get_idealban(ci, user, mask, sizeof(mask));
01537         reason =
01538             ci->forbidreason ? ci->forbidreason : getstring(user->na,
01539                                                             CHAN_MAY_NOT_BE_USED);
01540         set_modes = 1;
01541         goto kick;
01542     }
01543 
01544     if (nick_recognized(user))
01545         nc = user->na->nc;
01546     else
01547         nc = NULL;
01548 
01549     /*
01550      * Before we go through akick lists, see if they're excepted FIRST
01551      * We cannot kick excempted users that are akicked or not on the channel access list
01552      * as that will start services <-> server wars which ends up as a DoS against services.
01553      *
01554      * UltimateIRCd 3.x at least informs channel staff when a joining user is matching an exempt.
01555      */
01556     if (ircd->except && is_excepted(ci, user) == 1) {
01557         return 0;
01558     }
01559 
01560     for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
01561         if (!(akick->flags & AK_USED))
01562             continue;
01563         if ((akick->flags & AK_ISNICK && akick->u.nc == nc)
01564             || (!(akick->flags & AK_ISNICK)
01565                 && match_usermask(akick->u.mask, user))) {
01566             if (debug >= 2)
01567                 alog("debug: %s matched akick %s", user->nick,
01568                      (akick->flags & AK_ISNICK) ? akick->u.nc->
01569                      display : akick->u.mask);
01570             if (akick->flags & AK_ISNICK)
01571                 get_idealban(ci, user, mask, sizeof(mask));
01572             else
01573                 strscpy(mask, akick->u.mask, sizeof(mask));
01574             reason = akick->reason ? akick->reason : CSAutokickReason;
01575             goto kick;
01576         }
01577     }
01578 
01579     if (check_access(user, ci, CA_NOJOIN)) {
01580         get_idealban(ci, user, mask, sizeof(mask));
01581         reason = getstring(user->na, CHAN_NOT_ALLOWED_TO_JOIN);
01582         goto kick;
01583     }
01584 
01585     return 0;
01586 
01587   kick:
01588     if (debug)
01589         alog("debug: channel: AutoKicking %s!%s@%s from %s", user->nick,
01590              user->username, user->host, chan);
01591 
01592     /* Remember that the user has not been added to our channel user list
01593      * yet, so we check whether the channel does not exist OR has no user
01594      * on it (before SJOIN would have created the channel structure, while
01595      * JOIN would not). */
01596     /* Don't check for CI_INHABIT before for the Channel record cos else
01597      * c may be NULL even if it exists */
01598     if ((!(c = findchan(chan)) || c->usercount == 0)
01599         && !(ci->flags & CI_INHABIT)) {
01600         anope_cmd_join(s_ChanServ, chan, (c ? c->creation_time : chants));
01601         /* Lets hide the channel from /list just incase someone does /list
01602          * while we are here. - katsklaw
01603          * We don't want to block users from joining a legit chan though.. - Viper
01604          */
01605         if (set_modes)
01606             anope_cmd_mode(s_ChanServ, chan, "+ntsi");
01607         t = add_timeout(CSInhabit, timeout_leave, 0);
01608         t->data = sstrdup(chan);
01609         ci->flags |= CI_INHABIT;
01610     }
01611 
01612     if (c) {
01613         if (ircdcap->tsmode) {
01614             snprintf(buf, BUFSIZE - 1, "%ld", (long int) time(NULL));
01615             av[0] = chan;
01616             av[1] = buf;
01617             av[2] = sstrdup("+b");
01618             av[3] = mask;
01619             ac = 4;
01620         } else {
01621             av[0] = chan;
01622             av[1] = sstrdup("+b");
01623             av[2] = mask;
01624             ac = 3;
01625         }
01626 
01627         do_cmode(whosends(ci), ac, av);
01628 
01629         if (ircdcap->tsmode)
01630             free(av[2]);
01631         else
01632             free(av[1]);
01633     }
01634 
01635     anope_cmd_mode(whosends(ci), chan, "+b %s", mask);
01636     anope_cmd_kick(whosends(ci), chan, user->nick, "%s", reason);
01637 
01638     return 1;
01639 }
01640 
01641 /*************************************************************************/
01642 
01643 /* Record the current channel topic in the ChannelInfo structure. */
01644 
01645 void record_topic(const char *chan)
01646 {
01647     Channel *c;
01648     ChannelInfo *ci;
01649 
01650     if (readonly)
01651         return;
01652 
01653     c = findchan(chan);
01654     if (!c || !(ci = c->ci))
01655         return;
01656 
01657     if (ci->last_topic)
01658         free(ci->last_topic);
01659 
01660     if (c->topic)
01661         ci->last_topic = sstrdup(c->topic);
01662     else
01663         ci->last_topic = NULL;
01664 
01665     strscpy(ci->last_topic_setter, c->topic_setter, NICKMAX);
01666     ci->last_topic_time = c->topic_time;
01667 }
01668 
01669 /*************************************************************************/
01670 
01671 /* Restore the topic in a channel when it's created, if we should. */
01672 
01673 void restore_topic(char *chan)
01674 {
01675     Channel *c = findchan(chan);
01676     ChannelInfo *ci;
01677 
01678     if (!c || !(ci = c->ci))
01679         return;
01680     /* We can be sure that the topic will be in sync when we return -GD */
01681     c->topic_sync = 1;
01682     if (!(ci->flags & CI_KEEPTOPIC)) {
01683         /* We need to reset the topic here, since it's currently empty and
01684          * should be updated with a TOPIC from the IRCd soon. -GD
01685          */
01686         ci->last_topic = NULL;
01687         strscpy(ci->last_topic_setter, whosends(ci), NICKMAX);
01688         ci->last_topic_time = time(NULL);
01689         return;
01690     }
01691     if (c->topic)
01692         free(c->topic);
01693     if (ci->last_topic) {
01694         c->topic = sstrdup(ci->last_topic);
01695         strscpy(c->topic_setter, ci->last_topic_setter, NICKMAX);
01696         c->topic_time = ci->last_topic_time;
01697     } else {
01698         c->topic = NULL;
01699         strscpy(c->topic_setter, whosends(ci), NICKMAX);
01700     }
01701     if (ircd->join2set) {
01702         if (whosends(ci) == s_ChanServ) {
01703             anope_cmd_join(s_ChanServ, chan, c->creation_time);
01704             anope_cmd_mode(NULL, chan, "+o %s", GET_BOT(s_ChanServ));
01705         }
01706     }
01707     anope_cmd_topic(whosends(ci), c->name, c->topic_setter,
01708                     c->topic ? c->topic : "", c->topic_time);
01709     if (ircd->join2set) {
01710         if (whosends(ci) == s_ChanServ) {
01711             anope_cmd_part(s_ChanServ, c->name, NULL);
01712         }
01713     }
01714 }
01715 
01716 /*************************************************************************/
01717 
01718 /* See if the topic is locked on the given channel, and return 1 (and fix
01719  * the topic) if so. */
01720 
01721 int check_topiclock(Channel * c, time_t topic_time)
01722 {
01723     ChannelInfo *ci;
01724 
01725     if (!c) {
01726         if (debug) {
01727             alog("debug: check_topiclock called with NULL values");
01728         }
01729         return 0;
01730     }
01731 
01732     if (!(ci = c->ci) || !(ci->flags & CI_TOPICLOCK))
01733         return 0;
01734 
01735     if (c->topic)
01736         free(c->topic);
01737     if (ci->last_topic) {
01738         c->topic = sstrdup(ci->last_topic);
01739         strscpy(c->topic_setter, ci->last_topic_setter, NICKMAX);
01740     } else {
01741         c->topic = NULL;
01742         /* Bot assigned & Symbiosis ON?, the bot will set the topic - doc */
01743         /* Altough whosends() also checks for BSMinUsers -GD */
01744         strscpy(c->topic_setter, whosends(ci), NICKMAX);
01745     }
01746 
01747     if (ircd->topictsforward) {
01748         /* Because older timestamps are rejected */
01749         /* Some how the topic_time from do_topic is 0 set it to current + 1 */
01750         if (!topic_time) {
01751             c->topic_time = time(NULL) + 1;
01752         } else {
01753             c->topic_time = topic_time + 1;
01754         }
01755     } else {
01756         /* If no last topic, we can't use last topic time! - doc */
01757         if (ci->last_topic)
01758             c->topic_time = ci->last_topic_time;
01759         else
01760             c->topic_time = time(NULL) + 1;
01761     }
01762 
01763     if (ircd->join2set) {
01764         if (whosends(ci) == s_ChanServ) {
01765             anope_cmd_join(s_ChanServ, c->name, c->creation_time);
01766             anope_cmd_mode(NULL, c->name, "+o %s", GET_BOT(s_ChanServ));
01767         }
01768     }
01769 
01770     anope_cmd_topic(whosends(ci), c->name, c->topic_setter,
01771                     c->topic ? c->topic : "", c->topic_time);
01772 
01773     if (ircd->join2set) {
01774         if (whosends(ci) == s_ChanServ) {
01775             anope_cmd_part(s_ChanServ, c->ci->name, NULL);
01776         }
01777     }
01778     return 1;
01779 }
01780 
01781 /*************************************************************************/
01782 
01783 /* Remove all channels which have expired. */
01784 
01785 void expire_chans()
01786 {
01787     ChannelInfo *ci, *next;
01788     int i;
01789     time_t now = time(NULL);
01790 
01791     if (!CSExpire)
01792         return;
01793 
01794     for (i = 0; i < 256; i++) {
01795         for (ci = chanlists[i]; ci; ci = next) {
01796             next = ci->next;
01797             if (!ci->c && now - ci->last_used >= CSExpire
01798                 && !(ci->
01799                      flags & (CI_VERBOTEN | CI_NO_EXPIRE | CI_SUSPENDED)))
01800             {
01801                 send_event(EVENT_CHAN_EXPIRE, 1, ci->name);
01802                 alog("Expiring channel %s (founder: %s)", ci->name,
01803                      (ci->founder ? ci->founder->display : "(none)"));
01804                 delchan(ci);
01805             }
01806         }
01807     }
01808 }
01809 
01810 /*************************************************************************/
01811 
01812 /* Remove a (deleted or expired) nickname from all channel lists. */
01813 
01814 void cs_remove_nick(const NickCore * nc)
01815 {
01816     int i, j, k;
01817     ChannelInfo *ci, *next;
01818     ChanAccess *ca;
01819     AutoKick *akick;
01820 
01821     for (i = 0; i < 256; i++) {
01822         for (ci = chanlists[i]; ci; ci = next) {
01823             next = ci->next;
01824             if (ci->founder == nc) {
01825                 if (ci->successor) {
01826                     NickCore *nc2 = ci->successor;
01827                     if (!nick_is_services_admin(nc2) && nc2->channelmax > 0
01828                         && nc2->channelcount >= nc2->channelmax) {
01829                         alog("%s: Successor (%s) of %s owns too many channels, " "deleting channel", s_ChanServ, nc2->display, ci->name);
01830                         delchan(ci);
01831                         continue;
01832                     } else {
01833                         alog("%s: Transferring foundership of %s from deleted " "nick %s to successor %s", s_ChanServ, ci->name, nc->display, nc2->display);
01834                         ci->founder = nc2;
01835                         ci->successor = NULL;
01836                         nc2->channelcount++;
01837                     }
01838                 } else {
01839                     alog("%s: Deleting channel %s owned by deleted nick %s", s_ChanServ, ci->name, nc->display);
01840                     if (ircd->regmode) {
01841                         /* Maybe move this to delchan() ? */
01842                         if ((ci->c) && (ci->c->mode & ircd->regmode)) {
01843                             ci->c->mode &= ~ircd->regmode;
01844                             anope_cmd_mode(whosends(ci), ci->name, "-r");
01845                         }
01846                     }
01847 
01848                     delchan(ci);
01849                     continue;
01850                 }
01851             }
01852 
01853             if (ci->successor == nc)
01854                 ci->successor = NULL;
01855 
01856             for (ca = ci->access, j = ci->accesscount; j > 0; ca++, j--) {
01857                 if (ca->in_use && ca->nc == nc) {
01858                     ca->in_use = 0;
01859                     ca->nc = NULL;
01860                 }
01861             }
01862             CleanAccess(ci);
01863 
01864             for (akick = ci->akick, j = 0; j < ci->akickcount; akick++, j++) {
01865                 if ((akick->flags & AK_USED) && (akick->flags & AK_ISNICK)
01866                     && akick->u.nc == nc) {
01867                     if (akick->creator) {
01868                         free(akick->creator);
01869                         akick->creator = NULL;
01870                     }
01871                     if (akick->reason) {
01872                         free(akick->reason);
01873                         akick->reason = NULL;
01874                     }
01875                     akick->flags = 0;
01876                     akick->addtime = 0;
01877                     akick->u.nc = NULL;
01878 
01879                     /* Only one occurance can exist in every akick list.. ~ Viper */
01880                     break;
01881                 }
01882             }
01883 
01884             /* Are there any akicks behind us? 
01885              * If so, move all following akicks.. ~ Viper */
01886             if (j < ci->akickcount - 1) {
01887                 for (k = j + 1; k < ci->akickcount; j++, k++) {
01888                     if (ci->akick[k].flags & AK_USED) {
01889                         /* Move the akick one place ahead and clear the original */
01890                         if (ci->akick[k].flags & AK_ISNICK) {
01891                             ci->akick[j].u.nc = ci->akick[k].u.nc;
01892                             ci->akick[k].u.nc = NULL;
01893                         } else {
01894                             ci->akick[j].u.mask = sstrdup(ci->akick[k].u.mask);
01895                             free(ci->akick[k].u.mask);
01896                             ci->akick[k].u.mask = NULL;
01897                         }
01898 
01899                         if (ci->akick[k].reason) {
01900                             ci->akick[j].reason = sstrdup(ci->akick[k].reason);
01901                             free(ci->akick[k].reason);
01902                             ci->akick[k].reason = NULL;
01903                         } else
01904                             ci->akick[j].reason = NULL;
01905 
01906                         ci->akick[j].creator = sstrdup(ci->akick[k].creator);
01907                         free(ci->akick[k].creator);
01908                         ci->akick[k].creator = NULL;
01909 
01910                         ci->akick[j].flags = ci->akick[k].flags;
01911                         ci->akick[k].flags = 0;
01912 
01913                         ci->akick[j].addtime = ci->akick[k].addtime;
01914                         ci->akick[k].addtime = 0;
01915                     }
01916                 }
01917             }
01918 
01919             /* After moving only the last entry should still be empty.
01920              * Free the place no longer in use... ~ Viper */
01921             ci->akickcount = j;
01922             ci->akick = srealloc(ci->akick,sizeof(AutoKick) * ci->akickcount);
01923         }
01924     }
01925 }
01926 
01927 /*************************************************************************/
01928 
01929 /* Removes any reference to a bot */
01930 
01931 void cs_remove_bot(const BotInfo * bi)
01932 {
01933     int i;
01934     ChannelInfo *ci;
01935 
01936     for (i = 0; i < 256; i++)
01937         for (ci = chanlists[i]; ci; ci = ci->next)
01938             if (ci->bi == bi)
01939                 ci->bi = NULL;
01940 }
01941 
01942 /*************************************************************************/
01943 
01944 /* Return the ChannelInfo structure for the given channel, or NULL if the
01945  * channel isn't registered. */
01946 
01947 ChannelInfo *cs_findchan(const char *chan)
01948 {
01949     ChannelInfo *ci;
01950 
01951     if (!chan || !*chan) {
01952         if (debug) {
01953             alog("debug: cs_findchan() called with NULL values");
01954         }
01955         return NULL;
01956     }
01957 
01958     for (ci = chanlists[(unsigned char) tolower(chan[1])]; ci;
01959          ci = ci->next) {
01960         if (stricmp(ci->name, chan) == 0)
01961             return ci;
01962     }
01963     return NULL;
01964 }
01965 
01966 /*************************************************************************/
01967 
01968 /* Return 1 if the user's access level on the given channel falls into the
01969  * given category, 0 otherwise.  Note that this may seem slightly confusing
01970  * in some cases: for example, check_access(..., CA_NOJOIN) returns true if
01971  * the user does _not_ have access to the channel (i.e. matches the NOJOIN
01972  * criterion). */
01973 
01974 int check_access(User * user, ChannelInfo * ci, int what)
01975 {
01976     int level;
01977     int limit;
01978 
01979     if (!user || !ci) {
01980         return 0;
01981     }
01982 
01983     level = get_access(user, ci);
01984     limit = ci->levels[what];
01985 
01986     /* Resetting the last used time */
01987     if (level > 0)
01988         ci->last_used = time(NULL);
01989 
01990     if (level >= ACCESS_FOUNDER)
01991         return (what == CA_AUTODEOP || what == CA_NOJOIN) ? 0 : 1;
01992     /* Hacks to make flags work */
01993     if (what == CA_AUTODEOP && (ci->flags & CI_SECUREOPS) && level == 0)
01994         return 1;
01995     if (limit == ACCESS_INVALID)
01996         return 0;
01997     if (what == CA_AUTODEOP || what == CA_NOJOIN)
01998         return level <= ci->levels[what];
01999     else
02000         return level >= ci->levels[what];
02001 }
02002 
02003 /*************************************************************************/
02004 /*********************** ChanServ private routines ***********************/
02005 /*************************************************************************/
02006 
02007 /* Insert a channel alphabetically into the database. */
02008 
02009 void alpha_insert_chan(ChannelInfo * ci)
02010 {
02011     ChannelInfo *ptr, *prev;
02012     char *chan;
02013 
02014     if (!ci) {
02015         if (debug) {
02016             alog("debug: alpha_insert_chan called with NULL values");
02017         }
02018         return;
02019     }
02020 
02021     chan = ci->name;
02022 
02023     for (prev = NULL, ptr = chanlists[(unsigned char) tolower(chan[1])];
02024          ptr != NULL && stricmp(ptr->name, chan) < 0;
02025          prev = ptr, ptr = ptr->next);
02026     ci->prev = prev;
02027     ci->next = ptr;
02028     if (!prev)
02029         chanlists[(unsigned char) tolower(chan[1])] = ci;
02030     else
02031         prev->next = ci;
02032     if (ptr)
02033         ptr->prev = ci;
02034 }
02035 
02036 /*************************************************************************/
02037 
02038 /* Add a channel to the database.  Returns a pointer to the new ChannelInfo
02039  * structure if the channel was successfully registered, NULL otherwise.
02040  * Assumes channel does not already exist. */
02041 
02042 ChannelInfo *makechan(const char *chan)
02043 {
02044     int i;
02045     ChannelInfo *ci;
02046 
02047     ci = scalloc(sizeof(ChannelInfo), 1);
02048     strscpy(ci->name, chan, CHANMAX);
02049     ci->time_registered = time(NULL);
02050     reset_levels(ci);
02051     ci->ttb = scalloc(2 * TTB_SIZE, 1);
02052     for (i = 0; i < TTB_SIZE; i++)
02053         ci->ttb[i] = 0;
02054     alpha_insert_chan(ci);
02055     return ci;
02056 }
02057 
02058 /*************************************************************************/
02059 
02060 /* Remove a channel from the ChanServ database.  Return 1 on success, 0
02061  * otherwise. */
02062 
02063 int delchan(ChannelInfo * ci)
02064 {
02065     int i;
02066     NickCore *nc;
02067     User *u;
02068     struct u_chaninfolist *cilist, *cilist_next;
02069 
02070     if (!ci) {
02071         if (debug) {
02072             alog("debug: delchan called with NULL values");
02073         }
02074         return 0;
02075     }
02076 
02077     nc = ci->founder;
02078 
02079     if (debug >= 2) {
02080         alog("debug: delchan removing %s", ci->name);
02081     }
02082 
02083     if (ci->bi) {
02084         ci->bi->chancount--;
02085     }
02086 
02087     if (debug >= 2) {
02088         alog("debug: delchan top of removing the bot");
02089     }
02090     if (ci->c) {
02091         if (ci->bi && ci->c->usercount >= BSMinUsers) {
02092             anope_cmd_part(ci->bi->nick, ci->c->name, NULL);
02093         }
02094         ci->c->ci = NULL;
02095     }
02096     if (debug >= 2) {
02097         alog("debug: delchan() Bot has been removed moving on");
02098     }
02099 
02100     if (debug >= 2) {
02101         alog("debug: delchan() founder cleanup");
02102     }
02103     for (i = 0; i < 1024; i++) {
02104         for (u = userlist[i]; u; u = u->next) {
02105             cilist = u->founder_chans;
02106             while (cilist) {
02107                 cilist_next = cilist->next;
02108                 if (cilist->chan == ci) {
02109                     if (debug)
02110                         alog("debug: Dropping founder login of %s for %s",
02111                              u->nick, ci->name);
02112                     if (cilist->next)
02113                         cilist->next->prev = cilist->prev;
02114                     if (cilist->prev)
02115                         cilist->prev->next = cilist->next;
02116                     else
02117                         u->founder_chans = cilist->next;
02118                     free(cilist);
02119                 }
02120                 cilist = cilist_next;
02121             }
02122         }
02123     }
02124     if (debug >= 2) {
02125         alog("debug: delchan() founder cleanup done");
02126     }
02127 
02128     if (ci->next)
02129         ci->next->prev = ci->prev;
02130     if (ci->prev)
02131         ci->prev->next = ci->next;
02132     else
02133         chanlists[(unsigned char) tolower(ci->name[1])] = ci->next;
02134     if (ci->desc)
02135         free(ci->desc);
02136     if (ci->url)
02137         free(ci->url);
02138     if (ci->email)
02139         free(ci->email);
02140     if (ci->entry_message)
02141         free(ci->entry_message);
02142 
02143     if (ci->mlock_key)
02144         free(ci->mlock_key);
02145     if (ircd->fmode) {
02146         if (ci->mlock_flood)
02147             free(ci->mlock_flood);
02148     }
02149     if (ircd->Lmode) {
02150         if (ci->mlock_redirect)
02151             free(ci->mlock_redirect);
02152     }
02153     if (ircd->jmode) {
02154         if (ci->mlock_throttle)
02155             free(ci->mlock_throttle);
02156     }
02157     if (ci->last_topic)
02158         free(ci->last_topic);
02159     if (ci->forbidby)
02160         free(ci->forbidby);
02161     if (ci->forbidreason)
02162         free(ci->forbidreason);
02163     if (ci->access)
02164         free(ci->access);
02165     if (debug >= 2) {
02166         alog("debug: delchan() top of the akick list");
02167     }
02168     for (i = 0; i < ci->akickcount; i++) {
02169         if (!(ci->akick[i].flags & AK_ISNICK) && ci->akick[i].u.mask)
02170             free(ci->akick[i].u.mask);
02171         if (ci->akick[i].reason)
02172             free(ci->akick[i].reason);
02173         if (ci->akick[i].creator)
02174             free(ci->akick[i].creator);
02175     }
02176     if (debug >= 2) {
02177         alog("debug: delchan() done with the akick list");
02178     }
02179     if (ci->akick)
02180         free(ci->akick);
02181     if (ci->levels)
02182         free(ci->levels);
02183     if (debug >= 2) {
02184         alog("debug: delchan() top of the memo list");
02185     }
02186     if (ci->memos.memos) {
02187         for (i = 0; i < ci->memos.memocount; i++) {
02188             if (ci->memos.memos[i].text)
02189                 free(ci->memos.memos[i].text);
02190             moduleCleanStruct(&ci->memos.memos[i].moduleData);
02191         }
02192         free(ci->memos.memos);
02193     }
02194     if (debug >= 2) {
02195         alog("debug: delchan() done with the memo list");
02196     }
02197     if (ci->ttb)
02198         free(ci->ttb);
02199 
02200     if (debug >= 2) {
02201         alog("debug: delchan() top of the badword list");
02202     }
02203     for (i = 0; i < ci->bwcount; i++) {
02204         if (ci->badwords[i].word)
02205             free(ci->badwords[i].word);
02206     }
02207     if (ci->badwords)
02208         free(ci->badwords);
02209     if (debug >= 2) {
02210         alog("debug: delchan() done with the badword list");
02211     }
02212 
02213 
02214     if (debug >= 2) {
02215         alog("debug: delchan() calling on moduleCleanStruct()");
02216     }
02217     moduleCleanStruct(&ci->moduleData);
02218 
02219     free(ci);
02220     if (nc)
02221         nc->channelcount--;
02222 
02223     if (debug >= 2) {
02224         alog("debug: delchan() all done");
02225     }
02226     return 1;
02227 }
02228 
02229 /*************************************************************************/
02230 
02231 /* Reset channel access level values to their default state. */
02232 
02233 void reset_levels(ChannelInfo * ci)
02234 {
02235     int i;
02236 
02237     if (!ci) {
02238         if (debug) {
02239             alog("debug: reset_levels called with NULL values");
02240         }
02241         return;
02242     }
02243 
02244     if (ci->levels)
02245         free(ci->levels);
02246     ci->levels = scalloc(CA_SIZE * sizeof(*ci->levels), 1);
02247     for (i = 0; def_levels[i][0] >= 0; i++)
02248         ci->levels[def_levels[i][0]] = def_levels[i][1];
02249 }
02250 
02251 /*************************************************************************/
02252 
02253 /* Does the given user have founder access to the channel? */
02254 
02255 int is_founder(User * user, ChannelInfo * ci)
02256 {
02257     if (!user || !ci) {
02258         return 0;
02259     }
02260 
02261     if (user->isSuperAdmin) {
02262         return 1;
02263     }
02264 
02265     if (user->na && user->na->nc == ci->founder) {
02266         if ((nick_identified(user)
02267              || (nick_recognized(user) && !(ci->flags & CI_SECURE))))
02268             return 1;
02269     }
02270     if (is_identified(user, ci))
02271         return 1;
02272     return 0;
02273 }
02274 
02275 /*************************************************************************/
02276 
02277 int is_real_founder(User * user, ChannelInfo * ci)
02278 {
02279     if (user->isSuperAdmin) {
02280         return 1;
02281     }
02282 
02283     if (user->na && user->na->nc == ci->founder) {
02284         if ((nick_identified(user)
02285              || (nick_recognized(user) && !(ci->flags & CI_SECURE))))
02286             return 1;
02287     }
02288     return 0;
02289 }
02290 
02291 /*************************************************************************/
02292 
02293 /* Has the given user password-identified as founder for the channel? */
02294 
02295 int is_identified(User * user, ChannelInfo * ci)
02296 {
02297     struct u_chaninfolist *c;
02298 
02299     for (c = user->founder_chans; c; c = c->next) {
02300         if (c->chan == ci)
02301             return 1;
02302     }
02303     return 0;
02304 }
02305 
02306 /*************************************************************************/
02307 
02308 /* Returns the ChanAccess entry for an user */
02309 
02310 ChanAccess *get_access_entry(NickCore * nc, ChannelInfo * ci)
02311 {
02312     ChanAccess *access;
02313     int i;
02314 
02315     if (!ci || !nc) {
02316         return NULL;
02317     }
02318 
02319     for (access = ci->access, i = 0; i < ci->accesscount; access++, i++)
02320         if (access->in_use && access->nc == nc)
02321             return access;
02322 
02323     return NULL;
02324 }
02325 
02326 /*************************************************************************/
02327 
02328 /* Return the access level the given user has on the channel.  If the
02329  * channel doesn't exist, the user isn't on the access list, or the channel
02330  * is CS_SECURE and the user hasn't IDENTIFY'd with NickServ, return 0. */
02331 
02332 int get_access(User * user, ChannelInfo * ci)
02333 {
02334     ChanAccess *access;
02335 
02336     if (!ci || !user)
02337         return 0;
02338 
02339     /* SuperAdmin always has highest level */
02340     if (user->isSuperAdmin)
02341         return ACCESS_SUPERADMIN;
02342 
02343     if (is_founder(user, ci))
02344         return ACCESS_FOUNDER;
02345 
02346     if (!user->na)
02347         return 0;
02348 
02349     if (nick_identified(user)
02350         || (nick_recognized(user) && !(ci->flags & CI_SECURE)))
02351         if ((access = get_access_entry(user->na->nc, ci)))
02352             return access->level;
02353 
02354     if (nick_identified(user))
02355         return 0;
02356 
02357     return 0;
02358 }
02359 
02360 /*************************************************************************/
02361 
02362 void update_cs_lastseen(User * user, ChannelInfo * ci)
02363 {
02364     ChanAccess *access;
02365 
02366     if (!ci || !user || !user->na)
02367         return;
02368 
02369     if (is_founder(user, ci) || nick_identified(user)
02370         || (nick_recognized(user) && !(ci->flags & CI_SECURE)))
02371         if ((access = get_access_entry(user->na->nc, ci)))
02372             access->last_seen = time(NULL);
02373 }
02374 
02375 /*************************************************************************/
02376 
02377 /* Returns the best ban possible for an user depending of the bantype
02378    value. */
02379 
02380 int get_idealban(ChannelInfo * ci, User * u, char *ret, int retlen)
02381 {
02382     char *mask;
02383 
02384     if (!ci || !u || !ret || retlen == 0)
02385         return 0;
02386 
02387     switch (ci->bantype) {
02388     case 0:
02389         snprintf(ret, retlen, "*!%s@%s", common_get_vident(u),
02390                  common_get_vhost(u));
02391         return 1;
02392     case 1:
02393         snprintf(ret, retlen, "*!%s%s@%s",
02394                  (strlen(common_get_vident(u)) <
02395                   (*(common_get_vident(u)) ==
02396                    '~' ? USERMAX + 1 : USERMAX) ? "*" : ""),
02397                  (*(common_get_vident(u)) ==
02398                   '~' ? common_get_vident(u) + 1 : common_get_vident(u)),
02399                  common_get_vhost(u));
02400         return 1;
02401     case 2:
02402         snprintf(ret, retlen, "*!*@%s", common_get_vhost(u));
02403         return 1;
02404     case 3:
02405         mask = create_mask(u);
02406         snprintf(ret, retlen, "*!%s", mask);
02407         free(mask);
02408         return 1;
02409 
02410     default:
02411         return 0;
02412     }
02413 }
02414 
02415 /*************************************************************************/
02416 
02417 char *cs_get_flood(ChannelInfo * ci)
02418 {
02419     if (!ci) {
02420         return NULL;
02421     } else {
02422         if (ircd->fmode) {
02423             return ci->mlock_flood;
02424         } else {
02425             return NULL;
02426         }
02427     }
02428 }
02429 
02430 /*************************************************************************/
02431 
02432 char *cs_get_throttle(ChannelInfo * ci)
02433 {
02434     if (!ci) {
02435         return NULL;
02436     } else {
02437         if (ircd->jmode) {
02438             return ci->mlock_throttle;
02439         } else {
02440             return NULL;
02441         }
02442     }
02443 }
02444 
02445 /*************************************************************************/
02446 
02447 char *cs_get_key(ChannelInfo * ci)
02448 {
02449     if (!ci) {
02450         return NULL;
02451     } else {
02452         return ci->mlock_key;
02453     }
02454 }
02455 
02456 /*************************************************************************/
02457 
02458 char *cs_get_limit(ChannelInfo * ci)
02459 {
02460     static char limit[16];
02461 
02462     if (!ci) {
02463         return NULL;
02464     }
02465 
02466     if (ci->mlock_limit == 0)
02467         return NULL;
02468 
02469     snprintf(limit, sizeof(limit), "%lu",
02470              (unsigned long int) ci->mlock_limit);
02471     return limit;
02472 }
02473 
02474 /*************************************************************************/
02475 
02476 char *cs_get_redirect(ChannelInfo * ci)
02477 {
02478     if (!ci) {
02479         return NULL;
02480     } else {
02481         if (ircd->Lmode) {
02482             return ci->mlock_redirect;
02483         } else {
02484             return NULL;
02485         }
02486     }
02487 }
02488 
02489 /*************************************************************************/
02490 
02491 /* This is a dummy function part of making anope accept modes
02492  * it does actively parse.. ~ Viper */
02493 char *cs_get_unkwn(ChannelInfo * ci)
02494 {
02495     return NULL;
02496 }
02497 
02498 /*************************************************************************/
02499 
02500 void cs_set_flood(ChannelInfo * ci, char *value)
02501 {
02502     if (!ci) {
02503         return;
02504     }
02505 
02506     if (ci->mlock_flood)
02507         free(ci->mlock_flood);
02508 
02509     /* This looks ugly, but it works ;) */
02510     if (anope_flood_mode_check(value)) {
02511         ci->mlock_flood = sstrdup(value);
02512     } else {
02513         ci->mlock_on &= ~ircd->chan_fmode;
02514         ci->mlock_flood = NULL;
02515     }
02516 }
02517 
02518 /*************************************************************************/
02519 
02520 void cs_set_throttle(ChannelInfo * ci, char *value)
02521 {
02522     if (!ci)
02523         return;
02524 
02525     if (ci->mlock_throttle)
02526         free(ci->mlock_throttle);
02527 
02528     if (anope_jointhrottle_mode_check(value)) {
02529         ci->mlock_throttle = sstrdup(value);
02530     } else {
02531         ci->mlock_on &= ~ircd->chan_jmode;
02532         ci->mlock_throttle = NULL;
02533     }
02534 }
02535 
02536 /*************************************************************************/
02537 
02538 void cs_set_key(ChannelInfo * ci, char *value)
02539 {
02540     if (!ci) {
02541         return;
02542     }
02543 
02544     if (ci->mlock_key)
02545         free(ci->mlock_key);
02546 
02547     /* Don't allow keys with a coma */
02548     if (value && *value != ':' && !strchr(value, ',')) {
02549         ci->mlock_key = sstrdup(value);
02550     } else {
02551         ci->mlock_on &= ~anope_get_key_mode();
02552         ci->mlock_key = NULL;
02553     }
02554 }
02555 
02556 /*************************************************************************/
02557 
02558 void cs_set_limit(ChannelInfo * ci, char *value)
02559 {
02560     if (!ci) {
02561         return;
02562     }
02563 
02564     ci->mlock_limit = value ? strtoul(value, NULL, 10) : 0;
02565 
02566     if (ci->mlock_limit <= 0)
02567         ci->mlock_on &= ~anope_get_limit_mode();
02568 }
02569 
02570 /*************************************************************************/
02571 
02572 void cs_set_redirect(ChannelInfo * ci, char *value)
02573 {
02574     if (!ci) {
02575         return;
02576     }
02577 
02578     if (ci->mlock_redirect)
02579         free(ci->mlock_redirect);
02580 
02581     /* Don't allow keys with a coma */
02582     if (value && *value == '#') {
02583         ci->mlock_redirect = sstrdup(value);
02584     } else {
02585         ci->mlock_on &= ~ircd->chan_lmode;
02586         ci->mlock_redirect = NULL;
02587     }
02588 }
02589 
02590 /*************************************************************************/
02591 
02592 /* This is a dummy function to make anope parse a param for a mode,
02593  * yet we don't use that param internally.. ~ Viper */
02594 void cs_set_unkwn(ChannelInfo * ci, char *value)
02595 {
02596     /* Do nothing.. */
02597 }
02598 
02599 /*************************************************************************/
02600 
02601 int get_access_level(ChannelInfo * ci, NickAlias * na)
02602 {
02603     ChanAccess *access;
02604     int num;
02605 
02606     if (!ci || !na) {
02607         return 0;
02608     }
02609 
02610     if (na->nc == ci->founder) {
02611         return ACCESS_FOUNDER;
02612     }
02613 
02614     for (num = 0; num < ci->accesscount; num++) {
02615 
02616         access = &ci->access[num];
02617 
02618         if (access->nc && access->nc == na->nc && access->in_use) {
02619             return access->level;
02620         }
02621 
02622     }
02623 
02624     return 0;
02625 
02626 }
02627 
02628 const char *get_xop_level(int level)
02629 {
02630     if (level < ACCESS_VOP) {
02631         return "Err";
02632     } else if (ircd->halfop && level < ACCESS_HOP) {
02633         return "VOP";
02634     } else if (!ircd->halfop && level < ACCESS_AOP) {
02635         return "VOP";
02636     } else if (ircd->halfop && level < ACCESS_AOP) {
02637         return "HOP";
02638     } else if (level < ACCESS_SOP) {
02639         return "AOP";
02640     } else if (level < ACCESS_FOUNDER) {
02641         return "SOP";
02642     } else {
02643         return "Founder";
02644     }
02645 
02646 }
02647 
02648 /*************************************************************************/
02649 /*********************** ChanServ command routines ***********************/
02650 /*************************************************************************/
02651 
02652 /*************************************************************************/
02653 
02654 
02655 /*************************************************************************/
02656 
02657 /* `last' is set to the last index this routine was called with
02658  * `perm' is incremented whenever a permission-denied error occurs
02659  */
02660 
02661 
02662 /*************************************************************************/
02663 
02664 /* Is the mask stuck? */
02665 
02666 AutoKick *is_stuck(ChannelInfo * ci, char *mask)
02667 {
02668     int i;
02669     AutoKick *akick;
02670 
02671     if (!ci) {
02672         return NULL;
02673     }
02674 
02675     for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
02676         if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)
02677             || !(akick->flags & AK_STUCK))
02678             continue;
02679         /* Example: mask = *!*@*.org and akick->u.mask = *!*@*.anope.org */
02680         if (match_wild_nocase(mask, akick->u.mask))
02681             return akick;
02682         if (ircd->reversekickcheck) {
02683             /* Example: mask = *!*@irc.anope.org and akick->u.mask = *!*@*.anope.org */
02684             if (match_wild_nocase(akick->u.mask, mask))
02685                 return akick;
02686         }
02687     }
02688 
02689     return NULL;
02690 }
02691 
02692 /* Ban the stuck mask in a safe manner. */
02693 
02694 void stick_mask(ChannelInfo * ci, AutoKick * akick)
02695 {
02696     char *av[2];
02697     Entry *ban;
02698 
02699     if (!ci) {
02700         return;
02701     }
02702 
02703     if (ci->c->bans && ci->c->bans->entries != 0) {
02704         for (ban = ci->c->bans->entries; ban; ban = ban->next) {
02705             /* If akick is already covered by a wider ban.
02706                Example: c->bans[i] = *!*@*.org and akick->u.mask = *!*@*.epona.org */
02707             if (entry_match_mask(ban, sstrdup(akick->u.mask), 0))
02708                 return;
02709 
02710             if (ircd->reversekickcheck) {
02711                 /* If akick is wider than a ban already in place.
02712                    Example: c->bans[i] = *!*@irc.epona.org and akick->u.mask = *!*@*.epona.org */
02713                 if (match_wild_nocase(akick->u.mask, ban->mask))
02714                     return;
02715             }
02716         }
02717     }
02718 
02719     /* Falling there means set the ban */
02720     av[0] = sstrdup("+b");
02721     av[1] = akick->u.mask;
02722     anope_cmd_mode(whosends(ci), ci->c->name, "+b %s", akick->u.mask);
02723     chan_set_modes(s_ChanServ, ci->c, 2, av, 1);
02724     free(av[0]);
02725 }
02726 
02727 /* Ban the stuck mask in a safe manner. */
02728 
02729 void stick_all(ChannelInfo * ci)
02730 {
02731     int i;
02732     char *av[2];
02733     AutoKick *akick;
02734 
02735     if (!ci) {
02736         return;
02737     }
02738 
02739     for (akick = ci->akick, i = 0; i < ci->akickcount; akick++, i++) {
02740         if (!(akick->flags & AK_USED) || (akick->flags & AK_ISNICK)
02741             || !(akick->flags & AK_STUCK))
02742             continue;
02743 
02744         av[0] = sstrdup("+b");
02745         av[1] = akick->u.mask;
02746         anope_cmd_mode(whosends(ci), ci->c->name, "+b %s", akick->u.mask);
02747         chan_set_modes(s_ChanServ, ci->c, 2, av, 1);
02748         free(av[0]);
02749     }
02750 }
02751 
02755 void CleanAccess(ChannelInfo *ci)
02756 {
02757         int a, b;
02758 
02759         if (!ci)
02760                 return;
02761 
02762         for (b = 0; b < ci->accesscount; b++)
02763         {
02764                 if (ci->access[b].in_use)
02765                 {
02766                         for (a = 0; a < ci->accesscount; a++)
02767                         {
02768                                 if (a > b)
02769                                         break;
02770                                 if (!ci->access[a].in_use)
02771                                 {
02772                                         ci->access[a].in_use = 1;
02773                                         ci->access[a].level = ci->access[b].level;
02774                                         ci->access[a].nc = ci->access[b].nc;
02775                                         ci->access[a].last_seen = ci->access[b].last_seen;
02776                                         ci->access[b].nc = NULL;
02777                                         ci->access[b].in_use = 0;
02778                                         break;
02779                                 }
02780                         }
02781                 }
02782         }
02783 
02784         /* After reordering, entries on the end of the list may be empty, remove them */
02785         for (b = ci->accesscount - 1; b >= 0; --b)
02786         {
02787                 if (ci->access[b].in_use)
02788                         break;
02789                 ci->accesscount--;
02790         }
02791 
02792         /* Reallocate the access list to only use the memory we need */
02793         ci->access = srealloc(ci->access, sizeof(ChanAccess) * ci->accesscount);
02794 }
02795