/* Completely removes a channel. * * This includes the removal of all channel-bans, -exempts and -invites, as * well as all user flags related to the channel. */ void remove_channel(struct chanset_t *chan) { if (chan != chanset_default) { irc_log(chan, "Parting"); /* Remove the channel from the list, so that noone can pull it away from under our feet during the check_part() call. */ chanset_unlink(chan); /* Using chan->name is important here, especially for !chans <cybah> */ if (!conf.bot->hub && shouldjoin(chan) && chan->name[0]) dprintf(DP_SERVER, "PART %s\n", chan->name); clear_channel(chan, 0); noshare = 1; /* Remove channel-bans */ while (chan->bans) u_delmask('b', chan, chan->bans->mask, 1); /* Remove channel-exempts */ while (chan->exempts) u_delmask('e', chan, chan->exempts->mask, 1); /* Remove channel-invites */ while (chan->invites) u_delmask('I', chan, chan->invites->mask, 1); /* Remove channel specific user flags */ user_del_chan(chan->dname); noshare = 0; } free(chan->channel.key); if (chan->key) free(chan->key); if (chan->rmkey) free(chan->rmkey); free(chan); }
static void got_cjoin(char *botnick, char *code, char *par) { if (!par[0]) return; char *chname = newsplit(&par), *options = NULL; struct chanset_t *chan = findchan_by_dname(chname); int match = 0; if (conf.bot->hub) { newsplit(&par); /* hubs ignore the botmatch param */ options = par; } else { /* ALL hubs should add the channel, leaf should check the list for a match */ bool inactive = 0; char *bots = newsplit(&par); match = parsebots(bots, conf.bot->nick); if (strstr(par, "+inactive")) inactive = 1; if (chan && !match) return; if (!match) { size_t size = strlen(par) + 12 + 1; options = (char *) my_calloc(1, size); simple_snprintf(options, size, "%s +inactive", par); } else if (match && chan && !shouldjoin(chan)) { if (!inactive) do_chanset(NULL, chan, "-inactive", DO_LOCAL); return; } else options = par; } if (chan) return; sdprintf("OPTIONS: %s", options); char result[RESULT_LEN] = ""; if (channel_add(result, chname, options) == ERROR) /* drummer */ putlog(LOG_BOTS, "@", "Invalid channel or channel options from %s for %s: %s", botnick, chname, result); if (conf.bot->hub) write_userfile(-1); if (!match && !conf.bot->hub) free(options); }
static void got_jn(int idx, char *code, char *par) { char *chname = newsplit(&par); if (!chname || !chname[0]) return; struct chanset_t *chan = NULL; if (!(chan = findchan_by_dname(chname))) return; if (chan->channel.jointime && channel_inactive(chan)) { chan->status &= ~CHAN_INACTIVE; chan->channel.jointime = 0; if (!conf.bot->hub && shouldjoin(chan)) join_chan(chan); } }
static int check_slowjoinpart(struct chanset_t *chan) { /* slowpart */ if (chan->channel.parttime && (chan->channel.parttime < now)) { chan->channel.parttime = 0; dprintf(DP_MODE, "PART %s\n", chan->name); if (chan) /* this should NOT be necesary, but some unforseen bug requires it.. */ remove_channel(chan); return 1; /* if we keep looping, we'll segfault. */ /* slowjoin */ } else if ((chan->channel.jointime) && (chan->channel.jointime < now)) { chan->status &= ~CHAN_INACTIVE; chan->channel.jointime = 0; if (shouldjoin(chan)) join_chan(chan); } else if (channel_closed(chan)) { enforce_closed(chan); } return 0; }
void rcmd_chans(char *fbot, char *fhand, char *fidx) { if (conf.bot->hub) return; struct chanset_t *chan = NULL; char buf[1024] = "", reply[1024] = ""; if (server_online) { for (chan = chanset; chan; chan = chan->next) { if (!channel_active(chan) && (shouldjoin(chan) || chan->channel.jointime)) { if (buf[0]) strlcat(buf, " ", sizeof(buf)); strlcat(buf, chan->dname, sizeof(buf)); } } if (buf[0]) simple_snprintf(reply, sizeof(reply), "[%s] I am not in: %s", cursrvname, buf); } else simple_snprintf(reply, sizeof(reply), "I am not online."); if (reply[0]) botnet_send_cmdreply(conf.bot->nick, fbot, fhand, fidx, reply); }
static void remote_tell_who(int idx, char *nick, int chan) { int i = 10, k, l, ok = 0; char s[1024] = "", *realnick = NULL; struct chanset_t *c = NULL; realnick = strchr(nick, ':'); if (realnick) realnick++; else realnick = nick; putlog(LOG_BOTS, "*", "#%s# who", realnick); strlcpy(s, "Channels: ", sizeof(s)); for (c = chanset; c; c = c->next) if (!channel_secret(c) && shouldjoin(c)) { l = strlen(c->dname); if (i + l < 1021) { if (i > 10) { strlcat(s, ", ", sizeof(s)); strlcat(s, c->dname, sizeof(s)); } else { strlcpy(s, c->dname, sizeof(s)); i += (l + 2); } } } if (i > 10) { botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s (%s)", s, ver); } else { botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s (%s)", "no channels", ver); } if (admin[0]) botnet_send_priv(idx, conf.bot->nick, nick, NULL, "Admin: %s", admin); if (chan == 0) { botnet_send_priv(idx, conf.bot->nick, nick, NULL, "Party line members: (^ = admin, * = owner, + = master, @ = op)"); } else { botnet_send_priv(idx, conf.bot->nick, nick, NULL, "People on channel %s%d: (^ = admin, * = owner, + = master, @ = op)\n", (chan < GLOBAL_CHANS) ? "" : "*", chan % GLOBAL_CHANS); } for (i = 0; i < dcc_total; i++) { if (dcc[i].type && dcc[i].type->flags & DCT_REMOTEWHO) { if (dcc[i].u.chat->channel == chan) { k = simple_snprintf(s, sizeof(s), " %c%-15s %s", (geticon(i) == '-' ? ' ' : geticon(i)), dcc[i].nick, dcc[i].host); if (now - dcc[i].timeval > 300) { unsigned long mydays, hrs, mins; mydays = (now - dcc[i].timeval) / 86400; hrs = ((now - dcc[i].timeval) - (mydays * 86400)) / 3600; mins = ((now - dcc[i].timeval) - (hrs * 3600)) / 60; if (mydays > 0) simple_snprintf(s + k, sizeof(s) - k, " (idle %lud%luh)", mydays, hrs); else if (hrs > 0) simple_snprintf(s + k, sizeof(s) - k, " (idle %luh%lum)", hrs, mins); else simple_snprintf(s + k, sizeof(s) - k, " (idle %lum)", mins); } botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s", s); if (dcc[i].u.chat->away != NULL) botnet_send_priv(idx, conf.bot->nick, nick, NULL, " AWAY: %s", dcc[i].u.chat->away); } } } for (i = 0; i < dcc_total; i++) { if (dcc[i].type && dcc[i].type == &DCC_BOT) { if (!ok) { ok = 1; botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s:", "Bots connected"); } simple_snprintf(s, sizeof(s), " %s%c%-15s %s", dcc[i].status & STAT_CALLED ? "<-" : "->", dcc[i].status & STAT_SHARE ? '+' : ' ', dcc[i].nick, dcc[i].u.bot->version); botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s", s); } } ok = 0; for (i = 0; i < dcc_total; i++) { if (dcc[i].type && dcc[i].type->flags & DCT_REMOTEWHO) { if (dcc[i].u.chat->channel != chan) { if (!ok) { ok = 1; botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s:", "Other people on the bot"); } l = simple_snprintf(s, sizeof(s), " %c%-15s %s", (geticon(i) == '-' ? ' ' : geticon(i)), dcc[i].nick, dcc[i].host); if (now - dcc[i].timeval > 300) { k = (now - dcc[i].timeval) / 60; if (k < 60) simple_snprintf(s + l, sizeof(s) - l, " (idle %dm)", k); else simple_snprintf(s + l, sizeof(s) - l, " (idle %dh%dm)", k / 60, k % 60); } botnet_send_priv(idx, conf.bot->nick, nick, NULL, "%s", s); if (dcc[i].u.chat->away != NULL) botnet_send_priv(idx, conf.bot->nick, nick, NULL, " AWAY: %s", dcc[i].u.chat->away); } } } }
void restart(int idx) { const char *reason = updating ? STR("Updating...") : STR("Restarting..."); Tempfile *socks = new Tempfile("socks"); int fd = 0; sdprintf("%s", reason); if (tands > 0) { botnet_send_chat(-1, conf.bot->nick, (char *) reason); botnet_send_bye(reason); } /* kill all connections except STDOUT/server */ for (fd = 0; fd < dcc_total; fd++) { if (dcc[fd].type && dcc[fd].type != &SERVER_SOCKET && dcc[fd].sock != STDOUT) { if (dcc[fd].sock >= 0) killsock(dcc[fd].sock); lostdcc(fd); } } const char salt1[] = SALT1; EncryptedStream stream(salt1); /* write out all leftover dcc[] entries */ for (fd = 0; fd < dcc_total; fd++) if (dcc[fd].type && dcc[fd].sock != STDOUT) dcc_write(stream, fd); /* write out all leftover socklist[] entries */ for (fd = 0; fd < MAXSOCKS; fd++) if (socklist[fd].sock != STDOUT) sock_write(stream, fd); if (server_online) { if (botname[0]) stream << bd::String::printf(STR("+botname %s\n"), botname); if (rolls) stream << bd::String::printf(STR("+rolls %d\n"), rolls); if (altnick_char) stream << bd::String::printf(STR("+altnick_char %c\n"), altnick_char); if (burst) stream << bd::String::printf(STR("+burst %d\n"), burst); if (flood_count) stream << bd::String::printf(STR("+flood_count %d\n"), flood_count); if (my_cookie_counter) stream << bd::String::printf(STR("+my_cookie_counter %lu\n"), my_cookie_counter); stream << bd::String::printf(STR("+server_online %li\n"), (long)server_online); } stream << bd::String::printf(STR("+online_since %li\n"), (long)online_since); if (floodless) stream << bd::String::printf(STR("+server_floodless %d\n"), floodless); if (in_deaf) stream << bd::String::printf(STR("+in_deaf\n")); if (in_callerid) stream << bd::String::printf(STR("+in_callerid\n")); for (struct chanset_t *chan = chanset; chan; chan = chan->next) if (shouldjoin(chan) && (channel_active(chan) || channel_pending(chan))) stream << bd::String::printf(STR("+chan %s\n"), chan->dname); stream << bd::String::printf(STR("+buildts %li\n"), (long)buildts); stream << bd::String::printf(STR("+ip4 %s\n"), myipstr(AF_INET)); stream << bd::String::printf(STR("+ip6 %s\n"), myipstr(AF_INET6)); replay_cache(-1, &stream); stream.writeFile(socks->fd); socks->my_close(); write_userfile(idx); /* if (server_online) { do_chanset(NULL, NULL, STR("+inactive"), DO_LOCAL); dprintf(DP_DUMP, STR("JOIN 0\n")); } */ fixmod(binname); /* replace image now */ char *argv[4] = { NULL, NULL, NULL, NULL }; argv[0] = strdup(binname); if (!backgrd || term_z || sdebug) { char shit[7] = ""; simple_snprintf(shit, sizeof(shit), STR("-%s%s%s"), !backgrd ? "n" : "", term_z ? "t" : "", sdebug ? "D" : ""); argv[1] = strdup(shit); argv[2] = strdup(conf.bot->nick); } else { argv[1] = strdup(conf.bot->nick); } unlink(conf.bot->pid_file); FILE *fp = NULL; if (!(fp = fopen(conf.bot->pid_file, "w"))) return; fprintf(fp, "%d %s\n", getpid(), socks->file); fclose(fp); execvp(argv[0], &argv[0]); /* hopefully this is never reached */ putlog(LOG_MISC, "*", STR("Could not restart: %s"), strerror(errno)); return; }
void show_channels(int idx, char *handle) { struct userrec *u = NULL; size_t maxChannelLength = 0; bd::Array<bd::String> channelNames; bd::HashTable<bd::String, struct chanset_t*> channels; bd::String group; if (handle && handle[0] != '%') { u = get_user_by_handle(userlist, handle); } else { u = dcc[idx].user; if (handle && handle[0] == '%') { group = handle + 1; } } for (struct chanset_t* chan = chanset; chan; chan = chan->next) { struct flag_record fr = { FR_CHAN | FR_GLOBAL, 0, 0, 0 }; const bd::String chname(chan->dname); // If a group was passed, ensure it matches if (group.length() && chan->groups->find(group) == chan->groups->npos) { continue; } get_user_flagrec(u, &fr, chan->dname); if (group.length() || real_chk_op(fr, chan, 0)) { if (maxChannelLength < chname.length()) { maxChannelLength = chname.length(); } channelNames << chname; channels[chname] = chan; } } if (channelNames.length()) { char format[120] = ""; simple_snprintf(format, sizeof(format), " %%c%%-%zus %%-s%%-s%%-s%%-s%%-s%%-s\n", (maxChannelLength+2)); if (group.length()) { dprintf(idx, "group '%s' is in %zu channel%s:\n", group.c_str(), channelNames.length(), (channelNames.length() > 1) ? "s" : ""); } else { dprintf(idx, "%s %s access to %zu channel%s:\n", handle ? u->handle : "You", handle ? "has" : "have", channelNames.length(), (channelNames.length() > 1) ? "s" : ""); } for (size_t i = 0; i < channelNames.length(); ++i) { const bd::String chname(channelNames[i]); const struct chanset_t* chan = channels[chname]; dprintf(idx, format, !conf.bot->hub && me_op(chan) ? '@' : ' ', chan->dname, ((conf.bot->hub && channel_inactive(chan)) || (!conf.bot->hub && !shouldjoin(chan))) ? "(inactive) " : "", channel_privchan(chan) ? "(private) " : "", chan->manop ? "(no manop) " : "", channel_bitch(chan) && !channel_botbitch(chan) ? "(bitch) " : channel_botbitch(chan) ? "(botbitch) " : "", channel_closed(chan) ? "(closed) " : "", channel_backup(chan) ? "(backup)" : ""); } } else { if (group.length()) { dprintf(idx, "No channels found for group '%s'\n", group.c_str()); } else { dprintf(idx, "%s %s not have access to any channels.\n", handle ? u->handle : "You", handle ? "does" : "do"); } } }
void channels_report(int idx, int details) { int i; char s[1024] = "", s2[100] = ""; struct flag_record fr = {FR_CHAN | FR_GLOBAL, 0, 0, 0 }; for (struct chanset_t *chan = chanset; chan; chan = chan->next) { if (idx != DP_STDOUT) get_user_flagrec(dcc[idx].user, &fr, chan->dname, chan); if (!privchan(fr, chan, PRIV_OP) && ((idx == DP_STDOUT) || glob_master(fr) || chan_master(fr))) { s[0] = 0; if (chan_bitch(chan)) strlcat(s, "bitch, ", sizeof(s)); if (s[0]) s[strlen(s) - 2] = 0; if (!s[0]) strlcpy(s, "lurking", sizeof(s)); get_mode_protect(chan, s2, sizeof(s2)); if (channel_closed(chan)) { if (chan->closed_invite) strlcat(s2, "i", sizeof(s2)); if (chan->closed_private) strlcat(s2, "p", sizeof(s2)); } if (shouldjoin(chan)) { if (channel_active(chan)) { /* If it's a !chan, we want to display it's unique name too <cybah> */ if (chan->dname[0]=='!') { dprintf(idx, " %-20s: %2d member%s enforcing \"%s\" (%s), " "unique name %s\n", chan->dname, chan->channel.members, (chan->channel.members==1) ? "," : "s,", s2, s, chan->name); } else { dprintf(idx, " %-20s: %2d member%s enforcing \"%s\" (%s)\n", chan->dname, chan->channel.members, chan->channel.members == 1 ? "," : "s,", s2, s); } } else { if (!conf.bot->hub) dprintf(idx, " %-20s: (%s), enforcing \"%s\" (%s)\n", chan->dname, channel_pending(chan) ? "pending" : "not on channel", s2, s); else dprintf(idx, " %-20s: (%s), enforcing \"%s\" (%s)\n", chan->dname, "limbo", s2, s); } } else { dprintf(idx, " %-20s: channel is set +inactive\n", chan->dname); } if (details) { s[0] = 0; i = 0; i += my_strcpy(s + i, "dynamic "); if (channel_enforcebans(chan)) i += my_strcpy(s + i, "enforcebans "); if (channel_dynamicbans(chan)) i += my_strcpy(s + i, "dynamicbans "); if (!channel_nouserbans(chan)) i += my_strcpy(s + i, "userbans "); if (channel_bitch(chan)) i += my_strcpy(s + i, "bitch "); /* if (channel_revenge(chan)) i += my_strcpy(s + i, "revenge "); if (channel_revenge(chan)) i += my_strcpy(s + i, "revengebot "); */ if (channel_secret(chan)) i += my_strcpy(s + i, "secret "); if (channel_cycle(chan)) i += my_strcpy(s + i, "cycle "); if (channel_dynamicexempts(chan)) i += my_strcpy(s + i, "dynamicexempts "); if (!channel_nouserexempts(chan)) i += my_strcpy(s + i, "userexempts "); if (channel_dynamicinvites(chan)) i += my_strcpy(s + i, "dynamicinvites "); if (!channel_nouserinvites(chan)) i += my_strcpy(s + i, "userinvites "); if (!shouldjoin(chan)) i += my_strcpy(s + i, "inactive "); if (channel_nodesynch(chan)) i += my_strcpy(s + i, "nodesynch "); if (channel_closed(chan)) i += my_strcpy(s + i, "closed "); if (HAVE_TAKE && channel_take(chan)) i += my_strcpy(s + i, "take "); if (channel_voice(chan)) i += my_strcpy(s + i, "voice "); if (channel_autoop(chan)) i += my_strcpy(s + i, "autoop "); if (channel_meankicks(chan)) i += my_strcpy(s + i, "meankicks "); if (channel_rbl(chan)) i += my_strcpy(s + i, "rbl "); if (channel_voicebitch(chan)) i += my_strcpy(s + i, "voicebitch "); if (channel_protect(chan)) i += my_strcpy(s + i, "protect "); /* Chanflag template * if (channel_temp(chan)) * i += my_strcpy(s + i, "temp "); */ if (channel_nomassjoin(chan)) i += my_strcpy(s + i, "nomassjoin "); if (channel_botbitch(chan)) i += my_strcpy(s + i, "botbitch "); if (channel_backup(chan)) i += my_strcpy(s + i, "backup "); if (channel_fastop(chan)) i += my_strcpy(s + i, "fastop "); if (channel_privchan(chan)) i += my_strcpy(s + i, "private "); dprintf(idx, " Options: %s\n", s); if (chan->limitraise) dprintf(idx, " Raising limit +%d every 2 minutes\n", chan->limitraise); /* if (chan->revenge_mode) dprintf(idx, " revenge-mode %d\n", chan->revenge_mode); */ dprintf(idx, " Bans last %d mins.\n", chan->ban_time); dprintf(idx, " Exemptions last %d mins.\n", chan->exempt_time); dprintf(idx, " Invitations last %d mins.\n", chan->invite_time); } } } }
static void cmd_slowjoin(int idx, char *par) { int intvl = 0, delay = 0, count = 0; char *chname = NULL, *p = NULL, buf[2048] = "", buf2[RESULT_LEN] = ""; struct chanset_t *chan = NULL; tand_t *bot = NULL; /* slowjoin #chan 60 */ putlog(LOG_CMDS, "*", "#%s# slowjoin %s", dcc[idx].nick, par); chname = newsplit(&par); p = newsplit(&par); intvl = atoi(p); if (!chname[0] || !p[0]) { dprintf(idx, "Usage: slowjoin <channel> <interval-seconds> [channel options]\n"); return; } if (intvl < 10) { dprintf(idx, "Interval must be at least 10 seconds\n"); return; } if ((chan = findchan_by_dname(chname))) { dprintf(idx, "Already on %s\n", chan->dname); return; } if (!strchr(CHANMETA, chname[0])) { dprintf(idx, "Invalid channel name\n"); return; } simple_snprintf(buf, sizeof(buf), "+inactive addedby %s addedts %li ", dcc[idx].nick, (long)now); if (par[0]) strlcat(buf, par, sizeof(buf)); if (channel_add(buf2, chname, buf) == ERROR) { dprintf(idx, "Invalid channel or channel options.\n"); if (buf2[0]) dprintf(idx, " %s\n", buf2); return; } buf2[0] = 0; chan = findchan_by_dname(chname); if (!chan) { dprintf(idx, "Hmmm... Channel didn't get added. Weird *shrug*\n"); return; } simple_snprintf(buf2, sizeof(buf2), "cjoin %s %s", chan->dname, buf); putallbots(buf2); if (conf.bot->hub) count = 0; chan->status &= ~CHAN_INACTIVE; for (bot = tandbot; bot; bot = bot->next) { char tmp[100] = ""; tmp[0] = 0; if (bot->u) { if (bot_hublevel(bot->u) < 999) { simple_snprintf(tmp, sizeof(tmp), "sj %s 0", chname); } else { struct flag_record fr = { FR_CHAN|FR_GLOBAL|FR_BOT, 0, 0, 0 }; get_user_flagrec(bot->u, &fr, chname); /* Only send the 'sj' command if the bot is supposed to be in the channel (backups and such) */ if (bot_shouldjoin(bot->u, &fr, chan, 1)) { /* Variation: 60 secs intvl should be 60 +/- 15 */ int v = (random() % (intvl / 2)) - (intvl / 4); delay += intvl; simple_snprintf(tmp, sizeof(tmp), "sj %s %i", chname, delay + v); count++; } } if (tmp[0]) putbot(bot->bot, tmp); } } if (!conf.bot->hub && shouldjoin(chan)) count++; dprintf(idx, "%i bots joining %s during the next %i seconds\n", count, chan->dname, delay); if (!conf.bot->hub && shouldjoin(chan)) join_chan(chan); }