+}
+
+/**
+ * Generate a valid IRC mask from "any" string given.
+ *
+ * @param Pattern Source string to generate an IRC mask for.
+ * @param mask Buffer to store the mask.
+ * @param len Size of the buffer.
+ */
+GLOBAL void
+Lists_MakeMask(const char *Pattern, char *mask, size_t len)
+{
+ char *excl, *at;
+
+ assert(Pattern != NULL);
+
+ excl = strchr(Pattern, '!');
+ at = strchr(Pattern, '@');
+
+ if (at && at < excl)
+ excl = NULL;
+
+ if (!at && !excl) {
+ /* Neither "!" nor "@" found: use string as nickname */
+ strlcpy(mask, Pattern, len - 5);
+ strlcat(mask, "!*@*", len);
+ } else if (!at && excl) {
+ /* Domain part is missing */
+ strlcpy(mask, Pattern, len - 3);
+ strlcat(mask, "@*", len);
+ } else if (at && !excl) {
+ /* User name is missing */
+ *at = '\0'; at++;
+ strlcpy(mask, Pattern, len - 5);
+ strlcat(mask, "!*@", len);
+ strlcat(mask, at, len);
+ at--; *at = '@';
+ } else {
+ /* All parts (nick, user and domain name) are given */
+ strlcpy(mask, Pattern, len);
+ }
+} /* Lists_MakeMask */
+
+/**
+ * Check if a client is listed in a list.
+ *
+ * @param h List head.
+ * @param Client Client to check.
+ * @return true if client is listed, false if not.
+ */
+bool
+Lists_Check(struct list_head *h, CLIENT *Client)
+{
+ return Lists_CheckReason(h, Client, NULL, 0);
+}
+
+/**
+ * Check if a client is listed in a list and store the reason.
+ *
+ * @param h List head.
+ * @param Client Client to check.
+ * @param reason Buffer to store the reason.
+ * @param len Size of the buffer if reason should be saved.
+ * @return true if client is listed, false if not.
+ */
+bool
+Lists_CheckReason(struct list_head *h, CLIENT *Client, char *reason, size_t len)
+{
+ struct list_elem *e, *last, *next;
+
+ assert(h != NULL);
+
+ e = h->first;
+ last = NULL;
+
+ while (e) {
+ next = e->next;
+ if (MatchCaseInsensitive(e->mask, Client_MaskCloaked(Client))) {
+ if (len && e->reason)
+ strlcpy(reason, e->reason, len);
+ if (e->onlyonce) {
+ /* Entry is valid only once, delete it */
+ LogDebug("Deleted \"%s\" from list (used).",
+ e->mask);
+ Lists_Unlink(h, last, e);
+ }
+ return true;
+ }
+ last = e;
+ e = next;
+ }
+
+ return false;
+}
+
+/**
+ * Check list and purge expired entries.
+ *
+ * @param h List head.
+ */
+GLOBAL void
+Lists_Expire(struct list_head *h, const char *ListName)
+{
+ struct list_elem *e, *last, *next;
+ time_t now;
+
+ assert(h != NULL);
+
+ e = h->first;
+ last = NULL;
+ now = time(NULL);
+
+ while (e) {
+ next = e->next;
+ if (e->valid_until > 0 && e->valid_until < now) {
+ /* Entry is expired, delete it */
+ if (e->reason)
+ Log(LOG_NOTICE|LOG_snotice,
+ "Deleted \"%s\" (\"%s\") from %s list (expired).",
+ e->mask, e->reason, ListName);
+ else
+ Log(LOG_NOTICE|LOG_snotice,
+ "Deleted \"%s\" from %s list (expired).",
+ e->mask, ListName);
+ Lists_Unlink(h, last, e);
+ e = next;
+ continue;
+ }
+ last = e;
+ e = next;
+ }
+}
+
+/**
+ * Return the number of entries of a list.
+ *
+ * @param h List head.
+ * @return Number of items.
+ */
+GLOBAL unsigned long
+Lists_Count(struct list_head *h)
+{
+ struct list_elem *e;
+ unsigned long count = 0;
+
+ assert(h != NULL);