1    | /*
2    |  * $Log: tm_xpress.c,v $
3    |  * Revision 1.7  2004/05/18 02:05:31  nzmb
4    |  * Fixed wrong e-mail title and compiler warning in send_diary() function.
5    |  *
6    |  * Revision 1.6  2003/07/18 01:24:07  nzmb
7    |  * Changed it so the "diary" command by itself defaults to "diary record"
8    |  *
9    |  * Revision 1.5  2003/07/12 01:48:43  nzmb
10   |  * Master now gets notified when a player enters a new diary entry.
11   |  *
12   |  * Revision 1.4  2003/06/29 21:37:43  nzmb
13   |  * Made EOG draw entries broadcasted at the end of the game.
14   |  *
15   |  * Revision 1.3  2003/06/22 04:10:23  nzmb
16   |  * Added code to allow users to record diary entries, read them, and delete them
17   |  * if they make a mistake. The diaries will be broadcast when the games end (this
18   |  * part is not as of now, yet written).
19   |  *
20   |  * Revision 1.2  2002/07/17 11:48:11  millis
21   |  * Added Log to header
22   |  *
23   |  */
24   | 
25   | /*
26   |  * tm_xpress.c -- Tim Miller's extended press functionality. Will include
27   |  * EOG diarys and szine style press published at deadline.
28   |  */
29   | 
30   | #include <stdio.h>
31   | #include <stdlib.h>
32   | #include <string.h>
33   | #include <unistd.h>
34   | #include <sys/stat.h>
35   | 
36   | #include "dip.h"
37   | #include "mail.h"
38   | #include "functions.h"
39   | 
40   | void new_diary_entry(void);
41   | void list_entries(void);
42   | void read_entry(int entry);
43   | void delete_entry(int entry);
44   | int  get_numentries(char *gamename, char pabbr);
45   | 
46   | int process_ppress(void)
47   | {
48   | 	char pfilename[1000];
49   | 	char b;
50   | 	
51   | 	/* see if this is even allowed */
52   | 	if(!(dipent.x2flags & X2F_POSTALPRESS))
53   | 	{
54   | 		fprintf(rfp,"Postal press is not allowed. Skipping:\n");
55   | 		ppress_skip = 1;
56   | 		return 1;
57   | 	}
58   | 
59   | 	/* this is cool -- open up the press file */
60   | 	sprintf(pfilename,"%s%s/ppress-%s", GAME_DIR, dipent.name, dipent.phase);
61   | 	if((ppfp = fopen(pfilename, "a")) == NULL)
62   | 	{
63   | 		fprintf(log_fp, "Error opening ppress file %s.\n", pfilename);
64   | 		bailout(E_FATAL);
65   | 	}
66   | 
67   | 	ppress_read = 1;
68   | 	broadcast_master_only = 1;
69   | 	b = dipent.pl[dipent.players[player].power];
70   | 	fprintf(mbfp,"%s as %c in %s submitted press:\n", raddr,
71   | 		b, dipent.name);
72   | 	fprintf(ppfp,"\nPress from %c:\n", b);
73   | 	fprintf(rfp, "\nAppending to press file:\n");
74   | 	sprintf(subjectline, "%s:%s - %s postal press recorded", JUDGE_CODE,
75   | 		dipent.name, dipent.phase);
76   | 	return 0;
77   | }
78   | 
79   | void process_diary(char *cmd)
80   | {
81   | 	char *ch, *tmp = NULL;
82   | 	int read = 0;	 /* read a specified entry */
83   | 	int delete = 0;  /* delete a specified entry */
84   | 	int entry = -1;	 /* number of entry to perform action on */
85   | 	int record = 0;
86   | 
87   | 	if(cmd[0] == '\0')
88   | 		record++;
89   | 	ch = strchr(cmd,'\n');
90   | 	if(ch)
91   | 		*ch = '\0'; /* remove any newline */
92   | 
93   | 	ch = strchr(cmd, ' ');
94   | 	if(ch)
95   | 	{
96   | 		tmp = ch + 1;
97   | 		*ch = '\0';  /* make the first arg its own null terminated string */
98   | 	}
99   | 
100  | 	if(record || !strcasecmp(cmd, "record"))
101  | 	{
102  | 		/* record a new diary entry */
103  | 		new_diary_entry();
104  | 		broadcast_master_only = 1;
105  | 		sprintf(subjectline, "%s:%s - %s New diary entry from %c",
106  | 			JUDGE_CODE, dipent.name, dipent.phase,
107  | 			dipent.pl[dipent.players[player].power]);
108  | 		return;
109  | 	}
110  | 	if(!strcasecmp(cmd, "list"))
111  | 	{
112  | 		/* list previously made entries */
113  | 		list_entries();
114  | 		return;
115  | 	}
116  | 	if(!strcasecmp(cmd, "read"))
117  | 		read++;
118  | 	else if(!strcasecmp(cmd, "delete"))
119  | 		delete++;
120  | 	else {
121  | 		fprintf(rfp,"Bad diary option %s.\n",cmd);
122  | 		fprintf(rfp,"Skipping following message...\n");
123  | 		diary_skip++;
124  | 		return;
125  | 	}
126  | 
127  | 	if(!ch)
128  | 	{
129  | 		fprintf(rfp, "You must specify an entry number to %s.\n\n", cmd);
130  | 		return;
131  | 	}
132  | 
133  | 	entry = (int)strtol(tmp,NULL,10);
134  | 	if(entry < 0)
135  | 	{
136  | 		fprintf(rfp,"Bad entry %s.\n", tmp);
137  | 		return;
138  | 	}
139  | 
140  | 	if(read)
141  | 		read_entry(entry);
142  | 	if(delete)
143  | 		delete_entry(entry);
144  | }
145  | 
146  | void new_diary_entry(void)
147  | {
148  | 	int next_entry;
149  | 	char fname[512];
150  | 	char pabbr = dipent.pl[dipent.players[player].power];
151  | 
152  | 	next_entry = get_numentries(dipent.name, pabbr);
153  | 	if(next_entry < 0)
154  | 	{
155  | 		fprintf(rfp,"Error: could not open new diary entry.\n\n");
156  | 		diary_skip++;
157  | 		return;
158  | 	}
159  | 
160  | 	/* determine the new entry file & open it */
161  | 	sprintf(fname,"%s%s/diary-%c-%d", GAME_DIR, dipent.name,
162  | 		pabbr, next_entry);
163  | 	diaryfp = fopen(fname, "w");
164  | 	if(!diaryfp)
165  | 	{
166  | 		fprintf(log_fp, "Could not open diary file %s!\n", fname);
167  | 		fflush(log_fp);
168  | 		bailout(E_FATAL);
169  | 	}
170  | 
171  | 	fprintf(rfp, "Recording new diary entry #%d...\n\n", next_entry);
172  | 	fprintf(diaryfp, "Diary entry from %s in %s for phase %s:\n\n\n",
173  | 		powers[dipent.players[player].power], dipent.name,
174  | 		dipent.phase);
175  | 	diary_read = 1;
176  | }
177  | 
178  | void read_entry(int entry)
179  | {
180  | 	char entryfname[512];
181  | 	char line[1000];
182  | 	FILE *diary_read;
183  | 
184  | 	sprintf(entryfname,"%s%s/diary-%c-%d", GAME_DIR, dipent.name,
185  | 		dipent.pl[dipent.players[player].power], entry);
186  | 	diary_read = fopen(entryfname, "r");
187  | 	if(!diary_read)
188  | 	{
189  | 		fprintf(rfp, "Cannot open diary entry #%d -- ", entry);
190  | 		fprintf(rfp, "perhaps said entry doesn't exist?\n\n");
191  | 		return;
192  | 	}
193  | 
194  | 	fprintf(rfp, "Reading entry %d ... \n\n", entry);
195  | 	while(fgets(line, sizeof line, diary_read))
196  | 		fprintf(rfp,"%s", line);
197  | 	fprintf(rfp, "\n\nEnd of entry\n\n");
198  | }
199  | 
200  | void delete_entry(int entry)
201  | {
202  | 	char pabbr, cmd[512];
203  | 
204  | 	pabbr = dipent.pl[dipent.players[player].power];
205  | 	if(entry < 0 || entry >= get_numentries(dipent.name, pabbr))
206  | 	{
207  | 		fprintf(rfp,"Cannot delete diary entry %d -- no such entry.\n\n", entry);
208  | 		return;
209  | 	}
210  | 
211  | 	sprintf(cmd,"rm -f %s%s/diary-%c-%d", GAME_DIR, dipent.name,
212  | 		pabbr, entry);
213  | 	system(cmd);
214  | 	fprintf(rfp, "Diary entry %d removed.\n\n", entry);
215  | }
216  | 
217  | void list_entries(void)
218  | {
219  | 	int nentries, i;
220  | 	char pabbr;
221  | 	struct stat statbuf;
222  | 	struct tm *mod_tm;
223  | 	char fname[1000];
224  | 	char *months[] = {"Non", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 
225  | 
226  | 	pabbr = dipent.pl[dipent.players[player].power];
227  | 	nentries = get_numentries(dipent.name, pabbr);
228  | 	if(nentries < 0)
229  | 	{
230  | 		fprintf(rfp,"Error fetching number of entries!\n");
231  | 	} else if(nentries == 0) {
232  | 		fprintf(rfp,"You haven't made any diary entries!\n");
233  | 	} else {
234  | 		fprintf(rfp,"\nExisting diary entries:\n\n");
235  | 		for(i = 0; i < nentries; i++)
236  | 		{
237  | 			sprintf(fname,"%s%s/diary-%c-%d", GAME_DIR,
238  | 				dipent.name, pabbr, i);
239  | 			if(stat(fname, &statbuf) != -1)
240  | 			{
241  | 				mod_tm = localtime(&(statbuf.st_mtime));
242  | 				fprintf(rfp, "Entry #%d: modified %s %d, %d %02d:%02d\n",
243  | 					i, months[mod_tm->tm_mon + 1],
244  | 					mod_tm->tm_mday, 1900 + mod_tm->tm_year,
245  | 					mod_tm->tm_hour, mod_tm->tm_min); 
246  | 			}
247  | 			else
248  | 			{
249  | 				nentries++;
250  | 			}
251  | 		}
252  | 		fprintf(rfp,"\n\n");
253  | 	}
254  | }
255  | 
256  | int get_numentries(char *gamename, char pabbr)
257  | {
258  | 	char command[1000];
259  | 	char nstring[256];
260  | 	FILE *cmdpipe;
261  | 	int nentries = -1;
262  | 
263  | 	sprintf(command,"ls %s%s/diary-%c* | wc -w",
264  | 		GAME_DIR, gamename, pabbr);
265  | 	cmdpipe = popen(command, "r");
266  | 	if(cmdpipe)
267  | 	{
268  | 		fread(nstring, 1, 255, cmdpipe);
269  | 		pclose(cmdpipe);
270  | 	
271  | 		if(strstr(nstring, "No such file"))
272  | 			nentries = 0;
273  | 		else
274  | 			nentries = (int)strtol(nstring, NULL, 10);
275  | 	}
276  | 
277  | 	return nentries;
278  | }
279  | 
280  | void send_diary(void)
281  | {
282  | 	/*
283  | 	 * send each diary out at the end of the game.
284  | 	 */
285  | 	int i, j, k, ndiaries;
286  | 	char subjectln[256];
287  | 	char diary_fl[256];
288  | 	char line[1000];
289  | 	char pabbr;
290  | 	struct stat sbuf;
291  | 
292  | 	for(i = 0; i < dipent.n; i++)
293  | 	{
294  | 		/*
295  | 		 * cycle through all the players who may have
296  | 		 * left diaries
297  | 		 */
298  | 		if(dipent.players[i].power < 0)
299  | 			continue;
300  | 		pabbr = dipent.pl[dipent.players[i].power];
301  | 		ndiaries = get_numentries(dipent.name, pabbr);
302  | 		if(ndiaries < 0)
303  | 			/* error don't send anything */
304  | 			ndiaries = 0;
305  | 
306  | 		for(j = 0; j < ndiaries; j++)
307  | 		{
308  | 			/* send all diaries */
309  | 			sprintf(subjectln, "%s:%s diary #%d from %c",
310  | 				JUDGE_CODE, dipent.name, j, pabbr);
311  | 			sprintf(diary_fl, "%s%s/diary-%c-%d", GAME_DIR,
312  | 				dipent.name, pabbr, j);
313  | 			if(stat(diary_fl, &sbuf) == -1)
314  | 			{
315  | 				ndiaries++;
316  | 				continue;
317  | 			}
318  | 
319  | 			for(k = 0; k < dipent.n; k++)
320  | 			{
321  | 				/* to everyone */
322  | 				if(dipent.players[k].power < 0)
323  | 					continue;
324  | 				sprintf(line, "%s %s \"%s\" %s", SMAIL_CMD,
325  | 					diary_fl, subjectln, dipent.players[k].address);
326  | 				execute(line);
327  | 			}
328  | 		}
329  | 	}
330  | }