/* 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, unsigned long timestamp, const char *realip);
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);
}
}
}
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
{
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
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;
}
* 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) {
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;
}
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, 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));
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 '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)
{