/** * os_logonnews.C: Logon News stuff... * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Copyright © 2005-2006 William Pitcock * Rights to this code are as documented in doc/pod/license.pod. * * $Id: os_logonnews.C,v 1.6 2007/09/22 14:27:27 pippijn Exp $ */ #include "atheme.h" #include #include static char const rcsid[] = "$Id: os_logonnews.C,v 1.6 2007/09/22 14:27:27 pippijn Exp $"; REGISTER_MODULE ("operserv/logonnews", false, "William Pitcock "); E cmdvec os_cmdtree; static void os_cmd_logonnews (sourceinfo_t *si, int parc, char *parv[]); static void write_newsdb (void); static void load_newsdb (void); command_t const os_logonnews = { "LOGONNEWS", "Manages logon news.", PRIV_GLOBAL, 3, os_cmd_logonnews }; struct logonnews_ { char *nick; char *target; time_t news_ts; char *story; }; typedef struct logonnews_ logonnews_t; list_t logon_news; static void write_newsdb (void) { FILE *f; node_t *n; logonnews_t *l; if (!(f = fopen (DATADIR "/news.db.new", "w"))) { slog (LG_DEBUG, "write_newsdb(): cannot write news database: %s", strerror (errno)); return; } LIST_FOREACH (n, logon_news.head) { l = static_cast (n->data); fprintf (f, "GL %s %s %ld %s\n", l->nick, l->target, l->news_ts, l->story); } fclose (f); if ((rename (DATADIR "/news.db.new", DATADIR "/news.db")) < 0) { slog (LG_DEBUG, "write_newsdb(): couldn't rename news database."); return; } } static void load_newsdb (void) { FILE *f; node_t *n; char *item, rBuf[BUFSIZE]; if (!(f = fopen (DATADIR "/news.db", "r"))) { slog (LG_DEBUG, "read_newsdb(): cannot open news database: %s", strerror (errno)); return; } while (fgets (rBuf, BUFSIZE, f)) { item = strtok (rBuf, " "); strip (item); if (!strcmp (item, "GL")) { char *nick = strtok (NULL, " "); char *target = strtok (NULL, " "); char *news_ts = strtok (NULL, " "); char *story = strtok (NULL, ""); logonnews_t *l; if (!nick || !target || !news_ts || !story) continue; l = new logonnews_t; l->nick = sstrdup (nick); l->target = sstrdup (target); l->news_ts = atol (news_ts); l->story = sstrdup (story); n = node_create (); node_add (l, n, &logon_news); } } fclose (f); } static void display_news (user_t *u) { node_t *n; logonnews_t *l; char dBuf[BUFSIZE]; struct tm tm; int count = 0; /* abort if it's an internal client */ if (is_internal_client (u)) return; if (logon_news.count > 0) { notice (globsvs.nick, u->nick, "*** \2Message(s) of the Day\2 ***"); LIST_FOREACH_PREV (n, logon_news.tail) { l = static_cast (n->data); tm = *localtime (&l->news_ts); strftime (dBuf, BUFSIZE, "%H:%M on %m/%d/%y", &tm); notice (globsvs.nick, u->nick, "[\2%s\2] Notice from %s, posted %s:", l->target, l->nick, dBuf); notice (globsvs.nick, u->nick, "%s", l->story); count++; /* only display three latest entries, max. */ if (count == 3) break; } notice (globsvs.nick, u->nick, "*** \2End of Message(s) of the Day\2 ***"); } } static void os_cmd_logonnews (sourceinfo_t *si, int parc, char *parv[]) { char *action = parv[0]; char *target = parv[1]; char *story = parv[2]; logonnews_t *l; node_t *n; if (!action) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS"); command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD|DEL|LIST [target] [message]"); return; } if (!strcasecmp (action, "ADD")) { if (!target || !story) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS ADD"); command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD "); return; } l = new logonnews_t; l->nick = sstrdup (get_source_name (si)); l->news_ts = NOW; l->story = sstrdup (story); l->target = sstrdup (target); n = node_create (); node_add (l, n, &logon_news); write_newsdb (); command_success_nodata (si, "Added entry to logon news."); logcommand (si, CMDLOG_ADMIN, "LOGONNEWS ADD %s %s", target, story); return; } else if (!strcasecmp (action, "DEL")) { int x = 0; int id; if (!target) { command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS DEL"); command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS DEL "); return; } id = atoi (target); if (id <= 0) { command_fail (si, fault::badparams, STR_INVALID_PARAMS, "LOGONNEWS DEL"); command_fail (si, fault::badparams, "Syntax: LOGONNEWS DEL "); return; } /* search for it */ LIST_FOREACH (n, logon_news.head) { l = static_cast (n->data); x++; if (x == id) { logcommand (si, CMDLOG_ADMIN, "LOGONNEWS DEL %s %s", l->target, l->story); node_del (n, &logon_news); sfree (l->nick); sfree (l->target); sfree (l->story); delete l; write_newsdb (); command_success_nodata (si, "Deleted entry %d from logon news.", id); return; } } command_fail (si, fault::nosuch_target, "Entry %d not found in logon news.", id); return; } else if (!strcasecmp (action, "LIST")) { int x = 0; LIST_FOREACH (n, logon_news.head) { l = static_cast (n->data); x++; command_success_nodata (si, "%d: [\2%s\2] by \2%s\2, \2%s\2", x, l->target, l->nick, l->story); } command_success_nodata (si, "End of list."); logcommand (si, CMDLOG_GET, "LOGONNEWS LIST"); return; } else { command_fail (si, fault::badparams, STR_INVALID_PARAMS, "LOGONNEWS"); command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD|DEL|LIST [target] [message]"); return; } } bool _modinit (module *m) { user_t::callback.add.attach (display_news); os_cmdtree << os_logonnews; load_newsdb (); return true; } void _moddeinit (void) { user_t::callback.add.detach (display_news); os_cmdtree >> os_logonnews; }