1 |
/** |
2 |
* os_logonnews.C: Logon News stuff... |
3 |
* |
4 |
* Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team |
5 |
* Rights to this code are as documented in COPYING. |
6 |
* |
7 |
* |
8 |
* Portions of this file were derived from sources bearing the following license: |
9 |
* Copyright © 2005-2006 William Pitcock <nenolod -at- nenolod.net> |
10 |
* Rights to this code are as documented in doc/pod/license.pod. |
11 |
* |
12 |
* $Id: os_logonnews.C,v 1.5 2007-09-16 18:54:43 pippijn Exp $ |
13 |
*/ |
14 |
|
15 |
#include "atheme.h" |
16 |
#include <libermyth.h> |
17 |
#include <ermyth/module.h> |
18 |
|
19 |
static char const rcsid[] = "$Id: os_logonnews.C,v 1.5 2007-09-16 18:54:43 pippijn Exp $"; |
20 |
|
21 |
REGISTER_MODULE ("operserv/logonnews", false, "William Pitcock <nenolod -at- nenolod.net>"); |
22 |
|
23 |
E cmdvec os_cmdtree; |
24 |
|
25 |
static void os_cmd_logonnews (sourceinfo_t *si, int parc, char *parv[]); |
26 |
static void write_newsdb (void); |
27 |
static void load_newsdb (void); |
28 |
|
29 |
command_t const os_logonnews = { "LOGONNEWS", "Manages logon news.", PRIV_GLOBAL, 3, os_cmd_logonnews }; |
30 |
|
31 |
struct logonnews_ |
32 |
{ |
33 |
char *nick; |
34 |
char *target; |
35 |
time_t news_ts; |
36 |
char *story; |
37 |
}; |
38 |
|
39 |
typedef struct logonnews_ logonnews_t; |
40 |
|
41 |
list_t logon_news; |
42 |
|
43 |
static void |
44 |
write_newsdb (void) |
45 |
{ |
46 |
FILE *f; |
47 |
node_t *n; |
48 |
logonnews_t *l; |
49 |
|
50 |
if (!(f = fopen (DATADIR "/news.db.new", "w"))) |
51 |
{ |
52 |
slog (LG_DEBUG, "write_newsdb(): cannot write news database: %s", strerror (errno)); |
53 |
return; |
54 |
} |
55 |
|
56 |
LIST_FOREACH (n, logon_news.head) |
57 |
{ |
58 |
l = static_cast<logonnews_t *> (n->data); |
59 |
fprintf (f, "GL %s %s %ld %s\n", l->nick, l->target, l->news_ts, l->story); |
60 |
} |
61 |
|
62 |
fclose (f); |
63 |
|
64 |
if ((rename (DATADIR "/news.db.new", DATADIR "/news.db")) < 0) |
65 |
{ |
66 |
slog (LG_DEBUG, "write_newsdb(): couldn't rename news database."); |
67 |
return; |
68 |
} |
69 |
} |
70 |
|
71 |
static void |
72 |
load_newsdb (void) |
73 |
{ |
74 |
FILE *f; |
75 |
node_t *n; |
76 |
char *item, rBuf[BUFSIZE]; |
77 |
|
78 |
if (!(f = fopen (DATADIR "/news.db", "r"))) |
79 |
{ |
80 |
slog (LG_DEBUG, "read_newsdb(): cannot open news database: %s", strerror (errno)); |
81 |
return; |
82 |
} |
83 |
|
84 |
while (fgets (rBuf, BUFSIZE, f)) |
85 |
{ |
86 |
item = strtok (rBuf, " "); |
87 |
strip (item); |
88 |
|
89 |
if (!strcmp (item, "GL")) |
90 |
{ |
91 |
char *nick = strtok (NULL, " "); |
92 |
char *target = strtok (NULL, " "); |
93 |
char *news_ts = strtok (NULL, " "); |
94 |
char *story = strtok (NULL, ""); |
95 |
logonnews_t *l; |
96 |
|
97 |
if (!nick || !target || !news_ts || !story) |
98 |
continue; |
99 |
|
100 |
l = new logonnews_t; |
101 |
l->nick = sstrdup (nick); |
102 |
l->target = sstrdup (target); |
103 |
l->news_ts = atol (news_ts); |
104 |
l->story = sstrdup (story); |
105 |
|
106 |
n = node_create (); |
107 |
node_add (l, n, &logon_news); |
108 |
} |
109 |
} |
110 |
|
111 |
fclose (f); |
112 |
} |
113 |
|
114 |
static void |
115 |
display_news (user_t *u) |
116 |
{ |
117 |
node_t *n; |
118 |
logonnews_t *l; |
119 |
char dBuf[BUFSIZE]; |
120 |
struct tm tm; |
121 |
int count = 0; |
122 |
|
123 |
/* abort if it's an internal client */ |
124 |
if (is_internal_client (u)) |
125 |
return; |
126 |
|
127 |
if (logon_news.count > 0) |
128 |
{ |
129 |
notice (globsvs.nick, u->nick, "*** \2Message(s) of the Day\2 ***"); |
130 |
|
131 |
LIST_FOREACH_PREV (n, logon_news.tail) |
132 |
{ |
133 |
l = static_cast<logonnews_t *> (n->data); |
134 |
tm = *localtime (&l->news_ts); |
135 |
strftime (dBuf, BUFSIZE, "%H:%M on %m/%d/%y", &tm); |
136 |
notice (globsvs.nick, u->nick, "[\2%s\2] Notice from %s, posted %s:", l->target, l->nick, dBuf); |
137 |
notice (globsvs.nick, u->nick, "%s", l->story); |
138 |
count++; |
139 |
|
140 |
/* only display three latest entries, max. */ |
141 |
if (count == 3) |
142 |
break; |
143 |
} |
144 |
|
145 |
notice (globsvs.nick, u->nick, "*** \2End of Message(s) of the Day\2 ***"); |
146 |
} |
147 |
} |
148 |
|
149 |
static void |
150 |
os_cmd_logonnews (sourceinfo_t *si, int parc, char *parv[]) |
151 |
{ |
152 |
char *action = parv[0]; |
153 |
char *target = parv[1]; |
154 |
char *story = parv[2]; |
155 |
logonnews_t *l; |
156 |
node_t *n; |
157 |
|
158 |
if (!action) |
159 |
{ |
160 |
command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS"); |
161 |
command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD|DEL|LIST [target] [message]"); |
162 |
return; |
163 |
} |
164 |
|
165 |
if (!strcasecmp (action, "ADD")) |
166 |
{ |
167 |
if (!target || !story) |
168 |
{ |
169 |
command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS ADD"); |
170 |
command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD <target> <message>"); |
171 |
return; |
172 |
} |
173 |
|
174 |
l = new logonnews_t; |
175 |
l->nick = sstrdup (get_source_name (si)); |
176 |
l->news_ts = NOW; |
177 |
l->story = sstrdup (story); |
178 |
l->target = sstrdup (target); |
179 |
|
180 |
n = node_create (); |
181 |
node_add (l, n, &logon_news); |
182 |
|
183 |
write_newsdb (); |
184 |
|
185 |
command_success_nodata (si, "Added entry to logon news."); |
186 |
logcommand (si, CMDLOG_ADMIN, "LOGONNEWS ADD %s %s", target, story); |
187 |
return; |
188 |
} |
189 |
else if (!strcasecmp (action, "DEL")) |
190 |
{ |
191 |
int x = 0; |
192 |
int id; |
193 |
|
194 |
if (!target) |
195 |
{ |
196 |
command_fail (si, fault::needmoreparams, STR_INSUFFICIENT_PARAMS, "LOGONNEWS DEL"); |
197 |
command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS DEL <id>"); |
198 |
return; |
199 |
} |
200 |
|
201 |
id = atoi (target); |
202 |
|
203 |
if (id <= 0) |
204 |
{ |
205 |
command_fail (si, fault::badparams, STR_INVALID_PARAMS, "LOGONNEWS DEL"); |
206 |
command_fail (si, fault::badparams, "Syntax: LOGONNEWS DEL <id>"); |
207 |
return; |
208 |
} |
209 |
|
210 |
/* search for it */ |
211 |
LIST_FOREACH (n, logon_news.head) |
212 |
{ |
213 |
l = static_cast<logonnews_t *> (n->data); |
214 |
x++; |
215 |
|
216 |
if (x == id) |
217 |
{ |
218 |
logcommand (si, CMDLOG_ADMIN, "LOGONNEWS DEL %s %s", l->target, l->story); |
219 |
|
220 |
node_del (n, &logon_news); |
221 |
|
222 |
sfree (l->nick); |
223 |
sfree (l->target); |
224 |
sfree (l->story); |
225 |
delete l; |
226 |
|
227 |
write_newsdb (); |
228 |
|
229 |
command_success_nodata (si, "Deleted entry %d from logon news.", id); |
230 |
return; |
231 |
} |
232 |
} |
233 |
|
234 |
command_fail (si, fault::nosuch_target, "Entry %d not found in logon news.", id); |
235 |
return; |
236 |
} |
237 |
else if (!strcasecmp (action, "LIST")) |
238 |
{ |
239 |
int x = 0; |
240 |
|
241 |
LIST_FOREACH (n, logon_news.head) |
242 |
{ |
243 |
l = static_cast<logonnews_t *> (n->data); |
244 |
x++; |
245 |
|
246 |
command_success_nodata (si, "%d: [\2%s\2] by \2%s\2, \2%s\2", x, l->target, l->nick, l->story); |
247 |
} |
248 |
|
249 |
command_success_nodata (si, "End of list."); |
250 |
logcommand (si, CMDLOG_GET, "LOGONNEWS LIST"); |
251 |
return; |
252 |
} |
253 |
else |
254 |
{ |
255 |
command_fail (si, fault::badparams, STR_INVALID_PARAMS, "LOGONNEWS"); |
256 |
command_fail (si, fault::needmoreparams, "Syntax: LOGONNEWS ADD|DEL|LIST [target] [message]"); |
257 |
return; |
258 |
} |
259 |
} |
260 |
|
261 |
bool |
262 |
_modinit (module *m) |
263 |
{ |
264 |
user_t::callback.add.attach (display_news); |
265 |
os_cmdtree << os_logonnews; |
266 |
load_newsdb (); |
267 |
|
268 |
return true; |
269 |
} |
270 |
|
271 |
void |
272 |
_moddeinit (void) |
273 |
{ |
274 |
user_t::callback.add.detach (display_news); |
275 |
os_cmdtree >> os_logonnews; |
276 |
} |