00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #define MODULE_NAME "channels"
00027 #define MAKING_CHANNELS
00028
00029 #include <sys/stat.h>
00030 #include "src/mod/module.h"
00031
00032 static Function *global = NULL;
00033
00034 static char chanfile[121], glob_chanmode[64];
00035 static char *lastdeletedmask;
00036
00037 static struct udef_struct *udef;
00038
00039 static int use_info, chan_hack, quiet_save, global_revenge_mode,
00040 global_stopnethack_mode, global_idle_kick, global_aop_min,
00041 global_aop_max, global_ban_time, global_exempt_time,
00042 global_invite_time, global_ban_type, allow_ps;
00043
00044
00045 static char glob_chanset[512];
00046
00047
00048 static int gfld_chan_thr, gfld_chan_time, gfld_deop_thr, gfld_deop_time,
00049 gfld_kick_thr, gfld_kick_time, gfld_join_thr, gfld_join_time,
00050 gfld_ctcp_thr, gfld_ctcp_time, gfld_nick_thr, gfld_nick_time;
00051
00052 #include "channels.h"
00053 #include "cmdschan.c"
00054 #include "tclchan.c"
00055 #include "userchan.c"
00056 #include "udefchan.c"
00057
00058
00059 static void *channel_malloc(int size, char *file, int line)
00060 {
00061 char *p;
00062
00063 #ifdef DEBUG_MEM
00064 p = ((void *) (global[0] (size, MODULE_NAME, file, line)));
00065 #else
00066 p = nmalloc(size);
00067 #endif
00068 egg_bzero(p, size);
00069 return p;
00070 }
00071
00072 static void set_mode_protect(struct chanset_t *chan, char *set)
00073 {
00074 int i, pos = 1;
00075 char *s, *s1;
00076
00077
00078 chan->mode_mns_prot = chan->mode_pls_prot = 0;
00079 chan->limit_prot = 0;
00080 chan->key_prot[0] = 0;
00081 for (s = newsplit(&set); *s; s++) {
00082 i = 0;
00083 switch (*s) {
00084 case '+':
00085 pos = 1;
00086 break;
00087 case '-':
00088 pos = 0;
00089 break;
00090 case 'i':
00091 i = CHANINV;
00092 break;
00093 case 'p':
00094 i = CHANPRIV;
00095 break;
00096 case 's':
00097 i = CHANSEC;
00098 break;
00099 case 'm':
00100 i = CHANMODER;
00101 break;
00102 case 'c':
00103 i = CHANNOCLR;
00104 break;
00105 case 'C':
00106 i = CHANNOCTCP;
00107 break;
00108 case 'R':
00109 i = CHANREGON;
00110 break;
00111 case 'M':
00112 i = CHANMODREG;
00113 break;
00114 case 'r':
00115 i = CHANLONLY;
00116 break;
00117 case 'D':
00118 i = CHANDELJN;
00119 break;
00120 case 'u':
00121 i = CHANSTRIP;
00122 break;
00123 case 'N':
00124 i = CHANNONOTC;
00125 break;
00126 case 'T':
00127 i = CHANNOAMSG;
00128 break;
00129 case 't':
00130 i = CHANTOPIC;
00131 break;
00132 case 'n':
00133 i = CHANNOMSG;
00134 break;
00135 case 'a':
00136 i = CHANANON;
00137 break;
00138 case 'q':
00139 i = CHANQUIET;
00140 break;
00141 case 'l':
00142 i = CHANLIMIT;
00143 chan->limit_prot = 0;
00144 if (pos) {
00145 s1 = newsplit(&set);
00146 if (s1[0])
00147 chan->limit_prot = atoi(s1);
00148 }
00149 break;
00150 case 'k':
00151 i = CHANKEY;
00152 chan->key_prot[0] = 0;
00153 if (pos) {
00154 s1 = newsplit(&set);
00155 if (s1[0])
00156 strcpy(chan->key_prot, s1);
00157 }
00158 break;
00159 }
00160 if (i) {
00161 if (pos) {
00162 chan->mode_pls_prot |= i;
00163 chan->mode_mns_prot &= ~i;
00164 } else {
00165 chan->mode_pls_prot &= ~i;
00166 chan->mode_mns_prot |= i;
00167 }
00168 }
00169 }
00170
00171 if (chan->mode_pls_prot & CHANSEC && !allow_ps)
00172 chan->mode_pls_prot &= ~CHANPRIV;
00173 }
00174
00175 static void get_mode_protect(struct chanset_t *chan, char *s)
00176 {
00177 char *p = s, s1[121];
00178 int i, tst;
00179
00180 s1[0] = 0;
00181 for (i = 0; i < 2; i++) {
00182 if (i == 0) {
00183 tst = chan->mode_pls_prot;
00184 if ((tst) || (chan->limit_prot != 0) || (chan->key_prot[0]))
00185 *p++ = '+';
00186 if (chan->limit_prot != 0) {
00187 *p++ = 'l';
00188 sprintf(&s1[strlen(s1)], "%d ", chan->limit_prot);
00189 }
00190 if (chan->key_prot[0]) {
00191 *p++ = 'k';
00192 sprintf(&s1[strlen(s1)], "%s ", chan->key_prot);
00193 }
00194 } else {
00195 tst = chan->mode_mns_prot;
00196 if (tst)
00197 *p++ = '-';
00198 if (tst & CHANKEY)
00199 *p++ = 'k';
00200 if (tst & CHANLIMIT)
00201 *p++ = 'l';
00202 }
00203 if (tst & CHANINV)
00204 *p++ = 'i';
00205 if (tst & CHANPRIV)
00206 *p++ = 'p';
00207 if (tst & CHANSEC)
00208 *p++ = 's';
00209 if (tst & CHANMODER)
00210 *p++ = 'm';
00211 if (tst & CHANNOCLR)
00212 *p++ = 'c';
00213 if (tst & CHANNOCTCP)
00214 *p++ = 'C';
00215 if (tst & CHANREGON)
00216 *p++ = 'R';
00217 if (tst & CHANMODREG)
00218 *p++ = 'M';
00219 if (tst & CHANLONLY)
00220 *p++ = 'r';
00221 if (tst & CHANDELJN)
00222 *p++ = 'D';
00223 if (tst & CHANSTRIP)
00224 *p++ = 'u';
00225 if (tst & CHANNONOTC)
00226 *p++ = 'N';
00227 if (tst & CHANNOAMSG)
00228 *p++ = 'T';
00229 if (tst & CHANTOPIC)
00230 *p++ = 't';
00231 if (tst & CHANNOMSG)
00232 *p++ = 'n';
00233 if (tst & CHANANON)
00234 *p++ = 'a';
00235 if (tst & CHANQUIET)
00236 *p++ = 'q';
00237 }
00238 *p = 0;
00239 if (s1[0]) {
00240 s1[strlen(s1) - 1] = 0;
00241 strcat(s, " ");
00242 strcat(s, s1);
00243 }
00244 }
00245
00246
00247
00248 static int ismodeline(masklist *m, char *user)
00249 {
00250 for (; m && m->mask[0]; m = m->next)
00251 if (!rfc_casecmp(m->mask, user))
00252 return 1;
00253 return 0;
00254 }
00255
00256
00257
00258 static int ismasked(masklist *m, char *user)
00259 {
00260 for (; m && m->mask[0]; m = m->next)
00261 if (match_addr(m->mask, user))
00262 return 1;
00263 return 0;
00264 }
00265
00266
00267
00268 inline static int chanset_unlink(struct chanset_t *chan)
00269 {
00270 struct chanset_t *c, *c_old = NULL;
00271
00272 for (c = chanset; c; c_old = c, c = c->next) {
00273 if (c == chan) {
00274 if (c_old)
00275 c_old->next = c->next;
00276 else
00277 chanset = c->next;
00278 return 1;
00279 }
00280 }
00281 return 0;
00282 }
00283
00284
00285
00286
00287
00288
00289 static void remove_channel(struct chanset_t *chan)
00290 {
00291 int i;
00292 module_entry *me;
00293
00294
00295
00296 (void) chanset_unlink(chan);
00297
00298 if ((me = module_find("irc", 1, 3)) != NULL)
00299 (me->funcs[IRC_DO_CHANNEL_PART]) (chan);
00300
00301 clear_channel(chan, 0);
00302 noshare = 1;
00303
00304 while (chan->bans)
00305 u_delban(chan, chan->bans->mask, 1);
00306
00307 while (chan->exempts)
00308 u_delexempt(chan, chan->exempts->mask, 1);
00309
00310 while (chan->invites)
00311 u_delinvite(chan, chan->invites->mask, 1);
00312
00313 user_del_chan(chan->dname);
00314 noshare = 0;
00315 nfree(chan->channel.key);
00316 for (i = 0; i < MODES_PER_LINE_MAX && chan->cmode[i].op; i++)
00317 nfree(chan->cmode[i].op);
00318 if (chan->key)
00319 nfree(chan->key);
00320 if (chan->rmkey)
00321 nfree(chan->rmkey);
00322 nfree(chan);
00323 }
00324
00325
00326
00327
00328 static int channels_chon(char *handle, int idx)
00329 {
00330 struct flag_record fr = { FR_CHAN | FR_ANYWH | FR_GLOBAL, 0, 0, 0, 0, 0 };
00331 int find, found = 0;
00332 struct chanset_t *chan = chanset;
00333
00334 if (dcc[idx].type == &DCC_CHAT) {
00335 if (!findchan_by_dname(dcc[idx].u.chat->con_chan) &&
00336 ((dcc[idx].u.chat->con_chan[0] != '*') ||
00337 (dcc[idx].u.chat->con_chan[1] != 0))) {
00338 get_user_flagrec(dcc[idx].user, &fr, NULL);
00339 if (glob_op(fr))
00340 found = 1;
00341 if (chan_owner(fr))
00342 find = USER_OWNER;
00343 else if (chan_master(fr))
00344 find = USER_MASTER;
00345 else
00346 find = USER_OP;
00347 fr.match = FR_CHAN;
00348 while (chan && !found) {
00349 get_user_flagrec(dcc[idx].user, &fr, chan->dname);
00350 if (fr.chan & find)
00351 found = 1;
00352 else
00353 chan = chan->next;
00354 }
00355 if (!chan)
00356 chan = chanset;
00357 if (chan)
00358 strcpy(dcc[idx].u.chat->con_chan, chan->dname);
00359 else
00360 strcpy(dcc[idx].u.chat->con_chan, "*");
00361 }
00362 }
00363 return 0;
00364 }
00365
00366 static char *convert_element(char *src, char *dst)
00367 {
00368 int flags;
00369
00370 Tcl_ScanElement(src, &flags);
00371
00372 #ifdef TCL_DONT_QUOTE_HASH
00373 flags |= TCL_DONT_QUOTE_HASH;
00374 #endif
00375 Tcl_ConvertElement(src, dst, flags);
00376 return dst;
00377 }
00378
00379 #define PLSMNS(x) (x ? '+' : '-')
00380
00381
00382
00383
00384
00385
00386
00387 static void write_channels()
00388 {
00389 FILE *f;
00390 char s[121], w[1024], w2[1024], name[163];
00391 char need1[242], need2[242], need3[242], need4[242], need5[242];
00392 struct chanset_t *chan;
00393 struct udef_struct *ul;
00394
00395 if (!chanfile[0])
00396 return;
00397 sprintf(s, "%s~new", chanfile);
00398 f = fopen(s, "w");
00399 chmod(s, userfile_perm);
00400 if (f == NULL) {
00401 putlog(LOG_MISC, "*", "ERROR writing channel file.");
00402 return;
00403 }
00404 if (!quiet_save)
00405 putlog(LOG_MISC, "*", "Writing channel file...");
00406 fprintf(f, "#Dynamic Channel File for %s (%s) -- written %s\n",
00407 botnetnick, ver, ctime(&now));
00408 for (chan = chanset; chan; chan = chan->next) {
00409 convert_element(chan->dname, name);
00410 get_mode_protect(chan, w);
00411 convert_element(w, w2);
00412 convert_element(chan->need_op, need1);
00413 convert_element(chan->need_invite, need2);
00414 convert_element(chan->need_key, need3);
00415 convert_element(chan->need_unban, need4);
00416 convert_element(chan->need_limit, need5);
00417 fprintf(f,
00418 "channel add %s { chanmode %s idle-kick %d stopnethack-mode %d "
00419 "revenge-mode %d need-op %s need-invite %s need-key %s "
00420 "need-unban %s need-limit %s flood-chan %d:%d flood-ctcp %d:%d "
00421 "flood-join %d:%d flood-kick %d:%d flood-deop %d:%d "
00422 "flood-nick %d:%d aop-delay %d:%d ban-type %d ban-time %d "
00423 "exempt-time %d invite-time %d %cenforcebans %cdynamicbans "
00424 "%cuserbans %cautoop %cautohalfop %cbitch %cgreet %cprotectops "
00425 "%cprotecthalfops %cprotectfriends %cdontkickops %cstatuslog "
00426 "%crevenge %crevengebot %cautovoice %csecret %cshared %ccycle "
00427 "%cseen %cinactive %cdynamicexempts %cuserexempts %cdynamicinvites "
00428 "%cuserinvites %cnodesynch %cstatic }" "\n",
00429 name, w2, chan->idle_kick, chan->stopnethack_mode,
00430 chan->revenge_mode, need1, need2, need3, need4, need5,
00431 chan->flood_pub_thr, chan->flood_pub_time,
00432 chan->flood_ctcp_thr, chan->flood_ctcp_time,
00433 chan->flood_join_thr, chan->flood_join_time,
00434 chan->flood_kick_thr, chan->flood_kick_time,
00435 chan->flood_deop_thr, chan->flood_deop_time,
00436 chan->flood_nick_thr, chan->flood_nick_time,
00437 chan->aop_min, chan->aop_max, chan->ban_type, chan->ban_time,
00438 chan->exempt_time, chan->invite_time,
00439 PLSMNS(channel_enforcebans(chan)),
00440 PLSMNS(channel_dynamicbans(chan)),
00441 PLSMNS(!channel_nouserbans(chan)),
00442 PLSMNS(channel_autoop(chan)),
00443 PLSMNS(channel_autohalfop(chan)),
00444 PLSMNS(channel_bitch(chan)),
00445 PLSMNS(channel_greet(chan)),
00446 PLSMNS(channel_protectops(chan)),
00447 PLSMNS(channel_protecthalfops(chan)),
00448 PLSMNS(channel_protectfriends(chan)),
00449 PLSMNS(channel_dontkickops(chan)),
00450 PLSMNS(channel_logstatus(chan)),
00451 PLSMNS(channel_revenge(chan)),
00452 PLSMNS(channel_revengebot(chan)),
00453 PLSMNS(channel_autovoice(chan)),
00454 PLSMNS(channel_secret(chan)),
00455 PLSMNS(channel_shared(chan)),
00456 PLSMNS(channel_cycle(chan)),
00457 PLSMNS(channel_seen(chan)),
00458 PLSMNS(channel_inactive(chan)),
00459 PLSMNS(channel_dynamicexempts(chan)),
00460 PLSMNS(!channel_nouserexempts(chan)),
00461 PLSMNS(channel_dynamicinvites(chan)),
00462 PLSMNS(!channel_nouserinvites(chan)),
00463 PLSMNS(channel_nodesynch(chan)),
00464 PLSMNS(channel_static(chan)));
00465 for (ul = udef; ul; ul = ul->next) {
00466 if (ul->defined && ul->name) {
00467 if (ul->type == UDEF_FLAG)
00468 fprintf(f, "channel set %s %c%s%s\n", name, getudef(ul->values,
00469 chan->dname) ? '+' : '-', "udef-flag-", ul->name);
00470 else if (ul->type == UDEF_INT)
00471 fprintf(f, "channel set %s %s%s %d\n", name, "udef-int-", ul->name,
00472 (int) getudef(ul->values, chan->dname));
00473 else if (ul->type == UDEF_STR) {
00474 char *p = (char *) getudef(ul->values, chan->dname);
00475
00476 if (!p)
00477 p = "{}";
00478
00479 fprintf(f, "channel set %s udef-str-%s %s\n", name, ul->name, p);
00480 } else
00481 debug1("UDEF-ERROR: unknown type %d", ul->type);
00482 }
00483 }
00484 if (fflush(f)) {
00485 putlog(LOG_MISC, "*", "ERROR writing channel file.");
00486 fclose(f);
00487 return;
00488 }
00489 }
00490 fclose(f);
00491 unlink(chanfile);
00492 movefile(s, chanfile);
00493 }
00494
00495 static void read_channels(int create, int reload)
00496 {
00497 struct chanset_t *chan, *chan_next;
00498
00499 if (!chanfile[0])
00500 return;
00501
00502 if (reload)
00503 for (chan = chanset; chan; chan = chan->next)
00504 chan->status |= CHAN_FLAGGED;
00505
00506 chan_hack = 1;
00507 if (!readtclprog(chanfile) && create) {
00508 FILE *f;
00509
00510
00511 putlog(LOG_MISC, "*", "Creating channel file");
00512 f = fopen(chanfile, "w");
00513 if (!f)
00514 putlog(LOG_MISC, "*", "Couldn't create channel file: %s. Dropping",
00515 chanfile);
00516 else
00517 fclose(f);
00518 }
00519 chan_hack = 0;
00520 if (!reload)
00521 return;
00522 for (chan = chanset; chan; chan = chan_next) {
00523 chan_next = chan->next;
00524 if (chan->status & CHAN_FLAGGED) {
00525 putlog(LOG_MISC, "*", "No longer supporting channel %s", chan->dname);
00526 remove_channel(chan);
00527 }
00528 }
00529 }
00530
00531 static void backup_chanfile()
00532 {
00533 char s[125];
00534
00535 if (quiet_save < 2)
00536 putlog(LOG_MISC, "*", "Backing up channel file...");
00537 egg_snprintf(s, sizeof s, "%s~bak", chanfile);
00538 copyfile(chanfile, s);
00539 }
00540
00541 static void channels_prerehash()
00542 {
00543 write_channels();
00544 }
00545
00546 static void channels_rehash()
00547 {
00548
00549 read_channels(1, 0);
00550 write_channels();
00551 }
00552
00553 static cmd_t my_chon[] = {
00554 {"*", "", (IntFunc) channels_chon, "channels:chon"},
00555 {NULL, NULL, NULL, NULL}
00556 };
00557
00558 static void channels_report(int idx, int details)
00559 {
00560 int i;
00561 char s[1024], s1[100], s2[100];
00562 struct chanset_t *chan;
00563 struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0, 0, 0 };
00564
00565 for (chan = chanset; chan; chan = chan->next) {
00566
00567
00568 if (idx != DP_STDOUT)
00569 get_user_flagrec(dcc[idx].user, &fr, chan->dname);
00570
00571
00572 if ((idx != DP_STDOUT) && !glob_master(fr) && !chan_master(fr))
00573 continue;
00574
00575 s[0] = 0;
00576
00577 sprintf(s, " %-20s: ", chan->dname);
00578
00579 if (channel_inactive(chan))
00580 strcat(s, "(inactive)");
00581 else if (channel_pending(chan))
00582 strcat(s, "(pending)");
00583 else if (!channel_active(chan))
00584 strcat(s, "(not on channel)");
00585 else {
00586
00587 s1[0] = 0;
00588 sprintf(s1, "%3d member%s", chan->channel.members,
00589 (chan->channel.members == 1) ? "" : "s");
00590 strcat(s, s1);
00591
00592 s2[0] = 0;
00593 get_mode_protect(chan, s2);
00594
00595 if (s2[0]) {
00596 s1[0] = 0;
00597 sprintf(s1, ", enforcing \"%s\"", s2);
00598 strcat(s, s1);
00599 }
00600
00601 s2[0] = 0;
00602
00603 if (channel_greet(chan))
00604 strcat(s2, "greet, ");
00605 if (channel_autoop(chan))
00606 strcat(s2, "auto-op, ");
00607 if (channel_bitch(chan))
00608 strcat(s2, "bitch, ");
00609
00610 if (s2[0]) {
00611 s2[strlen(s2) - 2] = 0;
00612
00613 s1[0] = 0;
00614 sprintf(s1, " (%s)", s2);
00615 strcat(s, s1);
00616 }
00617
00618
00619 if (chan->dname[0] == '!') {
00620 s1[0] = 0;
00621 sprintf(s1, ", unique name %s", chan->name);
00622 strcat(s, s1);
00623 }
00624 }
00625
00626 dprintf(idx, "%s\n", s);
00627
00628 if (details) {
00629 s[0] = 0;
00630 i = 0;
00631
00632 if (channel_enforcebans(chan))
00633 i += my_strcpy(s + i, "enforcebans ");
00634 if (channel_dynamicbans(chan))
00635 i += my_strcpy(s + i, "dynamicbans ");
00636 if (!channel_nouserbans(chan))
00637 i += my_strcpy(s + i, "userbans ");
00638 if (channel_autoop(chan))
00639 i += my_strcpy(s + i, "autoop ");
00640 if (channel_bitch(chan))
00641 i += my_strcpy(s + i, "bitch ");
00642 if (channel_greet(chan))
00643 i += my_strcpy(s + i, "greet ");
00644 if (channel_protectops(chan))
00645 i += my_strcpy(s + i, "protectops ");
00646 if (channel_protecthalfops(chan))
00647 i += my_strcpy(s + i, "protecthalfops ");
00648 if (channel_protectfriends(chan))
00649 i += my_strcpy(s + i, "protectfriends ");
00650 if (channel_dontkickops(chan))
00651 i += my_strcpy(s + i, "dontkickops ");
00652 if (channel_logstatus(chan))
00653 i += my_strcpy(s + i, "statuslog ");
00654 if (channel_revenge(chan))
00655 i += my_strcpy(s + i, "revenge ");
00656 if (channel_revenge(chan))
00657 i += my_strcpy(s + i, "revengebot ");
00658 if (channel_secret(chan))
00659 i += my_strcpy(s + i, "secret ");
00660 if (channel_shared(chan))
00661 i += my_strcpy(s + i, "shared ");
00662 if (!channel_static(chan))
00663 i += my_strcpy(s + i, "dynamic ");
00664 if (channel_autovoice(chan))
00665 i += my_strcpy(s + i, "autovoice ");
00666 if (channel_autohalfop(chan))
00667 i += my_strcpy(s + i, "autohalfop ");
00668 if (channel_cycle(chan))
00669 i += my_strcpy(s + i, "cycle ");
00670 if (channel_seen(chan))
00671 i += my_strcpy(s + i, "seen ");
00672 if (channel_dynamicexempts(chan))
00673 i += my_strcpy(s + i, "dynamicexempts ");
00674 if (!channel_nouserexempts(chan))
00675 i += my_strcpy(s + i, "userexempts ");
00676 if (channel_dynamicinvites(chan))
00677 i += my_strcpy(s + i, "dynamicinvites ");
00678 if (!channel_nouserinvites(chan))
00679 i += my_strcpy(s + i, "userinvites ");
00680 if (channel_inactive(chan))
00681 i += my_strcpy(s + i, "inactive ");
00682 if (channel_nodesynch(chan))
00683 i += my_strcpy(s + i, "nodesynch ");
00684
00685 dprintf(idx, " Options: %s\n", s);
00686
00687 if (chan->need_op[0])
00688 dprintf(idx, " To get ops, I do: %s\n", chan->need_op);
00689
00690 if (chan->need_invite[0])
00691 dprintf(idx, " To get invited, I do: %s\n", chan->need_invite);
00692
00693 if (chan->need_limit[0])
00694 dprintf(idx, " To get the channel limit raised, I do: %s\n",
00695 chan->need_limit);
00696
00697 if (chan->need_unban[0])
00698 dprintf(idx, " To get unbanned, I do: %s\n", chan->need_unban);
00699
00700 if (chan->need_key[0])
00701 dprintf(idx, " To get the channel key, I do: %s\n",
00702 chan->need_key);
00703
00704 if (chan->idle_kick)
00705 dprintf(idx, " Kicking idle users after %d minute%s\n",
00706 chan->idle_kick, (chan->idle_kick != 1) ? "s" : "");
00707
00708 if (chan->stopnethack_mode)
00709 dprintf(idx, " stopnethack-mode: %d\n", chan->stopnethack_mode);
00710
00711 if (chan->revenge_mode)
00712 dprintf(idx, " revenge-mode: %d\n", chan->revenge_mode);
00713
00714 dprintf(idx, " ban-type: %d\n", chan->ban_type);
00715 dprintf(idx, " Bans last %d minute%s.\n", chan->ban_time,
00716 (chan->ban_time == 1) ? "" : "s");
00717 dprintf(idx, " Exemptions last %d minute%s.\n", chan->exempt_time,
00718 (chan->exempt_time == 1) ? "" : "s");
00719 dprintf(idx, " Invitations last %d minute%s.\n", chan->invite_time,
00720 (chan->invite_time == 1) ? "" : "s");
00721 }
00722 }
00723 }
00724
00725 static int expmem_masklist(masklist *m)
00726 {
00727 int result = 0;
00728
00729 for (; m; m = m->next) {
00730 result += sizeof(masklist);
00731 if (m->mask)
00732 result += strlen(m->mask) + 1;
00733 if (m->who)
00734 result += strlen(m->who) + 1;
00735 }
00736 return result;
00737 }
00738
00739 static int channels_expmem()
00740 {
00741 int tot = 0, i;
00742 struct chanset_t *chan;
00743
00744 for (chan = chanset; chan; chan = chan->next) {
00745 tot += sizeof(struct chanset_t);
00746
00747 tot += strlen(chan->channel.key) + 1;
00748 if (chan->channel.topic)
00749 tot += strlen(chan->channel.topic) + 1;
00750 tot += (sizeof(struct memstruct) * (chan->channel.members + 1));
00751
00752 tot += expmem_masklist(chan->channel.ban);
00753 tot += expmem_masklist(chan->channel.exempt);
00754 tot += expmem_masklist(chan->channel.invite);
00755
00756 for (i = 0; i < MODES_PER_LINE_MAX && chan->cmode[i].op; i++)
00757 tot += strlen(chan->cmode[i].op) + 1;
00758 if (chan->key)
00759 tot += strlen(chan->key) + 1;
00760 if (chan->rmkey)
00761 tot += strlen(chan->rmkey) + 1;
00762 }
00763 tot += expmem_udef(udef);
00764 if (lastdeletedmask)
00765 tot += strlen(lastdeletedmask) + 1;
00766 return tot;
00767 }
00768
00769 static char *traced_globchanset(ClientData cdata, Tcl_Interp *irp,
00770 EGG_CONST char *name1,
00771 EGG_CONST char *name2, int flags)
00772 {
00773 int i, items;
00774 char *t, *s;
00775 EGG_CONST char **item, *s2;
00776
00777 if (flags & (TCL_TRACE_READS | TCL_TRACE_UNSETS)) {
00778 Tcl_SetVar2(interp, name1, name2, glob_chanset, TCL_GLOBAL_ONLY);
00779 if (flags & TCL_TRACE_UNSETS)
00780 Tcl_TraceVar(interp, "global-chanset",
00781 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
00782 traced_globchanset, NULL);
00783 } else {
00784 s2 = Tcl_GetVar2(interp, name1, name2, TCL_GLOBAL_ONLY);
00785 Tcl_SplitList(interp, s2, &items, &item);
00786 for (i = 0; i < items; i++) {
00787 if (!(item[i]) || (strlen(item[i]) < 2))
00788 continue;
00789 s = glob_chanset;
00790 while (s[0]) {
00791 t = strchr(s, ' ');
00792 t[0] = 0;
00793 if (!strcmp(s + 1, item[i] + 1)) {
00794 s[0] = item[i][0];
00795 t[0] = ' ';
00796 break;
00797 }
00798 t[0] = ' ';
00799 s = t + 1;
00800 }
00801 }
00802 if (item)
00803 Tcl_Free((char *) item);
00804 Tcl_SetVar2(interp, name1, name2, glob_chanset, TCL_GLOBAL_ONLY);
00805 }
00806 return NULL;
00807 }
00808
00809 static tcl_ints my_tcl_ints[] = {
00810 {"share-greet", NULL, 0},
00811 {"use-info", &use_info, 0},
00812 {"quiet-save", &quiet_save, 0},
00813 {"allow-ps", &allow_ps, 0},
00814 {"global-stopnethack-mode", &global_stopnethack_mode, 0},
00815 {"global-revenge-mode", &global_revenge_mode, 0},
00816 {"global-idle-kick", &global_idle_kick, 0},
00817 {"global-ban-time", &global_ban_time, 0},
00818 {"global-exempt-time", &global_exempt_time, 0},
00819 {"global-invite-time", &global_invite_time, 0},
00820 {"global-ban-type", &global_ban_type, 0},
00821
00822 {"ban-time", &global_ban_time, 0},
00823 {"exempt-time", &global_exempt_time, 0},
00824 {"invite-time", &global_invite_time, 0},
00825 {NULL, NULL, 0}
00826 };
00827
00828 static tcl_coups mychan_tcl_coups[] = {
00829 {"global-flood-chan", &gfld_chan_thr, &gfld_chan_time},
00830 {"global-flood-deop", &gfld_deop_thr, &gfld_deop_time},
00831 {"global-flood-kick", &gfld_kick_thr, &gfld_kick_time},
00832 {"global-flood-join", &gfld_join_thr, &gfld_join_time},
00833 {"global-flood-ctcp", &gfld_ctcp_thr, &gfld_ctcp_time},
00834 {"global-flood-nick", &gfld_nick_thr, &gfld_nick_time},
00835 {"global-aop-delay", &global_aop_min, &global_aop_max},
00836 {NULL, NULL, NULL}
00837 };
00838
00839 static tcl_strings my_tcl_strings[] = {
00840 {"chanfile", chanfile, 120, STR_PROTECT},
00841 {"global-chanmode", glob_chanmode, 64, 0},
00842 {NULL, NULL, 0, 0}
00843 };
00844
00845 static char *channels_close()
00846 {
00847 write_channels();
00848 free_udef(udef);
00849 if (lastdeletedmask)
00850 nfree(lastdeletedmask);
00851 rem_builtins(H_chon, my_chon);
00852 rem_builtins(H_dcc, C_dcc_irc);
00853 rem_tcl_commands(channels_cmds);
00854 rem_tcl_strings(my_tcl_strings);
00855 rem_tcl_ints(my_tcl_ints);
00856 rem_tcl_coups(mychan_tcl_coups);
00857 del_hook(HOOK_USERFILE, (Function) channels_writeuserfile);
00858 del_hook(HOOK_BACKUP, (Function) backup_chanfile);
00859 del_hook(HOOK_REHASH, (Function) channels_rehash);
00860 del_hook(HOOK_PRE_REHASH, (Function) channels_prerehash);
00861 del_hook(HOOK_MINUTELY, (Function) check_expired_bans);
00862 del_hook(HOOK_MINUTELY, (Function) check_expired_exempts);
00863 del_hook(HOOK_MINUTELY, (Function) check_expired_invites);
00864 Tcl_UntraceVar(interp, "global-chanset",
00865 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
00866 traced_globchanset, NULL);
00867 rem_help_reference("channels.help");
00868 rem_help_reference("chaninfo.help");
00869 module_undepend(MODULE_NAME);
00870 return NULL;
00871 }
00872
00873 EXPORT_SCOPE char *channels_start();
00874
00875 static Function channels_table[] = {
00876
00877 (Function) channels_start,
00878 (Function) channels_close,
00879 (Function) channels_expmem,
00880 (Function) channels_report,
00881
00882 (Function) u_setsticky_mask,
00883 (Function) u_delban,
00884 (Function) u_addban,
00885 (Function) write_bans,
00886
00887 (Function) get_chanrec,
00888 (Function) add_chanrec,
00889 (Function) del_chanrec,
00890 (Function) set_handle_chaninfo,
00891
00892 (Function) channel_malloc,
00893 (Function) u_match_mask,
00894 (Function) u_equals_mask,
00895 (Function) clear_channel,
00896
00897 (Function) set_handle_laston,
00898 (Function) NULL,
00899 (Function) & use_info,
00900 (Function) get_handle_chaninfo,
00901
00902 (Function) u_sticky_mask,
00903 (Function) ismasked,
00904 (Function) add_chanrec_by_handle,
00905 (Function) NULL,
00906
00907 (Function) NULL,
00908 (Function) NULL,
00909 (Function) NULL,
00910 (Function) NULL,
00911
00912 (Function) NULL,
00913 (Function) u_delexempt,
00914 (Function) u_addexempt,
00915 (Function) NULL,
00916
00917 (Function) NULL,
00918 (Function) NULL,
00919 (Function) NULL,
00920 (Function) u_delinvite,
00921
00922 (Function) u_addinvite,
00923 (Function) tcl_channel_add,
00924 (Function) tcl_channel_modify,
00925 (Function) write_exempts,
00926
00927 (Function) write_invites,
00928 (Function) ismodeline,
00929 (Function) initudef,
00930 (Function) ngetudef,
00931
00932 (Function) expired_mask,
00933 (Function) remove_channel,
00934 (Function) & global_ban_time,
00935 (Function) & global_exempt_time,
00936
00937 (Function) & global_invite_time,
00938 };
00939
00940 char *channels_start(Function *global_funcs)
00941 {
00942 global = global_funcs;
00943
00944 gfld_chan_thr = 10;
00945 gfld_chan_time = 60;
00946 gfld_deop_thr = 3;
00947 gfld_deop_time = 10;
00948 gfld_kick_thr = 3;
00949 gfld_kick_time = 10;
00950 gfld_join_thr = 5;
00951 gfld_join_time = 60;
00952 gfld_ctcp_thr = 5;
00953 gfld_ctcp_time = 60;
00954 global_idle_kick = 0;
00955 global_aop_min = 5;
00956 global_aop_max = 30;
00957 allow_ps = 0;
00958 lastdeletedmask = 0;
00959 use_info = 1;
00960 strcpy(chanfile, "chanfile");
00961 chan_hack = 0;
00962 quiet_save = 0;
00963 strcpy(glob_chanmode, "nt");
00964 udef = NULL;
00965 global_stopnethack_mode = 0;
00966 global_revenge_mode = 0;
00967 global_ban_type = 3;
00968 global_ban_time = 120;
00969 global_exempt_time = 60;
00970 global_invite_time = 60;
00971 strcpy(glob_chanset,
00972 "-enforcebans "
00973 "+dynamicbans "
00974 "+userbans "
00975 "-autoop "
00976 "-bitch "
00977 "+greet "
00978 "+protectops "
00979 "+statuslog "
00980 "-revenge "
00981 "-secret "
00982 "-autovoice "
00983 "+cycle "
00984 "+dontkickops "
00985 "-inactive "
00986 "-protectfriends "
00987 "+shared "
00988 "-seen "
00989 "+userexempts "
00990 "+dynamicexempts "
00991 "+userinvites "
00992 "+dynamicinvites "
00993 "-revengebot "
00994 "-protecthalfops "
00995 "-autohalfop "
00996 "-nodesynch "
00997 "-static ");
00998 module_register(MODULE_NAME, channels_table, 1, 1);
00999 if (!module_depend(MODULE_NAME, "eggdrop", 106, 20)) {
01000 module_undepend(MODULE_NAME);
01001 return "This module requires Eggdrop 1.6.20 or later.";
01002 }
01003 add_hook(HOOK_MINUTELY, (Function) check_expired_bans);
01004 add_hook(HOOK_MINUTELY, (Function) check_expired_exempts);
01005 add_hook(HOOK_MINUTELY, (Function) check_expired_invites);
01006 add_hook(HOOK_USERFILE, (Function) channels_writeuserfile);
01007 add_hook(HOOK_BACKUP, (Function) backup_chanfile);
01008 add_hook(HOOK_REHASH, (Function) channels_rehash);
01009 add_hook(HOOK_PRE_REHASH, (Function) channels_prerehash);
01010 Tcl_TraceVar(interp, "global-chanset",
01011 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01012 traced_globchanset, NULL);
01013 add_builtins(H_chon, my_chon);
01014 add_builtins(H_dcc, C_dcc_irc);
01015 add_tcl_commands(channels_cmds);
01016 add_tcl_strings(my_tcl_strings);
01017 add_help_reference("channels.help");
01018 add_help_reference("chaninfo.help");
01019 my_tcl_ints[0].val = &share_greet;
01020 add_tcl_ints(my_tcl_ints);
01021 add_tcl_coups(mychan_tcl_coups);
01022 read_channels(0, 1);
01023 return NULL;
01024 }