Annotation of ircnowd/src/ngircd/lists.c, Revision 1.1
1.1 ! tomglok 1: /*
! 2: * ngIRCd -- The Next Generation IRC Daemon
! 3: * Copyright (c)2001-2018 Alexander Barton (alex@barton.de) and Contributors.
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify
! 6: * it under the terms of the GNU General Public License as published by
! 7: * the Free Software Foundation; either version 2 of the License, or
! 8: * (at your option) any later version.
! 9: * Please read the file COPYING, README and AUTHORS for more information.
! 10: */
! 11:
! 12: #include "portab.h"
! 13:
! 14: /**
! 15: * @file
! 16: * Management of IRC lists: ban, invite, etc.
! 17: */
! 18:
! 19: #include <assert.h>
! 20: #include <stdlib.h>
! 21: #include <string.h>
! 22: #include <strings.h>
! 23: #include <time.h>
! 24:
! 25: #include "conn.h"
! 26: #include "log.h"
! 27: #include "match.h"
! 28:
! 29: #include "lists.h"
! 30:
! 31: struct list_elem {
! 32: struct list_elem *next; /** pointer to next list element */
! 33: char mask[MASK_LEN]; /** IRC mask */
! 34: char *reason; /** Optional "reason" text */
! 35: time_t valid_until; /** 0: unlimited; t(>0): until t */
! 36: bool onlyonce;
! 37: };
! 38:
! 39: /**
! 40: * Get IRC mask stored in list element.
! 41: *
! 42: * @param e List element.
! 43: * @return Pointer to IRC mask
! 44: */
! 45: GLOBAL const char *
! 46: Lists_GetMask(const struct list_elem *e)
! 47: {
! 48: assert(e != NULL);
! 49: return e->mask;
! 50: }
! 51:
! 52: /**
! 53: * Get optional "reason" text stored in list element.
! 54: *
! 55: * @param e List element.
! 56: * @return Pointer to "reason" text or empty string ("").
! 57: */
! 58: GLOBAL const char *
! 59: Lists_GetReason(const struct list_elem *e)
! 60: {
! 61: assert(e != NULL);
! 62: return e->reason ? e->reason : "";
! 63: }
! 64:
! 65: /**
! 66: * Get "validity" value stored in list element.
! 67: *
! 68: * @param e List element.
! 69: * @return Validity: 0=unlimited, >0 until this time stamp.
! 70: */
! 71: GLOBAL time_t
! 72: Lists_GetValidity(const struct list_elem *e)
! 73: {
! 74: assert(e != NULL);
! 75: return e->valid_until;
! 76: }
! 77:
! 78: /**
! 79: * Get "onlyonce" value stored in list element.
! 80: *
! 81: * @param e List element.
! 82: * @return True if the element was stored for single use, false otherwise.
! 83: */
! 84: GLOBAL bool
! 85: Lists_GetOnlyOnce(const struct list_elem *e)
! 86: {
! 87: assert(e != NULL);
! 88: return e->onlyonce;
! 89: }
! 90:
! 91: /**
! 92: * Get first list element of a list.
! 93: *
! 94: * @param h List head.
! 95: * @return Pointer to first list element.
! 96: */
! 97: GLOBAL struct list_elem*
! 98: Lists_GetFirst(const struct list_head *h)
! 99: {
! 100: assert(h != NULL);
! 101: return h->first;
! 102: }
! 103:
! 104: /**
! 105: * Get next list element of a list.
! 106: *
! 107: * @param e Current list element.
! 108: * @return Pointer to next list element.
! 109: */
! 110: GLOBAL struct list_elem*
! 111: Lists_GetNext(const struct list_elem *e)
! 112: {
! 113: assert(e != NULL);
! 114: return e->next;
! 115: }
! 116:
! 117: /**
! 118: * Add a new mask to a list.
! 119: *
! 120: * @param h List head.
! 121: * @param Mask The IRC mask to add to the list.
! 122: * @param ValidUntil 0: unlimited, 1: only once, t>1: until given time_t.
! 123: * @param Reason Reason string or NULL, if no reason should be saved.
! 124: * @return true on success, false otherwise.
! 125: */
! 126: bool
! 127: Lists_Add(struct list_head *h, const char *Mask, time_t ValidUntil,
! 128: const char *Reason, bool OnlyOnce)
! 129: {
! 130: struct list_elem *e, *newelem;
! 131:
! 132: assert(h != NULL);
! 133: assert(Mask != NULL);
! 134:
! 135: e = Lists_CheckDupeMask(h, Mask);
! 136: if (e) {
! 137: e->valid_until = ValidUntil;
! 138: if (Reason) {
! 139: if (e->reason)
! 140: free(e->reason);
! 141: e->reason = strdup(Reason);
! 142: }
! 143: return true;
! 144: }
! 145:
! 146: e = Lists_GetFirst(h);
! 147:
! 148: newelem = malloc(sizeof(struct list_elem));
! 149: if (!newelem) {
! 150: Log(LOG_EMERG,
! 151: "Can't allocate memory for new list entry!");
! 152: return false;
! 153: }
! 154:
! 155: strlcpy(newelem->mask, Mask, sizeof(newelem->mask));
! 156: if (Reason) {
! 157: newelem->reason = strdup(Reason);
! 158: if (!newelem->reason)
! 159: Log(LOG_EMERG,
! 160: "Can't allocate memory for new list reason text!");
! 161: }
! 162: else
! 163: newelem->reason = NULL;
! 164: newelem->valid_until = ValidUntil;
! 165: newelem->onlyonce = OnlyOnce;
! 166: newelem->next = e;
! 167: h->first = newelem;
! 168:
! 169: return true;
! 170: }
! 171:
! 172: /**
! 173: * Delete a list element from a list.
! 174: *
! 175: * @param h List head.
! 176: * @param p Pointer to previous list element or NULL, if there is none.
! 177: * @param victim List element to delete.
! 178: */
! 179: static void
! 180: Lists_Unlink(struct list_head *h, struct list_elem *p, struct list_elem *victim)
! 181: {
! 182: assert(victim != NULL);
! 183: assert(h != NULL);
! 184:
! 185: if (p)
! 186: p->next = victim->next;
! 187: else
! 188: h->first = victim->next;
! 189:
! 190: if (victim->reason)
! 191: free(victim->reason);
! 192:
! 193: free(victim);
! 194: }
! 195:
! 196: /**
! 197: * Delete a given IRC mask from a list.
! 198: *
! 199: * @param h List head.
! 200: * @param Mask IRC mask to delete from the list.
! 201: */
! 202: GLOBAL void
! 203: Lists_Del(struct list_head *h, const char *Mask)
! 204: {
! 205: struct list_elem *e, *last, *victim;
! 206:
! 207: assert(h != NULL);
! 208: assert(Mask != NULL);
! 209:
! 210: last = NULL;
! 211: e = Lists_GetFirst(h);
! 212: while (e) {
! 213: if (strcasecmp(e->mask, Mask) == 0) {
! 214: LogDebug("Deleted \"%s\" from list", e->mask);
! 215: victim = e;
! 216: e = victim->next;
! 217: Lists_Unlink(h, last, victim);
! 218: continue;
! 219: }
! 220: last = e;
! 221: e = e->next;
! 222: }
! 223: }
! 224:
! 225: /**
! 226: * Free a complete list.
! 227: *
! 228: * @param head List head.
! 229: */
! 230: GLOBAL void
! 231: Lists_Free(struct list_head *head)
! 232: {
! 233: struct list_elem *e, *victim;
! 234:
! 235: assert(head != NULL);
! 236:
! 237: e = head->first;
! 238: head->first = NULL;
! 239: while (e) {
! 240: LogDebug("Deleted \"%s\" from list" , e->mask);
! 241: victim = e;
! 242: e = e->next;
! 243: if (victim->reason)
! 244: free(victim->reason);
! 245: free(victim);
! 246: }
! 247: }
! 248:
! 249: /**
! 250: * Check if an IRC mask is already contained in a list.
! 251: *
! 252: * @param h List head.
! 253: * @param Mask IRC mask to test.
! 254: * @return true if mask is already stored in the list, false otherwise.
! 255: */
! 256: GLOBAL struct list_elem *
! 257: Lists_CheckDupeMask(const struct list_head *h, const char *Mask )
! 258: {
! 259: struct list_elem *e;
! 260: e = h->first;
! 261: while (e) {
! 262: if (strcasecmp(e->mask, Mask) == 0)
! 263: return e;
! 264: e = e->next;
! 265: }
! 266: return NULL;
! 267: }
! 268:
! 269: /**
! 270: * Generate a valid IRC mask from "any" string given.
! 271: *
! 272: * @param Pattern Source string to generate an IRC mask for.
! 273: * @param mask Buffer to store the mask.
! 274: * @param len Size of the buffer.
! 275: */
! 276: GLOBAL void
! 277: Lists_MakeMask(const char *Pattern, char *mask, size_t len)
! 278: {
! 279: char *excl, *at;
! 280:
! 281: assert(Pattern != NULL);
! 282:
! 283: excl = strchr(Pattern, '!');
! 284: at = strchr(Pattern, '@');
! 285:
! 286: if (at && at < excl)
! 287: excl = NULL;
! 288:
! 289: if (!at && !excl) {
! 290: /* Neither "!" nor "@" found: use string as nickname */
! 291: strlcpy(mask, Pattern, len - 5);
! 292: strlcat(mask, "!*@*", len);
! 293: } else if (!at && excl) {
! 294: /* Domain part is missing */
! 295: strlcpy(mask, Pattern, len - 3);
! 296: strlcat(mask, "@*", len);
! 297: } else if (at && !excl) {
! 298: /* User name is missing */
! 299: *at = '\0'; at++;
! 300: strlcpy(mask, Pattern, len - 5);
! 301: strlcat(mask, "!*@", len);
! 302: strlcat(mask, at, len);
! 303: at--; *at = '@';
! 304: } else {
! 305: /* All parts (nick, user and domain name) are given */
! 306: strlcpy(mask, Pattern, len);
! 307: }
! 308: } /* Lists_MakeMask */
! 309:
! 310: /**
! 311: * Check if a client is listed in a list.
! 312: *
! 313: * @param h List head.
! 314: * @param Client Client to check.
! 315: * @return true if client is listed, false if not.
! 316: */
! 317: bool
! 318: Lists_Check(struct list_head *h, CLIENT *Client)
! 319: {
! 320: return Lists_CheckReason(h, Client, NULL, 0);
! 321: }
! 322:
! 323: /**
! 324: * Check if a client is listed in a list and store the reason.
! 325: *
! 326: * @param h List head.
! 327: * @param Client Client to check.
! 328: * @param reason Buffer to store the reason.
! 329: * @param len Size of the buffer if reason should be saved.
! 330: * @return true if client is listed, false if not.
! 331: */
! 332: bool
! 333: Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
! 334: {
! 335: struct list_elem *e, *last, *next;
! 336:
! 337: assert(h != NULL);
! 338:
! 339: e = h->first;
! 340: last = NULL;
! 341:
! 342: while (e) {
! 343: next = e->next;
! 344: if (MatchCaseInsensitive(e->mask, Client_MaskCloaked(Client))) {
! 345: if (len && e->reason)
! 346: strlcpy(reason, e->reason, len);
! 347: if (e->onlyonce) {
! 348: /* Entry is valid only once, delete it */
! 349: LogDebug("Deleted \"%s\" from list (used).",
! 350: e->mask);
! 351: Lists_Unlink(h, last, e);
! 352: }
! 353: return true;
! 354: }
! 355: last = e;
! 356: e = next;
! 357: }
! 358:
! 359: return false;
! 360: }
! 361:
! 362: /**
! 363: * Check list and purge expired entries.
! 364: *
! 365: * @param h List head.
! 366: */
! 367: GLOBAL void
! 368: Lists_Expire(struct list_head *h, const char *ListName)
! 369: {
! 370: struct list_elem *e, *last, *next;
! 371: time_t now;
! 372:
! 373: assert(h != NULL);
! 374:
! 375: e = h->first;
! 376: last = NULL;
! 377: now = time(NULL);
! 378:
! 379: while (e) {
! 380: next = e->next;
! 381: if (e->valid_until > 0 && e->valid_until < now) {
! 382: /* Entry is expired, delete it */
! 383: if (e->reason)
! 384: Log(LOG_NOTICE|LOG_snotice,
! 385: "Deleted \"%s\" (\"%s\") from %s list (expired).",
! 386: e->mask, e->reason, ListName);
! 387: else
! 388: Log(LOG_NOTICE|LOG_snotice,
! 389: "Deleted \"%s\" from %s list (expired).",
! 390: e->mask, ListName);
! 391: Lists_Unlink(h, last, e);
! 392: e = next;
! 393: continue;
! 394: }
! 395: last = e;
! 396: e = next;
! 397: }
! 398: }
! 399:
! 400: /**
! 401: * Return the number of entries of a list.
! 402: *
! 403: * @param h List head.
! 404: * @return Number of items.
! 405: */
! 406: GLOBAL unsigned long
! 407: Lists_Count(struct list_head *h)
! 408: {
! 409: struct list_elem *e;
! 410: unsigned long count = 0;
! 411:
! 412: assert(h != NULL);
! 413:
! 414: e = h->first;
! 415: while (e) {
! 416: count++;
! 417: e = e->next;
! 418: }
! 419: return count;
! 420: }
! 421:
! 422: /* -eof- */
CVSweb