+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static struct {
+ struct Motd* local;
+ struct Motd* remote;
+ struct Motd* other;
+} MotdList;
+
+/* Create a struct Motd and initialize it */
+static struct Motd *
+motd_create(const char *hostmask, const char *path, int maxcount)
+{
+ struct Motd* tmp;
+ int class = -1;
+ int type = MOTD_UNIVERSAL;
+ const char* s;
+
+ assert(0 != path);
+
+ if (hostmask) { /* figure out if it's a class or hostmask */
+ for (s = hostmask; *s; s++)
+ if (!IsDigit(*s)) { /* not a digit, not a class... */
+ type = MOTD_HOSTMASK;
+ break;
+ }
+
+ type = MOTD_CLASS; /* all digits, convert to class */
+ class = atoi(hostmask);
+ }
+
+ /* allocate memory and initialize the structure */
+ tmp = (struct Motd *)MyMalloc(sizeof(struct Motd));
+
+ tmp->next = 0;
+ tmp->type = type;
+ if (type == MOTD_HOSTMASK)
+ DupString(tmp->id.hostmask, hostmask);
+ else if (type == MOTD_CLASS)
+ tmp->id.class = class;
+ DupString(tmp->path, path);
+ tmp->maxcount = maxcount;
+ tmp->cache = 0;
+
+ return tmp;
+}
+
+/* This function reads a motd out of a file (if needed) and caches it */
+static struct MotdCache *
+motd_cache(struct Motd *motd)
+{
+ FBFILE* file;
+ struct MotdCache* cache;
+ struct stat sb;
+ char line[MOTD_LINESIZE + 2]; /* \r\n */
+ char* tmp;
+ int i;
+
+ assert(0 != motd);
+ assert(0 != motd->path);
+
+ if (motd->cache)
+ return motd->cache;
+
+ /* gotta read in the file, now */
+ if (!(file = fbopen(motd->path, "r"))) {
+ Debug((DEBUG_ERROR, "Couldn't open \"%s\": %s", motd->path,
+ strerror(errno)));
+ return 0;
+ }
+
+ /* need the file's modification time */
+ if (-1 == fbstat(&sb, file)) {
+ fbclose(file);
+ return 0;
+ }
+
+ /* Ok, allocate a structure; we'll realloc later to trim memory */
+ cache = (struct MotdCache *)MyMalloc(sizeof(struct MotdCache) +
+ (MOTD_LINESIZE * (MOTD_MAXLINES - 1)));
+
+ cache->modtime = *localtime((time_t *) &sb.st_mtime); /* store modtime */
+
+ cache->count = 0;
+ while (cache->count < motd->maxcount && fbgets(line, sizeof(line), file)) {
+ /* copy over line, stopping when we overflow or hit line end */
+ for (tmp = line, i = 0;
+ i < (MOTD_LINESIZE - 1) && *tmp && *tmp != '\r' && *tmp != '\n';
+ tmp++, i++)
+ cache->motd[cache->count][i] = *tmp;
+ cache->motd[cache->count][i] = '\0';
+
+ cache->count++;
+ }
+
+ fbclose(file); /* close the file */
+
+ /* trim memory usage a little */
+ motd->cache = (struct MotdCache *)MyRealloc(cache, sizeof(struct MotdCache) +
+ (MOTD_LINESIZE *
+ (cache->count - 1)));
+
+ return motd->cache;
+}
+
+static void
+motd_decache(struct Motd *motd)
+{
+ struct MotdCache* cache;