/***************************************************************/ /* */ /* DEDUPE.C */ /* */ /* Code to suppress duplicate reminders */ /* */ /* This file is part of REMIND. */ /* Copyright (C) 1992-2026 by Dianne Skoll */ /* SPDX-License-Identifier: GPL-2.0-only */ /* */ /***************************************************************/ #include "config.h" #include "types.h" #include "globals.h" #include "protos.h" #include #include #include #include typedef struct dedupe_entry { struct hash_link link; int trigger_date; int trigger_time; char const *body; } DedupeEntry; static hash_table DedupeTable; static unsigned int DedupeHashFunc(void const *x) { DedupeEntry const *e = (DedupeEntry const *) x; unsigned int hashval = (unsigned int) e->trigger_date; if (e->trigger_time != NO_TIME) { hashval += (unsigned int) e->trigger_time; } hashval += HashVal_preservecase(e->body); return hashval; } static int CompareDedupes(void const *x, void const *y) { DedupeEntry const *a = (DedupeEntry const *) x; DedupeEntry const *b = (DedupeEntry const *) y; if (a->trigger_date != b->trigger_date) return a->trigger_date - b->trigger_date; if (a->trigger_time != b->trigger_time) return a->trigger_time - b->trigger_time; return strcmp(a->body, b->body); } /***************************************************************/ /* */ /* FreeDedupeEntry */ /* */ /* Free a DedupeEntry object */ /* */ /***************************************************************/ static void FreeDedupeEntry(DedupeEntry *e) { if (e->body) { free((char *) e->body); } free(e); } /***************************************************************/ /* */ /* FindDedupeEntry */ /* */ /* Check if we have a dedupe entry for a given date and body */ /* */ /***************************************************************/ static DedupeEntry * FindDedupeEntry(int trigger_date, int trigger_time, char const *body) { DedupeEntry *e; DedupeEntry candidate; candidate.body = body; candidate.trigger_date = trigger_date; candidate.trigger_time = trigger_time; e = hash_table_find(&DedupeTable, &candidate); return e; } /***************************************************************/ /* */ /* InsertDedupeEntry */ /* */ /* Insert a dedupe entry for given date and body. */ /* */ /***************************************************************/ static void InsertDedupeEntry(int trigger_date, int trigger_time, char const *body) { DedupeEntry *e; e = malloc(sizeof(DedupeEntry)); if (!e) { return; /* No error checking... what can we do? */ } e->trigger_date = trigger_date; e->trigger_time = trigger_time; e->body = strdup(body); if (!e->body) { free(e); return; } hash_table_insert(&DedupeTable, e); } /***************************************************************/ /* */ /* ShouldDedupe */ /* */ /* Returns 1 if we've already issued this exact reminder; 0 */ /* otherwise. If it returns 0, remembers that we have seen */ /* the reminder */ /* */ /***************************************************************/ int ShouldDedupe(int trigger_date, int trigger_time, char const *body) { DedupeEntry const *e = FindDedupeEntry(trigger_date, trigger_time, body); if (e) { return 1; } InsertDedupeEntry(trigger_date, trigger_time, body); return 0; } /***************************************************************/ /* */ /* ClearDedupeTable */ /* */ /* Free all the storage used by the dedupe table */ /* */ /***************************************************************/ void ClearDedupeTable(void) { DedupeEntry *e, *next; e = hash_table_next(&DedupeTable, NULL); while(e) { next = hash_table_next(&DedupeTable, e); hash_table_delete_no_resize(&DedupeTable, e); FreeDedupeEntry(e); e = next; } hash_table_free(&DedupeTable); InitDedupeTable(); } /***************************************************************/ /* */ /* InitDedupeTable */ /* */ /* Initialize the dedupe table at program startup */ /* */ /***************************************************************/ void InitDedupeTable(void) { if (hash_table_init(&DedupeTable, offsetof(DedupeEntry, link), DedupeHashFunc, CompareDedupes) < 0) { fprintf(ErrFp, "Unable to initialize function hash table: Out of memory. Exiting.\n"); exit(1); } } void dump_dedupe_hash_stats(void) { hash_table_dump_stats(&DedupeTable, ErrFp); }