/* @(#)$Id: channels.c,v 1.29 2000/02/26 15:59:30 seks Exp $ */ /* Undernet Channel Service (X) * Copyright (C) 1995-2002 Robin Thellend * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * The author can be contact by email at * * Please note that this software is unsupported and mostly * obsolete. It was replaced by GNUworld/CMaster. See * http://gnuworld.sourceforge.net/ for more information. */ #include "h.h" int cl_hash(char *channel) { register int i, j; for (i = j = 0; i < strlen(channel); i++) j += (unsigned char)toupper(channel[i]); return (j % 1000); } void NewChannel(char *channelname, time_t TS, int on) { register achannel *chan; register adefchan *defs; char buffer[200]; if (!channelname || !*channelname) { log("ERROR: NewChannel(): empty channel string!!!"); log(channelname); } /* find defaults (if any) */ for (defs = DefChanList; defs && strcasecmp(defs->name, channelname); defs = defs->next); chan = (achannel *) MALLOC(sizeof(achannel)); chan->name = (char *)MALLOC(strlen(channelname) + 1); strcpy(chan->name, channelname); chan->AmChanOp = on; chan->on = on; chan->lastact = now; chan->lasttopic = now; chan->lang = L_DEFAULT; if (defs) { chan->MassDeopPro = defs->MassDeopPro; chan->NickFloodPro = defs->NickFloodPro; chan->MsgFloodPro = defs->MsgFloodPro; chan->flags = defs->flags; chan->uflags = defs->uflags; chan->TS = defs->TS; strcpy(chan->mode, defs->mode); } else { /* channel default settings */ chan->MassDeopPro = MAX_DEOP_RATE; chan->NickFloodPro = MAX_NICKCHANGE_RATE; chan->MsgFloodPro = MAX_PUBLIC_MSG_RATE; chan->flags = CFL_ALWAYSOP; chan->uflags = 0; chan->TS = TS; chan->mode[0] = '\0'; } strcpy(chan->lastjoin, ""); chan->bans = NULL; chan->users = NULL; chan->modebuff = NULL; chan->next = ChannelList[cl_hash(channelname)]; ChannelList[cl_hash(channelname)] = chan; if (on) { changemode(chan->name, "+o", mynick, 1); if (*chan->mode != '\0') { strcpy(buffer, "-"); strcat(buffer, chan->mode); bounce(chan->name, buffer, chan->TS); } flushmode(chan->name); } } void DelChannel(char *channelname) { register achannel *chan; register achannel *prec = NULL; register auser *user; register modequeue *mode; register aban *ban; chan = ChannelList[cl_hash(channelname)]; while (chan) { if (!strcasecmp(chan->name, channelname)) { while ((user = chan->users) != NULL) { chan->users = user->next; FreeUser(user); } if (prec) { prec->next = chan->next; while ((mode = chan->modebuff) != NULL) { chan->modebuff = mode->next; TTLALLOCMEM -= sizeof(modequeue); free(mode); } while ((ban = chan->bans) != NULL) { chan->bans = ban->next; TTLALLOCMEM -= sizeof(aban); free(ban); } TTLALLOCMEM -= strlen(chan->name) + 1; free(chan->name); TTLALLOCMEM -= sizeof(achannel); free(chan); chan = prec->next; } else { ChannelList[cl_hash(channelname)] = chan->next; while ((mode = chan->modebuff) != NULL) { chan->modebuff = mode->next; TTLALLOCMEM -= sizeof(modequeue); free(mode); } while ((ban = chan->bans) != NULL) { chan->bans = ban->next; TTLALLOCMEM -= sizeof(aban); free(ban); } TTLALLOCMEM -= strlen(chan->name) + 1; free(chan->name); TTLALLOCMEM -= sizeof(achannel); free(chan); chan = ChannelList[cl_hash(channelname)]; } break; } else { prec = chan; chan = chan->next; } } } void FreeUser(auser * user) { register adeop *nodedeop; register amsg *nodemsg; while ((nodedeop = user->deophist) != NULL) { user->deophist = nodedeop->next; TTLALLOCMEM -= sizeof(adeop); free(nodedeop); } while ((nodemsg = user->msghist) != NULL) { user->msghist = nodemsg->next; TTLALLOCMEM -= sizeof(amsg); free(nodemsg); } TTLALLOCMEM -= sizeof(auser); free(user); /* phew! */ } achannel *ToChannel(char *channel) { register achannel *curr = ChannelList[cl_hash(channel)]; while (curr && strcasecmp(curr->name, channel) != 0) { curr = curr->next; } return curr; } auser *ToUser(char *channel, char *nick) { register auser *curr; register achannel *chan; chan = ToChannel(channel); if (!chan) { curr = NULL; #ifdef DEBUG printf("ToUser(): channel not found!\n"); #endif } else curr = chan->users; #ifdef DEBUG printf("Looking for %s...\n", nick); #endif while (curr && strcasecmp(nick, curr->N->nick)) { #ifdef DEBUG printf("ToUser(): is on -> %s!%s@%s\n", curr->N->nick, curr->N->username, curr->N->site); #endif curr = curr->next; } #ifdef DEBUG if (!curr) printf("ToUser(): user not found!\n"); #endif return (curr); } void GetOps(char *channel) { char buffer[200]; register aluser *user; #ifdef FAKE_UWORLD if (Uworld_status == 1) { sprintf(buffer, ":%s MODE %s +o %s\n", UFAKE_SERVER, channel, mynick); sendtoserv(buffer); log("REOP by fake Uworld"); sprintf(buffer, "+o %s", mynick); ModeChange(UFAKE_SERVER, channel, buffer); return; } #endif if ((user = ToLuser(UWORLD)) != NULL && !match(user->site, UWORLD_HOST)) user = NULL; #ifdef UWORLD2 if (user == NULL) { if ((user = ToLuser(UWORLD2)) != NULL && !match(user->site, UWORLD2_HOST)) user = NULL; } #endif if (user != NULL) { sprintf(buffer, ":%s PRIVMSG %s :" UWORLD_COMMAND "\n", mynick, user->nick, channel); sendtoserv(buffer); sprintf(buffer, "I ASK %s FOR REOP ON %s", user->nick, channel); log(buffer); } #ifdef DEBUG else { printf("GetOps(): %s isn't online...\n", UWORLD); } #endif /* If Uworld is not present, queue the request * and try again later.. * If he's present, send the request and check later on * if it worked. */ AddEvent(EVENT_GETOPS, now + GETOPS_FREQ, channel); } int GuessChannel(char *nick, char *output) { register aluser *luser; register avalchan *vchan; register achannelnode *nchan; register int found = 0; char tmp[80]; luser = ToLuser(nick); if (luser == NULL) { return 0; } vchan = luser->valchan; if (vchan && !strcmp(vchan->name, "*")) vchan = vchan->next; if (vchan && !vchan->next) { strcpy(output, vchan->name); return 1; } nchan = luser->channel; while (nchan != NULL) { if (nchan->N->on) { found++; strcpy(tmp, nchan->N->name); } nchan = nchan->next; } if (found == 1) { strcpy(output, tmp); return 1; } return 0; } int IsOpless(char *channel) { register achannel *chan; register auser *user; chan = ToChannel(channel); if (chan == NULL) return 0; user = chan->users; while (user != NULL && !user->chanop) user = user->next; if (user != NULL || chan->AmChanOp) return 0; else return 1; } void onopless(char *channel) { register achannel *chan; if ((chan = ToChannel(channel)) == NULL || !chan->on) { /* don't do anything if not on channel */ return; } GetOps(channel); } void oninvite(char *source, char *channel) { char buffer[1024]; #ifdef DEBUG printf("Received INVITE from %s to %s\n", source, channel); #endif sprintf(buffer, "I'M INVITED ON %s BY %s", channel, source); log(buffer); if (strlen(channel) > 150) { notice(source, "yeah.. I know that game!"); return; } if (Access(channel, source) >= LEVEL_JOIN) { join(source, channel, ""); } } int IsReg(char *channel) { struct stat st; register struct RegUser *reg; if (stat(make_dbfname(channel), &st) < 0) { for (reg = UserList[ul_hash(channel)]; reg != NULL; reg = reg->next) if (!strcasecmp(reg->channel, channel)) break; if (reg == NULL) return 0; } return 1; } void join(char *source, char *chan, char *arg) { char buffer[1024]; char channel[80]; register achannel *ch; register auser *user; register char *ptr; if (*arg == '#') { GetWord(0, arg, channel); } else { GetWord(0, chan, channel); } if (strchr(channel, ',') != NULL) { if (*source) notice(source, "Invalid channel name!"); return; } if (!strcmp(channel, "*")) { notice(source, "SYNTAX: join "); return; } for (ptr = channel; *ptr; ptr++) { *ptr = tolowertmp(*ptr); } if (*source && Access(channel, source) < LEVEL_JOIN) { ReplyNotAccess(source, channel); return; } if (*source && !IsReg(channel)) { notice(source, "That channel is not registered"); return; } /* The server's messages are unreliable for *long* channel names so I decided that the bot will simply NOT join any channel which have names longer than 45 characters... no big deal! */ if (strlen(channel) <= 45) { ch = ToChannel(channel); if (ch != NULL) { for (user = ch->users; user != NULL; user = user->next) { if (!strcasecmp(user->N->username, DEFAULT_USERNAME) && !strcasecmp(user->N->site, DEFAULT_HOSTNAME)) { if (*source) { sprintf(buffer, "%s is already on that channel", user->N->nick); notice(source, buffer); } return; } } } sprintf(buffer, "I JOIN %s", channel); log(buffer); sprintf(buffer, ":%s JOIN %s\n", mynick, channel); sendtoserv(buffer); if (ch == NULL) { NewChannel(channel, now, 1); } else { ch->on = 1; ch->lastact = now; if (IsOpless(channel) || ((ch->flags & CFL_ALWAYSOP) && !ch->AmChanOp)) AddEvent(EVENT_GETOPS, now + GETOPS_ONJOIN_DELAY, channel); } } #ifdef DEBUG else printf("ARGH! *VERY* long channel name.. won't join :/\n"); #endif } void joindefault(void) { register adefchan *chan; register achannel *ch; chan = DefChanList; while (chan) { ch = ToChannel(chan->name); /* join the channel if not already on */ if (ch == NULL || ch->on == 0) join("", chan->name, ""); chan = chan->next; } } void part(char *source, char *chan, char *arg) { char buffer[512]; char channel[80]; register achannel *ch; if (*arg == '#') { GetWord(0, arg, channel); } else { GetWord(0, chan, channel); GuessChannel(source, channel); } if (!strcmp(channel, "*")) { notice(source, "SYNTAX: part "); return; } ch = ToChannel(channel); if (ch == NULL) { notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); return; } if (*source && Access(channel, source) < LEVEL_PART) { ReplyNotAccess(source, channel); return; } ch->on = 0; ch->AmChanOp = 0; if (ch->users == NULL) DelChannel(channel); sprintf(buffer, "I LEAVE %s", channel); log(buffer); sprintf(buffer, ":%s PART %s\n", mynick, channel); sendtoserv(buffer); } void invite(char *source, char *ch, char *args) { char buffer[512]; char channel[80]; char target[80]; register achannel *chan; if (*args == '#') { GetWord(0, args, channel); args = ToWord(1, args); } else { GetWord(0, ch, channel); GuessChannel(source, channel); } if (!strcmp(channel, "*")) { notice(source, "SYNTAX: invite [channel]"); return; } if ((chan = ToChannel(channel)) == NULL || !chan->on) { notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); return; } if (chan->flags & CFL_OPONLY) { notice(source, replies[RPL_OPONLY][chan->lang]); return; } if (Access(channel, source) < INVITE_LEVEL) { ReplyNotAccess(source, channel); return; } if (IsSet(channel, 'i', NULL) && !chan->AmChanOp) { notice(source, replies[RPL_NOTCHANOP][chan->lang]); return; } GetWord(0, args, target); if (*target != '\0' && strcasecmp(target, source) && (source[0] != '+')) { notice(source, "You are only allowed to invite yourself"); return; } if(*target == '\0') strcpy(target, source); if (ToUser(channel, target) != NULL) { notice(source, replies[RPL_ALREADYONCHANNEL][chan->lang]); return; } sprintf(buffer, ":%s INVITE %s %s\n", mynick, target, channel); sendtoserv(buffer); /* No need to confirm the invitation since it was sent to * the user already! */ if (strcasecmp(target, source)) { sprintf(buffer, replies[RPL_IINVITED][chan->lang], target, channel); notice(source, buffer); sprintf(buffer, replies[RPL_YOUAREINVITED][chan->lang], source, channel); notice(target, buffer); } } void onjoin(char *source, char *channel) { char buffer[512]; char mask[200], reason[200]; char *ptr; register achannel *chan; register achannelnode *c; register aluser *user; register auser *usr, *tmp; register RegUser *reg; #ifdef DEBUG printf("onjoin( %s, %s)\n", source, channel); #endif user = ToLuser(source); if (user == NULL) { /* a server would send a KILL, but I think * it'll be ok to ignore it */ sprintf(buffer, "ERROR onjoin(): Unknown USER %s!", source); log(buffer); return; } if (channel[0] == ':') channel++; while (channel) { ptr = strchr(channel, ','); if (ptr != NULL) *(ptr++) = '\0'; /* join 0 */ if (!strcmp(channel, "0")) { while ((c = user->channel) != NULL) { onpart(source, c->N->name); } channel = ptr; continue; } #ifdef DEBUG printf("JOIN: %s!%s@%s on channel %s\n", user->nick, user->username, user->site, channel); #endif if (!*channel) { log("ERROR: onjoin(): JOIN to null channel!"); log(source); log(channel); channel = ptr; continue; } chan = ToChannel(channel); if (!chan) { #ifdef DEBUG printf("onjoin(): New channel\n"); #endif NewChannel(channel, now + TSoffset, 0); chan = ToChannel(channel); } chan->lastact = now; c = (achannelnode *) MALLOC(sizeof(achannelnode)); c->N = chan; c->nickhist = NULL; c->next = user->channel; user->channel = c; strcpy(chan->lastjoin, source); usr = (auser *) MALLOC(sizeof(auser)); usr->chanop = 0; usr->deophist = NULL; usr->lastact = now; usr->msghist = NULL; usr->N = user; usr->next = chan->users; chan->users = usr; if (chan->on) { for (tmp = chan->users; tmp != NULL; tmp = tmp->next) { if (!strcasecmp(tmp->N->username, DEFAULT_USERNAME) && !strcasecmp(tmp->N->site, DEFAULT_HOSTNAME) && tmp->N->time <= logTS) { sprintf(buffer, "PAL's already on %s (%ld <= %ld)", chan->name, tmp->N->time, logTS); log(buffer); part("", chan->name, ""); } } } try_find(channel, user); reg = IsValid(user, channel); sprintf(buffer, "%s!%s@%s", user->nick, user->username, user->site); if (chan->on && chan->AmChanOp && IsShit(channel, buffer, mask, reason) >= AUTO_KICK_SHIT_LEVEL) { log("Detected banned user (AUTO-KICK LEVEL)"); notice(source, "*** Sorry. You are on my banlist ***"); mban("", channel, mask); sprintf(buffer, "%s %s [%s]", mask, mask, reason); kick("", channel, buffer); } else if (chan->on && chan->AmChanOp && reg && (reg->flags & UFL_AUTOOP) && reg->suspend < now && *reg->passwd != '\0' && !(chan->flags & CFL_NOOP) && IsShit(channel, buffer, NULL, NULL) < NO_OP_SHIT_LEVEL ) { op("", channel, source); } if (chan->on && chan->AmChanOp && (chan->flags & CFL_AUTOTOPIC) && chan->lasttopic + AUTOTOPIC_FREQ < now) { adefchan *def = DefChanList; while (def != NULL && strcasecmp(def->name, chan->name)) def = def->next; if (def != NULL && (def->url || def->topic)) { chan->lasttopic = now; sprintf(buffer, "%s (%s)", (def->topic) ? def->topic : "", (def->url) ? def->url : ""); topic("", chan->name, buffer); } } channel = ptr; } } void onpart(char *nick, char *channel) { char buffer[200]; register auser *user; register aluser *luser; register auser *prec = NULL; register achannel *chan; register achannelnode **ch, *c; register anickchange *nickhist; #ifdef DEBUG printf("PART: %s from %s\n", nick, channel); #endif luser = ToLuser(nick); if (luser == NULL) { sprintf(buffer, "ERROR: onpart(): Unknown USER %s!", nick); log(buffer); #ifdef HISTORY History(NULL); #endif return; } chan = ToChannel(channel); if (chan == NULL) { user = NULL; log("ERROR: onpart(): null channel!? /*core dumped*/"); log(nick); log(channel); /*dumpcore(""); */ return; } else { chan->lastact = now; user = chan->users; } while (user) { if (!strcasecmp(user->N->nick, nick)) { /* remove the structure from mem */ if (prec) { prec->next = user->next; FreeUser(user); user = prec->next; } else { chan->users = user->next; FreeUser(user); user = chan->users; } break; } else { prec = user; user = user->next; } } ch = &luser->channel; while (*ch && strcasecmp(channel, (*ch)->N->name)) ch = &(*ch)->next; c = *ch; if (c == NULL) { #ifdef DEBUG printf("WARNING: onpart(): channel %s not found!\n", channel); #endif } else { *ch = c->next; while ((nickhist = c->nickhist) != NULL) { c->nickhist = nickhist->next; TTLALLOCMEM -= sizeof(anickchange); free(nickhist); } TTLALLOCMEM -= sizeof(achannelnode); free(c); } if (chan != NULL && chan->users == NULL && !chan->on) { DelChannel(channel); } if (IsOpless(channel)) onopless(channel); } void onkick(char *source, char *channel, char *body) { char nick[NICK_LENGTH]; char buffer[1024]; register achannel *chan; register auser *user; register int count; GetWord(0, body, nick); if (!strcasecmp(mynick, nick)) { user = ToUser(channel, source); if (user == NULL) { sprintf(buffer, "I'M KICKED OFF %s by %s", channel, source); } else { sprintf(buffer, "I'M KICKED OFF %s BY %s!%s@%s (%d) %s", channel, user->N->nick, user->N->username, user->N->site, Access(channel, source), ToWord(1, body)); } log(buffer); broadcast(buffer, 0); chan = ToChannel(channel); if ((chan->flags & CFL_ALWAYSOP) && Access(channel, source) >= ALWAYSOP_OVERRIDE_LEVEL) { chan->flags &= ~CFL_ALWAYSOP; sprintf(buffer, "AlwaysOp is turned off on %s", channel); log(buffer); RemChan(source, channel, channel); notice(source, replies[RPL_ALWAYSOPWASACTIVE][chan->lang]); } if (chan->flags & CFL_ALWAYSOP) { /* In AlwaysOp mode, if someone KICKs the bot, he/she * gets deops/suspended/shitlisted for predetermined * time and levels */ if (user != NULL) { count = IsShit(channel, source, NULL, NULL); notice(source, replies[RPL_ALWAYSOP][chan->lang]); switch (count) { case 0: case 1: case 2: case 3: case 4: log("First warning"); notice(source, replies[RPL_KICK1ST][chan->lang]); changemode(channel, "-o", source, 0); flushmode(channel); user->chanop = 0; break; case 5: case 6: case 7: case 8: case 9: log("Second warning"); notice(source, replies[RPL_KICK2ND][chan->lang]); kick("", channel, source); break; default: changemode(channel, "-o", source, 0); flushmode(channel); user->chanop = 0; sprintf(buffer, "%s!%s@%s %d", user->N->nick, user->N->username, user->N->site, DEOPME_SUSPEND_TIME); suspend("", channel, buffer); sprintf(buffer, "Suspended %s!%s@%s on %s for repeatedly kicking me", user->N->nick, user->N->username, user->N->site, channel); SpecLog(buffer); broadcast(buffer, 0); } sprintf(buffer, "%s %d %d *** KICK WHILE ALWAYSOP ACTIVE ***", source, DEOP_SHITLIST_TIME, (count < 10) ? count + 5 : DEOP_SHITLIST_LEVEL); AddToShitList("", channel, buffer, 0); } part("", channel, ""); join("", channel, ""); GetOps(channel); } else { part("", channel, ""); } } CheckFlood(source, channel, 80); } void QuitAll(void) { register int j; if (ServerList != NULL) onsquit("", ServerList->name, NULL); for (j = 0; j < 1000; j++) { while (ChannelList[j] != NULL) { DelChannel(ChannelList[j]->name); } } } void CheckIdleChannels(void) { register achannel *chan, *tmp; register int i; char buffer[200]; for (i = 0; i < 1000; i++) { chan = ChannelList[i]; while (chan != NULL) { tmp = chan->next; if (chan->on && chan->lastact + MAX_IDLE_TIME <= now) { sprintf(buffer, "Channel %s has exceeded the idle time limit of %.2f hours", chan->name, (float)MAX_IDLE_TIME / 3600.0); SpecLog(buffer); part("", chan->name, ""); RemChan("", chan->name, ""); } chan = tmp; } } } void topic(char *source, char *chan, char *args) { char buffer[1024]; char channel[80]; register achannel *ch; strcpy(channel, chan); if (*source) { if (*args == '#') { GetWord(0, args, channel); args = ToWord(1, args); } else { strcpy(channel, chan); GuessChannel(source, channel); } if (!strcmp(channel, "*")) { notice(source, "SYNTAX: topic "); return; } if (Access(channel, source) < TOPIC_LEVEL) { ReplyNotAccess(source, channel); return; } if (!*args) { notice(source, "SYNTAX: topic [channel] "); return; } } ch = ToChannel(channel); if (ch == NULL) { notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); return; } if (ch->flags & CFL_OPONLY) { notice(source, replies[RPL_OPONLY][ch->lang]); return; } ch->lastact = now; sprintf(buffer, "I CHANGED TOPIC on %s to %s", channel, args); log(buffer); sprintf(buffer, ":%s TOPIC %s :%s\n", mynick, channel, args); sendtoserv(buffer); } void ontopic(char *source, char *target, char *body) { CheckFlood(source, target, strlen(body) + 60); } void onnotice(char *source, char *target, char *body) { if (*target == '#') CheckFlood(source, target, strlen(body) + 10); else CheckPrivateFlood(source, strlen(body) + 10, "NOTICE-"); } void SetChanFlag(char *source, char *ch, char *args) { char buffer[200]; char channel[80]; char variable[80]; char svalue[80]; register int value, acc, i, found; register achannel *chan; if (*args == '#') { GetWord(0, args, channel); args = ToWord(1, args); } else { strcpy(channel, ch); GuessChannel(source, channel); } acc = Access(channel, source); GetWord(0, args, variable); GetWord(1, args, svalue); if (!strcmp(channel, "*") || !*variable) { notice(source, "SYNTAX: set [#channel] "); return; } chan = ToChannel(channel); if (chan == NULL) { notice(source, replies[RPL_CHANNOTEXIST][L_DEFAULT]); return; } value = atoi(svalue); if (!strncasecmp(variable, "FLOODPRO", strlen(variable))) { if (acc < CH_FLOOD_LIMIT_LEVEL) { ReplyNotAccess(source, channel); return; } if (value != 0 && (value < 3 || value > 20)) { notice(source, replies[RPL_BADFLOODLIMIT][chan->lang]); return; } chan->MsgFloodPro = value; sprintf(buffer, replies[RPL_SETFLOODLIMIT][chan->lang], value); notice(source, buffer); sprintf(buffer, "%s SET FLOODPRO ON %s TO %d", source, channel, value); log(buffer); } else if (!strncasecmp(variable, "NICKFLOODPRO", strlen(variable))) { if (acc < CH_NICK_FLOOD_LIMIT_LEVEL) { ReplyNotAccess(source, channel); return; } if (value != 0 && (value < 3 || value > 10)) { notice(source, replies[RPL_BADNICKFLOODLIMIT][chan->lang]); return; } chan->NickFloodPro = value; sprintf(buffer, replies[RPL_SETNICKFLOODLIMIT][chan->lang], value); notice(source, buffer); sprintf(buffer, "%s SET NICKFLOODPRO ON %s TO %d", source, channel, value); log(buffer); } else if (!strncasecmp(variable, "MASSDEOPPRO", strlen(variable))) { if (acc < CH_MASSDEOP_LIMIT_LEVEL) { ReplyNotAccess(source, channel); return; } if (value != 0 && (value < 3 || value > 10)) { notice(source, replies[RPL_BADMASSDEOPLIMIT][chan->lang]); return; } chan->MassDeopPro = value; sprintf(buffer, replies[RPL_SETMASSDEOPLIMIT][chan->lang], value); notice(source, buffer); sprintf(buffer, "%s SET MASSDEOPPRO ON %s TO %d", source, channel, value); log(buffer); } else if (!strncasecmp(variable, "NOOP", strlen(variable))) { if (acc < CH_NOOP_LEVEL) { ReplyNotAccess(source, channel); return; } if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) { chan->flags |= CFL_NOOP; notice(source, replies[RPL_NOOPON][chan->lang]); massdeop(channel); sprintf(buffer, "%s SET NOOP ON %s ON", source, channel); log(buffer); } else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) { chan->flags &= ~CFL_NOOP; notice(source, replies[RPL_NOOPOFF][chan->lang]); sprintf(buffer, "%s SET NOOP ON %s OFF", source, channel); log(buffer); } else notice(source, replies[RPL_BADNOOP][chan->lang]); } else if (!strncasecmp(variable, "ALWAYSOP", strlen(variable))) { if (acc < CH_ALWAYSOP_LEVEL) { ReplyNotAccess(source, channel); return; } if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) { chan->flags |= CFL_ALWAYSOP; notice(source, replies[RPL_ALWAYSOPON][chan->lang]); sprintf(buffer, "%s SET ALWAYSOP ON %s ON", source, channel); log(buffer); /* looks like ppl would like X to op himself when * ALWAYSOP is truned on... fine ;) */ if (!chan->AmChanOp) { GetOps(chan->name); } } else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) { chan->flags &= ~CFL_ALWAYSOP; notice(source, replies[RPL_ALWAYSOPOFF][chan->lang]); sprintf(buffer, "%s SET ALWAYSOP ON %s OFF", source, channel); log(buffer); } else notice(source, replies[RPL_BADALWAYSOP][chan->lang]); } else if (!strncasecmp(variable, "OPONLY", strlen(variable))) { if (acc < CH_OPONLY_LEVEL) { ReplyNotAccess(source, channel); return; } if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) { chan->flags |= CFL_OPONLY; notice(source, replies[RPL_OPONLYON][chan->lang]); sprintf(buffer, "%s SET OPONLY ON %s ON", source, channel); log(buffer); } else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) { chan->flags &= ~CFL_OPONLY; notice(source, replies[RPL_OPONLYOFF][chan->lang]); sprintf(buffer, "%s SET OPONLY ON %s OFF", source, channel); log(buffer); } else notice(source, replies[RPL_BADOPONLY][chan->lang]); } else if (!strncasecmp(variable, "STRICTOP", strlen(variable))) { if (acc < CH_STRICTOP_LEVEL) { ReplyNotAccess(source, channel); return; } if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) { chan->flags |= CFL_STRICTOP; notice(source, replies[RPL_STRICTOPON][chan->lang]); sprintf(buffer, "%s SET STRICTOP ON %s ON", source, channel); log(buffer); } else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) { chan->flags &= ~CFL_STRICTOP; notice(source, replies[RPL_STRICTOPOFF][chan->lang]); sprintf(buffer, "%s SET STRICTOP ON %s OFF", source, channel); log(buffer); } else notice(source, replies[RPL_BADSTRICTOP][chan->lang]); } else if (!strncasecmp(variable, "USERFLAGS", strlen(variable))) { if (acc < CH_USERFLAGS_LEVEL) { ReplyNotAccess(source, channel); return; } if (value < 0 || value > 3) { notice(source, replies[RPL_BADUSERFLAGS][chan->lang]); return; } chan->uflags = (unsigned long)value; sprintf(buffer, replies[RPL_SETUSERFLAGS][chan->lang], value); notice(source, buffer); sprintf(buffer, "%s SET USERFLAGS TO %d on %s", source, value, channel); log(buffer); } else if (!strncasecmp(variable, "LANGUAGE", strlen(variable))) { if (acc < CH_LANG_LEVEL) { ReplyNotAccess(source, channel); return; } found = 0; for (i = 0; i < NO_LANG; i++) { if (!strcasecmp(svalue, Lang[i].abbr) || !strcasecmp(svalue, Lang[i].name)) { chan->lang = i; found = 1; break; } } if (!found) { strcpy(buffer, replies[RPL_KNOWNLANG][chan->lang]); for (i = 0; i < NO_LANG; i++) { strcat(buffer, " "); strcat(buffer, Lang[i].abbr); strcat(buffer, " ("); strcat(buffer, Lang[i].name); strcat(buffer, ")"); } notice(source, buffer); } else { sprintf(buffer, replies[RPL_SETLANG][chan->lang], Lang[chan->lang].abbr, Lang[chan->lang].name); notice(source, buffer); } } else if (!strncasecmp(variable, "TOPIC", strlen(variable)) || !strncasecmp(variable, "DESCRIPTION", strlen(variable))) { register adefchan *def; if (acc < CH_TOPIC_LEVEL) { ReplyNotAccess(source, channel); return; } def = DefChanList; while (def && strcasecmp(def->name, channel)) def = def->next; if (!def) { notice(source, "You must use 'addchan' first."); return; } strncpy(def->topic, ToWord(1, args), 79); def->topic[79] = '\0'; notice(source, "New description set"); } else if (!strncasecmp(variable, "URL", strlen(variable))) { register adefchan *def; register char *ptr; if (acc < CH_URL_LEVEL) { ReplyNotAccess(source, channel); return; } def = DefChanList; while (def && strcasecmp(def->name, channel)) def = def->next; if (!def) { notice(source, "You must use 'addchan' first."); return; } for (ptr = svalue; *ptr; ptr++) { if (*(unsigned char *)ptr >= 0x80 || *ptr < 0x20 || strchr("<>;\"&\\", *ptr)) { notice(source, "Invalid URL"); return; } } strncpy(def->url, svalue, 79); def->url[79] = '\0'; notice(source, "New URL set"); } else if (!strncasecmp(variable, "AUTOTOPIC", strlen(variable))) { if (acc < CH_AUTOTOPIC_LEVEL) { ReplyNotAccess(source, channel); return; } if (!strcasecmp(svalue, "ON") || !strcasecmp(svalue, "EIN")) { chan->flags |= CFL_AUTOTOPIC; notice(source, replies[RPL_AUTOTOPICON][chan->lang]); sprintf(buffer, "%s SET AUTOTOPIC ON %s ON", source, channel); log(buffer); } else if (!strcasecmp(svalue, "OFF") || !strcasecmp(svalue, "AUS")) { chan->flags &= ~CFL_AUTOTOPIC; notice(source, replies[RPL_AUTOTOPICOFF][chan->lang]); sprintf(buffer, "%s SET AUTOTOPIC ON %s OFF", source, channel); log(buffer); } else notice(source, replies[RPL_BADAUTOTOPIC][chan->lang]); } } void showstatus(char *source, char *ch, char *args) { char buffer[512]; char channel[80]; char global[] = "*"; register achannel *chan; register auser *user; register aluser *luser; register achannelnode *lchan; register int i, j, k, isoper = 0; register time_t t; register int days, hours, mins, secs; register RegUser *reg; int srcaccess; if (*args == '#' || *args == '*') { GetWord(0, args, channel); args = ToWord(1, args); } else { strcpy(channel, ch); GuessChannel(source, channel); } luser = ToLuser(source); if (luser) isoper = (luser->mode & LFL_ISOPER) ? 1 : 0; if (!strcmp(channel, "*") && !IsValid(luser, channel) && !isoper) { notice(source, "SYNTAX: status "); return; } if ((srcaccess = Access(channel, source)) < STATUS_ACCESS && Access(global, source) < XADMIN_LEVEL && !isoper) { ReplyNotAccess(source, channel); return; } if (!strcmp(channel, "*")) { /* count the number of channels */ for (i = j = k = 0; j < 1000; j++) { chan = ChannelList[j]; while (chan) { if (chan->on) i++; k++; chan = chan->next; } } sprintf(buffer, "I'm on %d channel%c (out of %d)", i, (i > 1) ? 's' : ' ', k); notice(source, buffer); for (i = j = k = 0; j < 1000; j++) { luser = Lusers[j]; while (luser) { lchan = luser->channel; while (lchan) { if (lchan->N->on) { i++; break; } lchan = lchan->next; } k++; luser = luser->next; } } sprintf(buffer, "I'm seeing %d users (out of %d)", i, k + 1 /* add self */ ); notice(source, buffer); sprintf(buffer, "Total read bytes: %lu Total sent bytes: %lu", TTLREADBYTES, TTLSENTBYTES); notice(source, buffer); sprintf(buffer, "Total sent bytes in http: %lu", HTTPTTLSENTBYTES); notice(source, buffer); sprintf(buffer, "Total allocated memory: %lu", TTLALLOCMEM); notice(source, buffer); t = now - TSonline; days = (int)t / 86400; t %= 86400; hours = (int)t / 3600; t %= 3600; mins = (int)t / 60; t %= 60; secs = (int)t; if (days > 0) sprintf(buffer, "Service Up %d day%s %d:%s%d:%s%d", days, (days > 1) ? "s" : "", hours, (mins <= 9) ? "0" : "", mins, (secs <= 9) ? "0" : "", secs); else sprintf(buffer, "Service Up %d:%s%d:%s%d", hours, (mins <= 9) ? "0" : "", mins, (secs <= 9) ? "0" : "", secs); notice(source, buffer); } else { chan = ToChannel(channel); if (!chan || !chan->on) { notice(source, replies[RPL_NOTONCHANNEL][L_DEFAULT]); return; } /* count the number of users */ i = j = 0; user = chan->users; while (user) { if (user->chanop) j++; i++; user = user->next; } if (chan->AmChanOp) j++; if (chan->lang != L_GERMAN) { sprintf(buffer, replies[RPL_STATUS1][chan->lang], channel, i + 1, (i > 0) ? "s" : "", j, (j > 1) ? "s" : ""); } else { sprintf(buffer, replies[RPL_STATUS1][chan->lang], channel, i + 1, j); } notice(source, buffer); if (srcaccess >= STATUS_ACCESS_MODE || isoper) { sprintf(buffer, replies[RPL_STATUS2][chan->lang], chan->mode); notice(source, buffer); } sprintf(buffer, "MassDeopPro: %3d NickFloodPro: %3d FloodPro: %3d", chan->MassDeopPro, chan->NickFloodPro, chan->MsgFloodPro); notice(source, buffer); if (chan->lang != L_GERMAN) { sprintf(buffer, "NoOp: %3s AlwaysOp: %3s OpOnly: %3s StrictOp: %3s AutoTopic: %3s", (chan->flags & CFL_NOOP) ? "ON" : "OFF", (chan->flags & CFL_ALWAYSOP) ? "ON" : "OFF", (chan->flags & CFL_OPONLY) ? "ON" : "OFF", (chan->flags & CFL_STRICTOP) ? "ON" : "OFF", (chan->flags & CFL_AUTOTOPIC) ? "ON" : "OFF"); } else { sprintf(buffer, "NoOp: %3s AlwaysOp: %3s OpOnly: %3s StrictOp: %3s AutoTopic: %3s", (chan->flags & CFL_NOOP) ? "EIN" : "AUS", (chan->flags & CFL_ALWAYSOP) ? "EIN" : "AUS", (chan->flags & CFL_OPONLY) ? "EIN" : "AUS", (chan->flags & CFL_STRICTOP) ? "EIN" : "AUS", (chan->flags & CFL_AUTOTOPIC) ? "EIN" : "AUS"); } notice(source, buffer); if (chan->uflags) { sprintf(buffer, replies[RPL_STATUS3][chan->lang], (chan->uflags & UFL_AUTOOP) ? " AUTOOP" : ""); notice(source, buffer); } sprintf(buffer, replies[RPL_STATUS4][chan->lang], Lang[chan->lang].name); notice(source, buffer); i = (now - chan->lastact); if (i != 0) { sprintf(buffer, replies[RPL_STATUS5][chan->lang], i, (i > 1) ? "s" : ""); notice(source, buffer); } strcpy(buffer, "Auth:"); for (j = 0; j < 1000; j++) { luser = Lusers[j]; while (luser) { if ((reg = IsValid(luser, chan->name)) != NULL) { sprintf(buffer + strlen(buffer), " %s(%s%d)", luser->nick, *reg->channel == '*' ? "*" : "", reg->access); } if (strlen(buffer) > 400) { notice(source, buffer); strcpy(buffer, "Auth:"); } luser = luser->next; } } if (strlen(buffer) > 5) notice(source, buffer); } } void SendBurst(void) { register achannel *chan; register adefchan *defs; char buffer[512], buffer2[200]; register char *ptr; sprintf(buffer, ":%s JOIN ", mynick); /* find defaults (if any) */ for (defs = DefChanList; defs != NULL; defs = defs->next) { chan = (achannel *) MALLOC(sizeof(achannel)); for (ptr = defs->name; *ptr; ptr++) { *ptr = tolowertmp(*ptr); } chan->name = (char *)MALLOC(strlen(defs->name) + 1); strcpy(chan->name, defs->name); chan->AmChanOp = 1; chan->on = 1; chan->lastact = now; chan->lasttopic = now; chan->lang = 0; chan->MassDeopPro = defs->MassDeopPro; chan->NickFloodPro = defs->NickFloodPro; chan->MsgFloodPro = defs->MsgFloodPro; chan->flags = defs->flags; chan->uflags = defs->uflags; chan->TS = defs->TS; strcpy(chan->mode, defs->mode); strcpy(chan->lastjoin, ""); chan->bans = NULL; chan->users = NULL; chan->modebuff = NULL; chan->next = ChannelList[cl_hash(chan->name)]; ChannelList[cl_hash(chan->name)] = chan; if (*ToWord(2, buffer)) strcat(buffer, ","); strcat(buffer, chan->name); if (defs->next == NULL || strlen(buffer) > 400) { strcat(buffer, "\n"); sendtoserv(buffer); sprintf(buffer, ":%s JOIN ", mynick); } changemode(chan->name, "+o", mynick, 1); if (*chan->mode != '\0') { strcpy(buffer2, "-"); strcat(buffer2, chan->mode); bounce(chan->name, buffer2, chan->TS); } } for (defs = DefChanList; defs != NULL; defs = defs->next) flushmode(defs->name); } void showusers(char *chan) { auser *user; aluser *u; achannel *channel; int index = 0; #ifdef DEBUG printf("ACK\n"); #endif for (index = 0; index < 1000; index++) { channel = ChannelList[index]; while (channel) { if (match(channel->name, chan)) { user = channel->users; while (user) { u = user->N; printf("%s: %s!%s@%s %d\n", channel->name, u->nick, u->username, u->site, user->chanop); user = user->next; } printf("MODE FOR %s is %s\n", channel->name, channel->mode); } channel = channel->next; } } } void showchannels(void) { achannel *channel; aban *b; modequeue *mode; int index; #ifdef DEBUG printf("ACK\n"); #endif for (index = 0; index < 1000; index++) { channel = ChannelList[index]; while (channel != NULL) { printf("%s TS: %ld on: %d amchanop: %d\n", channel->name, channel->TS, channel->on, channel->AmChanOp); b = channel->bans; printf("%s - banlist\n", channel->name); while (b != NULL) { printf("\t%s\n", b->pattern); b = b->next; } printf("%s - modebuff\n", channel->name); mode = channel->modebuff; while (mode != NULL) { printf("\t%d %s %s\n", mode->AsServer, mode->flag, mode->arg); mode = mode->next; } channel = channel->next; } } }