summaryrefslogtreecommitdiff
path: root/src/sessions.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sessions.c')
-rw-r--r--src/sessions.c472
1 files changed, 282 insertions, 190 deletions
diff --git a/src/sessions.c b/src/sessions.c
index 29bb4b5f4..2bf0605ea 100644
--- a/src/sessions.c
+++ b/src/sessions.c
@@ -47,12 +47,6 @@
* exceptions. Comments and suggestions are more than welcome!
*
* -TheShadow (02 April 1999)
- *
- * The whole exception system has been rewritten to use linked list instead of
- * an array due to a bug we couldn't track down. We don't need the numerical
- * system anymore, it's not necessary to delete ranges.
- *
- * -Certus (04 July 2006)
*/
/*************************************************************************/
@@ -66,82 +60,10 @@
Session *sessionlist[1024];
int32 nsessions = 0;
-Exception *exceptionlist[1024];
+Exception *exceptions = NULL;
int16 nexceptions = 0;
/*************************************************************************/
-/************************ Exception Manipulation *************************/
-/*************************************************************************/
-
-Exception *exception_add(User * u, const char *mask, const int limit,
- const char *reason, const char *who,
- const time_t expires)
-{
- int i, index;
- Exception *exception, *ptr, *prev;
-
- /* Check if an exception already exists for this mask */
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- if (!stricmp(mask, exception->mask)) {
- if (exception->limit != limit) {
- exception->limit = limit;
- if (u)
- notice_lang(s_OperServ, u, OPER_EXCEPTION_CHANGED,
- mask, exception->limit);
- return NULL;
- } else {
- if (u)
- notice_lang(s_OperServ, u, OPER_EXCEPTION_EXISTS,
- mask);
- return NULL;
- }
- }
- }
- }
-
- nexceptions++;
- exception = scalloc(sizeof(Exception), 1);
-
- exception->mask = sstrdup(mask);
- exception->limit = limit;
- exception->reason = sstrdup(reason);
- exception->time = time(NULL);
- strscpy(exception->who, who, NICKMAX);
- exception->expires = expires;
-
- index = HASH(mask); /* bang! into the list! */
-
- exception->prev = NULL;
- exception->next = exceptionlist[index];
- if (exception->next)
- exception->next->prev = exception;
- exceptionlist[index] = exception;
-
- return exception;
-}
-
-/*************************************************************************/
-
-static int exception_del(Exception *exception)
-{
- /* Remove the exception from the list */
- if (exception->next)
- exception->next->prev = exception->prev;
- if (exception->prev)
- exception->prev->next = exception->next;
- else
- exceptionlist[HASH(exception->mask)] = exception->next;
-
- free(exception->mask);
- free(exception->reason);
- free(exception);
- nexceptions--;
-
- return 1;
-}
-
-/*************************************************************************/
/****************************** Statistics *******************************/
/*************************************************************************/
@@ -164,18 +86,14 @@ void get_session_stats(long *nrec, long *memuse)
void get_exception_stats(long *nrec, long *memuse)
{
- Exception *exception;
long mem;
int i;
mem = sizeof(Exception) * nexceptions;
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- mem += strlen(exception->mask) + 1;
- mem += strlen(exception->reason) + 1;
- }
+ for (i = 0; i < nexceptions; i++) {
+ mem += strlen(exceptions[i].mask) + 1;
+ mem += strlen(exceptions[i].reason) + 1;
}
-
*nrec = nexceptions;
*memuse = mem;
}
@@ -410,20 +328,22 @@ void del_session(const char *host)
void expire_exceptions(void)
{
int i;
- Exception *exception, *tmpexc;
time_t now = time(NULL);
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = tmpexc) {
- tmpexc = exception->next;
- if (exception->expires == 0 || exception->expires > now)
- continue;
- if (WallExceptionExpire)
- anope_cmd_global(s_OperServ,
- "Session limit exception for %s has expired.",
- exception->mask);
- exception_del(exception);
- }
+ for (i = 0; i < nexceptions; i++) {
+ if (exceptions[i].expires == 0 || exceptions[i].expires > now)
+ continue;
+ if (WallExceptionExpire)
+ anope_cmd_global(s_OperServ,
+ "Session limit exception for %s has expired.",
+ exceptions[i].mask);
+ free(exceptions[i].mask);
+ free(exceptions[i].reason);
+ nexceptions--;
+ memmove(exceptions + i, exceptions + i + 1,
+ sizeof(Exception) * (nexceptions - i));
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+ i--;
}
}
@@ -432,12 +352,10 @@ void expire_exceptions(void)
Exception *find_host_exception(const char *host)
{
int i;
- Exception *exception;
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- if (match_wild_nocase(exception->mask, host))
- return exception;
+ for (i = 0; i < nexceptions; i++) {
+ if (match_wild_nocase(exceptions[i].mask, host)) {
+ return &exceptions[i];
}
}
@@ -460,7 +378,7 @@ Exception *find_host_exception(const char *host)
void load_exceptions()
{
dbFILE *f;
- int i, index;
+ int i;
uint16 n;
uint16 tmp16;
uint32 tmp32;
@@ -474,31 +392,21 @@ void load_exceptions()
case 7:
SAFE(read_int16(&n, f));
nexceptions = n;
+ exceptions = scalloc(sizeof(Exception) * nexceptions, 1);
if (!nexceptions) {
close_db(f);
return;
}
for (i = 0; i < nexceptions; i++) {
-
- Exception *exception = scalloc(sizeof(Exception), 1);
-
- SAFE(read_string(&exception->mask, f));
+ SAFE(read_string(&exceptions[i].mask, f));
SAFE(read_int16(&tmp16, f));
- exception->limit = tmp16;
- SAFE(read_buffer(exception->who, f));
- SAFE(read_string(&exception->reason, f));
+ exceptions[i].limit = tmp16;
+ SAFE(read_buffer(exceptions[i].who, f));
+ SAFE(read_string(&exceptions[i].reason, f));
SAFE(read_int32(&tmp32, f));
- exception->time = tmp32;
+ exceptions[i].time = tmp32;
SAFE(read_int32(&tmp32, f));
- exception->expires = tmp32;
-
- index = HASH(exception->mask);
-
- exception->prev = NULL;
- exception->next = exceptionlist[index];
- if (exception->next)
- exception->next->prev = exception;
- exceptionlist[index] = exception;
+ exceptions[i].expires = tmp32;
}
break;
@@ -530,22 +438,19 @@ void save_exceptions()
{
dbFILE *f;
int i;
- Exception *exception;
static time_t lastwarn = 0;
if (!
(f = open_db(s_OperServ, ExceptionDBName, "w", EXCEPTION_VERSION)))
return;
SAFE(write_int16(nexceptions, f));
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- SAFE(write_string(exception->mask, f));
- SAFE(write_int16(exception->limit, f));
- SAFE(write_buffer(exception->who, f));
- SAFE(write_string(exception->reason, f));
- SAFE(write_int32(exception->time, f));
- SAFE(write_int32(exception->expires, f));
- }
+ for (i = 0; i < nexceptions; i++) {
+ SAFE(write_string(exceptions[i].mask, f));
+ SAFE(write_int16(exceptions[i].limit, f));
+ SAFE(write_buffer(exceptions[i].who, f));
+ SAFE(write_string(exceptions[i].reason, f));
+ SAFE(write_int32(exceptions[i].time, f));
+ SAFE(write_int32(exceptions[i].expires, f));
}
close_db(f);
}
@@ -558,20 +463,156 @@ void save_rdb_exceptions()
{
#ifdef USE_RDB
int i;
- Exception *exception;
+ Exception *e;
if (!rdb_open())
return;
rdb_clear_table("anope_os_exceptions");
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- rdb_save_exceptions(exception);
- }
+ for (i = 0; i < nexceptions; i++) {
+ e = &exceptions[i];
+ rdb_save_exceptions(e);
}
rdb_close();
#endif
}
+/*************************************************************************/
+/************************ Exception Manipulation *************************/
+/*************************************************************************/
+
+int exception_add(User * u, const char *mask, const int limit,
+ const char *reason, const char *who,
+ const time_t expires)
+{
+ int i;
+
+ /* Check if an exception already exists for this mask */
+ for (i = 0; i < nexceptions; i++) {
+ if (!stricmp(mask, exceptions[i].mask)) {
+ if (exceptions[i].limit != limit) {
+ exceptions[i].limit = limit;
+ if (u)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_CHANGED,
+ mask, exceptions[i].limit);
+ return -2;
+ } else {
+ if (u)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_EXISTS,
+ mask);
+ return -1;
+ }
+ }
+ }
+
+ nexceptions++;
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+
+ exceptions[nexceptions - 1].mask = sstrdup(mask);
+ exceptions[nexceptions - 1].limit = limit;
+ exceptions[nexceptions - 1].reason = sstrdup(reason);
+ exceptions[nexceptions - 1].time = time(NULL);
+ strscpy(exceptions[nexceptions - 1].who, who, NICKMAX);
+ exceptions[nexceptions - 1].expires = expires;
+ exceptions[nexceptions - 1].num = nexceptions - 1;
+
+ return 1;
+}
+
+/*************************************************************************/
+
+static int exception_del(const int index)
+{
+ if (index < 0 || index >= nexceptions)
+ return 0;
+
+ free(exceptions[index].mask);
+ free(exceptions[index].reason);
+ nexceptions--;
+ memmove(exceptions + index, exceptions + index + 1,
+ sizeof(Exception) * (nexceptions - index));
+ exceptions = srealloc(exceptions, sizeof(Exception) * nexceptions);
+
+ return 1;
+}
+
+/* We use the "num" property to keep track of the position of each exception
+ * when deleting using ranges. This is because an exception's position changes
+ * as others are deleted. The positions will be recalculated once the process
+ * is complete. -TheShadow
+ */
+
+static int exception_del_callback(User * u, int num, va_list args)
+{
+ int i;
+ int *last = va_arg(args, int *);
+
+ *last = num;
+ for (i = 0; i < nexceptions; i++) {
+ if (num - 1 == exceptions[i].num)
+ break;
+ }
+ if (i < nexceptions)
+ return exception_del(i);
+ else
+ return 0;
+}
+
+static int exception_list(User * u, const int index, int *sent_header)
+{
+ if (index < 0 || index >= nexceptions)
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_COLHEAD);
+ *sent_header = 1;
+ }
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_FORMAT, index + 1,
+ exceptions[index].limit, exceptions[index].mask);
+ return 1;
+}
+
+static int exception_list_callback(User * u, int num, va_list args)
+{
+ int *sent_header = va_arg(args, int *);
+
+ return exception_list(u, num - 1, sent_header);
+}
+
+static int exception_view(User * u, const int index, int *sent_header)
+{
+ char timebuf[32], expirebuf[256];
+ struct tm tm;
+ time_t t = time(NULL);
+
+ if (index < 0 || index >= nexceptions)
+ return 0;
+ if (!*sent_header) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
+ *sent_header = 1;
+ }
+
+ tm = *localtime(exceptions[index].time ? &exceptions[index].time : &t);
+ strftime_lang(timebuf, sizeof(timebuf),
+ u, STRFTIME_SHORT_DATE_FORMAT, &tm);
+
+ expire_left(u->na, expirebuf, sizeof(expirebuf),
+ exceptions[index].expires);
+
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_VIEW_FORMAT,
+ index + 1, exceptions[index].mask,
+ *exceptions[index].who ?
+ exceptions[index].who : "<unknown>",
+ timebuf, expirebuf, exceptions[index].limit,
+ exceptions[index].reason);
+ return 1;
+}
+
+static int exception_view_callback(User * u, int num, va_list args)
+{
+ int *sent_header = va_arg(args, int *);
+
+ return exception_view(u, num - 1, sent_header);
+}
/*************************************************************************/
@@ -588,6 +629,9 @@ void save_rdb_exceptions()
* Syntax: EXCEPTION VIEW [mask]
* Displays detailed information about each exception or those matching
* mask.
+ *
+ * Syntax: EXCEPTION MOVE num position
+ * Moves the exception at position num to position.
*/
int do_exception(User * u)
@@ -607,11 +651,11 @@ int do_exception(User * u)
cmd = "";
if (stricmp(cmd, "ADD") == 0) {
- /* gotta keep this check because of the dbs :( -Certus */
if (nexceptions >= 32767) {
notice_lang(s_OperServ, u, OPER_EXCEPTION_TOO_MANY);
return MOD_CONT;
}
+
mask = strtok(NULL, " ");
if (mask && *mask == '+') {
expiry = mask;
@@ -643,27 +687,24 @@ int do_exception(User * u)
MaxSessionLimit);
return MOD_CONT;
- } else { /* finally when can add it */
- Exception *exception;
-
+ } else {
if (strchr(mask, '!') || strchr(mask, '@')) {
notice_lang(s_OperServ, u,
OPER_EXCEPTION_INVALID_HOSTMASK);
return MOD_CONT;
}
- exception = exception_add(u, mask, limit, reason, u->nick, expires);
+ x = exception_add(u, mask, limit, reason, u->nick, expires);
- if (exception)
- notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask, limit);
+ if (x == 1) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_ADDED, mask,
+ limit);
+ }
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
}
} else if (stricmp(cmd, "DEL") == 0) {
- Exception *exception;
- int deleted = 0;
-
mask = strtok(NULL, " ");
if (!mask) {
@@ -672,76 +713,127 @@ int do_exception(User * u)
return MOD_CONT;
}
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- if (!stricmp(mask, exception->mask)) {
- exception_del(exception);
- notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED, mask);
+ if (isdigit(*mask) && strspn(mask, "1234567890,-") == strlen(mask)) {
+ int count, deleted, last = -1;
+ deleted =
+ process_numlist(mask, &count, exception_del_callback, u,
+ &last);
+ if (!deleted) {
+ if (count == 1) {
+ notice_lang(s_OperServ, u,
+ OPER_EXCEPTION_NO_SUCH_ENTRY, last);
+ } else {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
+ }
+ } else if (deleted == 1) {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_ONE);
+ } else {
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED_SEVERAL,
+ deleted);
+ }
+ } else {
+ int deleted = 0;
+
+ for (i = 0; i < nexceptions; i++) {
+ if (stricmp(mask, exceptions[i].mask) == 0) {
+ exception_del(i);
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_DELETED,
+ mask);
deleted = 1;
break;
}
}
+ if (!deleted && i == nexceptions)
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask);
}
- if (!deleted)
- notice_lang(s_OperServ, u, OPER_EXCEPTION_NOT_FOUND, mask);
+ /* Renumber the exception list. I don't believe in having holes in
+ * lists - it makes code more complex, harder to debug and we end up
+ * with huge index numbers. Imho, fixed numbering is only beneficial
+ * when one doesn't have range capable manipulation. -TheShadow */
+
+ for (i = 0; i < nexceptions; i++)
+ exceptions[i].num = i;
if (readonly)
notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else if (stricmp(cmd, "MOVE") == 0) {
+ Exception *exception;
+ char *n1str = strtok(NULL, " "); /* From position */
+ char *n2str = strtok(NULL, " "); /* To position */
+ int n1, n2;
+
+ if (!n2str) {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_MOVE_SYNTAX);
+ return MOD_CONT;
+ }
+
+ n1 = atoi(n1str) - 1;
+ n2 = atoi(n2str) - 1;
+
+ if ((n1 >= 0 && n1 < nexceptions) && (n2 >= 0 && n2 < nexceptions)
+ && (n1 != n2)) {
+ exception = scalloc(sizeof(Exception), 1);
+ memcpy(exception, &exceptions[n1], sizeof(Exception));
+
+ if (n1 < n2) {
+ /* Shift upwards */
+ memmove(&exceptions[n1], &exceptions[n1 + 1],
+ sizeof(Exception) * (n2 - n1));
+ memmove(&exceptions[n2], exception, sizeof(Exception));
+ } else {
+ /* Shift downwards */
+ memmove(&exceptions[n2 + 1], &exceptions[n2],
+ sizeof(Exception) * (n1 - n2));
+ memmove(&exceptions[n2], exception, sizeof(Exception));
+ }
+
+ free(exception);
+ notice_lang(s_OperServ, u, OPER_EXCEPTION_MOVED,
+ exceptions[n1].mask, n1 + 1, n2 + 1);
+
+ /* Renumber the exception list. See the DEL block above for why. */
+ for (i = 0; i < nexceptions; i++)
+ exceptions[i].num = i;
+
+ if (readonly)
+ notice_lang(s_OperServ, u, READ_ONLY_MODE);
+ } else {
+ syntax_error(s_OperServ, u, "EXCEPTION",
+ OPER_EXCEPTION_MOVE_SYNTAX);
+ }
} else if (stricmp(cmd, "LIST") == 0) {
int sent_header = 0;
- Exception *exception;
-
expire_exceptions();
mask = strtok(NULL, " ");
-
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- if (!mask || match_wild_nocase(mask, exception->mask)) {
- if (!sent_header) {
- notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
- notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_COLHEAD);
- sent_header = 1;
- }
- notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_FORMAT,
- exception->limit, exception->mask);
- }
+ if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, exception_list_callback, u,
+ &sent_header);
+ } else {
+ for (i = 0; i < nexceptions; i++) {
+ if (!mask || match_wild_nocase(mask, exceptions[i].mask))
+ exception_list(u, i, &sent_header);
}
}
-
if (!sent_header)
notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);
} else if (stricmp(cmd, "VIEW") == 0) {
int sent_header = 0;
- Exception *exception;
- char timebuf[32], expirebuf[256];
- struct tm tm;
- time_t t = time(NULL);
-
expire_exceptions();
mask = strtok(NULL, " ");
-
- for (i = 0; i < 1024; i++) {
- for (exception = exceptionlist[i]; exception; exception = exception->next) {
- if (!mask || match_wild_nocase(mask, exception->mask)) {
- if (!sent_header) {
- notice_lang(s_OperServ, u, OPER_EXCEPTION_LIST_HEADER);
- sent_header = 1;
- }
- tm = *localtime(exception->time ? &exception->time : &t);
- strftime_lang(timebuf, sizeof(timebuf), u,
- STRFTIME_SHORT_DATE_FORMAT, &tm);
- expire_left(u->na, expirebuf, sizeof(expirebuf), exception->expires);
- notice_lang(s_OperServ, u, OPER_EXCEPTION_VIEW_FORMAT, exception->mask,
- exception->who ? exception->who : "<unknown>", timebuf, expirebuf,
- exception->limit, exception->reason);
- }
+ if (mask && strspn(mask, "1234567890,-") == strlen(mask)) {
+ process_numlist(mask, NULL, exception_view_callback, u,
+ &sent_header);
+ } else {
+ for (i = 0; i < nexceptions; i++) {
+ if (!mask || match_wild_nocase(mask, exceptions[i].mask))
+ exception_view(u, i, &sent_header);
}
}
-
if (!sent_header)
notice_lang(s_OperServ, u, OPER_EXCEPTION_NO_MATCH);