/* proto-p10.c - IRC protocol output
- * Copyright 2000-2006 srvx Development Team
+ * Copyright 2000-2008 srvx Development Team
*
* This file is part of srvx.
*
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 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);
+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;
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 +s6 :%s",
- srv->name, srv->hops+1, srv->boot, srv->link, srv->numeric, extranum, srv->description);
+ putsock(P10_SERVER " %s %d %lu %lu J10 %s%s +s6 :%s",
+ srv->name, srv->hops+1, srv->boot, srv->link_time, srv->numeric, extranum, srv->description);
} else {
- putsock("%s " P10_SERVER " %s %d %li %li %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);
+ putsock("%s " P10_SERVER " %s %d %lu %lu %c10 %s%s +s6 :%s",
+ self->numeric, srv->name, srv->hops+1, srv->boot, srv->link_time, (srv->self_burst ? 'J' : 'P'), srv->numeric, extranum, srv->description);
}
}
modes[modelen] = 0;
/* 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",
- user->uplink->numeric, user->nick, user->uplink->hops+1, user->timestamp, user->ident, user->hostname, modes, b64ip, user->numeric, user->info);
+ 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 {
- putsock("%s " P10_NICK " %s %d %li %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);
+ putsock("%s " P10_NICK " %s %d %lu %s %s %s %s :%s",
+ user->uplink->numeric, user->nick, user->uplink->hops+1, (unsigned long)user->timestamp, user->ident, user->hostname, b64ip, user->numeric, user->info);
}
}
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
void
irc_nick(struct userNode *user, UNUSED_ARG(const char *old_nick))
{
- putsock("%s " P10_NICK " %s "FMT_TIME_T, user->numeric, user->nick, now);
+ putsock("%s " P10_NICK " %s %lu", user->numeric, user->nick, (unsigned long)now);
}
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 " FMT_TIME_T ".%06u", self->numeric, who, orig_ts, diff, now.tv_sec, (unsigned)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
irc_gline(struct server *srv, struct gline *gline)
{
if (gline->lastmod)
- putsock("%s " P10_GLINE " %s +%s %ld %ld :%s",
- self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->lastmod, gline->reason);
+ 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);
else
- putsock("%s " P10_GLINE " %s +%s %ld :%s",
- self->numeric, (srv ? srv->numeric : "*"), gline->target, gline->expires-now, gline->reason);
+ putsock("%s " P10_GLINE " %s +%s %lu :%s",
+ self->numeric, (srv ? srv->numeric : "*"), gline->target, (unsigned long)(gline->expires-now), gline->reason);
}
void
-irc_settime(const char *srv_name_mask, time_t new_time)
+irc_settime(const char *srv_name_mask, unsigned long new_time)
{
ioset_set_time(new_time);
if (!strcmp(srv_name_mask, "*"))
srv_name_mask = "";
- putsock("%s " P10_SETTIME " " FMT_TIME_T " %s", self->numeric, new_time, srv_name_mask);
+ putsock("%s " P10_SETTIME " %lu %s", self->numeric, new_time, srv_name_mask);
}
void
unsigned int first_ban;
unsigned int n;
- base_len = sprintf(burst_line, "%s " P10_BURST " %s " FMT_TIME_T " ",
- self->numeric, chan->name, chan->timestamp);
+ base_len = sprintf(burst_line, "%s " P10_BURST " %s %lu ",
+ self->numeric, chan->name,
+ (unsigned long)chan->timestamp);
len = irc_make_chanmode(chan, burst_line+base_len);
pos = base_len + len;
if (len > 0 && chan->members.used > 0)
void
irc_mode(struct userNode *from, struct chanNode *target, const char *modes)
{
- putsock("%s " P10_MODE " %s %s "FMT_TIME_T,
+ putsock("%s " P10_MODE " %s %s %lu",
(from ? from->numeric : self->numeric),
- target->name, modes, target->timestamp);
+ target->name, modes, (unsigned long)target->timestamp);
}
void
{
if (what->members.used == 1) {
putsock("%s " P10_CREATE " %s %lu",
- who->numeric, what->name, what->timestamp);
+ who->numeric, what->name, (unsigned long)what->timestamp);
} else {
- putsock("%s " P10_JOIN " %s %lu", who->numeric, what->name, what->timestamp);
+ putsock("%s " P10_JOIN " %s %lu", who->numeric, what->name,
+ (unsigned long)what->timestamp);
}
}
void
irc_svsnick(struct userNode *from, struct userNode *target, const char *newnick)
{
- putsock("%s " P10_SVSNICK " %s %s "FMT_TIME_T, from->uplink->numeric, target->numeric, newnick, now);
+ putsock("%s " P10_SVSNICK " %s %s %lu", from->uplink->numeric, target->numeric, newnick, (unsigned long)now);
}
void
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 (srv->boot <= PREHISTORY) {
/* Server from the mists of time.. */
if (srv->hops == 1) {
- log_module(MAIN_LOG, LOG_ERROR, "Server %s claims to have booted at time "FMT_TIME_T". This is absurd.", srv->name, srv->boot);
+ log_module(MAIN_LOG, LOG_ERROR, "Server %s claims to have booted at time %lu. This is absurd.", srv->name, (unsigned long)srv->boot);
}
} else if ((str = conf_get_data("server/reliable_clock", RECDB_QSTRING))
&& enabled_string(str)) {
* 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) {
- extern time_t burst_begin;
+ extern unsigned long burst_begin;
burst_begin = now;
}
return 1;
static CMD_FUNC(cmd_eob_ack)
{
- extern time_t burst_begin;
+ extern unsigned long burst_begin;
if (GetServerH(origin) == self->uplink) {
burst_length = now - burst_begin;
struct create_desc {
struct userNode *user;
- time_t when;
+ unsigned long when;
};
static void
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;
}
long mode;
int oplevel = -1;
char *user, *end, sep;
- time_t in_timestamp;
+ unsigned long in_timestamp;
if (argc < 3)
return 0;
static CMD_FUNC(cmd_topic)
{
struct chanNode *cn;
- time_t chan_ts, topic_ts;
+ unsigned long chan_ts, topic_ts;
if (argc < 3)
return 0;
static CMD_FUNC(cmd_num_gline)
{
- time_t lastmod;
+ unsigned long lastmod;
if (argc < 6)
return 0;
lastmod = (argc > 5) ? strtoul(argv[5], NULL, 0) : 0;
static CMD_FUNC(cmd_gline)
{
- time_t lastmod;
+ unsigned long lastmod;
if (argc < 3)
return 0;
return 1;
}
-static oper_func_t *of_list;
-static unsigned int of_size = 0, of_used = 0;
-
void
free_user(struct userNode *user)
{
for (nn=0; nn<dead_users.used; nn++)
free_user(dead_users.list[nn]);
userList_clean(&dead_users);
- free(his_servername);
- free(his_servercomment);
}
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
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) {
}
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, 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();
- time_t timestamp = now;
+ unsigned long timestamp = now;
struct userNode *old_user = GetUserH(nick);
if (!modes)
{
char numeric[COMBO_NUMERIC_LEN+1];
int local_num = get_local_numeric();
- time_t timestamp = now;
+ unsigned long timestamp = now;
struct userNode *old_user = GetUserH(nick);
if (old_user) {
}
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)
+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)
{
struct userNode *oldUser, *uNode;
unsigned int n, ignore_user, dummy;
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 (dummy) {
++modes;
} else if (!is_valid_nick(nick)) {
- log_module(MAIN_LOG, LOG_WARNING, "AddUser(%p, %s, ...): invalid nickname detected.", uplink, 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) {
- /* "Old" user is really newer; remove them */
+ 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 {
/* User being added is too new; do not add them to
}
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 '-': add = 0; break;
case 'o':
do_user_mode(FLAGS_OPER);
- if (add) {
+ if (!add) {
+ userList_remove(&curr_opers, user);
+ } else if (!userList_contains(&curr_opers, user)) {
userList_append(&curr_opers, user);
call_oper_funcs(user);
- } else {
- userList_remove(&curr_opers, user);
}
break;
case 'i': do_user_mode(FLAGS_INVISIBLE);
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(word + 1, &sep, 10);
+ } else if (*sep != ' ' && *sep != '\0') {
+ ts = 0;
+ }
+ }
+ tag[ii] = '\0';
while (*word == ' ')
word++;
- call_account_func(user, tag);
+ call_account_func(user, tag, ts, id);
}
break;
case 'f':
}
}
+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)
{
case 't': do_chan_mode(MODE_TOPICLIMIT); 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)) {
case 'U':
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 (add) {
- if (in_arg >= argc)
+ if ((in_arg >= argc)
+ || keyncpy(change->new_upass, modes[in_arg++], sizeof(change->new_upass)))
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)) {
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 '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 '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 '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++)
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)
{