#include <stdlib.h>
#include <string.h>
+#define PASTWATCH 157680000 /* number of seconds in 5 years */
+
+/*
+ * If the expiration value, interpreted as an absolute timestamp, is
+ * more recent than 5 years in the past, we interpret it as an
+ * absolute timestamp; otherwise, we assume it's relative and convert
+ * it to an absolute timestamp. Either way, the output of this macro
+ * is an absolute timestamp--not guaranteed to be a *valid* timestamp,
+ * but you can't have everything in a macro ;)
+ */
+#define abs_expire(exp) \
+ ((exp) >= CurrentTime - PASTWATCH ? (exp) : (exp) + CurrentTime)
+
/*
* ms_gline - server message handler
*
struct Gline *agline = 0;
unsigned int flags = 0;
enum GlineAction action = GLINE_MODIFY;
- time_t expire_off = 0, lastmod = 0, lifetime = 0;
+ time_t expire = 0, lastmod = 0, lifetime = 0;
char *mask = parv[2], *target = parv[1], *reason = "No reason", *tmp = 0;
if (parc < 3)
if ((action == GLINE_LOCAL_ACTIVATE || action == GLINE_LOCAL_DEACTIVATE) &&
!IsMe(acptr)) {
Debug((DEBUG_DEBUG, "I am forwarding a local change to a global gline "
- "to a remote server; target %s, mask %s, operforce %s, action %s",
+ "to a remote server; target %s, mask %s, operforce %s, action %c",
target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_LOCAL_ACTIVATE ? ">" : "<"));
+ action == GLINE_LOCAL_ACTIVATE ? '>' : '<'));
sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s", acptr,
flags & GLINE_OPERFORCE ? "!" : "",
- action == GLINE_LOCAL_ACTIVATE ? ">" : "<", mask);
+ action == GLINE_LOCAL_ACTIVATE ? '>' : '<', mask);
return 0; /* all done */
}
if (parc < 5) /* check parameter count... */
return need_more_params(sptr, "GLINE");
- expire_off = atoi(parv[3]); /* get expiration... */
+ expire = atoi(parv[3]); /* get expiration... */
+ expire = abs_expire(expire); /* convert to absolute... */
reason = parv[parc - 1]; /* and reason */
if (IsMe(acptr)) {
Debug((DEBUG_DEBUG, "I am creating a local G-line here; target %s, "
"mask %s, operforce %s, action %s, expire %Tu, reason: %s",
target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_ACTIVATE ? "+" : "-", expire_off, reason));
+ action == GLINE_ACTIVATE ? "+" : "-", expire, reason));
- return gline_add(cptr, sptr, mask, reason, expire_off, lastmod,
+ return gline_add(cptr, sptr, mask, reason, expire, lastmod,
lifetime, flags | GLINE_ACTIVE);
}
} else if (IsMe(acptr)) { /* destroying a local G-line */
assert(!IsMe(acptr));
Debug((DEBUG_DEBUG, "I am forwarding a local G-line to a remote server; "
- "target %s, mask %s, operforce %s, action %s, expire %Tu, "
+ "target %s, mask %s, operforce %s, action %c, expire %Tu, "
"lastmod %Tu, reason: %s", target, mask,
flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_ACTIVATE ? "+" : "-", expire_off, CurrentTime,
+ action == GLINE_ACTIVATE ? '+' : '-', expire, CurrentTime,
reason));
sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
acptr, flags & GLINE_OPERFORCE ? "!" : "",
- action == GLINE_ACTIVATE ? '+' : '-', mask, expire_off,
- CurrentTime, reason);
+ action == GLINE_ACTIVATE ? '+' : '-', mask,
+ expire - CurrentTime, CurrentTime, reason);
return 0; /* all done */
}
case GLINE_LOCAL_DEACTIVATE: /* locally deactivating a G-line */
if (!agline) /* no G-line to locally activate or deactivate? */
return send_reply(sptr, ERR_NOSUCHGLINE, mask);
+ lastmod = agline->gl_lastmod;
break; /* no additional parameters to manipulate */
case GLINE_ACTIVATE: /* activating a G-line */
case GLINE_MODIFY: /* modifying a G-line */
/* convert expire and lastmod, look for lifetime and reason */
if (parc > 4) { /* protect against fall-through from 4-param form */
- if (parc < 5)
- return need_more_params(sptr, "GLINE");
-
- expire_off = atoi(parv[3]); /* convert expiration and lastmod */
+ expire = atoi(parv[3]); /* convert expiration and lastmod */
+ expire = abs_expire(expire);
lastmod = atoi(parv[4]);
flags |= GLINE_EXPIRE; /* we have an expiration time update */
if (!agline || /* gline creation, has to be the reason */
/* trial-convert as lifetime, and if it doesn't fully convert,
* it must be the reason */
- ((lifetime = strtoul(parv[5], &tmp, 10)) && !*tmp)) {
+ (!(lifetime = strtoul(parv[5], &tmp, 10)) && !*tmp)) {
lifetime = 0;
reason = parv[5];
}
}
+ if (!lastmod) /* must have a lastmod parameter by now */
+ return need_more_params(sptr, "GLINE");
+
Debug((DEBUG_DEBUG, "I have a global G-line I am acting upon now; "
"target %s, mask %s, operforce %s, action %s, expire %Tu, "
"lastmod %Tu, lifetime %Tu, reason: %s; gline %s! (fields "
(action == GLINE_DEACTIVATE ? "-" :
(action == GLINE_LOCAL_ACTIVATE ? ">" :
(action == GLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))),
- expire_off, lastmod, lifetime, reason,
+ expire, lastmod, lifetime, reason,
agline ? "EXISTS" : "does not exist",
flags & GLINE_EXPIRE ? "expire" : "",
flags & GLINE_LIFETIME ? "lifetime" : "",
* Let's actually do the action!
*/
if (agline)
- return gline_modify(cptr, sptr, agline, action, reason, expire_off,
+ return gline_modify(cptr, sptr, agline, action, reason, expire,
lastmod, lifetime, flags);
assert(action != GLINE_LOCAL_ACTIVATE);
assert(action != GLINE_LOCAL_DEACTIVATE);
assert(action != GLINE_MODIFY);
- return gline_add(cptr, sptr, mask, reason, expire_off, lastmod, lifetime,
+ if (!expire) { /* Cannot *add* a G-line we don't have, but try hard */
+ Debug((DEBUG_DEBUG, "Propagating G-line %s for G-line we don't have",
+ action == GLINE_ACTIVATE ? "activation" : "deactivation"));
+
+ /* propagate the G-line, even though we don't have it */
+ sendcmdto_serv_butone(sptr, CMD_GLINE, cptr, "* %c%s %Tu",
+ action == GLINE_ACTIVATE ? '+' : '-',
+ mask, lastmod);
+
+ return 0;
+ }
+
+ return gline_add(cptr, sptr, mask, reason, expire, lastmod, lifetime,
flags | ((action == GLINE_ACTIVATE) ? GLINE_ACTIVE : 0));
}
struct Gline *agline = 0;
unsigned int flags = 0;
enum GlineAction action = GLINE_MODIFY;
- time_t expire_off = 0;
- char *mask = parv[1], *target = 0, *reason = 0;
+ time_t expire = 0;
+ char *mask = parv[1], *target = 0, *reason = 0, *end;
if (parc < 2)
return gline_list(sptr, 0);
return need_more_params(sptr, "GLINE");
target = parv[2]; /* get the target... */
- expire_off = atoi(parv[3]); /* and the expiration */
+ expire = strtol(parv[3], &end, 10) + CurrentTime; /* and the expiration */
+ if (*end != '\0')
+ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[3]);
flags |= GLINE_EXPIRE; /* remember that we got an expire time */
if (parc > 4) { /* also got a reason... */
- reason = parv[4];
+ reason = parv[parc - 1];
flags |= GLINE_REASON;
}
case GLINE_LOCAL_ACTIVATE: /* locally activate a G-line */
case GLINE_LOCAL_DEACTIVATE: /* locally deactivate a G-line */
- if (parc > 2) /* if target is available, pick it */
+ if (parc > 2) { /* if target is available, pick it */
target = parv[2];
+ if (target[0] == '*' && target[1] == '\0')
+ return send_reply(sptr, ERR_NOSUCHSERVER, target);
+ }
break;
case GLINE_ACTIVATE: /* activating/adding a G-line */
if (parc > 3) {
/* get expiration and target */
- expire_off = atoi(parv[parc - 2]);
reason = parv[parc - 1];
+ expire = strtol(parv[parc - 2], &end, 10) + CurrentTime;
+ if (*end != '\0')
+ return send_reply(sptr, SND_EXPLICIT | ERR_BADEXPIRE, "%s :Bad expire time", parv[parc - 2]);
flags |= GLINE_EXPIRE | GLINE_REASON; /* remember that we got 'em */
return send_reply(sptr, ERR_NOPRIVILEGES);
Debug((DEBUG_DEBUG, "I am forwarding a local change to a global gline "
- "to a remote server; target %s, mask %s, operforce %s, action %s",
+ "to a remote server; target %s, mask %s, operforce %s, action %c",
cli_name(acptr), mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_LOCAL_ACTIVATE ? ">" : "<"));
+ action == GLINE_LOCAL_ACTIVATE ? '>' : '<'));
sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s", acptr,
- flags & GLINE_OPERFORCE ? "!" : "",
- action == GLINE_LOCAL_ACTIVATE ? ">" : "<", mask);
+ flags & GLINE_OPERFORCE ? "!" : "",
+ action == GLINE_LOCAL_ACTIVATE ? '>' : '<', mask);
return 0; /* all done */
}
return send_reply(sptr, ERR_NOPRIVILEGES);
Debug((DEBUG_DEBUG, "I am forwarding a local G-line to a remote "
- "server; target %s, mask %s, operforce %s, action %s, "
+ "server; target %s, mask %s, operforce %s, action %c, "
"expire %Tu, reason %s", target, mask,
flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_ACTIVATE ? "+" : "-", expire_off, reason));
+ action == GLINE_ACTIVATE ? '+' : '-', expire, reason));
sendcmdto_one(sptr, CMD_GLINE, acptr, "%C %s%c%s %Tu %Tu :%s",
acptr, flags & GLINE_OPERFORCE ? "!" : "",
- action == GLINE_ACTIVATE ? "+" : "-", mask, expire_off,
- CurrentTime, reason);
+ action == GLINE_ACTIVATE ? '+' : '-', mask,
+ expire - CurrentTime, CurrentTime, reason);
return 0; /* all done */
}
Debug((DEBUG_DEBUG, "I am creating a local G-line here; target %s, "
"mask %s, operforce %s, action %s, expire %Tu, reason: %s",
target, mask, flags & GLINE_OPERFORCE ? "YES" : "NO",
- action == GLINE_ACTIVATE ? "+" : "-", expire_off, reason));
+ action == GLINE_ACTIVATE ? "+" : "-", expire, reason));
- return gline_add(cptr, sptr, mask, reason, expire_off, 0, 0,
+ return gline_add(cptr, sptr, mask, reason, expire, 0, 0,
flags | GLINE_ACTIVE);
} else { /* OK, it's a deactivation/destruction */
if (!agline) /* G-line doesn't exist, so let's complain... */
}
}
- /* can't modify a G-line that doesn't exist... */
+ /* can't modify a G-line that doesn't exist...
+ * (and if we are creating a new one, we need a reason and expiration)
+ */
if (!agline &&
(action == GLINE_MODIFY || action == GLINE_LOCAL_ACTIVATE ||
- action == GLINE_LOCAL_DEACTIVATE))
+ action == GLINE_LOCAL_DEACTIVATE || !reason || !expire))
return send_reply(sptr, ERR_NOSUCHGLINE, mask);
/* check for G-line permissions... */
(action == GLINE_DEACTIVATE ? "-" :
(action == GLINE_LOCAL_ACTIVATE ? ">" :
(action == GLINE_LOCAL_DEACTIVATE ? "<" : "(MODIFY)"))),
- expire_off, reason, agline ? "EXISTS" : "does not exist",
+ expire, reason, agline ? "EXISTS" : "does not exist",
flags & GLINE_EXPIRE ? "expire" : "",
flags & GLINE_REASON ? "reason" : ""));
if (agline) /* modifying an existing G-line */
- return gline_modify(cptr, sptr, agline, action, reason, expire_off,
+ return gline_modify(cptr, sptr, agline, action, reason, expire,
CurrentTime, 0, flags);
assert(action != GLINE_LOCAL_ACTIVATE);
assert(action != GLINE_MODIFY);
/* create a new G-line */
- return gline_add(cptr, sptr, mask, reason, expire_off, CurrentTime, 0,
+ return gline_add(cptr, sptr, mask, reason, expire, CurrentTime, 0,
flags | ((action == GLINE_ACTIVATE) ? GLINE_ACTIVE : 0));
}