Fix crash after recursive aliasing
[capablanca.git] / lasker-2.2.3 / src / news.c
1 /*
2    Copyright (C) Andrew Tridgell 2002
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 /*
20   support for the 'news' command
21  */
22
23 #include "includes.h"
24
25 static TDB_CONTEXT *news_db;
26
27 /* close the news database */
28 void news_close(void)
29 {
30         if (!news_db) return;
31         tdb_close(news_db);
32         news_db = NULL;
33 }
34
35 /* 
36    open the news database
37    returns 0 on success
38  */
39 int news_open(void)
40 {
41         news_db = tdb_open(NEWS_DB, 0, 0, O_RDWR|O_CREAT, 0600);
42         if (!news_db) {
43                 d_printf("Unable to open news database!\n");
44                 return -1;
45         }
46         return 0;
47 }
48
49 /*
50   free up a news item
51 */
52 static void news_free(struct news *news)
53 {
54         FREE(news->poster);
55         FREE(news->title);
56         FREE(news->message);
57 }
58
59 /*
60   return the maximum news item number
61 */
62 static int news_max(int admin)
63 {
64         return tdb_get_int(news_db, admin?"ADMIN_MAXNUM":"MAXNUM", 0);
65 }
66
67 /*
68   save a news item
69 */
70 static int news_save(int num, struct news *news, int admin)
71 {
72         const char *s;
73         char *name;
74
75         /* marshall it into a string */
76         s = marshall_news(news);
77         if (!s) {
78                 return -1;
79         }
80
81         asprintf(&name, "%s%u", admin?"ADMIN/":"", num);
82         if (tdb_set_string(news_db, name, s) != 0) {
83                 free(name);
84                 free(s);
85                 return -1;
86         }
87
88         free(name);
89         free(s);
90
91         if (news_max(admin) < num) {
92                 tdb_set_int(news_db, admin?"ADMIN_MAXNUM":"MAXNUM", num);
93         }
94
95         return 0;
96 }
97
98
99 /*
100   load a news item
101 */
102 static int news_load(int num, struct news *news, int admin)
103 {
104         const char *s;
105         char *name;
106         int ret;
107
108         asprintf(&name, "%s%u", admin?"ADMIN/":"", num);
109         s = tdb_get_string(news_db, name);
110         if (!s) {
111                 free(name);
112                 return -1;
113         }
114         free(name);
115
116         ret = unmarshall_news(news, s);
117         free(s);
118         return ret;
119 }
120
121 /*
122   delete a news item
123 */
124 static int news_delete(int p, int num, int admin)
125 {
126         char *name;
127
128         asprintf(&name, "%s%u", admin?"ADMIN/":"", num);
129         if (tdb_delete_string(news_db, name) == 0) {
130                 pprintf(p,"Deleted news item %u\n", num);
131         } else {
132                 pprintf(p,"Unable to delete news item %u !\n", num);
133         }
134         free(name);
135         return 0;
136 }
137
138
139 /*
140   summarise the news
141  */
142 static int news_summary(int p, int first, int how_many, int admin)
143 {
144         int i;
145         if (first < 1) {
146                 first = 1;
147         }
148         for (i=first; i< first+how_many; i++) {
149                 struct news news;
150                 if (news_load(i, &news, admin) == 0) {
151                         pprintf(p, "%4u (%s) %s\n", 
152                                 i, 
153                                 strday(&news.post_date), 
154                                 news.title);
155                         news_free(&news);
156                 }
157         }
158
159         return COM_OK;
160 }
161
162
163 /*
164   lookup a news item
165  */
166 static int do_news(int p, param_list param, int admin)
167 {
168         int num;
169         struct news news;
170
171         if (param[0].type == TYPE_NULL) {
172                 return news_summary(p, news_max(admin)-9, 10, admin);
173         }
174         if (strcasecmp(param[0].val.word, "all") == 0) {
175                 return news_summary(p, 1, news_max(admin), admin);
176         }
177
178         num = atoi(param[0].val.word);
179         if (num <= 0) {
180                 pprintf(p, "Bad news item number '%s'\n", param[0].val.word);
181                 return COM_OK;
182         }
183
184         if (news_load(num, &news, admin) != 0) {
185                 pprintf(p, "News item %u not found\n", num);
186                 return COM_OK;
187         }
188
189         pprintf_more(p,"%4u (%s) %s\n\n%s\n\nPosted by %s.\n", 
190                      num, 
191                      strday(&news.post_date), 
192                      news.title,
193                      news.message,
194                      news.poster);
195
196         news_free(&news);
197
198         return COM_OK;
199 }
200
201 /*
202   lookup a news item
203  */
204 int com_news(int p, param_list param)
205 {
206         return do_news(p, param, 0);
207 }
208
209
210 /*
211   lookup a admin news item
212  */
213 int com_anews(int p, param_list param)
214 {
215         return do_news(p, param, 1);
216 }
217
218
219 /*
220   create a new news item
221 */
222 static int cnewsi(int p, const char *title, int admin)
223 {
224         struct player *pp = &player_globals.parray[p];
225         struct news news;
226         int ret, num;
227
228         ZERO_STRUCT(news);
229         news.poster = strdup(pp->name);
230         news.post_date = time(NULL);
231         news.message = strdup("");
232         news.title = strndup(title, 45);
233
234         num = news_max(admin) + 1;
235         ret = news_save(num, &news, admin);
236         
237         if (ret == 0) {
238                 pprintf(p,"Created news item %u\n", num);
239         } else {
240                 pprintf(p,"Failed to create news item %u !\n", num);
241         }
242
243         news_free(&news);
244         return ret;
245 }
246
247 /*
248   add to a news item
249 */
250 static int cnewsf(int p, int num, const char *message, int admin)
251 {
252         struct news news;
253         char *msg;
254
255         if (news_load(num, &news, admin) != 0) {
256                 pprintf(p, "News item %u not found\n", num);
257                 return -1;
258         }
259
260         asprintf(&msg, "%s%s\n", news.message, message);
261         FREE(news.message);
262         news.message = msg;
263
264         if (news_save(num, &news, admin) != 0) {
265                 pprintf(p, "News item %u could not be updated !\n", num);
266                 news_free(&news);
267                 return -1;
268         }
269
270         pprintf(p, "News item %u updated\n", num);
271
272         news_free(&news);
273         return 0;
274 }
275
276 /*
277   set title on a news item
278 */
279 static int cnewst(int p, int num, const char *title, int admin)
280 {
281         struct news news;
282
283         if (news_load(num, &news, admin) != 0) {
284                 pprintf(p, "News item %u not found\n", num);
285                 return -1;
286         }
287
288         FREE(news.title);
289         news.title = strndup(title, 45);
290
291         if (news_save(num, &news, admin) != 0) {
292                 pprintf(p, "News item %u could not be updated !\n", num);
293                 news_free(&news);
294                 return -1;
295         }
296
297         pprintf(p, "News item %u updated\n", num);
298
299         news_free(&news);
300         return 0;
301 }
302
303 /*
304   set poster on a news item
305 */
306 static int cnewsp(int p, int num, int admin)
307 {
308         struct player *pp = &player_globals.parray[p];
309         struct news news;
310
311         if (news_load(num, &news, admin) != 0) {
312                 pprintf(p, "News item %u not found\n", num);
313                 return -1;
314         }
315
316         FREE(news.poster);
317         news.poster = strdup(pp->name);
318
319         if (news_save(num, &news, admin) != 0) {
320                 pprintf(p, "News item %u could not be updated !\n", num);
321                 news_free(&news);
322                 return -1;
323         }
324
325         pprintf(p, "News item %u updated\n", num);
326
327         news_free(&news);
328         return 0;
329 }
330
331 /*
332   delete last line of an item
333 */
334 static int cnewsd(int p, int num, int admin)
335 {
336         struct news news;
337         char *s;
338
339         if (news_load(num, &news, admin) != 0) {
340                 pprintf(p, "News item %u not found\n", num);
341                 return -1;
342         }
343
344         news.message[strlen(news.message)-1] = 0;
345         s = strrchr(news.message, '\n');
346         if (s) {
347                 s[1] = 0;
348         } else {
349                 news.message[0] = 0;
350         }
351
352         if (news_save(num, &news, admin) != 0) {
353                 pprintf(p, "News item %u could not be updated !\n", num);
354                 news_free(&news);
355                 return -1;
356         }
357
358         pprintf(p, "News item %u updated\n", num);
359
360         news_free(&news);
361         return 0;
362 }
363
364
365 /*
366   set expiry on a news item
367 */
368 static int cnewse(int p, int num, int expiry, int admin)
369 {
370         struct news news;
371
372         if (news_load(num, &news, admin) != 0) {
373                 pprintf(p, "News item %u not found\n", num);
374                 return -1;
375         }
376
377         if (expiry == -1) {
378                 news_free(&news);
379                 return news_delete(p, num, admin);
380         } else if (expiry == 0) {
381                 news.expires = 0;
382         } else {
383                 news.expires = time(NULL) + (expiry * 24*60*60);
384         }
385
386         if (news_save(num, &news, admin) != 0) {
387                 pprintf(p, "News item %u could not be updated !\n", num);
388                 news_free(&news);
389                 return -1;
390         }
391
392         pprintf(p, "News item %u updated\n", num);
393
394         news_free(&news);
395         return 0;
396 }
397
398 /*
399   create a normal news item
400 */
401 int com_cnewsi(int p, param_list param)
402 {
403         cnewsi(p, param[0].val.string, 0);
404         return COM_OK;
405 }
406
407 /*
408   add to a normal news item
409 */
410 int com_cnewsf(int p, param_list param)
411 {
412         cnewsf(p, param[0].val.integer, 
413                param[1].type != TYPE_NULL?param[1].val.string:"", 
414                0);
415         return COM_OK;
416 }
417
418 /*
419   set title on a normal news item
420 */
421 int com_cnewst(int p, param_list param)
422 {
423         cnewst(p, param[0].val.integer, param[1].val.string, 0);
424         return COM_OK;
425 }
426
427 /*
428   set poster on a normal news item
429 */
430 int com_cnewsp(int p, param_list param)
431 {
432         cnewsp(p, param[0].val.integer, 0);
433         return COM_OK;
434 }
435
436 /*
437   set expiry on a normal news item
438 */
439 int com_cnewse(int p, param_list param)
440 {
441         cnewse(p, 
442                param[0].val.integer, 
443                param[1].type != TYPE_NULL?param[1].val.integer:-1, 
444                0);
445         return COM_OK;
446 }
447
448 /*
449   delete last line on a normal news item
450 */
451 int com_cnewsd(int p, param_list param)
452 {
453         cnewsd(p, param[0].val.integer, 0);
454         return COM_OK;
455 }
456
457 /*
458   create a admin news item
459 */
460 int com_canewsi(int p, param_list param)
461 {
462         cnewsi(p, param[0].val.string, 1);
463         return COM_OK;
464 }
465
466 /*
467   add to a admin news item
468 */
469 int com_canewsf(int p, param_list param)
470 {
471         cnewsf(p, param[0].val.integer, 
472                param[1].type != TYPE_NULL?param[1].val.string:"", 
473                1);
474         return COM_OK;
475 }
476
477 /*
478   set title on a admin news item
479 */
480 int com_canewst(int p, param_list param)
481 {
482         cnewst(p, param[0].val.integer, param[1].val.string, 1);
483         return COM_OK;
484 }
485
486 /*
487   set poster on a admin news item
488 */
489 int com_canewsp(int p, param_list param)
490 {
491         cnewsp(p, param[0].val.integer, 1);
492         return COM_OK;
493 }
494
495 /*
496   set expiry on a admin news item
497 */
498 int com_canewse(int p, param_list param)
499 {
500         cnewse(p, param[0].val.integer, 
501                param[1].type != TYPE_NULL?param[1].val.integer:-1, 
502                1);
503         return COM_OK;
504 }
505
506 /*
507   delete last line on a admin news item
508 */
509 int com_canewsd(int p, param_list param)
510 {
511         cnewsd(p, param[0].val.integer, 1);
512         return COM_OK;
513 }
514
515
516 /*
517   tell user about new news
518 */
519 void news_login(int p)
520 {
521         struct player *pp = &player_globals.parray[p];
522         int max;
523
524         max = news_max(0);
525         if (max > pp->latest_news) {
526                 pprintf(p,"\nThere are %u new news items since your last login\n", 
527                         max - pp->latest_news);
528                 pp->latest_news = max;
529         }
530
531         if (!check_admin(p, ADMIN_ADMIN)) return;
532
533         max = news_max(1);
534         if (max > pp->admin_latest_news) {
535                 pprintf(p,"\nThere are %u new admin news items since your last login\n", 
536                         max - pp->admin_latest_news);
537                 pp->admin_latest_news = max;
538         }
539 }