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 "irc"
00027 #define MAKING_IRC
00028
00029 #include "src/mod/module.h"
00030 #include "irc.h"
00031 #include "server.mod/server.h"
00032 #include "channels.mod/channels.h"
00033
00034 #ifdef HAVE_UNAME
00035 # include <sys/utsname.h>
00036 #endif
00037
00038 static p_tcl_bind_list H_topc, H_splt, H_sign, H_rejn, H_part, H_pub, H_pubm;
00039 static p_tcl_bind_list H_nick, H_mode, H_kick, H_join, H_need;
00040
00041 static Function *global = NULL, *channels_funcs = NULL, *server_funcs = NULL;
00042
00043 static int ctcp_mode;
00044 static int net_type;
00045 static int strict_host;
00046 static int wait_split = 300;
00047 static int max_bans = 20;
00048 static int max_exempts = 20;
00049 static int max_invites = 20;
00050 static int max_modes = 20;
00051 static int bounce_bans = 1;
00052 static int bounce_exempts = 0;
00053 static int bounce_invites = 0;
00054 static int bounce_modes = 0;
00055 static int learn_users = 0;
00056 static int wait_info = 15;
00057 static int invite_key = 1;
00058 static int no_chanrec_info = 0;
00059 static int modesperline = 3;
00060 static int mode_buf_len = 200;
00061 static int use_354 = 0;
00062 static int kick_method = 1;
00063
00064
00065 static int kick_fun = 0;
00066 static int ban_fun = 0;
00067 static int keepnick = 1;
00068 static int prevent_mixing = 1;
00069 static int rfc_compliant = 1;
00070 static int include_lk = 1;
00071
00072 static char opchars[8];
00073
00074 #include "chan.c"
00075 #include "mode.c"
00076 #include "cmdsirc.c"
00077 #include "msgcmds.c"
00078 #include "tclirc.c"
00079
00080
00081
00082
00083 static int want_to_revenge(struct chanset_t *chan, struct userrec *u,
00084 struct userrec *u2, char *badnick, char *victim,
00085 int mevictim)
00086 {
00087 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00088
00089
00090 if (match_my_nick(badnick))
00091 return 0;
00092
00093 get_user_flagrec(u, &fr, chan->dname);
00094
00095
00096 if (!chan_friend(fr) && !glob_friend(fr) && rfc_casecmp(badnick, victim)) {
00097 if (mevictim && channel_revengebot(chan))
00098 return 1;
00099 else if (channel_revenge(chan) && u2) {
00100 struct flag_record fr2 = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00101
00102 get_user_flagrec(u2, &fr2, chan->dname);
00103
00104 if ((channel_protectfriends(chan) && (chan_friend(fr2) ||
00105 (glob_friend(fr2) && !chan_deop(fr2)))) ||
00106 (channel_protectops(chan) && (chan_op(fr2) || (glob_op(fr2) &&
00107 !chan_deop(fr2)))))
00108 return 1;
00109 }
00110 }
00111 return 0;
00112 }
00113
00114
00115
00116 static void punish_badguy(struct chanset_t *chan, char *whobad,
00117 struct userrec *u, char *badnick, char *victim,
00118 int mevictim, int type)
00119 {
00120 char reason[1024], ct[81], *kick_msg;
00121 memberlist *m;
00122 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00123
00124 m = ismember(chan, badnick);
00125 if (!m)
00126 return;
00127 get_user_flagrec(u, &fr, chan->dname);
00128
00129
00130 egg_strftime(ct, 7, "%d %b", localtime(&now));
00131
00132
00133 reason[0] = 0;
00134 switch (type) {
00135 case REVENGE_KICK:
00136 kick_msg = IRC_KICK_PROTECT;
00137 simple_sprintf(reason, "kicked %s off %s", victim, chan->dname);
00138 break;
00139 case REVENGE_DEOP:
00140 simple_sprintf(reason, "deopped %s on %s", victim, chan->dname);
00141 kick_msg = IRC_DEOP_PROTECT;
00142 break;
00143 default:
00144 kick_msg = "revenge!";
00145 }
00146 putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason);
00147
00148
00149 if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) {
00150 char s[UHOSTLEN], s1[UHOSTLEN];
00151 memberlist *mx = NULL;
00152
00153
00154 if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) {
00155 fr.match = FR_CHAN;
00156 if (chan_op(fr))
00157 fr.chan &= ~USER_OP;
00158 else
00159 fr.chan |= USER_DEOP;
00160 set_user_flagrec(u, &fr, chan->dname);
00161 putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad,
00162 reason);
00163 }
00164
00165 else if (u) {
00166
00167 fr.match = FR_CHAN;
00168 fr.chan |= USER_DEOP;
00169 set_user_flagrec(u, &fr, chan->dname);
00170 simple_sprintf(s, "(%s) %s", ct, reason);
00171 putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s);
00172 }
00173
00174 else {
00175 strcpy(s1, whobad);
00176 maskaddr(s1, s, chan->ban_type);
00177 strcpy(s1, badnick);
00178
00179
00180
00181 while (get_user_by_handle(userlist, s1)) {
00182 if (!strncmp(s1, "bad", 3)) {
00183 int i;
00184
00185 i = atoi(s1 + 3);
00186 simple_sprintf(s1 + 3, "%d", i + 1);
00187 } else
00188 strcpy(s1, "bad1");
00189 }
00190 userlist = adduser(userlist, s1, s, "-", 0);
00191 fr.match = FR_CHAN;
00192 fr.chan = USER_DEOP;
00193 fr.udef_chan = 0;
00194 u = get_user_by_handle(userlist, s1);
00195 if ((mx = ismember(chan, badnick)))
00196 mx->user = u;
00197 set_user_flagrec(u, &fr, chan->dname);
00198 simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad);
00199 set_user(&USERENTRY_COMMENT, u, (void *) s);
00200 putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason);
00201 }
00202 }
00203
00204
00205 if (!mevictim)
00206 add_mode(chan, '-', 'o', badnick);
00207
00208 if (chan->revenge_mode > 2) {
00209 char s[UHOSTLEN], s1[UHOSTLEN];
00210
00211 splitnick(&whobad);
00212 maskaddr(whobad, s1, chan->ban_type);
00213 simple_sprintf(s, "(%s) %s", ct, reason);
00214 u_addban(chan, s1, botnetnick, s, now + (60 * chan->ban_time), 0);
00215 if (!mevictim && HALFOP_CANDOMODE('b')) {
00216 add_mode(chan, '+', 'b', s1);
00217 flush_mode(chan, QUICK);
00218 }
00219 }
00220
00221 if (!mevictim && (chan->revenge_mode > 1) && (!channel_dontkickops(chan) ||
00222 (!chan_op(fr) && (!glob_op(fr) || chan_deop(fr)))) &&
00223 !chan_sentkick(m) && (me_op(chan) || (me_halfop(chan) &&
00224 !chan_hasop(m) && (strchr(NOHALFOPS_MODES, 'b') == NULL)))) {
00225 dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, badnick, kick_msg);
00226 m->flags |= SENTKICK;
00227 }
00228 }
00229
00230
00231
00232
00233 static void maybe_revenge(struct chanset_t *chan, char *whobad,
00234 char *whovictim, int type)
00235 {
00236 char *badnick, *victim;
00237 int mevictim;
00238 struct userrec *u, *u2;
00239
00240 if (!chan || (type < 0))
00241 return;
00242
00243
00244 u = get_user_by_host(whobad);
00245 badnick = splitnick(&whobad);
00246
00247
00248 u2 = get_user_by_host(whovictim);
00249 victim = splitnick(&whovictim);
00250 mevictim = match_my_nick(victim);
00251
00252
00253 if (want_to_revenge(chan, u, u2, badnick, victim, mevictim))
00254 punish_badguy(chan, whobad, u, badnick, victim, mevictim, type);
00255 }
00256
00257
00258
00259 static void set_key(struct chanset_t *chan, char *k)
00260 {
00261 nfree(chan->channel.key);
00262 if (k == NULL) {
00263 chan->channel.key = (char *) channel_malloc(1);
00264 chan->channel.key[0] = 0;
00265 return;
00266 }
00267 chan->channel.key = (char *) channel_malloc(strlen(k) + 1);
00268 strcpy(chan->channel.key, k);
00269 }
00270
00271 static int hand_on_chan(struct chanset_t *chan, struct userrec *u)
00272 {
00273 char s[UHOSTLEN];
00274 memberlist *m;
00275
00276 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00277 sprintf(s, "%s!%s", m->nick, m->userhost);
00278 if (u == get_user_by_host(s))
00279 return 1;
00280 }
00281 return 0;
00282 }
00283
00284 static void refresh_who_chan(char *channame)
00285 {
00286 if (use_354)
00287 dprintf(DP_MODE, "WHO %s c%%chnuf\n", channame);
00288 else
00289 dprintf(DP_MODE, "WHO %s\n", channame);
00290 return;
00291 }
00292
00293
00294
00295
00296 static void newmask(masklist *m, char *s, char *who)
00297 {
00298 for (; m && m->mask[0] && rfc_casecmp(m->mask, s); m = m->next);
00299 if (m->mask[0])
00300 return;
00301
00302 m->next = (masklist *) channel_malloc(sizeof(masklist));
00303 m->next->next = NULL;
00304 m->next->mask = (char *) channel_malloc(1);
00305 m->next->mask[0] = 0;
00306 nfree(m->mask);
00307 m->mask = (char *) channel_malloc(strlen(s) + 1);
00308 strcpy(m->mask, s);
00309 m->who = (char *) channel_malloc(strlen(who) + 1);
00310 strcpy(m->who, who);
00311 m->timer = now;
00312 }
00313
00314
00315
00316 static int killmember(struct chanset_t *chan, char *nick)
00317 {
00318 memberlist *x, *old;
00319
00320 old = NULL;
00321 for (x = chan->channel.member; x && x->nick[0]; old = x, x = x->next)
00322 if (!rfc_casecmp(x->nick, nick))
00323 break;
00324 if (!x || !x->nick[0]) {
00325 if (!channel_pending(chan) && !channel_djoins(chan))
00326 putlog(LOG_MISC, "*", "(!) killmember(%s) -> nonexistent", nick);
00327 return 0;
00328 }
00329 if (old)
00330 old->next = x->next;
00331 else
00332 chan->channel.member = x->next;
00333 nfree(x);
00334 chan->channel.members--;
00335
00336
00337
00338
00339 if (chan->channel.members < 0) {
00340 chan->channel.members = 0;
00341 for (x = chan->channel.member; x && x->nick[0]; x = x->next)
00342 chan->channel.members++;
00343 putlog(LOG_MISC, "*", "(!) actually I know of %d members.",
00344 chan->channel.members);
00345 }
00346 if (!chan->channel.member) {
00347 chan->channel.member = (memberlist *) channel_malloc(sizeof(memberlist));
00348 chan->channel.member->nick[0] = 0;
00349 chan->channel.member->next = NULL;
00350 }
00351 return 1;
00352 }
00353
00354
00355
00356 static int me_op(struct chanset_t *chan)
00357 {
00358 memberlist *mx = NULL;
00359
00360 mx = ismember(chan, botname);
00361 if (!mx)
00362 return 0;
00363 if (chan_hasop(mx))
00364 return 1;
00365 else
00366 return 0;
00367 }
00368
00369
00370
00371 static int me_halfop(struct chanset_t *chan)
00372 {
00373 memberlist *mx = NULL;
00374
00375 mx = ismember(chan, botname);
00376 if (!mx)
00377 return 0;
00378 if (chan_hashalfop(mx))
00379 return 1;
00380 else
00381 return 0;
00382 }
00383
00384
00385
00386 static int me_voice(struct chanset_t *chan)
00387 {
00388 memberlist *mx;
00389
00390 mx = ismember(chan, botname);
00391 if (!mx)
00392 return 0;
00393 if (chan_hasvoice(mx))
00394 return 1;
00395 else
00396 return 0;
00397 }
00398
00399
00400
00401 static int any_ops(struct chanset_t *chan)
00402 {
00403 memberlist *x;
00404
00405 for (x = chan->channel.member; x && x->nick[0]; x = x->next)
00406 if (chan_hasop(x))
00407 break;
00408 if (!x || !x->nick[0])
00409 return 0;
00410 return 1;
00411 }
00412
00413
00414
00415 static void reset_chan_info(struct chanset_t *chan, int reset)
00416 {
00417 char beI[4] = "\0";
00418
00419 if (channel_inactive(chan)) {
00420 dprintf(DP_MODE, "PART %s\n", chan->name);
00421 return;
00422 }
00423
00424
00425 if (channel_pending(chan))
00426 return;
00427
00428 clear_channel(chan, reset);
00429 if ((reset & CHAN_RESETBANS) && !(chan->status & CHAN_ASKEDBANS)) {
00430 chan->status |= CHAN_ASKEDBANS;
00431 strcat(beI, "b");
00432 }
00433 if ((reset & CHAN_RESETEXEMPTS) &&
00434 !(chan->ircnet_status & CHAN_ASKED_EXEMPTS) && (use_exempts == 1)) {
00435 chan->ircnet_status |= CHAN_ASKED_EXEMPTS;
00436 strcat(beI, "e");
00437 }
00438 if ((reset & CHAN_RESETINVITED) &&
00439 !(chan->ircnet_status & CHAN_ASKED_INVITED) && (use_invites == 1)) {
00440 chan->ircnet_status |= CHAN_ASKED_INVITED;
00441 strcat(beI, "I");
00442 }
00443 if (beI[0])
00444 dprintf(DP_MODE, "MODE %s +%s\n", chan->name, beI);
00445 if (reset & CHAN_RESETMODES) {
00446
00447
00448 nfree(chan->channel.key);
00449 chan->channel.key = (char *) channel_malloc (1);
00450 chan->channel.key[0] = 0;
00451 chan->status &= ~CHAN_ASKEDMODES;
00452 dprintf(DP_MODE, "MODE %s\n", chan->name);
00453 }
00454 if (reset & CHAN_RESETWHO) {
00455 chan->status |= CHAN_PEND;
00456 chan->status &= ~CHAN_ACTIVE;
00457 refresh_who_chan(chan->name);
00458 }
00459 if (reset & CHAN_RESETTOPIC)
00460 dprintf(DP_MODE, "TOPIC %s\n", chan->name);
00461 }
00462
00463
00464
00465
00466 static void do_channel_part(struct chanset_t *chan)
00467 {
00468 if (!channel_inactive(chan) && chan->name[0]) {
00469
00470 dprintf(DP_SERVER, "PART %s\n", chan->name);
00471
00472
00473
00474 check_tcl_part(botname, botuserhost, NULL, chan->dname, NULL);
00475 }
00476 }
00477
00478
00479
00480
00481 static void status_log()
00482 {
00483 masklist *b;
00484 memberlist *m;
00485 struct chanset_t *chan;
00486 char s[20], s2[20];
00487 int chops, halfops, voice, nonops, bans, invites, exempts;
00488
00489 if (!server_online)
00490 return;
00491
00492 for (chan = chanset; chan != NULL; chan = chan->next) {
00493 if (channel_active(chan) && channel_logstatus(chan) &&
00494 !channel_inactive(chan)) {
00495 chops = 0;
00496 voice = 0;
00497 halfops = 0;
00498 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00499 if (chan_hasop(m))
00500 chops++;
00501 else if (chan_hashalfop(m))
00502 halfops++;
00503 else if (chan_hasvoice(m))
00504 voice++;
00505 }
00506 nonops = (chan->channel.members - (chops + voice + halfops));
00507
00508 for (bans = 0, b = chan->channel.ban; b->mask[0]; b = b->next)
00509 bans++;
00510 for (exempts = 0, b = chan->channel.exempt; b->mask[0]; b = b->next)
00511 exempts++;
00512 for (invites = 0, b = chan->channel.invite; b->mask[0]; b = b->next)
00513 invites++;
00514
00515 sprintf(s, "%d", exempts);
00516 sprintf(s2, "%d", invites);
00517
00518 putlog(LOG_MISC, chan->dname,
00519 "%s%s (%s) : [m/%d o/%d h/%d v/%d n/%d b/%d e/%s I/%s]",
00520 me_op(chan) ? "@" : me_voice(chan) ? "+" :
00521 me_halfop(chan) ? "%" : "", chan->dname, getchanmode(chan),
00522 chan->channel.members, chops, halfops, voice, nonops, bans,
00523 use_exempts ? s : "-", use_invites ? s2 : "-");
00524 }
00525 }
00526 }
00527
00528
00529
00530
00531
00532 static void check_lonely_channel(struct chanset_t *chan)
00533 {
00534 memberlist *m;
00535 char s[UHOSTLEN];
00536 int i = 0;
00537
00538 if (channel_pending(chan) || !channel_active(chan) || me_op(chan) ||
00539 channel_inactive(chan) || (chan->channel.mode & CHANANON))
00540 return;
00541
00542 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00543 if (!chan_issplit(m))
00544 i++;
00545 if (i == 1 && channel_cycle(chan) && !channel_stop_cycle(chan)) {
00546 if (chan->name[0] != '+') {
00547 putlog(LOG_MISC, "*", "Trying to cycle %s to regain ops.", chan->dname);
00548 dprintf(DP_MODE, "PART %s\n", chan->name);
00549
00550
00551 if (chan->key_prot[0])
00552 dprintf(DP_MODE, "JOIN %s%s %s\n", (chan->dname[0] == '!') ? "!" : "",
00553 chan->dname, chan->key_prot);
00554 else
00555 dprintf(DP_MODE, "JOIN %s%s\n", (chan->dname[0] == '!') ? "!" : "",
00556 chan->dname);
00557 chan->status &= ~CHAN_WHINED;
00558 }
00559 } else if (any_ops(chan)) {
00560 chan->status &= ~CHAN_WHINED;
00561 check_tcl_need(chan->dname, "op");
00562 if (chan->need_op[0])
00563 do_tcl("need-op", chan->need_op);
00564 } else {
00565
00566
00567
00568 int ok = 1;
00569 struct userrec *u;
00570
00571 if (!channel_whined(chan)) {
00572
00573
00574
00575 if (chan->name[0] != '+' && channel_logstatus(chan))
00576 putlog(LOG_MISC, "*", "%s is active but has no ops :(", chan->dname);
00577 chan->status |= CHAN_WHINED;
00578 }
00579 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00580 sprintf(s, "%s!%s", m->nick, m->userhost);
00581 u = get_user_by_host(s);
00582 if (!match_my_nick(m->nick) && (!u || !(u->flags & USER_BOT))) {
00583 ok = 0;
00584 break;
00585 }
00586 }
00587 if (ok && channel_cycle(chan)) {
00588
00589 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00590 if (!match_my_nick(m->nick))
00591 dprintf(DP_SERVER, "PRIVMSG %s :go %s\n", m->nick, chan->dname);
00592 } else {
00593
00594 check_tcl_need(chan->dname, "op");
00595 if (chan->need_op[0])
00596 do_tcl("need-op", chan->need_op);
00597 }
00598 }
00599 }
00600
00601 static void check_expired_chanstuff()
00602 {
00603 masklist *b, *e;
00604 memberlist *m, *n;
00605 char *key, s[UHOSTLEN];
00606 struct chanset_t *chan;
00607 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00608
00609 if (!server_online)
00610 return;
00611 for (chan = chanset; chan; chan = chan->next) {
00612 if (channel_active(chan)) {
00613 if (me_op(chan) || me_halfop(chan)) {
00614 if (channel_dynamicbans(chan) && chan->ban_time)
00615 for (b = chan->channel.ban; b->mask[0]; b = b->next)
00616 if (now - b->timer > 60 * chan->ban_time &&
00617 !u_sticky_mask(chan->bans, b->mask) &&
00618 !u_sticky_mask(global_bans, b->mask) &&
00619 expired_mask(chan, b->who)) {
00620 putlog(LOG_MODES, chan->dname,
00621 "(%s) Channel ban on %s expired.", chan->dname, b->mask);
00622 add_mode(chan, '-', 'b', b->mask);
00623 b->timer = now;
00624 }
00625
00626 if (use_exempts && channel_dynamicexempts(chan) && chan->exempt_time)
00627 for (e = chan->channel.exempt; e->mask[0]; e = e->next)
00628 if (now - e->timer > 60 * chan->exempt_time &&
00629 !u_sticky_mask(chan->exempts, e->mask) &&
00630 !u_sticky_mask(global_exempts, e->mask) &&
00631 expired_mask(chan, e->who)) {
00632
00633 int match = 0;
00634
00635 for (b = chan->channel.ban; b->mask[0]; b = b->next)
00636 if (mask_match(b->mask, e->mask)) {
00637 match = 1;
00638 break;
00639 }
00640
00641
00642
00643 if (match) {
00644 putlog(LOG_MODES, chan->dname,
00645 "(%s) Channel exemption %s NOT expired. Exempt still set!",
00646 chan->dname, e->mask);
00647 } else {
00648 putlog(LOG_MODES, chan->dname,
00649 "(%s) Channel exemption on %s expired.",
00650 chan->dname, e->mask);
00651 add_mode(chan, '-', 'e', e->mask);
00652 }
00653 e->timer = now;
00654 }
00655
00656 if (use_invites && channel_dynamicinvites(chan) &&
00657 chan->invite_time && !(chan->channel.mode & CHANINV))
00658 for (b = chan->channel.invite; b->mask[0]; b = b->next)
00659 if (now - b->timer > 60 * chan->invite_time &&
00660 !u_sticky_mask(chan->invites, b->mask) &&
00661 !u_sticky_mask(global_invites, b->mask) &&
00662 expired_mask(chan, b->who)) {
00663 putlog(LOG_MODES, chan->dname,
00664 "(%s) Channel invitation on %s expired.",
00665 chan->dname, b->mask);
00666 add_mode(chan, '-', 'I', b->mask);
00667 b->timer = now;
00668 }
00669
00670 if (chan->idle_kick)
00671 for (m = chan->channel.member; m && m->nick[0]; m = m->next)
00672 if (now - m->last >= chan->idle_kick * 60 &&
00673 !match_my_nick(m->nick) && !chan_issplit(m)) {
00674 sprintf(s, "%s!%s", m->nick, m->userhost);
00675 get_user_flagrec(m->user ? m->user : get_user_by_host(s),
00676 &fr, chan->dname);
00677 if ((!(glob_bot(fr) || glob_friend(fr) || (glob_op(fr) &&
00678 !chan_deop(fr)) || chan_friend(fr) || chan_op(fr))) &&
00679 (me_op(chan) || (me_halfop(chan) && !chan_hasop(m)))) {
00680 dprintf(DP_SERVER, "KICK %s %s :idle %d min\n", chan->name,
00681 m->nick, chan->idle_kick);
00682 m->flags |= SENTKICK;
00683 }
00684 }
00685 }
00686 for (m = chan->channel.member; m && m->nick[0]; m = n) {
00687 n = m->next;
00688 if (m->split && now - m->split > wait_split) {
00689 sprintf(s, "%s!%s", m->nick, m->userhost);
00690 check_tcl_sign(m->nick, m->userhost,
00691 m->user ? m->user : get_user_by_host(s),
00692 chan->dname, "lost in the netsplit");
00693 putlog(LOG_JOIN, chan->dname,
00694 "%s (%s) got lost in the net-split.", m->nick, m->userhost);
00695 killmember(chan, m->nick);
00696 }
00697 m = n;
00698 }
00699 check_lonely_channel(chan);
00700 } else if (!channel_inactive(chan) && !channel_pending(chan)) {
00701
00702 key = chan->channel.key[0] ? chan->channel.key : chan->key_prot;
00703 if (key[0])
00704 dprintf(DP_SERVER, "JOIN %s %s\n",
00705 chan->name[0] ? chan->name : chan->dname, key);
00706 else
00707 dprintf(DP_SERVER, "JOIN %s\n",
00708 chan->name[0] ? chan->name : chan->dname);
00709 }
00710 }
00711 }
00712
00713 static int channels_6char STDVAR
00714 {
00715 Function F = (Function) cd;
00716 char x[20];
00717
00718 BADARGS(7, 7, " nick user@host handle desto/chan keyword/nick text");
00719
00720 CHECKVALIDITY(channels_6char);
00721 sprintf(x, "%d", (int) F(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]));
00722 Tcl_AppendResult(irp, x, NULL);
00723 return TCL_OK;
00724 }
00725
00726 static int channels_5char STDVAR
00727 {
00728 Function F = (Function) cd;
00729
00730 BADARGS(6, 6, " nick user@host handle channel text");
00731
00732 CHECKVALIDITY(channels_5char);
00733 F(argv[1], argv[2], argv[3], argv[4], argv[5]);
00734 return TCL_OK;
00735 }
00736
00737 static int channels_4char STDVAR
00738 {
00739 Function F = (Function) cd;
00740
00741 BADARGS(5, 5, " nick uhost hand chan/param");
00742
00743 CHECKVALIDITY(channels_4char);
00744 F(argv[1], argv[2], argv[3], argv[4]);
00745 return TCL_OK;
00746 }
00747
00748 static int channels_2char STDVAR
00749 {
00750 Function F = (Function) cd;
00751
00752 BADARGS(3, 3, " channel type");
00753
00754 CHECKVALIDITY(channels_2char);
00755 F(argv[1], argv[2]);
00756 return TCL_OK;
00757 }
00758
00759 static void check_tcl_joinspltrejn(char *nick, char *uhost, struct userrec *u,
00760 char *chname, p_tcl_bind_list table)
00761 {
00762 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00763 char args[1024];
00764
00765 simple_sprintf(args, "%s %s!%s", chname, nick, uhost);
00766 get_user_flagrec(u, &fr, chname);
00767 Tcl_SetVar(interp, "_jp1", nick, 0);
00768 Tcl_SetVar(interp, "_jp2", uhost, 0);
00769 Tcl_SetVar(interp, "_jp3", u ? u->handle : "*", 0);
00770 Tcl_SetVar(interp, "_jp4", chname, 0);
00771 check_tcl_bind(table, args, &fr, " $_jp1 $_jp2 $_jp3 $_jp4",
00772 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE);
00773 }
00774
00775
00776
00777 static void check_tcl_part(char *nick, char *uhost, struct userrec *u,
00778 char *chname, char *text)
00779 {
00780 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00781 char args[1024];
00782
00783 simple_sprintf(args, "%s %s!%s", chname, nick, uhost);
00784 get_user_flagrec(u, &fr, chname);
00785 Tcl_SetVar(interp, "_p1", nick, 0);
00786 Tcl_SetVar(interp, "_p2", uhost, 0);
00787 Tcl_SetVar(interp, "_p3", u ? u->handle : "*", 0);
00788 Tcl_SetVar(interp, "_p4", chname, 0);
00789 Tcl_SetVar(interp, "_p5", text ? text : "", 0);
00790 check_tcl_bind(H_part, args, &fr, " $_p1 $_p2 $_p3 $_p4 $_p5",
00791 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE);
00792 }
00793
00794 static void check_tcl_signtopcnick(char *nick, char *uhost, struct userrec *u,
00795 char *chname, char *reason,
00796 p_tcl_bind_list table)
00797 {
00798 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00799 char args[1024];
00800
00801 if (table == H_sign)
00802 simple_sprintf(args, "%s %s!%s", chname, nick, uhost);
00803 else
00804 simple_sprintf(args, "%s %s", chname, reason);
00805 get_user_flagrec(u, &fr, chname);
00806 Tcl_SetVar(interp, "_stnm1", nick, 0);
00807 Tcl_SetVar(interp, "_stnm2", uhost, 0);
00808 Tcl_SetVar(interp, "_stnm3", u ? u->handle : "*", 0);
00809 Tcl_SetVar(interp, "_stnm4", chname, 0);
00810 Tcl_SetVar(interp, "_stnm5", reason, 0);
00811 check_tcl_bind(table, args, &fr, " $_stnm1 $_stnm2 $_stnm3 $_stnm4 $_stnm5",
00812 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE);
00813 }
00814
00815 static void check_tcl_mode(char *nick, char *uhost, struct userrec *u,
00816 char *chname, char *mode, char *target)
00817 {
00818 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00819 char args[512];
00820
00821 get_user_flagrec(u, &fr, chname);
00822 simple_sprintf(args, "%s %s", chname, mode);
00823 Tcl_SetVar(interp, "_mode1", nick, 0);
00824 Tcl_SetVar(interp, "_mode2", uhost, 0);
00825 Tcl_SetVar(interp, "_mode3", u ? u->handle : "*", 0);
00826 Tcl_SetVar(interp, "_mode4", chname, 0);
00827 Tcl_SetVar(interp, "_mode5", mode, 0);
00828 Tcl_SetVar(interp, "_mode6", target, 0);
00829 check_tcl_bind(H_mode, args, &fr,
00830 " $_mode1 $_mode2 $_mode3 $_mode4 $_mode5 $_mode6",
00831 MATCH_MODE | BIND_USE_ATTR | BIND_STACKABLE);
00832 }
00833
00834 static void check_tcl_kick(char *nick, char *uhost, struct userrec *u,
00835 char *chname, char *dest, char *reason)
00836 {
00837 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00838 char args[512];
00839
00840 get_user_flagrec(u, &fr, chname);
00841 simple_sprintf(args, "%s %s %s", chname, dest, reason);
00842 Tcl_SetVar(interp, "_kick1", nick, 0);
00843 Tcl_SetVar(interp, "_kick2", uhost, 0);
00844 Tcl_SetVar(interp, "_kick3", u ? u->handle : "*", 0);
00845 Tcl_SetVar(interp, "_kick4", chname, 0);
00846 Tcl_SetVar(interp, "_kick5", dest, 0);
00847 Tcl_SetVar(interp, "_kick6", reason, 0);
00848 check_tcl_bind(H_kick, args, &fr,
00849 " $_kick1 $_kick2 $_kick3 $_kick4 $_kick5 $_kick6",
00850 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE);
00851 }
00852
00853 static int check_tcl_pub(char *nick, char *from, char *chname, char *msg)
00854 {
00855 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00856 int x;
00857 char buf[512], *args = buf, *cmd, host[161], *hand;
00858 struct userrec *u;
00859
00860 strcpy(args, msg);
00861 cmd = newsplit(&args);
00862 simple_sprintf(host, "%s!%s", nick, from);
00863 u = get_user_by_host(host);
00864 hand = u ? u->handle : "*";
00865 get_user_flagrec(u, &fr, chname);
00866 Tcl_SetVar(interp, "_pub1", nick, 0);
00867 Tcl_SetVar(interp, "_pub2", from, 0);
00868 Tcl_SetVar(interp, "_pub3", hand, 0);
00869 Tcl_SetVar(interp, "_pub4", chname, 0);
00870 Tcl_SetVar(interp, "_pub5", args, 0);
00871 x = check_tcl_bind(H_pub, cmd, &fr, " $_pub1 $_pub2 $_pub3 $_pub4 $_pub5",
00872 MATCH_EXACT | BIND_USE_ATTR | BIND_HAS_BUILTINS);
00873 if (x == BIND_NOMATCH)
00874 return 0;
00875 if (x == BIND_EXEC_LOG)
00876 putlog(LOG_CMDS, chname, "<<%s>> !%s! %s %s", nick, hand, cmd, args);
00877 return 1;
00878 }
00879
00880 static int check_tcl_pubm(char *nick, char *from, char *chname, char *msg)
00881 {
00882 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00883 int x;
00884 char buf[1024], host[161];
00885 struct userrec *u;
00886
00887 simple_sprintf(buf, "%s %s", chname, msg);
00888 simple_sprintf(host, "%s!%s", nick, from);
00889 u = get_user_by_host(host);
00890 get_user_flagrec(u, &fr, chname);
00891 Tcl_SetVar(interp, "_pubm1", nick, 0);
00892 Tcl_SetVar(interp, "_pubm2", from, 0);
00893 Tcl_SetVar(interp, "_pubm3", u ? u->handle : "*", 0);
00894 Tcl_SetVar(interp, "_pubm4", chname, 0);
00895 Tcl_SetVar(interp, "_pubm5", msg, 0);
00896 x = check_tcl_bind(H_pubm, buf, &fr, " $_pubm1 $_pubm2 $_pubm3 $_pubm4 $_pubm5",
00897 MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE | BIND_STACKRET);
00898
00899
00900
00901
00902
00903
00904 if (x == BIND_NOMATCH)
00905 return 0;
00906 if (x == BIND_EXEC_LOG)
00907 return 2;
00908
00909 return 1;
00910 }
00911
00912 static void check_tcl_need(char *chname, char *type)
00913 {
00914 char buf[1024];
00915
00916 simple_sprintf(buf, "%s %s", chname, type);
00917 Tcl_SetVar(interp, "_need1", chname, 0);
00918 Tcl_SetVar(interp, "_need2", type, 0);
00919 check_tcl_bind(H_need, buf, 0, " $_need1 $_need2",
00920 MATCH_MASK | BIND_STACKABLE);
00921 }
00922
00923 static tcl_strings mystrings[] = {
00924 {"opchars", opchars, 7, 0},
00925 {NULL, NULL, 0, 0}
00926 };
00927
00928 static tcl_ints myints[] = {
00929 {"learn-users", &learn_users, 0},
00930 {"wait-split", &wait_split, 0},
00931 {"wait-info", &wait_info, 0},
00932 {"bounce-bans", &bounce_bans, 0},
00933 {"bounce-exempts", &bounce_exempts, 0},
00934 {"bounce-invites", &bounce_invites, 0},
00935 {"bounce-modes", &bounce_modes, 0},
00936 {"modes-per-line", &modesperline, 0},
00937 {"mode-buf-length", &mode_buf_len, 0},
00938 {"use-354", &use_354, 0},
00939 {"kick-method", &kick_method, 0},
00940 {"kick-fun", &kick_fun, 0},
00941 {"ban-fun", &ban_fun, 0},
00942 {"invite-key", &invite_key, 0},
00943 {"no-chanrec-info", &no_chanrec_info, 0},
00944 {"max-bans", &max_bans, 0},
00945 {"max-exempts", &max_exempts, 0},
00946 {"max-invites", &max_invites, 0},
00947 {"max-modes", &max_modes, 0},
00948 {"net-type", &net_type, 0},
00949 {"strict-host", &strict_host, 0},
00950 {"ctcp-mode", &ctcp_mode, 0},
00951 {"keep-nick", &keepnick, 0},
00952 {"prevent-mixing", &prevent_mixing, 0},
00953 {"rfc-compliant", &rfc_compliant, 0},
00954 {"include-lk", &include_lk, 0},
00955 {NULL, NULL, 0}
00956 };
00957
00958
00959
00960 static void flush_modes()
00961 {
00962 struct chanset_t *chan;
00963 memberlist *m;
00964
00965 if (modesperline > MODES_PER_LINE_MAX)
00966 modesperline = MODES_PER_LINE_MAX;
00967
00968 for (chan = chanset; chan; chan = chan->next) {
00969 for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
00970 if (m->delay && m->delay <= now) {
00971 m->delay = 0L;
00972 m->flags &= ~FULL_DELAY;
00973 if (chan_sentop(m)) {
00974 m->flags &= ~SENTOP;
00975 add_mode(chan, '+', 'o', m->nick);
00976 }
00977 if (chan_senthalfop(m)) {
00978 m->flags &= ~SENTHALFOP;
00979 add_mode(chan, '+', 'h', m->nick);
00980 }
00981 if (chan_sentvoice(m)) {
00982 m->flags &= ~SENTVOICE;
00983 add_mode(chan, '+', 'v', m->nick);
00984 }
00985 }
00986 }
00987 flush_mode(chan, NORMAL);
00988 }
00989 }
00990
00991 static void irc_report(int idx, int details)
00992 {
00993 struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 };
00994 char ch[1024], q[256], *p;
00995 int k, l;
00996 struct chanset_t *chan;
00997
00998 strcpy(q, "Channels: ");
00999 k = 10;
01000 for (chan = chanset; chan; chan = chan->next) {
01001 if (idx != DP_STDOUT)
01002 get_user_flagrec(dcc[idx].user, &fr, chan->dname);
01003 if ((idx == DP_STDOUT) || glob_master(fr) || chan_master(fr)) {
01004 p = NULL;
01005 if (!channel_inactive(chan)) {
01006 if (chan->status & CHAN_JUPED)
01007 p = MISC_JUPED;
01008 else if (!(chan->status & CHAN_ACTIVE))
01009 p = MISC_TRYING;
01010 else if (chan->status & CHAN_PEND)
01011 p = MISC_PENDING;
01012 else if ((chan->dname[0] != '+') && !me_op(chan))
01013 p = MISC_WANTOPS;
01014 }
01015 l = simple_sprintf(ch, "%s%s%s%s, ", chan->dname, p ? " (" : "",
01016 p ? p : "", p ? ")" : "");
01017 if ((k + l) > 70) {
01018 dprintf(idx, " %s\n", q);
01019 strcpy(q, " ");
01020 k = 10;
01021 }
01022 k += my_strcpy(q + k, ch);
01023 }
01024 }
01025 if (k > 10) {
01026 q[k - 2] = 0;
01027 dprintf(idx, " %s\n", q);
01028 }
01029 }
01030
01031 static void do_nettype()
01032 {
01033 switch (net_type) {
01034 case 0:
01035 kick_method = 1;
01036 modesperline = 4;
01037 use_354 = 0;
01038 use_exempts = 1;
01039 use_invites = 1;
01040 max_bans = 100;
01041 max_exempts = 100;
01042 max_invites = 100;
01043 max_modes = 100;
01044 rfc_compliant = 1;
01045 include_lk = 0;
01046 break;
01047 case 1:
01048 kick_method = 4;
01049 modesperline = 3;
01050 use_354 = 0;
01051 use_exempts = 1;
01052 use_invites = 1;
01053 max_bans = 30;
01054 max_exempts = 30;
01055 max_invites = 30;
01056 max_modes = 30;
01057 rfc_compliant = 1;
01058 include_lk = 1;
01059 break;
01060 case 2:
01061 kick_method = 1;
01062 modesperline = 6;
01063 use_354 = 1;
01064 use_exempts = 0;
01065 use_invites = 0;
01066 max_bans = 45;
01067 max_exempts = 45;
01068 max_invites = 45;
01069 max_modes = 45;
01070 rfc_compliant = 1;
01071 include_lk = 1;
01072 break;
01073 case 3:
01074 kick_method = 1;
01075 modesperline = 6;
01076 use_354 = 0;
01077 use_exempts = 0;
01078 use_invites = 0;
01079 max_bans = 100;
01080 max_exempts = 100;
01081 max_invites = 100;
01082 max_modes = 100;
01083 rfc_compliant = 0;
01084 include_lk = 1;
01085 break;
01086 case 4:
01087 kick_method = 1;
01088 modesperline = 4;
01089 use_354 = 0;
01090 use_exempts = 1;
01091 use_invites = 1;
01092 max_bans = 20;
01093 max_exempts = 20;
01094 max_invites = 20;
01095 max_modes = 20;
01096 rfc_compliant = 1;
01097 include_lk = 0;
01098 break;
01099 default:
01100 break;
01101 }
01102
01103 add_hook(HOOK_RFC_CASECMP, (Function) (intptr_t) rfc_compliant);
01104 }
01105
01106 static char *traced_nettype(ClientData cdata, Tcl_Interp *irp,
01107 EGG_CONST char *name1,
01108 EGG_CONST char *name2, int flags)
01109 {
01110 do_nettype();
01111 return NULL;
01112 }
01113
01114 static char *traced_rfccompliant(ClientData cdata, Tcl_Interp *irp,
01115 EGG_CONST char *name1,
01116 EGG_CONST char *name2, int flags)
01117 {
01118
01119
01120
01121
01122 add_hook(HOOK_RFC_CASECMP, (Function) (intptr_t) rfc_compliant);
01123 return NULL;
01124 }
01125
01126 static int irc_expmem()
01127 {
01128 return 0;
01129 }
01130
01131 static char *irc_close()
01132 {
01133 struct chanset_t *chan;
01134
01135
01136 dprintf(DP_MODE, "JOIN 0\n");
01137
01138 for (chan = chanset; chan; chan = chan->next)
01139 clear_channel(chan, 1);
01140 del_bind_table(H_topc);
01141 del_bind_table(H_splt);
01142 del_bind_table(H_sign);
01143 del_bind_table(H_rejn);
01144 del_bind_table(H_part);
01145 del_bind_table(H_nick);
01146 del_bind_table(H_mode);
01147 del_bind_table(H_kick);
01148 del_bind_table(H_join);
01149 del_bind_table(H_pubm);
01150 del_bind_table(H_pub);
01151 del_bind_table(H_need);
01152 rem_tcl_strings(mystrings);
01153 rem_tcl_ints(myints);
01154 rem_builtins(H_dcc, irc_dcc);
01155 rem_builtins(H_msg, C_msg);
01156 rem_builtins(H_raw, irc_raw);
01157 rem_tcl_commands(tclchan_cmds);
01158 rem_help_reference("irc.help");
01159 del_hook(HOOK_MINUTELY, (Function) check_expired_chanstuff);
01160 del_hook(HOOK_5MINUTELY, (Function) status_log);
01161 del_hook(HOOK_ADD_MODE, (Function) real_add_mode);
01162 del_hook(HOOK_IDLE, (Function) flush_modes);
01163 Tcl_UntraceVar(interp, "rfc-compliant",
01164 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01165 traced_rfccompliant, NULL);
01166 Tcl_UntraceVar(interp, "net-type",
01167 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01168 traced_nettype, NULL);
01169 module_undepend(MODULE_NAME);
01170 return NULL;
01171 }
01172
01173 EXPORT_SCOPE char *irc_start();
01174
01175 static Function irc_table[] = {
01176
01177 (Function) irc_start,
01178 (Function) irc_close,
01179 (Function) irc_expmem,
01180 (Function) irc_report,
01181
01182 (Function) & H_splt,
01183 (Function) & H_rejn,
01184 (Function) & H_nick,
01185 (Function) & H_sign,
01186
01187 (Function) & H_join,
01188 (Function) & H_part,
01189 (Function) & H_mode,
01190 (Function) & H_kick,
01191
01192 (Function) & H_pubm,
01193 (Function) & H_pub,
01194 (Function) & H_topc,
01195 (Function) recheck_channel,
01196
01197 (Function) me_op,
01198 (Function) recheck_channel_modes,
01199 (Function) & H_need,
01200 (Function) do_channel_part,
01201
01202 (Function) check_this_ban,
01203 (Function) check_this_user,
01204 (Function) me_halfop,
01205 (Function) me_voice,
01206
01207 (Function) getchanmode,
01208 };
01209
01210 char *irc_start(Function *global_funcs)
01211 {
01212 struct chanset_t *chan;
01213
01214 global = global_funcs;
01215
01216 module_register(MODULE_NAME, irc_table, 1, 4);
01217 if (!module_depend(MODULE_NAME, "eggdrop", 106, 20)) {
01218 module_undepend(MODULE_NAME);
01219 return "This module requires Eggdrop 1.6.20 or later.";
01220 }
01221 if (!(server_funcs = module_depend(MODULE_NAME, "server", 1, 0))) {
01222 module_undepend(MODULE_NAME);
01223 return "This module requires server module 1.0 or later.";
01224 }
01225 if (!(channels_funcs = module_depend(MODULE_NAME, "channels", 1, 1))) {
01226 module_undepend(MODULE_NAME);
01227 return "This module requires channels module 1.1 or later.";
01228 }
01229 for (chan = chanset; chan; chan = chan->next) {
01230 if (!channel_inactive(chan)) {
01231 if (chan->key_prot[0])
01232 dprintf(DP_SERVER, "JOIN %s %s\n",
01233 chan->name[0] ? chan->name : chan->dname, chan->key_prot);
01234 else
01235 dprintf(DP_SERVER, "JOIN %s\n",
01236 chan->name[0] ? chan->name : chan->dname);
01237 }
01238 chan->status &= ~(CHAN_ACTIVE | CHAN_PEND | CHAN_ASKEDBANS);
01239 chan->ircnet_status &= ~(CHAN_ASKED_INVITED | CHAN_ASKED_EXEMPTS);
01240 }
01241 add_hook(HOOK_MINUTELY, (Function) check_expired_chanstuff);
01242 add_hook(HOOK_5MINUTELY, (Function) status_log);
01243 add_hook(HOOK_ADD_MODE, (Function) real_add_mode);
01244 add_hook(HOOK_IDLE, (Function) flush_modes);
01245 Tcl_TraceVar(interp, "net-type",
01246 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01247 traced_nettype, NULL);
01248 Tcl_TraceVar(interp, "rfc-compliant",
01249 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
01250 traced_rfccompliant, NULL);
01251 strcpy(opchars, "@");
01252 add_tcl_strings(mystrings);
01253 add_tcl_ints(myints);
01254 add_builtins(H_dcc, irc_dcc);
01255 add_builtins(H_msg, C_msg);
01256 add_builtins(H_raw, irc_raw);
01257 add_tcl_commands(tclchan_cmds);
01258 add_help_reference("irc.help");
01259 H_topc = add_bind_table("topc", HT_STACKABLE, channels_5char);
01260 H_splt = add_bind_table("splt", HT_STACKABLE, channels_4char);
01261 H_sign = add_bind_table("sign", HT_STACKABLE, channels_5char);
01262 H_rejn = add_bind_table("rejn", HT_STACKABLE, channels_4char);
01263 H_part = add_bind_table("part", HT_STACKABLE, channels_5char);
01264 H_nick = add_bind_table("nick", HT_STACKABLE, channels_5char);
01265 H_mode = add_bind_table("mode", HT_STACKABLE, channels_6char);
01266 H_kick = add_bind_table("kick", HT_STACKABLE, channels_6char);
01267 H_join = add_bind_table("join", HT_STACKABLE, channels_4char);
01268 H_pubm = add_bind_table("pubm", HT_STACKABLE, channels_5char);
01269 H_pub = add_bind_table("pub", 0, channels_5char);
01270 H_need = add_bind_table("need", HT_STACKABLE, channels_2char);
01271 do_nettype();
01272 return NULL;
01273 }