*
* This file is part of x3.
*
- * srvx is free software; you can redistribute it and/or modify
+ * x3 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
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
+#include "nickserv.h"
#include "chanserv.h"
+#include "hash.h"
+#include "helpfile.h"
+#include "hosthiding.h"
#include "proto-common.c"
+#include "opserv.h"
/* Full commands. */
#define CMD_ACCOUNT "ACCOUNT"
#define CMD_ADMIN "ADMIN"
+#define CMD_ALIST "ALIST"
#define CMD_ASLL "ASLL"
#define CMD_AWAY "AWAY"
#define CMD_BURST "BURST"
#define CMD_PROTO "PROTO"
#define CMD_QUIT "QUIT"
#define CMD_REHASH "REHASH"
+#define CMD_REMOVE "REMOVE"
#define CMD_RESET "RESET"
#define CMD_RESTART "RESTART"
#define CMD_RPING "RPING"
#define CMD_RPONG "RPONG"
+#define CMD_SASL "SASL"
#define CMD_SERVER "SERVER"
#define CMD_SERVLIST "SERVLIST"
#define CMD_SERVSET "SERVSET"
#define CMD_SET "SET"
#define CMD_SETTIME "SETTIME"
+#define CMD_SGLINE "SGLINE"
+#define CMD_SHUN "SHUN"
#define CMD_SILENCE "SILENCE"
+#define CMD_SMO "SMO"
+#define CMD_SNO "SNO"
+#define CMD_SSHUN "SSHUN"
+#define CMD_SPAMFILTER "SPAMFILTER"
#define CMD_SQUERY "SQUERY"
#define CMD_SQUIT "SQUIT"
#define CMD_STATS "STATS"
+#define CMD_SVSJOIN "SVSJOIN"
#define CMD_SVSNICK "SVSNICK"
+#define CMD_SVSPART "SVSPART"
+#define CMD_SVSQUIT "SVSQUIT"
+#define CMD_SWHOIS "SWHOIS"
#define CMD_TIME "TIME"
#define CMD_TOPIC "TOPIC"
#define CMD_TRACE "TRACE"
#define CMD_WHO "WHO"
#define CMD_WHOIS "WHOIS"
#define CMD_WHOWAS "WHOWAS"
+#define CMD_ZLINE "ZLINE"
/* Tokenized commands. */
#define TOK_ACCOUNT "AC"
#define TOK_ADMIN "AD"
+#define TOK_ALIST "AL"
#define TOK_ASLL "LL"
#define TOK_AWAY "A"
#define TOK_BURST "B"
#define TOK_PROTO "PROTO"
#define TOK_QUIT "Q"
#define TOK_REHASH "REHASH"
+#define TOK_REMOVE "RM"
#define TOK_RESET "RESET"
#define TOK_RESTART "RESTART"
#define TOK_RPING "RI"
#define TOK_RPONG "RO"
+#define TOK_SASL "SASL"
#define TOK_SERVER "S"
#define TOK_SERVLIST "SERVSET"
#define TOK_SERVSET "SERVSET"
#define TOK_SET "SET"
#define TOK_SETTIME "SE"
+#define TOK_SGLINE "SGL"
+#define TOK_SHUN "SU"
#define TOK_SILENCE "U"
+#define TOK_SMO "SMO"
+#define TOK_SNO "SNO"
+#define TOK_SSHUN "SSU"
+#define TOK_SPAMFILTER "SF"
#define TOK_SQUERY "SQUERY"
#define TOK_SQUIT "SQ"
#define TOK_STATS "R"
+#define TOK_SVSJOIN "SJ"
#define TOK_SVSNICK "SN"
+#define TOK_SVSPART "SP"
+#define TOK_SVSQUIT "SX"
+#define TOK_SWHOIS "SW"
#define TOK_TIME "TI"
#define TOK_TOPIC "T"
#define TOK_TRACE "TR"
#define TOK_WHO "H"
#define TOK_WHOIS "W"
#define TOK_WHOWAS "X"
+#define TOK_ZLINE "ZL"
/* Protocol messages; aliased to full commands or tokens depending
on compile-time configuration. ircu prefers tokens WITH THE
#define P10_PROTO TYPE(PROTO)
#define P10_QUIT TYPE(QUIT)
#define P10_REHASH TYPE(REHASH)
+#define P10_REMOVE TYPE(REMOVE)
#define P10_RESET TYPE(RESET)
#define P10_RESTART TYPE(RESTART)
#define P10_RPING TYPE(RPING)
#define P10_RPONG TYPE(RPONG)
+#define P10_SASL TYPE(SASL)
#define P10_SERVER CMD_SERVER
#define P10_SERVLIST TYPE(SERVLIST)
#define P10_SERVSET TYPE(SERVSET)
#define P10_SET TYPE(SET)
#define P10_SETTIME TYPE(SETTIME)
+#define P10_SGLINE TYPE(SGLINE)
+#define P10_SHUN TYPE(SHUN)
#define P10_SILENCE TYPE(SILENCE)
+#define P10_SMO TYPE(SMO)
+#define P10_SNO TYPE(SNO)
+#define P10_SSHUN TYPE(SSHUN)
+#define P10_SPAMFILTER TYPE(SPAMFILTER)
#define P10_SQUERY TYPE(SQUERY)
#define P10_SQUIT TYPE(SQUIT)
#define P10_STATS TYPE(STATS)
+#define P10_SVSJOIN TYPE(SVSJOIN)
#define P10_SVSNICK TYPE(SVSNICK)
+#define P10_SVSPART TYPE(SVSPART)
+#define P10_SVSQUIT TYPE(SVSQUIT)
+#define P10_SWHOIS TYPE(SWHOIS)
#define P10_TIME TYPE(TIME)
#define P10_TOPIC TYPE(TOPIC)
#define P10_TRACE TYPE(TRACE)
#define P10_WHO TYPE(WHO)
#define P10_WHOIS TYPE(WHOIS)
#define P10_WHOWAS TYPE(WHOWAS)
+#define P10_ZLINE TYPE(ZLINE)
#define P10_EXEMPT TYPE(EXEMPT)
/* Servers claiming to have a boot or link time before PREHISTORY
*/
#define PREHISTORY 780000000
+#define MODELEN 40 + KEYLEN
+
static struct server *servers_num[64*64];
static privmsg_func_t *privmsg_funcs;
static unsigned int num_privmsg_funcs;
static privmsg_func_t *notice_funcs;
static unsigned int num_notice_funcs;
static struct dict *unbursted_channels;
-static char *his_servername;
-static char *his_servercomment;
+static const char *his_servername;
+static const char *his_servercomment;
+static int extended_accounts;
+
+/* These correspond to 1 << X: 01234567890123456789012345 */
+const char irc_user_mode_chars[] = "oOiw dkgh x BnIX azDRWHLq";
static struct userNode *AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip);
extern int off_channel;
+extern int DefConLevel;
+extern int DefConTimeOut;
+extern char *DefConChanModes;
+
+static int parse_oplevel(char *str);
+
+char privbuf[512] = "";
/* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
* server and Y's indentifying the client on that server. */
return un;
}
+extern struct userNode *opserv;
+static void
+check_ctcp(struct userNode *user, struct userNode *bot, char *text, UNUSED_ARG(int server_qualified))
+{
+ char *cmd;
+ /* if its a version reply, do an alert check (only alerts with version=something) */
+ if(bot == opserv) {
+ if(text[0] == '\001') {
+ text++;
+ cmd = mysep(&text, " ");
+ if(!irccasecmp(cmd, "VERSION")) {
+ char *version = mysep(&text, "\n");
+ if(!version)
+ version = "";
+ /* opserv_debug("Opserv got CTCP VERSION Notice from %s: %s", user->nick, version); */
+ /* TODO: setup a ctcp_funcs thing to handle this and other CTCPS properly */
+ user->version_reply = strdup(version);
+ /* TODO: put this in the db */
+ if(match_ircglob(version, "WebTV;*"))
+ user->no_notice = true; /* webbies cant see notices */
+ }
+ }
+ }
+}
+
+
static void
privmsg_user_helper(struct userNode *un, void *data)
{
}
} else {
if ((num < num_notice_funcs) && notice_funcs[num]) {
+ check_ctcp(pd->user, un, pd->text, pd->is_qualified);
notice_funcs[num](pd->user, un, pd->text, pd->is_qualified);
}
}
}
+/* equiv to user doing /connect server port target */
+void irc_connect(struct userNode *user, char *server, unsigned int port, struct server *target)
+{
+ putsock("%s " P10_CONNECT " %s %d %s", user->numeric, server, port, target->numeric);
+}
+
+void
+irc_squit_route(struct server *srv, const char *message, ...)
+{
+ va_list arg_list;
+ char buffer[MAXLEN];
+ va_start(arg_list, message);
+ vsnprintf(buffer, MAXLEN-2, message, arg_list);
+ buffer[MAXLEN-1] = 0;
+
+ /* When would we squit ourselves exactly?? -Rubin */
+ if(srv == self && cManager.uplink->state == CONNECTED ) {
+ unsigned int i;
+
+ /* Quit all clients linked to me. */
+ for(i = 0; i <= self->num_mask; i++) {
+ if(!self->users[i])
+ continue;
+ irc_quit(self->users[i], buffer);
+ }
+ }
+
+ putsock("%s " P10_SQUIT " %s %d :%s", self->numeric, srv->name, 0, buffer);
+
+ if(srv == self) {
+ /* Force a reconnect to the currently selected server. */
+ cManager.uplink->tries = 0;
+ log_module(MAIN_LOG, LOG_INFO, "Squitting from uplink: %s", buffer);
+ close_socket();
+ }
+}
+
void
irc_server(struct server *srv)
{
inttobase64(extranum, srv->num_mask, (srv->numeric[1] || (srv->num_mask >= 64*64)) ? 3 : 2);
if (srv == self) {
- /* The +s, ignored by Run's ircu, means "service" to Undernet's ircu */
- putsock(P10_SERVER " %s %d %li %li J10 %s%s +s :%s",
- srv->name, srv->hops+1, srv->boot, srv->link, srv->numeric, extranum, srv->description);
+ putsock(P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " J10 %s%s +s6o :%s",
+ srv->name, srv->hops+1, srv->boot, srv->link_time, srv->numeric, extranum, srv->description);
+ } else {
+ putsock("%s " P10_SERVER " %s %d " FMT_TIME_T " " FMT_TIME_T " %c10 %s%s +s6o :%s",
+ self->numeric, srv->name, srv->hops+1, srv->boot, srv->link_time, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
+ }
+}
+
+void
+irc_p10_pton(irc_in_addr_t *ip, const char *input)
+{
+ if (strlen(input) == 6) {
+ unsigned int value;
+ memset(ip, 0, 6 * sizeof(ip->in6[0]));
+ value = base64toint(input, 6);
+ if (value)
+ ip->in6[5] = htons(65535);
+ ip->in6[6] = htons(value >> 16);
+ ip->in6[7] = htons(value & 65535);
+ } else {
+ unsigned int pos = 0;
+ do {
+ if (*input == '_') {
+ unsigned int left;
+ for (left = (25 - strlen(input)) / 3 - pos; left; left--)
+ ip->in6[pos++] = 0;
+ input++;
+ } else {
+ ip->in6[pos++] = ntohs(base64toint(input, 3));
+ input += 3;
+ }
+ } while (pos < 8);
+ }
+}
+
+void
+irc_p10_ntop(char *output, const irc_in_addr_t *ip)
+{
+ if (!irc_in_addr_is_valid(*ip)) {
+ strcpy(output, "AAAAAA");
+ } else if (irc_in_addr_is_ipv4(*ip)) {
+ unsigned int in4;
+ in4 = (ntohs(ip->in6[6]) << 16) | ntohs(ip->in6[7]);
+ inttobase64(output, in4, 6);
+ output[6] = '\0';
+ } else if (irc_in_addr_is_ipv6(*ip)) {
+ unsigned int max_start, max_zeros, curr_zeros, zero, ii;
+ /* Can start by printing out the leading non-zero parts. */
+ for (ii = 0; (ip->in6[ii]) && (ii < 8); ++ii) {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ /* Find the longest run of zeros. */
+ for (max_start = zero = ii, max_zeros = curr_zeros = 0; ii < 8; ++ii) {
+ if (!ip->in6[ii])
+ curr_zeros++;
+ else if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ }
+ if (curr_zeros > max_zeros) {
+ max_start = ii - curr_zeros;
+ max_zeros = curr_zeros;
+ curr_zeros = 0;
+ }
+ /* Print the rest of the address */
+ for (ii = zero; ii < 8; ) {
+ if ((ii == max_start) && max_zeros) {
+ *output++ = '_';
+ ii += max_zeros;
+ } else {
+ inttobase64(output, ntohs(ip->in6[ii]), 3);
+ output += 3;
+ }
+ }
+ *output = '\0';
} else {
- putsock("%s " P10_SERVER " %s %d %li %li %c10 %s%s +s :%s",
- self->numeric, srv->name, srv->hops+1, srv->boot, srv->link, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
+ strcpy(output, "???");
}
}
void
irc_user(struct userNode *user)
{
- char b64ip[7];
- if (!user)
+ char b64ip[25];
+ if (!user || IsDummy(user))
return;
- inttobase64(b64ip, ntohl(user->ip.s_addr), 6);
+ irc_p10_ntop(b64ip, &user->ip);
if (user->modes) {
- int modelen;
char modes[32];
- modelen = 0;
- if (IsOper(user))
- modes[modelen++] = 'o';
- if (IsInvisible(user))
- modes[modelen++] = 'i';
- if (IsWallOp(user))
- modes[modelen++] = 'w';
- if (IsService(user))
- modes[modelen++] = 'k';
- if (IsServNotice(user))
- modes[modelen++] = 's';
- if (IsDeaf(user))
- modes[modelen++] = 'd';
- if (IsGlobal(user))
- modes[modelen++] = 'g';
- // sethost - reed/apples
- // if (IsHelperIrcu(user))
- if (IsSetHost(user))
- modes[modelen++] = 'h';
- if (IsFakeHost(user))
- modes[modelen++] = 'f';
- if (IsHiddenHost(user))
- modes[modelen++] = 'x';
- modes[modelen] = 0;
-
+ irc_user_modes(user, modes, sizeof(modes));
/* we don't need to put the + in modes because it's in the format string. */
- putsock("%s " P10_NICK " %s %d %li %s %s +%s %s %s :%s",
+ putsock("%s " P10_NICK " %s %d " FMT_TIME_T " %s %s +%s %s %s :%s",
user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, modes, b64ip, user->numeric, user->info);
} else {
- putsock("%s " P10_NICK " %s %d %li %s %s %s %s :%s",
+ putsock("%s " P10_NICK " %s %d " FMT_TIME_T " %s %s %s %s :%s",
user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, b64ip, user->numeric, user->info);
}
}
+void
+irc_rename(struct userNode *user, const char *new_handle)
+{
+ if(extended_accounts)
+ putsock("%s " P10_ACCOUNT " %s M %s", self->numeric, user->numeric, new_handle);
+}
+
+void
+irc_delete(struct userNode *user)
+{
+ if(extended_accounts)
+ putsock("%s " P10_ACCOUNT " %s U", self->numeric, user->numeric);
+}
+
void
irc_account(struct userNode *user, const char *stamp, time_t timestamp)
{
- putsock("%s " P10_ACCOUNT " %s R %s %lu", self->numeric, user->numeric, stamp, timestamp);
+ if(extended_accounts)
+ putsock("%s " P10_ACCOUNT " %s R %s "FMT_TIME_T, self->numeric, user->numeric, stamp, timestamp);
+ else
+ putsock("%s " P10_ACCOUNT " %s %s "FMT_TIME_T, self->numeric, user->numeric, stamp, timestamp);
}
void
putsock("%s " P10_WALLCHOPS " %s :%s", from->numeric, to, message);
}
+void
+irc_wallops(const char *format, ...)
+{
+ va_list arg_list;
+ char buffer[MAXLEN];
+ va_start(arg_list, format);
+ vsnprintf(buffer, MAXLEN-2, format, arg_list);
+ buffer[MAXLEN-1] = 0;
+ putsock("%s " P10_WALLOPS " :%s", self->numeric, buffer);
+}
+
+static int
+deliver_to_dummy(struct userNode *source, struct userNode *dest, const char *message, int type)
+{
+ unsigned int num;
+
+ if (!dest || !IsDummy(dest) || !IsLocal(dest))
+ return 0;
+ num = dest->num_local;
+ switch (type) {
+ default:
+ if ((num < num_notice_funcs) && notice_funcs[num])
+ notice_funcs[num](source, dest, message, 0);
+ break;
+ case 1:
+ if ((num < num_privmsg_funcs) && privmsg_funcs[num])
+ privmsg_funcs[num](source, dest, message, 0);
+ break;
+ }
+ return 1;
+}
+
void
irc_notice(struct userNode *from, const char *to, const char *message)
{
- putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
+ if (to[0] == '#' || to[0] == '$'
+ || !deliver_to_dummy(from, GetUserN(to), message, 0))
+ putsock("%s " P10_NOTICE " %s :%s", from->numeric, to, message);
}
void
irc_notice_user(struct userNode *from, struct userNode *to, const char *message)
{
- putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
+ if (!deliver_to_dummy(from, to, message, 0))
+ putsock("%s " P10_NOTICE " %s :%s", from->numeric, to->numeric, message);
}
void
irc_privmsg(struct userNode *from, const char *to, const char *message)
{
- putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
+ if (to[0] == '#' || to[0] == '$'
+ || !deliver_to_dummy(from, GetUserN(to), message, 1))
+ putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
+}
+
+void
+irc_privmsg_user(struct userNode *from, struct userNode *to, const char *message)
+{
+ putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to->numeric, message);
+}
+
+void
+irc_version_user(struct userNode *from, struct userNode *to)
+{
+ irc_privmsg_user(from, to, "\001VERSION\001");
}
void
irc_eob_ack(void)
{
putsock("%s " P10_EOB_ACK, self->numeric);
+
+ char *nick;
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ nick = strdup(str);
+
+ if (nick && (DefConLevel < 5)) {
+ DefConProcess(GetUserH(nick));
+
+ if (DefConTimeOut > 0)
+ timeq_add(now + DefConTimeOut, defcon_timeout, NULL);
+ }
+}
+
+void
+irc_rpong(const char *from1, const char *from2, const char *pingtime, const char *clientinfo)
+{
+ putsock("%s " P10_RPONG " %s %s %s :%s", self->numeric, from1, from2, pingtime, clientinfo);
}
void
putsock("%s " P10_PONG " %s :%s", self->numeric, who, data);
}
+void
+irc_pong_asll(const char *who, const char *orig_ts)
+{
+ char *delim;
+ struct timeval orig;
+ struct timeval sys_now;
+ int diff;
+
+ orig.tv_sec = strtoul(orig_ts, &delim, 10);
+ orig.tv_usec = (*delim == '.') ? strtoul(delim + 1, NULL, 10) : 0;
+ gettimeofday(&sys_now, NULL);
+ diff = (sys_now.tv_sec - orig.tv_sec) * 1000 + (sys_now.tv_usec - orig.tv_usec) / 1000;
+ putsock("%s " P10_PONG " %s %s %d %lu.%06lu", self->numeric, who, orig_ts, diff, (unsigned long)sys_now.tv_sec, (unsigned long)sys_now.tv_usec);
+}
+
void
irc_pass(const char *passwd)
{
}
void
-irc_gline(struct server *srv, struct gline *gline)
+irc_gline(struct server *srv, struct gline *gline, int silent)
{
- putsock("%s " P10_GLINE " %s +%s %ld :<%s> %s",
- self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->issuer, gline->reason);
+ putsock("%s " P10_GLINE " %s +%s " FMT_TIME_T " " FMT_TIME_T " :%s<%s> %s",
+ self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, now, silent ? "AUTO " : "", gline->issuer, gline->reason);
+}
+
+void
+irc_shun(struct server *srv, struct shun *shun)
+{
+ putsock("%s " P10_SHUN " %s +%s " FMT_TIME_T " " FMT_TIME_T " :<%s> %s",
+ self->numeric, (srv ? srv->numeric : "*"), shun->target, shun->expires-now, now, shun->issuer, shun->reason);
}
void
void
irc_ungline(const char *mask)
{
- putsock("%s " P10_GLINE " * -%s", self->numeric, mask);
+ putsock("%s " P10_GLINE " * -%s " FMT_TIME_T, self->numeric, mask, now);
}
-static void
+void
+irc_unshun(const char *mask)
+{
+ putsock("%s " P10_SHUN " * -%s " FMT_TIME_T, self->numeric, mask, now);
+}
+
+void
irc_burst(struct chanNode *chan)
{
char burst_line[512];
struct banNode *bn;
struct exemptNode *en;
long last_mode=-1;
+ unsigned int first_ban;
+ unsigned int first_exempt;
unsigned int n;
base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ",
self->numeric, chan->name, chan->timestamp);
len = irc_make_chanmode(chan, burst_line+base_len);
pos = base_len + len;
- if (len)
+ if (len > 0 && chan->members.used > 0)
burst_line[pos++] = ' ';
+ if(chan->members.used < 1)
+ return; /* dont burst empty channels (created by discrims) */
/* dump the users */
for (n=0; n<chan->members.used; n++) {
mn = chan->members.list[n];
pos = base_len;
last_mode = -1;
}
+
memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric));
pos += strlen(mn->user->numeric);
if (mn->modes && (mn->modes != last_mode)) {
if ((n+1)<chan->members.used)
burst_line[pos++] = ',';
}
+
+ if (len > 0 && (chan->banlist.used > 0 || chan->exemptlist.used > 0))
+ burst_line[pos++] = ' ';
+
if (chan->banlist.used) {
/* dump the bans */
- if (pos+2+strlen(chan->banlist.list[0]->ban) > 505) {
- burst_line[pos-1] = 0;
- putsock("%s", burst_line);
- pos = base_len;
- } else {
- burst_line[pos++] = ' ';
- }
+ first_ban = 1;
- burst_line[pos++] = ':';
- burst_line[pos++] = '%';
- base_len = pos;
- for (n=0; n<chan->banlist.used; n++) {
+ for (n=0; n<chan->banlist.used; ) {
+ if (first_ban && (pos < 500)) {
+ burst_line[pos++] = ':';
+ burst_line[pos++] = '%';
+ }
bn = chan->banlist.list[n];
len = strlen(bn->ban);
- if (pos+len+1 > 510) {
- burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
+ if (pos + 2 + len < 505) {
+ memcpy(burst_line + pos, bn->ban, len);
+ pos += len;
+ burst_line[pos++] = ' ';
+ first_ban = 0;
+ n++;
+ } else {
+ burst_line[pos-1] = 0;
putsock("%s", burst_line);
pos = base_len;
+ first_ban = 1;
}
- memcpy(burst_line+pos, bn->ban, len);
- pos += len;
- burst_line[pos++] = ' ';
}
}
- if (chan->exemptlist.used) {
- /* dump the exempt */
- if (pos+2+strlen(chan->exemptlist.list[0]->exempt) > 505) {
- burst_line[pos-1] = 0;
- putsock("%s", burst_line);
- pos = base_len;
- } else {
- burst_line[pos++] = ' ';
- }
- burst_line[pos++] = ' ';
- burst_line[pos++] = '~';
- burst_line[pos++] = ' ';
- base_len = pos;
- for (n=0; n<chan->exemptlist.used; n++) {
+ if (chan->exemptlist.used) {
+ /* dump the exempts */
+ first_exempt = 1;
+
+ for (n=0; n<chan->exemptlist.used; ) {
+ if (first_exempt && (pos < 500)) {
+ if (chan->banlist.used < 1) {
+ burst_line[pos++] = ':';
+ burst_line[pos++] = '%';
+ burst_line[pos++] = ' ';
+ }
+ burst_line[pos++] = '~';
+ burst_line[pos++] = ' ';
+ }
en = chan->exemptlist.list[n];
len = strlen(en->exempt);
- if (pos+len+1 > 510) {
- burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
+ if (pos + 2 + len < 505) {
+ memcpy(burst_line + pos, en->exempt, len);
+ pos += len;
+ burst_line[pos++] = ' ';
+ first_exempt = 0;
+ n++;
+ } else {
+ burst_line[pos-1] = 0;
putsock("%s", burst_line);
pos = base_len;
+ first_exempt = 1;
}
- memcpy(burst_line+pos, en->exempt, len);
- pos += len;
- burst_line[pos++] = ' ';
}
}
/* print the last line */
void
irc_mode(struct userNode *from, struct chanNode *target, const char *modes)
{
+ call_channel_mode_funcs(from, target, (char **)&modes, 0);
putsock("%s " P10_MODE " %s %s "FMT_TIME_T,
(from ? from->numeric : self->numeric),
target->name, modes, target->timestamp);
}
+/* Added to allow services to mode users
+ 2005 - 8 - 10 by Life4Christ
+*/
+void
+irc_umode(struct userNode *target, const char *modes)
+{
+ putsock("%s " P10_MODE " %s %s ",self->numeric,target->nick, modes);
+}
+
+
void
irc_invite(struct userNode *from, struct userNode *who, struct chanNode *to)
{
putsock("%s " P10_INVITE " %s %s", from->numeric, who->nick, to->name);
}
+void
+irc_silence(struct userNode *who, const char *mask, int add)
+{
+ putsock("%s " P10_SILENCE " %s %s%s", self->numeric, who->numeric, add ? "+" : "-", mask);
+}
+
void
irc_join(struct userNode *who, struct chanNode *what)
{
if (what->members.used == 1) {
- putsock("%s " P10_CREATE " %s %lu",
+ putsock("%s " P10_CREATE " %s "FMT_TIME_T,
who->numeric, what->name, what->timestamp);
} else {
- putsock("%s " P10_JOIN " %s %lu", who->numeric, what->name, what->timestamp);
+ putsock("%s " P10_JOIN " %s "FMT_TIME_T, who->numeric, what->name, what->timestamp);
}
}
+void
+irc_svsjoin(struct userNode *from, struct userNode *who, struct chanNode *to)
+{
+ putsock("%s " P10_SVSJOIN " %s %s "FMT_TIME_T, from->uplink->numeric, who->numeric, to->name, now);
+}
+
+void
+irc_svspart(struct userNode *from, struct userNode *who, struct chanNode *to)
+{
+ putsock("%s " P10_SVSPART " %s %s", from->uplink->numeric, who->numeric, to->name);
+}
+
+void
+irc_svsquit(struct userNode *from, struct userNode *who, char const *reason)
+{
+ putsock("%s " P10_SVSQUIT " %s :%s", from->uplink->numeric, who->numeric, reason);
+}
+
void
irc_kick(struct userNode *who, struct userNode *target, struct chanNode *channel, const char *msg)
{
putsock("%s " P10_SVSNICK " %s %s "FMT_TIME_T, from->uplink->numeric, target->numeric, newnick, now);
}
+void
+irc_swhois(struct userNode *from, struct userNode *target, const char *message)
+{
+ putsock("%s " P10_SWHOIS " %s %s%s", from->uplink->numeric, target->numeric, message ? ":" : "",
+ message ? message : "");
+
+}
+
void
irc_part(struct userNode *who, struct chanNode *what, const char *reason)
{
}
void
-irc_topic(struct userNode *who, struct chanNode *what, const char *topic)
-{
- putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic);
+irc_topic(struct userNode *service, struct userNode *who, struct chanNode *what, const char *topic)
+{
+
+ int type = 4, host_in_topic = 0, hasident = 0, hhtype = 0;
+ const char *hstr, *tstr, *hhstr, *htstr;
+ char *host, *hostmask;
+ char shost[MAXLEN];
+ char sident[MAXLEN];
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ hstr = conf_get_data("server/host_in_topic", RECDB_QSTRING);
+ hhstr = conf_get_data("server/hidden_host", RECDB_QSTRING);
+ htstr = conf_get_data("server/hidden_host_type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+ else
+ type = 4;/* default to 040 style topics */
+ if (htstr)
+ hhtype = atoi(htstr);
+
+ if (hstr) {
+ if (IsHiddenHost(who) && IsFakeHost(who))
+ safestrncpy(shost, who->fakehost, sizeof(shost));
+ else if (IsHiddenHost(who) && IsSetHost(who)) {
+ hostmask = strdup(who->sethost);
+ if ((host = (strrchr(hostmask, '@')))) {
+ hasident = 1;
+ *host++ = '\0';
+ } else
+ host = hostmask;
+
+ if (hasident)
+ safestrncpy(sident, hostmask, sizeof(shost));
+ else
+ safestrncpy(sident, who->ident, sizeof(shost));
+
+ safestrncpy(shost, host, sizeof(shost));
+ } else if (IsHiddenHost(who) && ((hhtype == 1) || (hhtype == 3)) && who->handle_info && hhstr) {
+ snprintf(shost, sizeof(shost), "%s.%s", who->handle_info->handle, hhstr);
+ } else if (IsHiddenHost(who) && ((hhtype == 2) || (hhtype == 3)) && who->crypthost[0]) {
+ safestrncpy(shost, who->crypthost, sizeof(shost));
+ } else
+ safestrncpy(shost, who->hostname, sizeof(shost));
+
+ host_in_topic = atoi(hstr);
+ }
+
+ if (type >= 5) {
+ putsock("%s " P10_TOPIC " %s %s%s%s%s%s " FMT_TIME_T " " FMT_TIME_T " :%s", service->numeric, what->name,
+ who->nick, host_in_topic ? "!" : "", host_in_topic ? (IsSetHost(who) ? sident : who->ident) : "",
+ host_in_topic ? "@" : "", host_in_topic ? shost : "", what->timestamp, now, topic);
+ } else {
+ who = service;
+ putsock("%s " P10_TOPIC " %s :%s", who->numeric, what->name, topic);
+ }
}
void
putsock(":%s %03d %s %s", self->name, num, user->nick, buffer);
}
+void
+irc_mark(struct userNode *user, char *mark)
+{
+ char *host = user->hostname;
+ int type = 4;
+ const char *tstr = NULL;
+ unsigned int ii = 0;
+ int markfound = 0;
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+ else
+ type = 4;
+
+ if (user->marks)
+ for (ii=0; ii<user->marks->used; ii++)
+ if (!irccasecmp(user->marks->list[ii], mark))
+ markfound = 1;
+
+ if (!markfound)
+ {
+ if (!user->marks)
+ user->marks = alloc_string_list(1);
+ string_list_append(user->marks, strdup(mark));
+ }
+
+ if (type >= 9)
+ {
+ putsock("%s " CMD_MARK " %s MARK %s", self->numeric, user->nick, mark);
+ return;
+ }
+
+ /* TODO: Allow mark overwrite. If they are marked, and their fakehost is oldmark.hostname, update it to newmark.hostname so mark can be called multiple times. Probably requires ircd modification also */
+ if(user->mark)
+ return;
+
+ /* if the mark will put us over the host length, clip some off the left hand side
+ * to make room...
+ */
+ if(strlen(host) + 1 + strlen(mark) > HOSTLEN)
+ host += 1 + ( (strlen(host) + 1 + strlen(mark)) - HOSTLEN );
+ putsock("%s " CMD_MARK " %s DNSBL +m %s.%s", self->numeric, user->nick, mark, host);
+ putsock("%s " CMD_MARK " %s DNSBL_DATA %s", self->numeric, user->nick, mark);
+
+ /* Save it in the user */
+ user->mark = strdup(mark);
+
+ /* If they are not otherwise marked, mark their host with fakehost */
+ if(!IsFakeHost(user) && !IsSetHost(user) && !(IsHiddenHost(user) && user->handle_info) )
+ {
+ struct modeNode *mn = NULL;
+ char fakehost[HOSTLEN];
+ unsigned int count = 0;
+ unsigned int n = 0;
+
+ putsock("%s " CMD_FAKEHOST " %s %s.%s", self->numeric, user->numeric, mark, host);
+ putsock("%s " CMD_MODE " %s +x", self->numeric, user->nick);
+
+ snprintf(fakehost, sizeof(fakehost), "%s.%s", mark, host);
+ safestrncpy(user->fakehost, fakehost, sizeof(user->fakehost));
+
+ for (n=count=0; n<user->channels.used; n++) {
+ mn = user->channels.list[n];
+ if (strlen(mn->channel->name) >= 1) /* Sanity */
+ check_bans(user, mn->channel->name);
+ }
+ }
+}
+
+void irc_sno(unsigned int mask, char const* format, ...) {
+ va_list arg_list;
+ char buffer[MAXLEN];
+ va_start(arg_list, format);
+ vsnprintf(buffer, MAXLEN-2, format, arg_list);
+ buffer[MAXLEN-1] = 0;
+ putsock("%s " CMD_SNO " %d :%s", self->numeric, mask, buffer);
+}
+
+void
+irc_sasl(struct server* dest, const char *identifier, const char *subcmd, const char *data)
+{
+ putsock("%s " P10_SASL " %s %s %s %s", self->numeric, dest->numeric, identifier, subcmd, data);
+}
+
static void send_burst(void);
static void
{
struct userNode *from;
struct userNode *who;
+ char buf[MAXLEN];
+ unsigned int i, mlen, len;
if (argc < 3)
return 0;
log_module(MAIN_LOG, LOG_ERROR, "Could not find WHOIS origin user %s", origin);
return 0;
}
- if(!(who = GetUserH(argv[2]))) {
+ if (!(who = GetUserH(argv[2]))) {
irc_numeric(from, ERR_NOSUCHNICK, "%s@%s :No such nick", argv[2], self->name);
return 1;
}
- if (IsHiddenHost(who) && !IsOper(from)) {
- /* Just stay quiet. */
- return 1;
+
+ if (IsFakeHost(who) && IsHiddenHost(who))
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->fakehost, who->info);
+ else if (IsHiddenHost(who) && who->handle_info && hidden_host_suffix)
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s.%s * :%s", who->nick, who->ident, who->handle_info->handle, hidden_host_suffix, who->info);
+ else
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
+
+ if (!IsService(who) || (from == who)) {
+ struct modeNode *mn;
+ mlen = strlen(self->name) + strlen(from->nick) + 12 + strlen(who->nick);
+ len = 0;
+ *buf = '\0';
+ for (i = who->channels.used; i > 0; )
+ {
+ mn = who->channels.list[--i];
+
+ if (!IsOper(from) && (mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from))
+ continue;
+
+ if (len + strlen(mn->channel->name) + mlen > MAXLEN - 5)
+ {
+ irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf);
+ *buf = '\0';
+ len = 0;
+ }
+
+ if (IsDeaf(who))
+ *(buf + len++) = '-';
+ if ((mn->channel->modes & (MODE_PRIVATE | MODE_SECRET)) && !GetUserMode(mn->channel, from))
+ *(buf + len++) = '*';
+ if (mn->modes & MODE_CHANOP)
+ *(buf + len++) = '@';
+ else if (mn->modes & MODE_HALFOP)
+ *(buf + len++) = '%';
+ else if (mn->modes & MODE_VOICE)
+ *(buf + len++) = '+';
+
+ if (len)
+ *(buf + len) = '\0';
+ strcpy(buf + len, mn->channel->name);
+ len += strlen(mn->channel->name);
+ strcat(buf + len, " ");
+ len++;
+ }
+ if (buf[0] != '\0')
+ irc_numeric(from, RPL_WHOISCHANNELS, "%s :%s", who->nick, buf);
}
- irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->ident, who->hostname, who->info);
- if (his_servername && his_servercomment)
+
+ if (his_servername && his_servercomment && !IsOper(from) && from != who)
irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, his_servername, his_servercomment);
else
irc_numeric(from, RPL_WHOISSERVER, "%s %s :%s", who->nick, who->uplink->name, who->uplink->description);
+
+ if (IsAway(who))
+ irc_numeric(from, RPL_AWAY, "%s :Away", who->nick);
if (IsOper(who))
- irc_numeric(from, RPL_WHOISOPERATOR, "%s :is a megalomaniacal power hungry tyrant", who->nick);
+ irc_numeric(from, RPL_WHOISOPERATOR, "%s :%s", who->nick, IsLocal(who) ? "is a megalomaniacal power hungry tyrant" : "is an IRC Operator");
+ if (who->handle_info)
+ irc_numeric(from, RPL_WHOISACCOUNT, "%s %s :is logged in as", who->nick, who->handle_info->handle);
+ if (IsHiddenHost(who) && who->handle_info && (IsOper(from) || from == who))
+ irc_numeric(from, RPL_WHOISACTUALLY, "%s %s@%s %s :Actual user@host, Actual IP", who->nick, who->ident, who->hostname, irc_ntoa(&who->ip));
+ if (IsLocal(who) && !IsService(who) && (IsOper(from) || from == who))
+ irc_numeric(from, RPL_WHOISIDLE, "%s %ld %ld :seconds idle, signon time", who->nick, now - who->idle_since, who->timestamp);
+
irc_numeric(from, RPL_ENDOFWHOIS, "%s :End of /WHOIS list", who->nick);
return 1;
}
* Alternately, we are same age, but we accept their time
* since we are linking to them. */
self->boot = srv->boot;
- ioset_set_time(srv->link);
+ ioset_set_time(srv->link_time
+);
}
}
if (srv == self->uplink) {
return 1;
}
+
static CMD_FUNC(cmd_eob)
{
struct server *sender;
dict_iterator_t it;
- unsigned int ii;
if (!(sender = GetServerH(origin)))
return 0;
unbursted_channels = NULL;
irc_eob();
irc_eob_ack();
+
+ /* now that we know who our uplink is,
+ * we can center the routing map and activate auto-routing.
+ */
+ //activate_routing(NULL, NULL, NULL);
+ routing_init();
}
sender->self_burst = 0;
recalc_bursts(sender);
- for (ii=0; ii<slf_used; ii++)
- slf_list[ii](sender);
+ call_server_link_funcs(sender);
+ /* let auto-routing figure out if we were
+ * wating on this server to link a child to it */
+ /* DONT call this if uplink is _US_ */
+ if(sender->uplink != self)
+ routing_handle_connect(sender->name, sender->uplink->name);
return 1;
}
return 1;
}
+static CMD_FUNC(cmd_rping)
+{
+ struct server *dest;
+
+ if (!(dest = GetServerN(argv[1])))
+ return 1; /* if its a jupe or something, return 1 so its silently ignored */
+
+ if (dest == self)
+ irc_rpong(argv[2], argv[3], argv[4], argv[5]);
+
+ return 1;
+}
+
+static CMD_FUNC(cmd_sasl)
+{
+ struct server *serv;
+
+ if (argc < 5)
+ return 0;
+
+ serv = GetServerH(origin);
+ if (!serv)
+ return 0;
+
+ call_sasl_input_func(serv, argv[2], argv[3], argv[4], (argc>5 ? argv[5] : NULL));
+
+ return 1;
+}
+
static CMD_FUNC(cmd_ping)
{
struct server *srv;
struct userNode *un;
- if(argc > 3)
- irc_pong(argv[2], argv[1]);
+ if (argc > 3)
+ irc_pong_asll(argv[2], argv[3]);
else if ((srv = GetServerH(origin)))
irc_pong(self->name, srv->numeric);
else if ((un = GetUserH(origin)))
return 1;
}
+static CMD_FUNC(cmd_svsjoin)
+{
+ struct create_desc cd;
+
+ if (!(cd.user = GetUserH(argv[1])))
+ return 0;
+ if (argc < 3)
+ return 0;
+ else if (argc < 4)
+ cd.when = now;
+ else
+ cd.when = atoi(argv[3]);
+ parse_foreach(argv[2], join_helper, create_helper, NULL, NULL, &cd);
+ return 1;
+}
+
static CMD_FUNC(cmd_pong)
{
if (argc < 3)
NickChange(user, argv[1], 1);
} else {
struct server *serv;
+ struct userNode *nuser;
char modes[MAXLEN];
/* new nick */
if (argc < 9)
unsplit_string(argv+6, argc-9, modes);
else
strcpy(modes, "+");
- AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]);
+ nuser = AddUser(serv, argv[1], argv[4], argv[5], modes, argv[argc-2], argv[argc-1], atoi(argv[3]), argv[argc-3]);
}
return 1;
}
user = GetUserN(argv[1]);
if (!user)
return 1; /* A QUIT probably passed the ACCOUNT. */
+
+ if(!extended_accounts) /* any need for this function without? */
+ return 1;
if(!strcmp(argv[2],"C"))
{
- if((hi = loc_auth(argv[4], argv[5])))
+ if((hi = loc_auth(NULL, argv[4], argv[5], NULL)))
{
/* Return a AC A */
- putsock("%s " P10_ACCOUNT " %s A %s %lu", self->numeric, server->numeric , argv[3], hi->registered);
+ putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
+ log_module(MAIN_LOG, LOG_DEBUG, "loc_auth: %s\n", user->nick);
+ }
+ else
+ {
+ /* Return a AC D */
+ putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]);
+ }
+ return 1;
+ }
+ else if(!strcmp(argv[2],"H")) /* New enhanced (host) version of C */
+ {
+ if((hi = loc_auth(NULL, argv[5], argv[6], argv[4] )))
+ {
+ /* Return a AC A */
+ putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
+ }
+ else
+ {
+ /* Return a AC D */
+ putsock("%s " P10_ACCOUNT " %s D %s", self->numeric, server->numeric , argv[3]);
+ }
+ return 1;
+ }
+ else if(!strcmp(argv[2],"S"))
+ {
+ if((hi = loc_auth(argv[5], argv[6], argv[7], argv[4])))
+ {
+ /* Return a AC A */
+ putsock("%s " P10_ACCOUNT " %s A %s "FMT_TIME_T, self->numeric, server->numeric , argv[3], hi->registered);
}
else
{
return 1;
}
+static struct {
+ char *name;
+ unsigned int priv;
+} privtab[] = {
+#define P(priv) { #priv, PRIV_ ## priv }
+ P(CHAN_LIMIT), P(MODE_LCHAN), P(WALK_LCHAN), P(DEOP_LCHAN),
+ P(SHOW_INVIS), P(SHOW_ALL_INVIS), P(UNLIMIT_QUERY), P(KILL),
+ P(LOCAL_KILL), P(REHASH), P(RESTART), P(DIE),
+ P(GLINE), P(LOCAL_GLINE), P(JUPE), P(LOCAL_JUPE),
+ P(OPMODE), P(LOCAL_OPMODE), P(SET), P(WHOX),
+ P(BADCHAN), P(LOCAL_BADCHAN), P(SEE_CHAN), P(PROPAGATE),
+ P(DISPLAY), P(SEE_OPERS), P(WIDE_GLINE), P(FORCE_OPMODE),
+ P(FORCE_LOCAL_OPMODE), P(REMOTEREHASH), P(CHECK), P(SEE_SECRET_CHAN),
+ P(SHUN), P(LOCAL_SHUN), P(WIDE_SHUN), P(ZLINE),
+ P(LOCAL_ZLINE), P(WIDE_ZLINE), P(LIST_CHAN), P(WHOIS_NOTICE),
+ P(HIDE_IDLE), P(XTRAOP), P(HIDE_CHANNELS), P(DISPLAY_MODE),
+ P(FREEFORM), P(REMOVE), P(SPAMFILTER),
+#undef P
+ { 0, 0 }
+};
+
+char *client_report_privs(struct userNode *client)
+{
+ int i;
+
+ privbuf[0] = '\0';
+ for (i = 0; privtab[i].name; i++) {
+ if (HasPriv(client, privtab[i].priv)) {
+ strcat(privbuf, privtab[i].name);
+ strcat(privbuf, " ");
+ }
+ }
+
+ privbuf[strlen(privbuf)] = 0;
+
+ return privbuf;
+}
+
+int clear_privs(struct userNode *who) {
+ int i = 0;
+ assert(0 != who);
+
+ for (i = 0; privtab[i].name; i++)
+ RevokePriv(who, privtab[i].priv);
+
+ return 0;
+}
+
+int client_modify_priv_by_name(struct userNode *who, char *priv, int what) {
+ int i = 0;
+ assert(0 != priv);
+ assert(0 != who);
+
+ for (i = 0; privtab[i].name; i++) {
+ if (0 == strcmp(privtab[i].name, priv)) {
+ if (what == PRIV_ADD)
+ GrantPriv(who, privtab[i].priv);
+ else if (what == PRIV_DEL) {
+ RevokePriv(who, privtab[i].priv);
+ }
+ }
+ }
+ return 0;
+}
+
+int check_priv(char *priv)
+{
+ int i;
+
+ for (i = 0; privtab[i].name; i++) {
+ if (0 == strcmp(privtab[i].name, priv)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void
+irc_privs(struct userNode *target, char *flag, int add)
+{
+ client_modify_priv_by_name(target, flag, add);
+ putsock("%s " P10_PRIVS " %s %s%s", self->numeric, target->numeric, (add == PRIV_ADD) ? "+" : "-", flag);
+}
+
+void
+irc_raw_privs(struct userNode *target, const char *privs)
+{
+ putsock("%s " P10_PRIVS " %s %s", self->numeric, target->numeric, privs);
+}
+
+static CMD_FUNC(cmd_privs)
+{
+ char *tstr = NULL;
+ char buf[512] = "";
+ char *p = 0;
+ char *tmp;
+
+ int what = PRIV_ADD;
+ int type = 0;
+
+ unsigned int i;
+
+ struct server *sender;
+ struct userNode *user;
+
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+
+
+ if (!(sender = GetServerH(origin))) { /* from oper */
+ return 1; /* ignore as no services have privs set */
+ } else { /* from server */
+ if (type < 5)
+ return 1; /* silently ignore */
+
+ user = argc > 1 ? GetUserN(argv[1]) : NULL;
+
+ if (!user)
+ return 0;
+
+ for (i=1; i<argc; i++) {
+ strcat(buf, argv[i]);
+ strcat(buf, " ");
+ }
+
+ for (i = 2; i < argc; i++) {
+ if (*argv[i] == '+') { what = PRIV_ADD; argv[i]++; }
+ if (*argv[i] == '-') { what = PRIV_DEL; argv[i]++; }
+ for (tmp = x3_strtok(&p, argv[i], ","); tmp;
+ tmp = x3_strtok(&p, NULL, ",")) {
+ if (!strcmp(tmp, "PRIV_NONE")) {
+ if (now > user->timestamp+5)
+ clear_privs(user);
+ break;
+ } else
+ client_modify_priv_by_name(user, tmp, what);
+ }
+ }
+ }
+ return 1;
+}
+
static CMD_FUNC(cmd_burst)
{
extern int rel_age;
static char exemptlist[MAXLEN], banlist[MAXLEN];
unsigned int next = 3, res = 1;
int ctype = 0, echeck = 0, bcheck = 0;
+ struct chanData *cData;
struct chanNode *cNode;
struct userNode *un;
struct modeNode *mNode;
long mode;
+ int oplevel = -1;
+ int type = 0;
char *user, *end, sep;
+ char *tstr;
time_t in_timestamp;
char* parm = NULL;
return 0;
modes[0] = 0;
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr) {
+ type = atoi(tstr);
+ }
+
exemptlist[0] = 0;
banlist[0] = 0;
const char *pos;
int n_modes;
for (pos=argv[next], n_modes = 1; *pos; pos++)
- if ((*pos == 'k') || (*pos == 'l'))
+ if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
+ || (*pos == 'U') || ((type > 7) && (*pos == 'L')))
n_modes++;
+ if (next + n_modes > argc)
+ n_modes = argc - next;
unsplit_string(argv+next, n_modes, modes);
next += n_modes;
break;
}
case '%': {
+ ctype = 1;
for(parm = mysep(&argv[next], " "); /* parm = first param */
parm; /* While param is not null */
parm = mysep(&argv[next], " ") /* parm = next param */
)
{
- switch (parm[0]) {
- case '%': {
- ctype = 1;
- break;
- }
- case '~': {
- ctype = 2;
- break;
- }
- default: {
- break;
- }
- }
+ if (0 == strcmp("~", parm))
+ ctype = 2;
if (ctype == 1) {
if (bcheck == 0) {
/* strip % char off start of very first ban */
irc_burst(cNode);
}
cNode = AddChannel(argv[1], in_timestamp, modes, banlist, exemptlist);
+ cData = cNode->channel_info;
+
+ if (!cData) {
+ if (cNode->modes & MODE_REGISTERED) {
+ irc_join(opserv, cNode);
+ irc_mode(opserv, cNode, "-z");
+ irc_part(opserv, cNode, "");
+ }
+ }
/* Burst channel members in now. */
for (user = members, sep = *members, mode = 0; sep; user = end) {
if (sep == ':') {
mode = 0;
while ((sep = *end++)) {
- if (sep == 'o')
+ if (sep == 'o') {
mode |= MODE_CHANOP;
- else if (sep == 'h')
+ oplevel = -1;
+ } else if (sep == 'h') {
mode |= MODE_HALFOP;
- else if (sep == 'v')
+ oplevel = -1;
+ } else if (sep == 'v') {
mode |= MODE_VOICE;
- else if (isdigit(sep)) {
+ oplevel = -1;
+ } else if (isdigit(sep)) {
mode |= MODE_CHANOP;
+ if (oplevel >= 0)
+ oplevel += parse_oplevel(end);
+ else
+ oplevel = parse_oplevel(end);
while (isdigit(*end)) end++;
} else
break;
if (rel_age < 0)
mode = 0;
}
- if (!(un = GetUserN(user))) {
- res = 0;
- continue;
+ if (!(un = GetUserN(user))) {
+ res = 0;
+ continue;
+ }
+ if ((mNode = AddChannelUser(un, cNode))) {
+ mNode->modes = mode;
+ mNode->oplevel = oplevel;
+ }
+ }
+
+ return res;
+}
+
+/* TODO:
+ * This is a stub that doesn't actually do anything. It should be completed
+ * so that bans on *!*@markname.* match users as it does in nefarious
+ */
+static CMD_FUNC(cmd_mark)
+{
+ const char *tstr;
+ int type = 4;
+ struct userNode *target;
+ /*
+ * log_module(MAIN_LOG, LOG_ERROR, "DEBUG: mark, user %s, type %s, arg %s", argv[1], argv[2], argv[3]);
+ */
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ if(tstr)
+ type = atoi(tstr);
+ else
+ type = 4;/* default to 040 style topics */
+
+ if(argc < 4)
+ return 0;
+ if(!strcasecmp(argv[2], "DNSBL")) {
+ /* DNSBL <modes> */
+ return 1;
+ }
+ else if(!strcasecmp(argv[2], "DNSBL_DATA") || !strcasecmp(argv[2], "MARK")) {
+ int markfound = 0;
+ unsigned int ii = 0;
+ /* DNSBL_DATA name */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose dnsbl mark is changing.", argv[1]);
+ return 0;
+ }
+ if (type >= 9) {
+ if (target->marks)
+ for (ii=0; ii<target->marks->used; ii++)
+ if (!irccasecmp(target->marks->list[ii], argv[3]))
+ markfound = 1;
+ if (!markfound)
+ {
+ if (!target->marks)
+ target->marks = alloc_string_list(1);
+ string_list_append(target->marks, strdup(argv[3]));
+ }
+ } else
+ target->mark = strdup(argv[3]);
+ return 1;
+
+ }
+ else if(!strcasecmp(argv[2], "CVERSION")) {
+ /* CTCP VERSION mark */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose version mark is changing.", argv[1]);
+ return 0;
}
- if ((mNode = AddChannelUser(un, cNode)))
- mNode->modes = mode;
+
+ char *version = unsplit_string(argv + 3, argc - 3, NULL);
+ if(!version)
+ version = "";
+
+ target->version_reply = strdup(version);
+
+ if(match_ircglob(version, "WebTV;*"))
+ target->no_notice = true; /* webbies cant see notices */
+
+ return 1;
}
+ else if(!strcasecmp(argv[2], "SSLCLIFP")) {
+ /* SSL fingerprint mark */
+ target = GetUserH(argv[1]);
+ if(!target) {
+ log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose SSL fingerprint mark is changing.", argv[1]);
+ return 0;
+ }
- return res;
+ char *sslfp = unsplit_string(argv + 3, argc - 3, NULL);
+ if(!sslfp)
+ sslfp = "";
+
+ target->sslfp = strdup(sslfp);
+
+ return 1;
+ }
+ /* unknown type of mark */
+ return 1;
}
static CMD_FUNC(cmd_mode)
cn->timestamp = atoi(argv[argc-1]);
}
+ if (checkDefCon(DEFCON_NO_MODE_CHANGE) && !IsOper(un)) {
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ if (str) {
+ char modes[MODELEN];
+ struct userNode *opserv = GetUserH(str);
+
+ send_message_type(4, un, opserv, "Channel modes cannot be changed due to DefCon level %d in effect, please try again soon", DefConLevel);
+ irc_make_chanmode(cn, modes);
+ irc_mode(opserv, cn, modes);
+ irc_mode(opserv, cn, DefConChanModes);
+ }
+ return 1;
+ }
+
+
return mod_chanmode(un, cn, argv+2, argc-2, MCP_ALLOW_OVB|MCP_FROM_SERVER|(un ? MC_NOTIFY : 0));
}
{
struct chanNode *cn;
time_t chan_ts, topic_ts;
+ struct userNode *user;
if (argc < 3)
return 0;
log_module(MAIN_LOG, LOG_ERROR, "Unable to find channel %s whose topic is being set", argv[1]);
return 0;
}
- if (argc >= 5) {
- /* Looks like an Asuka style topic burst. */
+
+
+ if (argc == 5) { /* Asuka / Topic Bursting IRCu's */
+ user = GetUserH(origin);
chan_ts = atoi(argv[2]);
topic_ts = atoi(argv[3]);
- } else {
+ } else if (argc >= 6) { /* Nefarious 0.5.0 */
+ user = GetUserH(strtok(argv[2], "!"));
+ chan_ts = atoi(argv[3]);
+ topic_ts = atoi(argv[4]);
+ } else { /* Regular IRCu (No Topic Bursting)*/
+ user = GetUserH(origin);
chan_ts = cn->timestamp;
topic_ts = now;
}
- SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0);
+
+ SetChannelTopic(cn, user, user, argv[argc-1], 0);
cn->topic_time = topic_ts;
return 1;
}
static CMD_FUNC(cmd_num_gline)
{
- if (argc < 6)
- return 0;
- gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0);
+ if (argc < 7) {
+ if (argc < 6)
+ return 0;
+ else
+ gline_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0, 0);
+ } else {
+ if (!strcmp(argv[5], "+"))
+ gline_add(origin, argv[3], atoi(argv[4])-now, argv[6], now, 0, 0);
+ }
+ return 1;
+}
+
+static CMD_FUNC(cmd_num_shun)
+{
+ if (argc < 7) {
+ if (argc < 6)
+ return 0;
+ else
+ shun_add(origin, argv[3], atoi(argv[4])-now, argv[5], now, 0);
+ } else {
+ if (!strcmp(argv[5], "+"))
+ shun_add(origin, argv[3], atoi(argv[4])-now, argv[6], now, 0);
+ }
return 1;
}
* Ghost response to a KILL we sent out earlier. So we only
* whine if the target is local.
*/
- if (!strncmp(argv[1], self->numeric, strlen(self->numeric)))
+ if (!strncmp(argv[1], self->numeric, strlen(self->numeric))) {
log_module(MAIN_LOG, LOG_ERROR, "Unable to find kill victim %s", argv[1]);
- return 0;
+ return 0;
+ }
+ return 1;
}
if (IsLocal(user) && IsService(user)) {
return 1;
}
-static CMD_FUNC(cmd_part)
+static CMD_FUNC(cmd_svspart)
+{
+ struct userNode *user;
+
+ if (argc < 3)
+ return 0;
+ user = GetUserN(argv[1]);
+ if (!user)
+ return 0;
+ parse_foreach(argv[2], part_helper, NULL, NULL, NULL, user);
+ return 1;
+}
+
+static CMD_FUNC(cmd_silence)
{
struct userNode *user;
+ char *mask;
+ char *new_mask;
+ unsigned int i;
if (argc < 2)
return 0;
- user = GetUserH(origin);
+
+ user = GetUserN(argv[1]);
+
+ /* Sanity, go nuts if this happens */
if (!user)
return 0;
- parse_foreach(argv[1], part_helper, NULL, NULL, NULL, user);
+
+ /* We can safely ignore this if a user adding a silence is not
+ * ignored. However this brings up a TODO. If a user logs in and
+ * they have silences on the IRCd then we need to set them here
+ * somehow
+ */
+ if (!user->handle_info)
+ return 1;
+
+ mask = argv[2];
+
+ if (*mask == '-') {
+ for (i=0; i<user->handle_info->ignores->used; i++) {
+ if (!irccasecmp(mask+1, user->handle_info->ignores->list[i]))
+ user->handle_info->ignores->list[i] = user->handle_info->ignores->list[--user->handle_info->ignores->used];
+ }
+ } else {
+ for (i=0; i<user->handle_info->ignores->used; i++) {
+ if (!strcmp(mask+1, user->handle_info->ignores->list[i]))
+ return 1; /* Already on the users NickServ ignore list, safely ignore */
+ }
+
+ new_mask = strdup(mask+1);
+ string_list_append(user->handle_info->ignores, new_mask);
+ }
return 1;
}
static CMD_FUNC(cmd_squit)
{
struct server *server;
+ char *uplink;
if (argc < 4)
return 0;
return 1;
}
+ uplink = strdup(server->uplink->name);
DelServer(server, 0, argv[3]);
+ /* if its a pingout and pingout connecting is enabled
+ or its a read error and readerror connecting is enabled
+ or were doing a "N" and i need to connect that server somewhere */
+ routing_handle_squit(argv[1], uplink, argv[3]);
+ free(uplink);
return 1;
}
static CMD_FUNC(cmd_privmsg)
{
struct privmsg_desc pd;
- if (argc != 3)
+ if (argc < 3)
return 0;
pd.user = GetUserH(origin);
if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user)))
return 1;
+
+ if (checkDefCon(DEFCON_OPER_ONLY) && !IsOper(pd.user)) {
+ const char *str;
+ str = conf_get_data("services/opserv/nick", RECDB_QSTRING);
+ if (str)
+ send_message_type(4, pd.user, GetUserH(str), "Services are currently not available, please try again soon");
+ return 1;
+ }
+
+ if (checkDefCon(DEFCON_SILENT_OPER_ONLY) && !IsOper(pd.user))
+ return 1; /* Silently Ignore */
+
pd.is_notice = 0;
- pd.text = argv[2];
+ pd.text = argv[argc - 1];
parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
+
return 1;
}
static CMD_FUNC(cmd_notice)
{
struct privmsg_desc pd;
+ struct server *srv;
+ int nuser = 0;
+
if (argc != 3)
return 0;
+
pd.user = GetUserH(origin);
- if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user)))
- return 1;
- pd.is_notice = 1;
- pd.text = argv[2];
- parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
+ if(!pd.user)
+ nuser = 1;
+ if (!pd.user || (IsGagged(pd.user) && !IsOper(pd.user))) {
+ }
+ else {
+ pd.is_notice = 1;
+ pd.text = argv[2];
+ parse_foreach(argv[1], privmsg_chan_helper, NULL, privmsg_user_helper, privmsg_invalid, &pd);
+ }
+
+ srv = GetServerH(origin);
+ if(srv) {
+ char *sargv[MAXNUMPARAMS];
+ int sargc;
+
+ sargc = split_line(argv[2], true, MAXNUMPARAMS, sargv);
+
+ if(!strcasecmp(sargv[0], "Connect:")) {
+ /* :Connect: Host shoe.loxxin.net not listed in ircd.conf */
+ if(!strcasecmp(sargv[3], "not") && !strcasecmp(sargv[4], "listed")) {
+ routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+3, sargc-3, NULL));
+ }
+ }
+ else if(!strcasecmp(sargv[0], "Link")) {
+ /* :Link with mephisto.etheria.cx cancelled: Server mephisto.etheria.cx[216.46.33.71]
+ *
+ * :Link with laptop.afternet.org cancelled: Connection refused
+ */
+ if(!strcasecmp(sargv[3], "cancelled:")) {
+ routing_handle_connect_failure(srv, sargv[2], unsplit_string(sargv+4, sargc-4, NULL));
+ }
+ }
+ }
return 1;
}
if (argv[2][0] == '+') {
if (argc < 5)
return 0;
- gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0);
+ gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0, 0);
return 1;
} else if (argv[2][0] == '-') {
gline_remove(argv[2]+1, 0);
return 0;
}
+static CMD_FUNC(cmd_sgline)
+{
+ struct server *sender;
+
+ if (argc < 4)
+ return 0;
+
+ if (!(sender = GetServerH(origin)))
+ return 0;
+
+ gline_add(origin, argv[1], strtoul(argv[2], NULL, 0), argv[argc-1], now, 1, 0);
+ return 1;
+}
+
+static CMD_FUNC(cmd_sshun)
+{
+ struct server *sender;
+
+ if (argc < 4)
+ return 0;
+
+ if (!(sender = GetServerH(origin)))
+ return 0;
+
+ shun_add(origin, argv[1], strtoul(argv[2], NULL, 0), argv[argc-1], now, 1);
+ return 1;
+}
+
+static CMD_FUNC(cmd_shun)
+{
+ if (argc < 3)
+ return 0;
+ if (argv[2][0] == '+') {
+ if (argc < 5)
+ return 0;
+ shun_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, 0);
+ return 1;
+ } else if (argv[2][0] == '-') {
+ shun_remove(argv[2]+1, 0);
+ return 1;
+ } else
+ return 0;
+}
+
static CMD_FUNC(cmd_svsnick)
{
struct userNode *target, *dest;
return 1;
}
-static oper_func_t *of_list;
-static unsigned int of_size = 0, of_used = 0;
-
void
free_user(struct userNode *user)
{
}
static void
-parse_cleanup(void)
+parse_cleanup(UNUSED_ARG(void *extra))
{
unsigned int nn;
free(of_list);
+ free(of_list_extra);
free(privmsg_funcs);
+ num_privmsg_funcs = 0;
free(notice_funcs);
+ num_notice_funcs = 0;
free(mcf_list);
dict_delete(irc_func_dict);
for (nn=0; nn<dead_users.used; nn++)
static void
p10_conf_reload(void) {
hidden_host_suffix = conf_get_data("server/hidden_host", RECDB_QSTRING);
+ his_servername = conf_get_data("server/his_servername", RECDB_QSTRING);
+ his_servercomment = conf_get_data("server/his_servercomment", RECDB_QSTRING);
}
static void
-remove_unbursted_channel(struct chanNode *cNode) {
+remove_unbursted_channel(struct chanNode *cNode, UNUSED_ARG(void *extra)) {
if (unbursted_channels)
dict_remove(unbursted_channels, cNode->name);
}
char numer[COMBO_NUMERIC_LEN+1];
/* read config items */
+ str = conf_get_data("server/extended_accounts", RECDB_QSTRING);
+ extended_accounts = str ? enabled_string(str) : 1;
str = conf_get_data("server/ping_freq", RECDB_QSTRING);
ping_freq = str ? ParseInterval(str) : 120;
str = conf_get_data("server/ping_timeout", RECDB_QSTRING);
else
inttobase64(numer, (numnick << 18) + (usermask & 0x3ffff), 5);
- str = conf_get_data("server/his_servername", RECDB_QSTRING);
- his_servername = str ? strdup(str) : NULL;
- str = conf_get_data("server/his_servercomment", RECDB_QSTRING);
- his_servercomment = str ? strdup(str) : NULL;
-
str = conf_get_data("server/hostname", RECDB_QSTRING);
desc = conf_get_data("server/description", RECDB_QSTRING);
if (!str || !desc) {
dict_insert(irc_func_dict, TOK_EOB_ACK, cmd_eob_ack);
dict_insert(irc_func_dict, CMD_MODE, cmd_mode);
dict_insert(irc_func_dict, TOK_MODE, cmd_mode);
+ dict_insert(irc_func_dict, CMD_MARK, cmd_mark);
+ dict_insert(irc_func_dict, TOK_MARK, cmd_mark);
dict_insert(irc_func_dict, CMD_NICK, cmd_nick);
dict_insert(irc_func_dict, TOK_NICK, cmd_nick);
dict_insert(irc_func_dict, CMD_ACCOUNT, cmd_account);
dict_insert(irc_func_dict, TOK_TOPIC, cmd_topic);
dict_insert(irc_func_dict, CMD_AWAY, cmd_away);
dict_insert(irc_func_dict, TOK_AWAY, cmd_away);
- dict_insert(irc_func_dict, CMD_SILENCE, cmd_dummy);
- dict_insert(irc_func_dict, TOK_SILENCE, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_SILENCE, cmd_silence);
+ dict_insert(irc_func_dict, TOK_SILENCE, cmd_silence);
dict_insert(irc_func_dict, CMD_KICK, cmd_kick);
dict_insert(irc_func_dict, TOK_KICK, cmd_kick);
dict_insert(irc_func_dict, CMD_SQUIT, cmd_squit);
dict_insert(irc_func_dict, TOK_NOTICE, cmd_notice);
dict_insert(irc_func_dict, CMD_STATS, cmd_stats);
dict_insert(irc_func_dict, TOK_STATS, cmd_stats);
+ dict_insert(irc_func_dict, CMD_SVSJOIN, cmd_svsjoin);
+ dict_insert(irc_func_dict, TOK_SVSJOIN, cmd_svsjoin);
dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick);
dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick);
+ dict_insert(irc_func_dict, CMD_SVSPART, cmd_svspart);
+ dict_insert(irc_func_dict, TOK_SVSPART, cmd_svspart);
+ dict_insert(irc_func_dict, CMD_SWHOIS, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_SWHOIS, cmd_dummy);
dict_insert(irc_func_dict, CMD_WHOIS, cmd_whois);
dict_insert(irc_func_dict, TOK_WHOIS, cmd_whois);
dict_insert(irc_func_dict, CMD_GLINE, cmd_gline);
dict_insert(irc_func_dict, TOK_GLINE, cmd_gline);
+ dict_insert(irc_func_dict, CMD_SGLINE, cmd_sgline);
+ dict_insert(irc_func_dict, TOK_SGLINE, cmd_sgline);
+ dict_insert(irc_func_dict, CMD_SHUN, cmd_shun);
+ dict_insert(irc_func_dict, TOK_SHUN, cmd_shun);
+ dict_insert(irc_func_dict, CMD_SSHUN, cmd_sshun);
+ dict_insert(irc_func_dict, TOK_SSHUN, cmd_sshun);
dict_insert(irc_func_dict, CMD_OPMODE, cmd_opmode);
dict_insert(irc_func_dict, TOK_OPMODE, cmd_opmode);
dict_insert(irc_func_dict, CMD_CLEARMODE, cmd_clearmode);
dict_insert(irc_func_dict, TOK_VERSION, cmd_version);
dict_insert(irc_func_dict, CMD_ADMIN, cmd_admin);
dict_insert(irc_func_dict, TOK_ADMIN, cmd_admin);
+ dict_insert(irc_func_dict, CMD_SMO, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_SMO, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_SNO, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_SNO, cmd_dummy);
+
+ dict_insert(irc_func_dict, CMD_RPING, cmd_rping);
+ dict_insert(irc_func_dict, TOK_RPING, cmd_rping);
+ dict_insert(irc_func_dict, CMD_RPONG, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_RPONG, cmd_dummy);
+
+ dict_insert(irc_func_dict, CMD_SASL, cmd_sasl);
+ dict_insert(irc_func_dict, TOK_SASL, cmd_sasl);
/* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
* Apparently to obliterate channels from any servers that think they
dict_insert(irc_func_dict, TOK_WALLUSERS, cmd_dummy);
/* Ignore dnsbl exemptions */
dict_insert(irc_func_dict, TOK_EXEMPT, cmd_dummy);
- dict_insert(irc_func_dict, TOK_MARK, cmd_dummy);
- /* Ignore privs */
- dict_insert(irc_func_dict, TOK_PRIVS, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_PRIVS, cmd_privs);
+ dict_insert(irc_func_dict, TOK_PRIVS, cmd_privs);
+ /* ignore ALIST for now */
+ dict_insert(irc_func_dict, TOK_ALIST, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_ALIST, cmd_dummy);
+ /* ignore SPAMFILTER */
+ dict_insert(irc_func_dict, TOK_SPAMFILTER, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_SPAMFILTER, cmd_dummy);
+ /* Ignore remote luser */
+ dict_insert(irc_func_dict, TOK_LUSERS, cmd_dummy);
/* We have reliable clock! Always! Wraaa! */
dict_insert(irc_func_dict, CMD_SETTIME, cmd_dummy);
dict_insert(irc_func_dict, TOK_SETTIME, cmd_dummy);
+ /* Ignore ZLINE/ZL/REMOVE/RM */
+ dict_insert(irc_func_dict, CMD_ZLINE, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_ZLINE, cmd_dummy);
+ dict_insert(irc_func_dict, CMD_REMOVE, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_REMOVE, cmd_dummy);
+
+ /* ignore /trace and /motd commands targetted at us */
+ dict_insert(irc_func_dict, TOK_TRACE, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_MOTD, cmd_dummy);
+ dict_insert(irc_func_dict, TOK_UPING, cmd_dummy);
+
/* handle topics */
dict_insert(irc_func_dict, "331", cmd_num_topic);
dict_insert(irc_func_dict, "332", cmd_num_topic);
dict_insert(irc_func_dict, "432", cmd_error_nick); /* Erroneus [sic] nickname */
/* ban list resetting */
/* "stats g" responses */
+ dict_insert(irc_func_dict, "230", cmd_dummy); /* ignore stats headers */
dict_insert(irc_func_dict, "247", cmd_num_gline);
+ dict_insert(irc_func_dict, "542", cmd_num_shun);
dict_insert(irc_func_dict, "219", cmd_dummy); /* "End of /STATS report" */
/* other numeric responses we might get */
dict_insert(irc_func_dict, "401", cmd_dummy); /* target left network */
memset(notice_funcs, 0, sizeof(privmsg_func_t)*num_notice_funcs);
userList_init(&dead_users);
- reg_del_channel_func(remove_unbursted_channel);
- reg_exit_func(parse_cleanup);
+ reg_del_channel_func(remove_unbursted_channel, NULL);
+ reg_exit_func(parse_cleanup, NULL);
+ // reg_notice_func(opserv, check_ctcp);
}
int
parse_foreach(char *target_list, foreach_chanfunc cf, foreach_nonchan nc, foreach_userfunc uf, foreach_nonuser nu, void *data)
{
char *j, old;
+
do {
j = target_list;
while (*j != 0 && *j != ',')
j++;
old = *j;
*j = 0;
+
if (IsChannelName(target_list)
|| (target_list[0] == '0' && target_list[1] == '\0')) {
struct chanNode *chan = GetChannel(target_list);
+
if (chan) {
if (cf)
cf(chan, data);
}
struct server *
-AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link, const char *numeric, const char *description)
+AddServer(struct server *uplink, const char *name, int hops, time_t boot, time_t link_time, const char *numeric, const char *description)
{
struct server* sNode;
int slen, mlen;
sNode->num_mask = base64toint(numeric+slen, mlen);
sNode->hops = hops;
sNode->boot = boot;
- sNode->link = link;
+ sNode->link_time = link_time;
strncpy(sNode->numeric, numeric, slen);
safestrncpy(sNode->description, description, sizeof(sNode->description));
sNode->users = calloc(sNode->num_mask+1, sizeof(*sNode->users));
}
struct userNode *
-AddService(const char *nick, const char *modes, const char *desc, const char *hostname)
+AddLocalUser(const char *nick, const char *ident, const char *hostname, const char *desc, const char *modes)
{
char numeric[COMBO_NUMERIC_LEN+1];
int local_num = get_local_numeric();
time_t timestamp = now;
struct userNode *old_user = GetUserH(nick);
+ if (!modes)
+ modes = "+oik";
+
if (old_user) {
if (IsLocal(old_user))
return old_user;
if (!hostname)
hostname = self->name;
make_numeric(self, local_num, numeric);
- /* TODO: Make these modes part of the conf file */
- return AddUser(self, nick, nick, hostname, modes ? modes : "+oik", numeric, desc, now, "AAAAAA");
+ return AddUser(self, nick, ident, hostname, modes, numeric, desc, timestamp, "AAAAAA");
}
struct userNode *
AddUser(struct server* uplink, const char *nick, const char *ident, const char *hostname, const char *modes, const char *numeric, const char *userinfo, time_t timestamp, const char *realip)
{
struct userNode *oldUser, *uNode;
- unsigned int n, ignore_user;
+ unsigned int ignore_user, dummy;
+ char *tstr;
+ int type;
if ((strlen(numeric) < 3) || (strlen(numeric) > 5)) {
- log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", uplink, nick, numeric);
+ log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): numeric %s wrong length!", (void*)uplink, nick, numeric);
return NULL;
}
if (!uplink) {
- log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", uplink, nick, numeric);
+ log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s doesn't exist!", (void*)uplink, nick, numeric);
return NULL;
}
if (uplink != GetServerN(numeric)) {
- log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", uplink, nick, numeric, uplink->name);
+ log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): server for numeric %s differs from nominal uplink %s.", (void*)uplink, nick, numeric, uplink->name);
return NULL;
}
- if (!is_valid_nick(nick)) {
- log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, nick);
+ dummy = modes && modes[0] == '*';
+ if (dummy) {
+ ++modes;
+ } else if (!is_valid_nick(nick)) {
+ log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", (void*)uplink, nick);
return NULL;
}
ignore_user = 0;
if ((oldUser = GetUserH(nick))) {
- if (IsLocal(oldUser) && (IsService(oldUser) || IsPersistent(oldUser))) {
- /* The service should collide the new user off. */
+ if (IsLocal(oldUser)
+ && (IsService(oldUser) || IsPersistent(oldUser))) {
+ /* The service should collide the new user off - but not
+ * if the new user is coming in during a burst. (During a
+ * burst, the bursting server will kill either our user --
+ * triggering a ReintroduceUser() -- or its own.)
+ */
oldUser->timestamp = timestamp - 1;
- irc_user(oldUser);
- }
- if (oldUser->timestamp > timestamp) {
+ ignore_user = 1;
+ if (!uplink->burst)
+ irc_user(oldUser);
+ } else if (oldUser->timestamp > timestamp) {
/* "Old" user is really newer; remove them */
DelUser(oldUser, 0, 1, "Overruled by older nick");
} else {
safestrncpy(uNode->info, userinfo, sizeof(uNode->info));
safestrncpy(uNode->hostname, hostname, sizeof(uNode->hostname));
safestrncpy(uNode->numeric, numeric, sizeof(uNode->numeric));
- uNode->ip.s_addr = htonl(base64toint(realip, 6));
+ irc_p10_pton(&uNode->ip, realip);
+
+ tstr = conf_get_data("server/type", RECDB_QSTRING);
+ type = atoi(tstr);
+ if (type == 7) {
+ if (irc_in_addr_is_ipv4(uNode->ip)) {
+ make_virtip((char*)irc_ntoa(&uNode->ip), (char*)irc_ntoa(&uNode->ip), uNode->cryptip);
+ make_virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+ } else if (irc_in_addr_is_ipv6(uNode->ip)) {
+ make_ipv6virthost((char*)irc_ntoa(&uNode->ip), uNode->hostname, uNode->crypthost);
+ }
+ }
+
+ if (!uNode->crypthost && uNode->cryptip)
+ snprintf(uNode->crypthost, sizeof(uNode->crypthost), "%s", strdup(uNode->cryptip));
+ uNode->idle_since = timestamp;
uNode->timestamp = timestamp;
modeList_init(&uNode->channels);
uNode->uplink = uplink;
uNode->num_local = base64toint(numeric+strlen(uNode->uplink->numeric), 3) & uNode->uplink->num_mask;
uNode->uplink->users[uNode->num_local] = uNode;
mod_usermode(uNode, modes);
+ if (dummy)
+ uNode->modes |= FLAGS_DUMMY;
+
+ set_geoip_info(uNode);
+
if (ignore_user)
return uNode;
}
if (IsLocal(uNode))
irc_user(uNode);
- for (n=0; n<nuf_used; n++)
- if (nuf_list[n](uNode))
- break;
+ call_new_user_funcs(uNode);
+
+ if ((uNode->loc == 1) && (uNode->handle_info))
+ send_func_list(uNode);
+
return uNode;
}
void
DelUser(struct userNode* user, struct userNode *killer, int announce, const char *why)
{
- unsigned int n;
verify(user);
/* remove user from all channels */
while (user->channels.used > 0)
- DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, false, 0);
+ DelChannelUser(user, user->channels.list[user->channels.used-1]->channel, NULL, 0);
/* Call these in reverse order so ChanServ can update presence
information before NickServ nukes the handle_info. */
- for (n = duf_used; n > 0; )
- duf_list[--n](user, killer, why);
+ call_del_user_funcs(user, killer, why);
user->uplink->clients--;
user->uplink->users[user->num_local] = NULL;
irc_kill(killer, user, why);
}
+ if (IsLocal(user)) {
+ unsigned int num = user->num_local;
+ if (num < num_privmsg_funcs)
+ privmsg_funcs[num] = NULL;
+ if (num < num_notice_funcs)
+ notice_funcs[num] = NULL;
+ }
+
modeList_clean(&user->channels);
+
+ /* Clean up version data */
+ if(user->version_reply) {
+ free(user->version_reply);
+ user->version_reply = NULL;
+ }
+
+ /* Clean up SSL fingerprint data */
+ if(user->sslfp) {
+ free(user->sslfp);
+ user->sslfp = NULL;
+ }
+
+ /* clean up mark */
+ if(user->mark) {
+ free(user->mark);
+ user->mark = NULL;
+ }
+ free_string_list(user->marks);
+ user->marks = NULL;
+
+ /* clean up geoip data if any */
+ if(user->country_code) free(user->country_code);
+ if(user->city) free(user->city);
+ if(user->region) free(user->region);
+ if(user->postal_code) free(user->postal_code);
+
/* We don't free them, in case we try to privmsg them or something
* (like when a stupid oper kills themself). We just put them onto
* a list of clients that get freed after processing each line.
free_user(user);
}
+static void call_oper_funcs(struct userNode *user);
+
void mod_usermode(struct userNode *user, const char *mode_change) {
- static void call_oper_funcs(struct userNode *user);
int add = 1;
const char *word = mode_change;
if (!user || !mode_change)
return;
+
+ call_user_mode_funcs(user, mode_change);
+
while (*word != ' ' && *word) word++;
while (*word == ' ') word++;
while (1) {
case '-': add = 0; break;
case 'o':
do_user_mode(FLAGS_OPER);
- if (add) {
- userList_append(&curr_opers, user);
- call_oper_funcs(user);
- } else {
- userList_remove(&curr_opers, user);
+ if (!add) {
+ userList_remove(&curr_opers, user);
+ } else if (!userList_contains(&curr_opers, user)) {
+ userList_append(&curr_opers, user);
+ call_oper_funcs(user);
}
break;
case 'O': do_user_mode(FLAGS_LOCOP); break;
invis_clients--;
break;
case 'w': do_user_mode(FLAGS_WALLOP); break;
- case 's': do_user_mode(FLAGS_SERVNOTICE); break;
case 'd': do_user_mode(FLAGS_DEAF); break;
case 'k': do_user_mode(FLAGS_SERVICE); break;
case 'g': do_user_mode(FLAGS_GLOBAL); break;
+ case 'B': do_user_mode(FLAGS_BOT); break;
+ case 'n': do_user_mode(FLAGS_HIDECHANS); break;
+ case 'I': do_user_mode(FLAGS_HIDEIDLE); break;
+ case 'X': do_user_mode(FLAGS_XTRAOP); break;
+ case 'C': do_user_mode(FLAGS_CLOAKHOST);
+ if (*word) {
+ char cloakhost[MAXLEN];
+ unsigned int ii;
+ for (ii=0; (*word != ' ') && (*word != '\0'); )
+ cloakhost[ii++] = *word++;
+ cloakhost[ii] = 0;
+ while (*word == ' ')
+ word++;
+ safestrncpy(user->crypthost, cloakhost, sizeof(user->crypthost));
+ }
+ break;
+ case 'c': do_user_mode(FLAGS_CLOAKIP);
+ if (*word) {
+ char cloakip[MAXLEN];
+ unsigned int ii;
+ for (ii=0; (*word != ' ') && (*word != '\0'); )
+ cloakip[ii++] = *word++;
+ cloakip[ii] = 0;
+ while (*word == ' ')
+ word++;
+ safestrncpy(user->cryptip, cloakip, sizeof(user->cryptip));
+ }
+ break;
// sethost - reed/apples
// case 'h': do_user_mode(FLAGS_HELPER); break;
// I check if there's an 'h' in the first part, and if there,
assign_fakehost(user, host, 0);
}
break;
+ case 'a': do_user_mode(FLAGS_ADMIN); break;
+ case 'z': do_user_mode(FLAGS_SSL); break;
+ case 'D': do_user_mode(FLAGS_PRIVDEAF); break;
+ case 'R': do_user_mode(FLAGS_ACCOUNTONLY); break;
+ case 'W': do_user_mode(FLAGS_WHOIS); break;
+ case 'H': do_user_mode(FLAGS_HIDEOPER); break;
+ case 'L': do_user_mode(FLAGS_NOLINK); break;
+ case 'q': do_user_mode(FLAGS_COMMONCHANSONLY); break;
}
#undef do_user_mode
}
}
+static int
+keyncpy(char output[], char input[], size_t output_size)
+{
+ size_t ii;
+
+ if (input[0] == ':')
+ {
+ output[0] = '\0';
+ return 1;
+ }
+
+ for (ii = 0; (ii + 1 < output_size) && (input[ii] != '\0'); ++ii)
+ {
+ output[ii] = input[ii];
+ }
+
+ output[ii] = '\0';
+ return 0;
+}
+
struct mod_chanmode *
-mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags)
+mod_chanmode_parse(struct chanNode *channel, char **modes, unsigned int argc, unsigned int flags, short base_oplevel)
{
struct mod_chanmode *change;
unsigned int ii, in_arg, ch_arg, add;
case 'Q': do_chan_mode(MODE_NOQUITMSGS); break;
case 'T': do_chan_mode(MODE_NOAMSG); break;
case 'O': do_chan_mode(MODE_OPERSONLY); break;
+ case 'a': do_chan_mode(MODE_ADMINSONLY); break;
case 'Z': do_chan_mode(MODE_SSLONLY); break;
case 'L': do_chan_mode(MODE_HIDEMODE); break;
case 'z':
if (!(flags & MCP_REGISTERED)) {
- do_chan_mode(MODE_REGISTERED);
+ do_chan_mode(MODE_REGISTERED);
} else {
- mod_chanmode_free(change);
- return NULL;
+ mod_chanmode_free(change);
+ return NULL;
}
break;
#undef do_chan_mode
break;
case 'k':
if (add) {
- if (in_arg >= argc)
+ if ((in_arg >= argc)
+ || keyncpy(change->new_key, modes[in_arg++], sizeof(change->new_key)))
goto error;
change->modes_set |= MODE_KEY;
- safestrncpy(change->new_key, modes[in_arg++], sizeof(change->new_key));
} else {
change->modes_clear |= MODE_KEY;
if (!(flags & MCP_KEY_FREE)) {
}
}
break;
+ case 'U':
+ if (add)
+ {
+ if ((in_arg >= argc)
+ || keyncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass)))
+ goto error;
+ change->modes_set |= MODE_UPASS;
+ } else {
+ change->modes_clear |= MODE_UPASS;
+ if (!(flags & MCP_UPASS_FREE)) {
+ if (in_arg >= argc)
+ goto error;
+ in_arg++;
+ }
+ }
+ break;
+ case 'A':
+ if (add) {
+ if ((in_arg >= argc)
+ || keyncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass)))
+ goto error;
+ change->modes_set |= MODE_APASS;
+ } else {
+ change->modes_clear |= MODE_APASS;
+ if (!(flags & MCP_APASS_FREE)) {
+ if (in_arg >= argc)
+ goto error;
+ in_arg++;
+ }
+ }
+ break;
case 'b':
if (!(flags & MCP_ALLOW_OVB))
goto error;
case 'o': case 'h': case 'v':
{
struct userNode *victim;
+ char *oplevel_str;
+ int oplevel;
+
+ if (in_arg >= argc)
+ goto error;
+ oplevel_str = strchr(modes[in_arg], ':');
+ if (oplevel_str)
+ {
+ /* XXYYY M #channel +o XXYYY:<oplevel> */
+ *oplevel_str++ = '\0';
+ oplevel = parse_oplevel(oplevel_str);
+ if (oplevel <= base_oplevel && !(flags & MCP_FROM_SERVER))
+ oplevel = base_oplevel + 1;
+ }
+ else if (channel->modes & MODE_UPASS)
+ oplevel = base_oplevel + 1;
+ else
+ oplevel = -1;
+
+ /* Check that oplevel is within bounds. */
+ if (oplevel > MAXOPLEVEL)
+ oplevel = MAXOPLEVEL;
+
if (!(flags & MCP_ALLOW_OVB))
goto error;
if (in_arg >= argc)
if (!victim)
continue;
if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
+ {
+ /* Apply the oplevel change */
+ change->args[ch_arg].u.member->oplevel = oplevel;
ch_arg++;
+ }
break;
}
default:
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
#undef DO_MODE_CHAR
if (change->modes_clear & channel->modes & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', channel->key);
+ if (change->modes_clear & channel->modes & MODE_UPASS)
+ mod_chanmode_append(&chbuf, 'U', channel->upass);
+ if (change->modes_clear & channel->modes & MODE_APASS)
+ mod_chanmode_append(&chbuf, 'A', channel->apass);
}
for (arg = 0; arg < change->argc; ++arg) {
if (!(change->args[arg].mode & MODE_REMOVE))
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
#undef DO_MODE_CHAR
if(change->modes_set & MODE_KEY)
mod_chanmode_append(&chbuf, 'k', change->new_key);
+ if (change->modes_set & MODE_UPASS)
+ mod_chanmode_append(&chbuf, 'U', change->new_upass);
+ if (change->modes_set & MODE_APASS)
+ mod_chanmode_append(&chbuf, 'A', change->new_apass);
if(change->modes_set & MODE_LIMIT) {
sprintf(int_buff, "%d", change->new_limit);
mod_chanmode_append(&chbuf, 'l', int_buff);
DO_MODE_CHAR(NOPRIVMSGS, 'n');
DO_MODE_CHAR(LIMIT, 'l');
DO_MODE_CHAR(KEY, 'k');
+ DO_MODE_CHAR(UPASS, 'U');
+ DO_MODE_CHAR(APASS, 'A');
DO_MODE_CHAR(DELAYJOINS, 'D');
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
DO_MODE_CHAR(NOQUITMSGS, 'Q');
DO_MODE_CHAR(NOAMSG, 'T');
DO_MODE_CHAR(OPERSONLY, 'O');
+ DO_MODE_CHAR(ADMINSONLY, 'a');
DO_MODE_CHAR(REGISTERED, 'z');
DO_MODE_CHAR(SSLONLY, 'Z');
DO_MODE_CHAR(HIDEMODE, 'L');
+
+ DO_MODE_CHAR(KEY, 'k');
+ DO_MODE_CHAR(LIMIT, 'l');
+ DO_MODE_CHAR(APASS, 'A');
+ DO_MODE_CHAR(UPASS, 'U');
#undef DO_MODE_CHAR
- switch (change->modes_set & (MODE_KEY|MODE_LIMIT)) {
- case MODE_KEY|MODE_LIMIT:
- used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
- break;
- case MODE_KEY:
- used += sprintf(outbuff+used, "k %s", change->new_key);
- break;
- case MODE_LIMIT:
- used += sprintf(outbuff+used, "l %d", change->new_limit);
- break;
- }
+
+#define DO_MODE_PARM(BIT, PARM) if (change->modes_set & MODE_##BIT) used += sprintf(outbuff+used, " %s", PARM);
+ DO_MODE_PARM(KEY, change->new_key);
+ if (change->modes_set & MODE_LIMIT) used += sprintf(outbuff+used, " %d", change->new_limit);
+ DO_MODE_PARM(APASS, change->new_apass);
+ DO_MODE_PARM(UPASS, change->new_upass);
+#undef DO_MODE_PARM
}
outbuff[used] = 0;
return outbuff;
static int
clear_chanmode(struct chanNode *channel, const char *modes)
{
- unsigned int remove;
+ unsigned int cleared;
- for (remove = 0; *modes; modes++) {
+ for (cleared = 0; *modes; modes++) {
switch (*modes) {
- case 'o': remove |= MODE_CHANOP; break;
- case 'h': remove |= MODE_HALFOP; break;
- case 'v': remove |= MODE_VOICE; break;
- case 'p': remove |= MODE_PRIVATE; break;
- case 's': remove |= MODE_SECRET; break;
- case 'm': remove |= MODE_MODERATED; break;
- case 't': remove |= MODE_TOPICLIMIT; break;
- case 'i': remove |= MODE_INVITEONLY; break;
- case 'n': remove |= MODE_NOPRIVMSGS; break;
+ case 'o': cleared |= MODE_CHANOP; break;
+ case 'h': cleared |= MODE_HALFOP; break;
+ case 'v': cleared |= MODE_VOICE; break;
+ case 'p': cleared |= MODE_PRIVATE; break;
+ case 's': cleared |= MODE_SECRET; break;
+ case 'm': cleared |= MODE_MODERATED; break;
+ case 't': cleared |= MODE_TOPICLIMIT; break;
+ case 'i': cleared |= MODE_INVITEONLY; break;
+ case 'n': cleared |= MODE_NOPRIVMSGS; break;
case 'k':
- remove |= MODE_KEY;
+ cleared |= MODE_KEY;
channel->key[0] = '\0';
break;
+ case 'A':
+ cleared |= MODE_APASS;
+ channel->apass[0] = '\0';
+ break;
+ case 'U':
+ cleared |= MODE_UPASS;
+ channel->upass[0] = '\0';
+ break;
case 'l':
- remove |= MODE_LIMIT;
+ cleared |= MODE_LIMIT;
channel->limit = 0;
break;
- case 'b': remove |= MODE_BAN; break;
- case 'e': remove |= MODE_EXEMPT; break;
- case 'D': remove |= MODE_DELAYJOINS; break;
- case 'r': remove |= MODE_REGONLY; break;
- case 'c': remove |= MODE_NOCOLORS; break;
- case 'C': remove |= MODE_NOCTCPS; break;
- case 'S': remove |= MODE_STRIPCOLOR; break;
- case 'M': remove |= MODE_MODUNREG; break;
- case 'N': remove |= MODE_NONOTICE; break;
- case 'Q': remove |= MODE_NOQUITMSGS; break;
- case 'T': remove |= MODE_NOAMSG; break;
- case 'O': remove |= MODE_OPERSONLY; break;
- case 'z': remove |= MODE_REGISTERED; break;
- case 'Z': remove |= MODE_SSLONLY; break;
- case 'L': remove |= MODE_HIDEMODE; break;
+ case 'b': cleared |= MODE_BAN; break;
+ case 'e': cleared |= MODE_EXEMPT; break;
+ case 'D': cleared |= MODE_DELAYJOINS; break;
+ case 'r': cleared |= MODE_REGONLY; break;
+ case 'c': cleared |= MODE_NOCOLORS; break;
+ case 'C': cleared |= MODE_NOCTCPS; break;
+ case 'S': cleared |= MODE_STRIPCOLOR; break;
+ case 'M': cleared |= MODE_MODUNREG; break;
+ case 'N': cleared |= MODE_NONOTICE; break;
+ case 'Q': cleared |= MODE_NOQUITMSGS; break;
+ case 'T': cleared |= MODE_NOAMSG; break;
+ case 'O': cleared |= MODE_OPERSONLY; break;
+ case 'a': cleared |= MODE_ADMINSONLY; break;
+ case 'z': cleared |= MODE_REGISTERED; break;
+ case 'Z': cleared |= MODE_SSLONLY; break;
+ case 'L': cleared |= MODE_HIDEMODE; break;
}
}
- if (!remove)
+ if (!cleared)
return 1;
/* Remove simple modes. */
- channel->modes &= ~remove;
+ channel->modes &= ~cleared;
/* If removing bans, kill 'em all. */
- if ((remove & MODE_BAN) && channel->banlist.used) {
+ if ((cleared & MODE_BAN) && channel->banlist.used) {
unsigned int i;
for (i=0; i<channel->banlist.used; i++)
free(channel->banlist.list[i]);
}
/* If removing exempts, kill 'em all. */
- if ((remove & MODE_EXEMPT) && channel->exemptlist.used) {
+ if ((cleared & MODE_EXEMPT) && channel->exemptlist.used) {
unsigned int i;
for (i=0; i<channel->exemptlist.used; i++)
free(channel->exemptlist.list[i]);
channel->exemptlist.used = 0;
}
- /* Remove member modes. */
- if ((remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) {
- int mask = ~(remove & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE));
+ /* Removed member modes. */
+ if ((cleared & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE)) && channel->members.used) {
+ int mask = ~(cleared & (MODE_CHANOP | MODE_HALFOP | MODE_VOICE));
unsigned int i;
for (i = 0; i < channel->members.used; i++)
{
unsigned int numeric = user->num_local;
if (numeric >= num_privmsg_funcs) {
- int newnum = numeric + 8;
+ int newnum = numeric + 8, ii;
privmsg_funcs = realloc(privmsg_funcs, newnum*sizeof(privmsg_func_t));
- memset(privmsg_funcs+num_privmsg_funcs, 0, (newnum-num_privmsg_funcs)*sizeof(privmsg_func_t));
+ for (ii = num_privmsg_funcs; ii < newnum; ++ii)
+ privmsg_funcs[ii] = NULL;
num_privmsg_funcs = newnum;
}
if (privmsg_funcs[numeric])
}
void
-unreg_privmsg_func(struct userNode *user, privmsg_func_t handler)
+unreg_privmsg_func(struct userNode *user)
{
- unsigned int x;
+ if (!IsLocal(user) || user->num_local >= num_privmsg_funcs)
+ return; /* this really only works with users */
- if (!user || handler)
- return; /* this really only works with users */
-
- memset(privmsg_funcs+user->num_local, 0, sizeof(privmsg_func_t));
-
- for (x = user->num_local+1; x < num_privmsg_funcs; x++)
- memmove(privmsg_funcs+x-1, privmsg_funcs+x, sizeof(privmsg_func_t));
-
- privmsg_funcs = realloc(privmsg_funcs, num_privmsg_funcs*sizeof(privmsg_func_t));
- num_privmsg_funcs--;
+ privmsg_funcs[user->num_local] = NULL;
}
{
unsigned int numeric = user->num_local;
if (numeric >= num_notice_funcs) {
- int newnum = numeric + 8;
+ int newnum = numeric + 8, ii;
notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t));
- memset(notice_funcs+num_notice_funcs, 0, (newnum-num_notice_funcs)*sizeof(privmsg_func_t));
+ for (ii = num_privmsg_funcs; ii < newnum; ++ii)
+ privmsg_funcs[ii] = NULL;
num_notice_funcs = newnum;
}
if (notice_funcs[numeric])
}
void
-unreg_notice_func(struct userNode *user, privmsg_func_t handler)
-{
- unsigned int x;
-
- if (!user || handler)
- return; /* this really only works with users */
-
- memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
-
- for (x = user->num_local+1; x < num_notice_funcs; x++)
- memmove(notice_funcs+x-1, notice_funcs+x, sizeof(privmsg_func_t));
-
- memset(notice_funcs+user->num_local, 0, sizeof(privmsg_func_t));
- notice_funcs = realloc(notice_funcs, num_notice_funcs*sizeof(privmsg_func_t));
- num_notice_funcs--;
-}
-
-void
-reg_oper_func(oper_func_t handler)
+unreg_notice_func(struct userNode *user)
{
- if (of_used == of_size) {
- if (of_size) {
- of_size <<= 1;
- of_list = realloc(of_list, of_size*sizeof(oper_func_t));
- } else {
- of_size = 8;
- of_list = malloc(of_size*sizeof(oper_func_t));
- }
- }
- of_list[of_used++] = handler;
-}
+ if (!IsLocal(user) || user->num_local >= num_privmsg_funcs)
+ return; /* this really only works with users */
-static void
-call_oper_funcs(struct userNode *user)
-{
- unsigned int n;
- if (IsLocal(user))
- return;
- for (n=0; n<of_used; n++)
- of_list[n](user);
+ notice_funcs[user->num_local] = NULL;
}
static void
for (it = dict_first(channels); it; it = iter_next(it))
dict_insert(unbursted_channels, iter_key(it), iter_data(it));
}
+
+/*
+ * Oplevel parsing
+ */
+static int
+parse_oplevel(char *str)
+{
+ int oplevel = 0;
+ while (isdigit(*str))
+ oplevel = oplevel * 10 + *str++ - '0';
+ return oplevel;
+}
+