/* proto-p10.c - IRC protocol output
- * Copyright 2000-2006 srvx Development Team
+ * Copyright 2000-2008 srvx Development Team
*
* This file is part of srvx.
*
#define CMD_EOB_ACK "EOB_ACK"
#define CMD_ERROR "ERROR"
#define CMD_FAKEHOST "FAKE"
+#define CMD_FAKEHOST2 "FAKE2"
#define CMD_GET "GET"
#define CMD_GLINE "GLINE"
#define CMD_HASH "HASH"
#define CMD_PROTO "PROTO"
#define CMD_QUIT "QUIT"
#define CMD_REHASH "REHASH"
+#define CMD_RELAY "RELAY"
#define CMD_RESET "RESET"
#define CMD_RESTART "RESTART"
#define CMD_RPING "RPING"
#define CMD_SQUIT "SQUIT"
#define CMD_STATS "STATS"
#define CMD_SVSNICK "SVSNICK"
+#define CMD_SVSMODE "SVSMODE"
+#define CMD_SVSJOIN "SVSJOIN"
+#define CMD_SVSPART "SVSPART"
#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_XQUERY "XQUERY"
+#define CMD_XRESPONSE "XRESPONSE"
/* Tokenized commands. */
#define TOK_ACCOUNT "AC"
#define TOK_EOB_ACK "EA"
#define TOK_ERROR "Y"
#define TOK_FAKEHOST "FA"
+#define TOK_FAKEHOST2 "NFH"
#define TOK_GET "GET"
#define TOK_GLINE "GL"
#define TOK_HASH "HASH"
#define TOK_PROTO "PROTO"
#define TOK_QUIT "Q"
#define TOK_REHASH "REHASH"
+#define TOK_RELAY "RL"
#define TOK_RESET "RESET"
#define TOK_RESTART "RESTART"
#define TOK_RPING "RI"
#define TOK_SQUIT "SQ"
#define TOK_STATS "R"
#define TOK_SVSNICK "SN"
+#define TOK_SVSMODE "SM"
+#define TOK_SVSJOIN "SJ"
+#define TOK_SVSPART "SP"
#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_XQUERY "XQ"
+#define TOK_XRESPONSE "XR"
/* Protocol messages; aliased to full commands or tokens depending
on compile-time configuration. ircu prefers tokens WITH THE
#define P10_EOB_ACK TYPE(EOB_ACK)
#define P10_ERROR TYPE(ERROR)
#define P10_FAKEHOST TYPE(FAKEHOST)
+#define P10_FAKEHOST2 TYPE(FAKEHOST2)
#define P10_GET TYPE(GET)
#define P10_GLINE TYPE(GLINE)
#define P10_HASH TYPE(HASH)
#define P10_PROTO TYPE(PROTO)
#define P10_QUIT TYPE(QUIT)
#define P10_REHASH TYPE(REHASH)
+#define P10_RELAY TYPE(RELAY)
#define P10_RESET TYPE(RESET)
#define P10_RESTART TYPE(RESTART)
#define P10_RPING TYPE(RPING)
#define P10_SQUIT TYPE(SQUIT)
#define P10_STATS TYPE(STATS)
#define P10_SVSNICK TYPE(SVSNICK)
+#define P10_SVSMODE TYPE(SVSMODE)
+#define P10_SVSJOIN TYPE(SVSJOIN)
+#define P10_SVSPART TYPE(SVSPART)
#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_XQUERY TYPE(XQUERY)
+#define P10_XRESPONSE TYPE(XRESPONSE)
/* Servers claiming to have a boot or link time before PREHISTORY
* trigger errors to the log. We hope no server has been running
static struct dict *unbursted_channels;
static const char *his_servername;
static const char *his_servercomment;
+static struct channelList dead_channels;
+
+/* These correspond to 1 << X: 012345678901234567890123 */
+const char irc_user_mode_chars[] = "o iw dkgn x ISDXHst";
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, unsigned long timestamp, const char *realip);
extern int off_channel;
-static int parse_oplevel(char *str);
+/*
+ * Oplevel parsing
+ */
+static int
+parse_oplevel(char *str)
+{
+ int oplevel = 0;
+ while (isdigit(*str))
+ oplevel = oplevel * 10 + *str++ - '0';
+ return oplevel;
+}
/* Numerics can be XYY, XYYY, or XXYYY; with X's identifying the
* server and Y's indentifying the client on that server. */
if (srv == self) {
/* The +s, ignored by Run's ircu, means "service" to Undernet's ircu */
putsock(P10_SERVER " %s %d %lu %lu J10 %s%s +s6 :%s",
- srv->name, srv->hops+1, srv->boot, srv->link, srv->numeric, extranum, srv->description);
+ srv->name, srv->hops+1, srv->boot, srv->link_time, srv->numeric, extranum, srv->description);
} else {
putsock("%s " P10_SERVER " %s %d %lu %lu %c10 %s%s +s6 :%s",
- self->numeric, srv->name, srv->hops+1, srv->boot, srv->link, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
+ self->numeric, srv->name, srv->hops+1, srv->boot, srv->link_time, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
}
}
do {
if (*input == '_') {
unsigned int left;
- for (left = (25 - strlen(input)) / 3; left; left--)
+ for (left = (25 - strlen(input)) / 3 - pos; left; left--)
ip->in6[pos++] = 0;
input++;
} else {
} else {
inttobase64(output, ntohs(ip->in6[ii]), 3);
output += 3;
+ ii += 1;
}
}
*output = '\0';
return;
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 (IsDeaf(user))
- modes[modelen++] = 'd';
- if (IsGlobal(user))
- modes[modelen++] = 'g';
- if (IsNoChan(user))
- modes[modelen++] = 'n';
- if (IsHiddenHost(user))
- modes[modelen++] = 'x';
- if (IsNoIdle(user))
- modes[modelen++] = 'I';
- modes[modelen] = 0;
-
- /* we don't need to put the + in modes because it's in the format string. */
+ irc_user_modes(user, modes, sizeof(modes));
putsock("%s " P10_NICK " %s %d %lu %s %s +%s %s %s :%s",
user->uplink->numeric, user->nick, user->uplink->hops+1, (unsigned long)user->timestamp, user->ident, user->hostname, modes, b64ip, user->numeric, user->info);
} else {
}
void
-irc_account(struct userNode *user, const char *stamp)
+irc_account(struct userNode *user, const char *stamp, unsigned long timestamp, unsigned long serial)
{
- putsock("%s " P10_ACCOUNT " %s %s", self->numeric, user->numeric, stamp);
+ putsock("%s " P10_ACCOUNT " %s %s %lu %lu", self->numeric, user->numeric, stamp, timestamp, serial);
}
void
-irc_fakehost(struct userNode *user, const char *host)
+irc_fakehost(struct userNode *user, const char *host, const char *ident, int force)
{
- putsock("%s " P10_FAKEHOST " %s %s", self->numeric, user->numeric, host);
+ /* SRVX added the possibility for FAKE IDENTS
+ * but this is currently *NOT* supported by our IRCu
+ *
+ * edit 24.11.11:
+ * NFH (P10_FAKEHOST2) is now supported by our IRCu (git-65-21592a4)
+ */
+ putsock("%s " P10_FAKEHOST2 " %s %s %s%s", self->numeric, user->numeric, ident, host, force ? " FORCE" : "");
+}
+
+void
+irc_relay(char *message)
+{
+ putsock("%s " P10_RELAY " %s", self->numeric, message);
+}
+
+void
+irc_simul(struct userNode *target, char *command)
+{
+ putsock("%s " P10_RELAY " %s SI %s :%s", self->numeric, target->numeric, target->numeric, command);
+}
+
+void
+irc_keepconn(struct userNode *target, unsigned int timeout)
+{
+ putsock("%s " P10_RELAY " %s KC %s %u", self->numeric, target->numeric, target->numeric, timeout);
}
void
putsock("%s " P10_PRIVMSG " %s :%s", from->numeric, to, message);
}
+void
+irc_svsmode(struct userNode *from, struct userNode *user, const char *modes)
+{
+putsock("%s " P10_SVSMODE " %s %s", from->numeric, user->numeric, modes);
+}
+
+void
+irc_svsjoin(struct userNode *from, struct userNode *user, struct chanNode *chan)
+{
+putsock("%s " P10_SVSJOIN " %s %s", from->numeric, user->numeric, chan->name);
+}
+
+void
+irc_svsjoinchan(struct userNode *from, struct userNode *user, const char *chan)
+{
+putsock("%s " P10_SVSJOIN " %s %s", from->numeric, user->numeric, chan);
+}
+
+void
+irc_svspart(struct userNode *from, struct userNode *user, struct chanNode *chan)
+{
+putsock("%s " P10_SVSPART " %s %s", from->numeric, user->numeric, chan->name);
+}
+
+void
+irc_svspartchan(struct userNode *from, struct userNode *user, const char *chan)
+{
+putsock("%s " P10_SVSPART " %s %s", from->numeric, user->numeric, chan);
+}
+
void
irc_eob(void)
{
{
char *delim;
struct timeval orig;
- struct timeval now;
+ 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(&now, NULL);
- diff = (now.tv_sec - orig.tv_sec) * 1000 + (now.tv_usec - orig.tv_usec) / 1000;
- putsock("%s " P10_PONG " %s %s %d %lu.%06lu", self->numeric, who, orig_ts, diff, (unsigned long)now.tv_sec, (unsigned long)now.tv_usec);
+ 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
void
irc_gline(struct server *srv, struct gline *gline)
{
+ //<prefix> GL <target> [!][+|-|>|<]<mask> [<expiration>] [<lastmod>] [<lifetime>] [:<reason>]
+ //expiration = relative time (seconds)
+ //lastmod = timestamp
+ //livetime = timestamp
if (gline->lastmod)
- putsock("%s " P10_GLINE " %s +%s %lu %lu :%s",
- self->numeric, (srv ? srv->numeric : "*"), gline->target, (unsigned long)(gline->expires-now), (unsigned long)gline->lastmod, gline->reason);
+ putsock("%s " P10_GLINE " %s +%s %lu %lu %lu :%s", self->numeric, (srv ? srv->numeric : "*"),
+ gline->target, gline->expires-now, gline->lastmod, gline->lifetime, gline->reason);
else
- putsock("%s " P10_GLINE " %s +%s %lu :%s",
- self->numeric, (srv ? srv->numeric : "*"), gline->target, (unsigned long)(gline->expires-now), gline->reason);
+ putsock("%s " P10_GLINE " %s +%s %lu :%s", self->numeric, (srv ? srv->numeric : "*"),
+ gline->target, gline->expires-now, gline->reason);
}
void
void
irc_ungline(const char *mask)
{
- putsock("%s " P10_GLINE " * -%s", self->numeric, mask);
+ putsock("%s " P10_GLINE " * -%s %lu", self->numeric, mask, now);
+ //putsock("%s " P10_GLINE " * %s * %lu", self->numeric, mask, now);
+}
+
+/* Return negative if *(struct modeNode**)pa is "less than" pb,
+ * positive if pa is "larger than" pb. Comparison is based on sorting
+ * so that non-voiced/non-opped users are first, voiced-only users are
+ * next, and the "strongest" oplevels are before "weaker" oplevels.
+ * Within those sets, ordering is arbitrary.
+ */
+static int
+modeNode_sort_p10(const void *pa, const void *pb)
+{
+ struct modeNode *a = *(struct modeNode**)pa;
+ struct modeNode *b = *(struct modeNode**)pb;
+
+ if (a->modes & MODE_CHANOP) {
+ if (!(b->modes & MODE_CHANOP))
+ return 1;
+ else if ((a->modes & MODE_VOICE) != (b->modes & MODE_VOICE))
+ return (a->modes & MODE_VOICE) - (b->modes & MODE_VOICE);
+ else if (a->oplevel != b->oplevel)
+ return a->oplevel - b->oplevel;
+ } else if (b->modes & MODE_CHANOP)
+ return -1;
+ else if ((a->modes & MODE_VOICE) != (b->modes & MODE_VOICE))
+ return (a->modes & MODE_VOICE) - (b->modes & MODE_VOICE);
+ return (a < b) ? -1 : 1;
}
static void
int pos, base_len, len;
struct modeNode *mn;
struct banNode *bn;
- long last_mode=-1;
+ int last_oplevel = 0;
+ int last_mode = 0;
+ int new_modes;
unsigned int first_ban;
unsigned int n;
if (len > 0 && chan->members.used > 0)
burst_line[pos++] = ' ';
+ /* sort the users for oplevel-sending purposes */
+ qsort(chan->members.list, chan->members.used, sizeof(chan->members.list[0]), modeNode_sort_p10);
+
/* dump the users */
for (n=0; n<chan->members.used; n++) {
mn = chan->members.list[n];
burst_line[pos-1] = 0; /* -1 to back up over the space or comma */
putsock("%s", burst_line);
pos = base_len;
- last_mode = -1;
+ last_mode = 0;
+ last_oplevel = 0;
}
memcpy(burst_line+pos, mn->user->numeric, strlen(mn->user->numeric));
pos += strlen(mn->user->numeric);
- if (mn->modes && (mn->modes != last_mode)) {
- last_mode = mn->modes;
+ new_modes = mn->modes & (MODE_CHANOP | MODE_VOICE);
+ if (new_modes != last_mode) {
+ last_mode = new_modes;
burst_line[pos++] = ':';
- if (last_mode & MODE_CHANOP)
- burst_line[pos++] = 'o';
- if (last_mode & MODE_VOICE)
+ if (new_modes & MODE_VOICE)
burst_line[pos++] = 'v';
+ /* Note: :vNNN (oplevel NNN with voice) resets the
+ * implicit oplevel back to zero, so we always use the raw
+ * oplevel value here. Read ircu's m_burst.c for more
+ * examples.
+ */
+ if (new_modes & MODE_CHANOP) {
+ last_oplevel = mn->oplevel;
+ if (mn->oplevel < MAXOPLEVEL)
+ pos += sprintf(burst_line + pos, "%u", mn->oplevel);
+ else
+ burst_line[pos++] = 'o';
+ }
+ } else if ((last_mode & MODE_CHANOP) && (mn->oplevel != last_oplevel)) {
+ pos += sprintf(burst_line + pos, ":%u", mn->oplevel - last_oplevel);
+ last_oplevel = mn->oplevel;
}
if ((n+1)<chan->members.used)
burst_line[pos++] = ',';
irc_kill(struct userNode *from, struct userNode *target, const char *message)
{
if (from) {
- putsock("%s " P10_KILL " %s :%s!%s (%s)",
- from->numeric, target->numeric, self->name, from->nick, message);
+ putsock("%s " P10_KILL " %s :%s (%s)",
+ from->numeric, target->numeric, from->nick, message);
} else {
putsock("%s " P10_KILL " %s :%s (%s)",
self->numeric, target->numeric, self->name, message);
putsock(":%s %03d %s %s", self->name, num, user->nick, buffer);
}
+void
+irc_xresponse(struct server *target, const char *routing, const char *response)
+{
+ putsock("%s " P10_XRESPONSE " %s %s :%s", self->numeric, target->numeric, routing, response);
+}
+
static void send_burst(void);
static void
return 1;
}
- if (IsFakeHost(who) && IsHiddenHost(who))
+ if (IsFakeHost(who) && IsFakeIdent(who) && IsHiddenHost(who))
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->fakeident, who->fakehost, who->info);
+ else if (IsFakeIdent(who) && IsHiddenHost(who))
+ irc_numeric(from, RPL_WHOISUSER, "%s %s %s * :%s", who->nick, who->fakeident, who->hostname, who->info);
+ else 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);
* 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;
}
+ handle_new_channel_created(name, cd->user);
+
AddChannelUser(cd->user, AddChannel(name, cd->when, NULL, NULL));
}
static CMD_FUNC(cmd_account)
{
struct userNode *user;
+ unsigned long timestamp = 0;
+ unsigned long serial = 0;
if ((argc < 3) || !origin || !GetServerH(origin))
return 0; /* Origin must be server. */
user = GetUserN(argv[1]);
if (!user)
return 1; /* A QUIT probably passed the ACCOUNT. */
- call_account_func(user, argv[2]);
+ if (argc > 3)
+ timestamp = strtoul(argv[3], NULL, 10);
+ if (argc > 4)
+ serial = strtoul(argv[4], NULL, 10);
+ call_account_func(user, argv[2], timestamp, serial);
return 1;
}
static CMD_FUNC(cmd_fakehost)
{
struct userNode *user;
+ const char *host, *ident;
if ((argc < 3) || !origin || !GetServerH(origin))
return 0;
if (!(user = GetUserN(argv[1])))
return 1;
- assign_fakehost(user, argv[2], 0);
+
+ if (argc > 3) {
+ ident = argv[2];
+ host = argv[3];
+ } else {
+ ident = NULL;
+ host = argv[2];
+ }
+
+ assign_fakehost(user, host, ident, 0, 0);
return 1;
}
struct userNode *un;
struct modeNode *mNode;
long mode;
- int oplevel = -1;
+ int oplevel = 0;
char *user, *end, sep;
unsigned long in_timestamp;
int n_modes;
for (pos=argv[next], n_modes = 1; *pos; pos++)
if ((*pos == 'k') || (*pos == 'l') || (*pos == 'A')
- || (*pos == 'U'))
+ || (*pos == 'U') || (*pos == 'a') || (*pos == 'F'))
n_modes++;
if (next + n_modes > argc)
n_modes = argc - next;
while ((sep = *end++)) {
if (sep == 'o') {
mode |= MODE_CHANOP;
- oplevel = -1;
+ oplevel = MAXOPLEVEL;
} else if (sep == 'v') {
mode |= MODE_VOICE;
- oplevel = -1;
+ oplevel = 0;
} else if (isdigit(sep)) {
mode |= MODE_CHANOP;
- if (oplevel >= 0)
- oplevel += parse_oplevel(end);
- else
- oplevel = parse_oplevel(end);
+ oplevel += parse_oplevel(end - 1);
while (isdigit(*end)) end++;
} else
break;
log_module(MAIN_LOG, LOG_ERROR, "Unable to find user %s whose mode is changing.", argv[1]);
return 0;
}
+ argv[2] = unsplit_string(argv + 2, argc - 2, NULL);
mod_usermode(un, argv[2]);
return 1;
}
static CMD_FUNC(cmd_topic)
{
struct chanNode *cn;
- unsigned long chan_ts, topic_ts;
+ unsigned long topic_ts;
if (argc < 3)
return 0;
}
if (argc >= 5) {
/* Looks like an Asuka style topic burst. */
- chan_ts = atoi(argv[2]);
topic_ts = atoi(argv[3]);
} else {
- chan_ts = cn->timestamp;
topic_ts = now;
}
SetChannelTopic(cn, GetUserH(origin), argv[argc-1], 0);
static CMD_FUNC(cmd_num_gline)
{
unsigned long lastmod;
+ unsigned long lifetime;
+
if (argc < 6)
return 0;
lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
- gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, 0);
+ lifetime = (argc > 6) ? strtoul(argv[6], NULL, 0) : 0;
+ gline_add(origin, argv[3], atoi(argv[4])-now, argv[argc - 1], now, lastmod, lifetime, 0);
return 1;
}
{
if (argc < 3)
return 0;
+ if (GetUserN(argv[2]) && IsOper(GetUserN(argv[2])))
+ operpart(GetChannel(argv[1]), GetUserN(argv[2]));
ChannelUserKicked(GetUserH(origin), GetUserN(argv[2]), GetChannel(argv[1]));
return 1;
}
static CMD_FUNC(cmd_gline)
{
+#define PASTWATCH (5*365*24*3600)
unsigned long lastmod;
+ unsigned long lifetime;
+ unsigned long expiration;
if (argc < 3)
return 0;
if (argv[2][0] == '+') {
if (argc < 5)
return 0;
- lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
- gline_add(origin, argv[2]+1, strtoul(argv[3], NULL, 0), argv[argc-1], now, lastmod, 0);
+ expiration = strtoul(argv[3], NULL, 10);
+ if (expiration < now - PASTWATCH)
+ expiration += now;
+ lastmod = (argc > 5) ? strtoul(argv[4], NULL, 10) : 0;
+ lifetime = (argc > 6) ? strtoul(argv[5], NULL, 10) : 0;
+ gline_add(origin, argv[2]+1, expiration - now, argv[argc-1], now, lastmod, lifetime, 0);
return 1;
} else if (argv[2][0] == '-') {
gline_remove(argv[2]+1, 0);
return 1;
}
-static oper_func_t *of_list;
-static unsigned int of_size = 0, of_used = 0;
+static CMD_FUNC(cmd_time)
+{
+ extern int clock_skew;
+ char buf[MAXLEN];
+ struct userNode *who;
+ time_t when;
+
+ who = GetUserH(origin);
+ if (!who)
+ return 0;
+
+ when = time(NULL);
+ strftime(buf, sizeof(buf), "%a %b %d %Y -- %H:%M %z", localtime(&when));
+ irc_numeric(who, 391, "%s %lu %d :%s", self->name, now, clock_skew, buf);
+ return 1;
+}
+
+static CMD_FUNC(cmd_relay)
+{
+ struct server *sNode;
+ unsigned int len;
+ char buf[3];
+ //<sender> RELAY <destination> <command>
+ len = strlen(argv[1]);
+ buf[2] = 0;
+ switch(len) {
+ case 2:
+ sNode = GetServerN(argv[1]);
+ break;
+ case 5:
+ buf[0] = argv[1][0];
+ buf[1] = argv[1][1];
+ sNode = GetServerN(buf);
+ break;
+ case 6:
+ buf[0] = argv[1][1];
+ buf[1] = argv[1][2];
+ sNode = GetServerN(buf);
+ break;
+ default:
+ /* Invalid destination. Ignore. */
+ return 0;
+ }
+ if(sNode->numeric == self->numeric) {
+ //ok someone relayed something to us!
+ if(strcmp("LQ", argv[2]) == 0) {
+ //oooh thats exciting - we've got a LOC Query! :D
+ //ok let's check the login datas
+ struct handle_info *hi;
+ char tmp[MAXLEN], tmp2[MAXLEN];
+ sprintf(tmp, "%s@%s",argv[7],argv[6]);
+ sprintf(tmp2, "%s@%s",argv[7],argv[5]);
+ if((hi = checklogin(argv[4],argv[argc-1],&argv[3][1],tmp,tmp2))) {
+ //login ok
+ struct devnull_class th = devnull_user_get_class(hi);
+ char devnull[MAXLEN];
+
+ if(th.modes) {
+ const char *devnull_modes = DEVNULL_MODES;
+ int ii, flen = 0;
+ char flags[50];
+ for (ii = 0; devnull_modes[ii]; ++ii)
+ if(th.modes & (1 << ii))
+ flags[flen++] = devnull_modes[ii];
+ flags[flen] = 0;
+ sprintf(devnull, "+%s %s %lu %lu", flags, (th.name ? th.name : "custom"), (DEVNULL_HAS_PRIV(&th, CHANLIMIT) ? th.maxchan : 0), (DEVNULL_HAS_PRIV(&th, MAXSENDQ) ? th.maxsendq : 0));
+ } else
+ devnull[0] = 0;
+
+ if(!HANDLE_FLAGGED(hi, AUTOHIDE))
+ sprintf(tmp,"%s LA %s 0 %s\n",argv[3],hi->handle,devnull);
+ else if(getfakehost(argv[4]))
+ sprintf(tmp,"%s LA %s %s %s\n",argv[3],hi->handle,getfakehost(argv[4]),devnull);
+ else {
+ extern const char *hidden_host_suffix;
+ sprintf(tmp,"%s LA %s %s.%s %s\n",argv[3],hi->handle,hi->handle,hidden_host_suffix,devnull);
+ }
+ irc_relay(tmp);
+ } else {
+ //login rejected
+ sprintf(tmp,"%s LR\n",argv[3]);
+ irc_relay(tmp);
+ }
+ } else if(strcmp("UC", argv[2]) == 0) {
+ char tmp[MAXLEN];
+ sprintf(tmp,"%s UC %s %s",argv[3],argv[3],argv[4]);
+ irc_relay(tmp);
+ } else if(strcmp("JA", argv[2]) == 0) {
+ struct userData *uData;
+ struct chanNode *cn;
+ struct userNode *user;
+ char tmp[MAXLEN];
+ cn = GetChannel(argv[4]);
+ if (!cn) return 0;
+ if (!(user = GetUserN(argv[3]))) return 0;
+ if(!cn->channel_info) {
+ //channel not registered
+ sprintf(tmp,"%s JAA %s %s\n",argv[3],cn->name,argv[6]);
+ } else if((uData = GetChannelUser(cn->channel_info, user->handle_info))) {
+ if(uData->access >= atoi(argv[5])) {
+ //we can join
+ sprintf(tmp,"%s JAA %s %s\n",argv[3],cn->name,argv[6]);
+ } else {
+ //access too low
+ sprintf(tmp,"%s JAR %s %i %i\n",argv[3],cn->name,uData->access,uData->access);
+ }
+ } else {
+ //0 access
+ sprintf(tmp,"%s JAR %s %s %s\n",argv[3],cn->name,"0","0");
+ }
+ irc_relay(tmp);
+ }
+ }
+ return 1;
+}
+
+static CMD_FUNC(cmd_xquery)
+{
+ struct server *source;
+ if ((argc < 4)
+ || !(source = GetServerH(origin)))
+ return 0;
+ call_xquery_funcs(source, argv[2], argv[3]);
+ return 1;
+}
void
free_user(struct userNode *user)
dict_insert(irc_func_dict, TOK_STATS, cmd_stats);
dict_insert(irc_func_dict, CMD_SVSNICK, cmd_svsnick);
dict_insert(irc_func_dict, TOK_SVSNICK, cmd_svsnick);
+ dict_insert(irc_func_dict, CMD_RELAY, cmd_relay);
+ dict_insert(irc_func_dict, TOK_RELAY, cmd_relay);
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_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_TIME, cmd_time);
+ dict_insert(irc_func_dict, TOK_TIME, cmd_time);
+ /* We don't handle XR or the (not really defined) XQUERY. */
+ dict_insert(irc_func_dict, TOK_XQUERY, cmd_xquery);
/* In P10, DESTRUCT doesn't do anything except be broadcast to servers.
* Apparently to obliterate channels from any servers that think they
memset(notice_funcs, 0, sizeof(privmsg_func_t)*num_notice_funcs);
userList_init(&dead_users);
+ channelList_init(&dead_channels);
reg_del_channel_func(remove_unbursted_channel);
reg_exit_func(parse_cleanup);
}
for (i=0; i<dead_users.used; i++)
free_user(dead_users.list[i]);
dead_users.used = 0;
+ for (i=0; i<dead_channels.used; i++)
+ UnlockChannel(dead_channels.list[i]);
+ dead_channels.used = 0;
}
return res;
}
}
struct server *
-AddServer(struct server *uplink, const char *name, int hops, unsigned long boot, unsigned long link, const char *numeric, const char *description)
+AddServer(struct server *uplink, const char *name, int hops, unsigned long boot, unsigned long 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));
{
char numeric[COMBO_NUMERIC_LEN+1];
int local_num = get_local_numeric();
- unsigned long timestamp = now;
struct userNode *old_user = GetUserH(nick);
if (!modes)
if (old_user) {
if (IsLocal(old_user))
return old_user;
- timestamp = old_user->timestamp - 1;
}
if (local_num == -1) {
log_module(MAIN_LOG, LOG_ERROR, "Unable to allocate numnick for service %s", nick);
ignore_user = 0;
if ((oldUser = GetUserH(nick))) {
if (IsLocal(oldUser)
- && (IsService(oldUser) || IsPersistent(oldUser))
- && !uplink->burst) {
+ && (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 {
}
if (IsLocal(uNode))
irc_user(uNode);
- for (n=0; n<nuf_used; n++)
- if (nuf_list[n](uNode))
- break;
+ for (n=0; (n<nuf_used) && !uNode->dead; n++)
+ nuf_list[n](uNode);
return uNode;
}
case 'o':
do_user_mode(FLAGS_OPER);
if (!add) {
+ operdel(user);
userList_remove(&curr_opers, user);
} else if (!userList_contains(&curr_opers, user)) {
+ operadd(user);
userList_append(&curr_opers, user);
call_oper_funcs(user);
}
case 'g': do_user_mode(FLAGS_GLOBAL); break;
case 'n': do_user_mode(FLAGS_NOCHAN); break;
case 'I': do_user_mode(FLAGS_NOIDLE); break;
+ case 'S': do_user_mode(FLAGS_NETSERV); break;
+ case 'D': do_user_mode(FLAGS_SECURITYSERV); break;
+ case 'X': do_user_mode(FLAGS_XTRAOP); break;
+ case 's': do_user_mode(FLAGS_SERVERNOTICE); break;
+ case 'H': do_user_mode(FLAGS_HIDDENOPER); break;
+ case 't': do_user_mode(FLAGS_SEENOIDLE); break;
case 'x': do_user_mode(FLAGS_HIDDEN_HOST); break;
case 'r':
if (*word) {
char tag[MAXLEN];
+ char *sep;
unsigned int ii;
- for (ii=0; (*word != ' ') && (*word != '\0'); )
+ unsigned long ts = 0;
+ unsigned long id = 0;
+
+ for (ii=0; (*word != ' ') && (*word != '\0') && (*word != ':'); )
tag[ii++] = *word++;
- tag[ii] = 0;
+ if (*word == ':') {
+ ts = strtoul(word + 1, &sep, 10);
+ if (*sep == ':') {
+ id = strtoul(sep + 1, &sep, 10);
+ } else if (*sep != ' ' && *sep != '\0') {
+ ts = 0;
+ }
+ word = sep;
+ }
+ tag[ii] = '\0';
while (*word == ' ')
word++;
- call_account_func(user, tag);
+ call_account_func(user, tag, ts, id);
}
break;
- case 'f':
+ case 'h':
if (*word) {
- char host[MAXLEN];
+ char mask[MAXLEN];
+ char *host, *ident;
unsigned int ii;
+
for (ii=0; (*word != ' ') && (*word != '\0'); )
- host[ii++] = *word++;
- host[ii] = 0;
+ mask[ii++] = *word++;
+ mask[ii] = 0;
while (*word == ' ')
word++;
- assign_fakehost(user, host, 0);
+
+ if ((host = strrchr(mask, '@'))) {
+ ident = mask;
+ *host++ = '\0';
+ } else {
+ ident = NULL;
+ host = mask;
+ }
+ user->modes |= FLAGS_HIDDEN_HOST;
+ assign_fakehost(user, host, ident, 0, 0);
}
break;
}
}
}
+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, short base_oplevel)
+mod_chanmode_parse(struct chanNode *channel, struct userNode *user, char **modes, unsigned int argc, unsigned int flags, short base_oplevel)
{
struct mod_chanmode *change;
unsigned int ii, in_arg, ch_arg, add;
case 'C': do_chan_mode(MODE_NOCTCPS); break;
case 'D': do_chan_mode(MODE_DELAYJOINS); break;
case 'c': do_chan_mode(MODE_NOCOLORS); break;
+ case 'M': do_chan_mode(MODE_NOAMSGS); break;
+ case 'N': do_chan_mode(MODE_NONOTICES); break;
+ case 'u': do_chan_mode(MODE_AUDITORIUM); break;
+ case 'S': do_chan_mode(MODE_SSLCHAN); break;
case 'i': do_chan_mode(MODE_INVITEONLY); break;
case 'm': do_chan_mode(MODE_MODERATED); break;
case 'n': do_chan_mode(MODE_NOPRIVMSGS); break;
case 's': do_chan_mode(MODE_SECRET); break;
case 't': do_chan_mode(MODE_TOPICLIMIT); break;
case 'z':
- if (!(flags & MCP_REGISTERED)) {
- do_chan_mode(MODE_REGISTERED);
+ if (!(flags & MCP_REGISTERED) && (!(flags & MCP_IGN_REGISTERED) || add)) {
+ do_chan_mode(MODE_REGISTERED);
+ } else if (flags & MCP_IGN_REGISTERED) {
+ /* ignore the modechange but continue parsing */
} else {
- mod_chanmode_free(change);
- return NULL;
+ mod_chanmode_free(change);
+ return NULL;
}
break;
#undef do_chan_mode
change->modes_clear |= MODE_LIMIT;
}
break;
- case 'k':
+ case 'a':
if (add) {
if (in_arg >= argc)
goto error;
+ change->modes_set |= MODE_ACCESS;
+ change->new_access = atoi(modes[in_arg++]);
+ } else {
+ change->modes_set &= ~MODE_ACCESS;
+ change->modes_clear |= MODE_ACCESS;
+ }
+ break;
+ case 'k':
+ if (add) {
+ 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 'f':
+ if (add) {
+ if (in_arg >= argc)
+ goto error;
+ char *mode = modes[in_arg++];
+ if(mode[0] == '!' && !(flags & MCP_OPERMODE)) //noflood flag also for overriders
+ goto error;//only allow opers
+ else if(mode[0] == '!')
+ mode++;
+
+ if(mode[0] == '+' || mode[0] == '@') {
+ mode++;
+ }
+ char *p;
+ int count = 0, time = 0;
+ for(p = mode; p[0]; p++) {
+ if(p[0] == ':') {
+ char tmpchar = p[0];
+ p[0] = '\0';
+ count = strtoul(mode,0,10);
+ p[0] = tmpchar;
+ p++;
+ time = strtoul(p,0,10);
+ break;
+ }
+ }
+ if(count <= 0 || time <= 0 || count > 100 || time > 600)
+ goto error;
+ change->modes_set |= MODE_NOFLOOD;
+ safestrncpy(change->new_noflood, modes[in_arg - 1], sizeof(change->new_noflood));
+ } else {
+ change->modes_clear |= MODE_NOFLOOD;
+ }
+ break;
+ case 'F':
+ if (add) {
+ if (in_arg >= argc)
+ goto error;
+ char *altchan = modes[in_arg++];
+ struct chanNode *target;
+ if(!IsChannelName(altchan) || !(target = GetChannel(altchan)))
+ goto error;
+ if(!(flags & MCP_OPERMODE)) {
+ //check if the user has the permissions to use this channel as target
+ struct modeNode *mn;
+ struct userData *uData;
+ struct chanData *cData;
+ if(user && (mn = GetUserMode(target, user)) && (mn->modes & MODE_CHANOP)) {
+ //allow - user is opped on target channel
+ } else if(user && user->handle_info &&
+ (uData = GetChannelUser(channel->channel_info, user->handle_info)) &&
+ (cData = uData->channel) &&
+ uData->access >= cData->lvlOpts[lvlGiveOps]
+ ) {
+ //allow - user has access to get op on the channel
+ } else
+ goto error;
+ }
+ change->modes_set |= MODE_ALTCHAN;
+ safestrncpy(change->new_altchan, altchan, sizeof(change->new_altchan));
+ } else {
+ change->modes_clear |= MODE_ALTCHAN;
+ }
+ break;
case 'U':
+ if (flags & MCP_NO_APASS)
+ goto error;
if (add)
{
- if (in_arg >= argc)
- goto error;
- change->modes_set |= MODE_UPASS;
- safestrncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass));
+ 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)) {
}
break;
case 'A':
+ if (flags & MCP_NO_APASS)
+ goto error;
if (add) {
- if (in_arg >= argc)
+ if ((in_arg >= argc)
+ || keyncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass)))
goto error;
change->modes_set |= MODE_APASS;
- safestrncpy(change->new_apass, modes[in_arg++], sizeof(change->new_apass));
} else {
change->modes_clear |= MODE_APASS;
if (!(flags & MCP_APASS_FREE)) {
else if (channel->modes & MODE_UPASS)
oplevel = base_oplevel + 1;
else
- oplevel = -1;
+ oplevel = MAXOPLEVEL;
/* Check that oplevel is within bounds. */
if (oplevel > MAXOPLEVEL)
continue;
if ((change->args[ch_arg].u.member = GetUserMode(channel, victim)))
{
- /* Apply the oplevel change */
- change->args[ch_arg].u.member->oplevel = oplevel;
+ /* Apply the oplevel change if the user is being (de-)opped */
+ if (modes[0][ii] == 'o')
+ change->args[ch_arg].u.member->oplevel = oplevel;
ch_arg++;
}
break;
change->modes_set &= ~(MODE_SECRET);
change->modes_clear |= MODE_SECRET;
}
+ if (change->modes_clear & MODE_REGISTERED) {
+ /* Horribly cheat by using the lock/unlock semantics. */
+ LockChannel(channel);
+ channelList_append(&dead_channels, channel);
+ }
return change;
error:
mod_chanmode_free(change);
DO_MODE_CHAR(INVITEONLY, 'i');
DO_MODE_CHAR(NOPRIVMSGS, 'n');
DO_MODE_CHAR(LIMIT, 'l');
+ DO_MODE_CHAR(ACCESS, 'a');
+ DO_MODE_CHAR(ALTCHAN, 'F');
+ DO_MODE_CHAR(NOFLOOD, 'f');
DO_MODE_CHAR(DELAYJOINS, 'D');
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(NONOTICES, 'N');
+ DO_MODE_CHAR(NOAMSGS, 'M');
+ DO_MODE_CHAR(AUDITORIUM, 'u');
+ DO_MODE_CHAR(SSLCHAN, 'S');
DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
if (change->modes_clear & channel->modes & MODE_KEY)
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(NONOTICES, 'N');
+ DO_MODE_CHAR(NOAMSGS, 'M');
+ DO_MODE_CHAR(AUDITORIUM, 'u');
+ DO_MODE_CHAR(SSLCHAN, 'S');
DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
if(change->modes_set & MODE_KEY)
sprintf(int_buff, "%d", change->new_limit);
mod_chanmode_append(&chbuf, 'l', int_buff);
}
+ if(change->modes_set & MODE_ACCESS) {
+ sprintf(int_buff, "%d", change->new_access);
+ mod_chanmode_append(&chbuf, 'a', int_buff);
+ }
+ if (change->modes_set & MODE_ALTCHAN)
+ mod_chanmode_append(&chbuf, 'F', change->new_altchan);
+ if (change->modes_set & MODE_NOFLOOD)
+ mod_chanmode_append(&chbuf, 'f', change->new_noflood);
}
for (arg = 0; arg < change->argc; ++arg) {
if (change->args[arg].mode & MODE_REMOVE)
mod_chanmode_format(struct mod_chanmode *change, char *outbuff)
{
unsigned int used = 0;
+ unsigned int args_used = 0;
+ char args[MAXLEN];
+
assert(change->argc <= change->alloc_argc);
if (change->modes_clear) {
outbuff[used++] = '-';
DO_MODE_CHAR(INVITEONLY, 'i');
DO_MODE_CHAR(NOPRIVMSGS, 'n');
DO_MODE_CHAR(LIMIT, 'l');
+ DO_MODE_CHAR(ACCESS, 'a');
+ DO_MODE_CHAR(ALTCHAN, 'F');
+ DO_MODE_CHAR(NOFLOOD, 'f');
DO_MODE_CHAR(KEY, 'k');
DO_MODE_CHAR(UPASS, 'U');
DO_MODE_CHAR(APASS, 'A');
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(NONOTICES, 'N');
+ DO_MODE_CHAR(NOAMSGS, 'M');
+ DO_MODE_CHAR(AUDITORIUM, 'u');
+ DO_MODE_CHAR(SSLCHAN, 'S');
DO_MODE_CHAR(REGISTERED, 'z');
#undef DO_MODE_CHAR
}
DO_MODE_CHAR(REGONLY, 'r');
DO_MODE_CHAR(NOCOLORS, 'c');
DO_MODE_CHAR(NOCTCPS, 'C');
+ DO_MODE_CHAR(NONOTICES, 'N');
+ DO_MODE_CHAR(NOAMSGS, 'M');
+ DO_MODE_CHAR(AUDITORIUM, 'u');
+ DO_MODE_CHAR(SSLCHAN, 'S');
DO_MODE_CHAR(REGISTERED, 'z');
+ DO_MODE_CHAR(LIMIT, 'l'), args_used += sprintf(args + args_used, " %d", change->new_limit);
+ DO_MODE_CHAR(KEY, 'k'), args_used += sprintf(args + args_used, " %s", change->new_key);
+ DO_MODE_CHAR(ACCESS, 'a'), args_used += sprintf(args + args_used, " %d", change->new_access);
+ DO_MODE_CHAR(ALTCHAN, 'F'), args_used += sprintf(args + args_used, " %s", change->new_altchan);
+ DO_MODE_CHAR(NOFLOOD, 'f'), args_used += sprintf(args + args_used, " %s", change->new_noflood);
+ DO_MODE_CHAR(UPASS, 'U'), args_used += sprintf(args + args_used, " %s", change->new_upass);
+ DO_MODE_CHAR(APASS, 'A'), args_used += sprintf(args + args_used, " %s", change->new_apass);
#undef DO_MODE_CHAR
- switch (change->modes_set & (MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS)) {
- /* Doing this implementation has been a pain in the arse, I hope I didn't forget a possible combination */
- case MODE_KEY|MODE_LIMIT|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "lkAU %d %s %s %s", change->new_limit, change->new_key, change->new_apass, change->new_upass);
- break;
-
- case MODE_KEY|MODE_LIMIT|MODE_APASS:
- used += sprintf(outbuff+used, "lkA %d %s %s", change->new_limit, change->new_key, change->new_apass);
- break;
- case MODE_KEY|MODE_LIMIT|MODE_UPASS:
- used += sprintf(outbuff+used, "lkU %d %s %s", change->new_limit, change->new_key, change->new_upass);
- break;
- case MODE_KEY|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "kAU %s %s %s", change->new_key, change->new_apass, change->new_upass);
- break;
-
- case MODE_KEY|MODE_APASS:
- used += sprintf(outbuff+used, "kA %s %s", change->new_key, change->new_apass);
- break;
- case MODE_KEY|MODE_UPASS:
- used += sprintf(outbuff+used, "kU %s %s", change->new_key, change->new_upass);
- break;
- case MODE_KEY|MODE_LIMIT:
- used += sprintf(outbuff+used, "lk %d %s", change->new_limit, change->new_key);
- break;
- case MODE_LIMIT|MODE_UPASS:
- used += sprintf(outbuff+used, "lU %d %s", change->new_limit, change->new_upass);
- break;
- case MODE_LIMIT|MODE_APASS:
- used += sprintf(outbuff+used, "lA %d %s", change->new_limit, change->new_apass);
- break;
- case MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "AU %s %s", change->new_apass, change->new_upass);
- break;
-
- case MODE_LIMIT|MODE_APASS|MODE_UPASS:
- used += sprintf(outbuff+used, "lAU %d %s %s", change->new_limit, change->new_apass, change->new_upass);
- break;
-
- case MODE_APASS:
- used += sprintf(outbuff+used, "A %s", change->new_apass);
- break;
- case MODE_UPASS:
- used += sprintf(outbuff+used, "U %s", change->new_upass);
- 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;
- }
}
- outbuff[used] = 0;
+ args[args_used] = '\0';
+ strcpy(outbuff + used, args);
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 '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 '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 'F':
+ cleared |= MODE_ALTCHAN;
+ channel->altchan[0] = '\0';
+ break;
+ case 'f':
+ cleared |= MODE_NOFLOOD;
+ channel->noflood[0] = '\0';
+ break;
case 'k':
- remove |= MODE_KEY;
+ cleared |= MODE_KEY;
channel->key[0] = '\0';
break;
case 'A':
- remove |= MODE_APASS;
+ cleared |= MODE_APASS;
channel->apass[0] = '\0';
break;
case 'U':
- remove |= MODE_UPASS;
+ 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 'D': remove |= MODE_DELAYJOINS; break;
- case 'r': remove |= MODE_REGONLY; break;
- case 'c': remove |= MODE_NOCOLORS; break;
- case 'C': remove |= MODE_NOCTCPS; break;
- case 'z': remove |= MODE_REGISTERED; break;
+ case 'a':
+ cleared |= MODE_ACCESS;
+ channel->access = 0;
+ break;
+ case 'b': cleared |= MODE_BAN; 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 'M': cleared |= MODE_NOAMSGS; break;
+ case 'u': cleared |= MODE_AUDITORIUM; break;
+ case 'S': cleared |= MODE_SSLCHAN; break;
+ case 'N': cleared |= MODE_NONOTICES; break;
+ case 'z': cleared |= MODE_REGISTERED; 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]);
}
/* Remove member modes. */
- if ((remove & (MODE_CHANOP | MODE_VOICE)) && channel->members.used) {
- int mask = ~(remove & (MODE_CHANOP | MODE_VOICE));
+ if ((cleared & (MODE_CHANOP | MODE_VOICE)) && channel->members.used) {
+ int mask = ~(cleared & (MODE_CHANOP | MODE_VOICE));
unsigned int i;
for (i = 0; i < channel->members.used; i++)
if (numeric >= num_notice_funcs) {
int newnum = numeric + 8, ii;
notice_funcs = realloc(notice_funcs, newnum*sizeof(privmsg_func_t));
- for (ii = num_privmsg_funcs; ii < newnum; ++ii)
- privmsg_funcs[ii] = NULL;
+ for (ii = num_notice_funcs; ii < newnum; ++ii)
+ notice_funcs[ii] = NULL;
num_notice_funcs = newnum;
}
if (notice_funcs[numeric])
notice_funcs[user->num_local] = NULL;
}
-void
-reg_oper_func(oper_func_t handler)
-{
- 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;
-}
-
-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);
-}
-
static void
send_burst(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;
-}