1 /*:ts=8*/
2 /*****************************************************************************
3  * FIDOGATE --- Gateway UNIX Mail/News <-> FTN NetMail/EchoMail
4  *
5  * $Id: flo.c,v 4.14 2004/08/22 20:19:11 n0ll Exp $
6  *
7  * Functions for handling BinkleyTerm-style FLO files
8  *
9  *****************************************************************************
10  * Copyright (C) 1990-2004
11  *  _____ _____
12  * |     |___  |   Martin Junius             <mj.at.n0ll.dot.net>
13  * | | | |   | |   Radiumstr. 18
14  * |_|_|_|@home|   D-51069 Koeln, Germany
15  *
16  * This file is part of FIDOGATE.
17  *
18  * FIDOGATE is free software; you can redistribute it and/or modify it
19  * under the terms of the GNU General Public License as published by the
20  * Free Software Foundation; either version 2, or (at your option) any
21  * later version.
22  *
23  * FIDOGATE is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * General Public License for more details.
27  *
28  * You should have received a copy of the GNU General Public License
29  * along with FIDOGATE; see the file COPYING.  If not, write to the Free
30  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31  *****************************************************************************/
32 
33 #include "fidogate.h"
34 
35 
36 /*
37  * Static vars holding data for flo_xxxx() functions
38  */
39 static char  flo_name[MAXPATH];		/* File name */
40 static FILE *flo_fp       = NULL;	/* File stream */
41 static long  flo_off_cur  = -1;		/* Offset beginning of current line
42 					 * (last one read by flo_gets()) */
43 static long  flo_off_next = -1;		/* Offset beginning of next line */
44 
45 
46 
47 /*
48  * Return FLO file pointer
49  */
flo_file(void)50 FILE *flo_file(void)
51 {
52     return flo_fp;
53 }
54 
55 
56 
57 /*
58  * Open FLO file for read/write, complete with BSY files and locking
59  */
flo_open(Node * node,int bsy)60 int flo_open(Node *node, int bsy)
61 {
62     return flo_openx(node, bsy, NULL, FALSE);
63 }
64 
65 
flo_openx(Node * node,int bsy,char * flav,int apmode)66 int flo_openx(Node *node, int bsy, char *flav, int apmode)
67 {
68     char *flo;
69     char *mode;
70 
71     mode = apmode ? AP_MODE : RP_MODE;
72 
73     /* Find existing or new FLO file */
74     flo = bink_find_flo(node, flav);
75     if(!flo)
76 	return ERROR;
77     BUF_COPY(flo_name, flo);
78 
79     /* Create directory if necessary */
80     if(bink_mkdir(node) == ERROR)
81 	return ERROR;
82 
83     /* Create BSY file */
84     if(bsy)
85 	if(bink_bsy_create(node, WAIT) == ERROR)
86 	    return ERROR;
87 
88  again:
89     /* Open FLO file for read/write */
90     debug(4, "Opening FLO file, mode=%s", mode);
91     flo_fp = fopen(flo_name, mode);
92     if(flo_fp == NULL)
93     {
94 	logit("$opening FLO file %s mode %s failed", flo_name, mode);
95 	if(bsy)
96 	    bink_bsy_delete(node);
97 	return ERROR;
98     }
99     chmod(flo_name, FLO_MODE);
100 
101     /* Lock it, waiting for lock to be granted */
102     debug(4, "Locking FLO file");
103     if(lock_file(flo_fp))
104     {
105 	/* Lock error ... */
106 	logit("$locking FLO file %s failed", flo_name);
107 	if(bsy)
108 	    bink_bsy_delete(node);
109 	fclose(flo_fp);
110 	return ERROR;
111     }
112 
113     /* Lock succeeded, but the FLO file may have been deleted */
114     if(access(flo_name, F_OK) == ERROR)
115     {
116 	debug(4, "FLO file %s deleted after locking", flo_name);
117 	fclose(flo_fp);
118 	if(apmode)
119 	{
120 	    if(bsy)
121 		bink_bsy_delete(node);
122 	    goto again;
123 	}
124 	else
125 	    return ERROR;
126     }
127 
128     debug(4, "FLO file %s open and locking succeeded", flo_name);
129 
130     flo_off_cur  = -1;			/* Nothing read yet */
131     flo_off_next = 0;			/* Next line will be the 1st one */
132 
133     return OK;
134 }
135 
136 
137 
138 /*
139  * Read entry line from FLO file
140  */
flo_gets(char * s,size_t len)141 char *flo_gets(char *s, size_t len)
142 {
143     long off;
144     char *ret;
145 
146     /* Current offset */
147     if( (off = ftell(flo_fp)) == -1 )
148     {
149 	logit("$ftell FLO file %s failed", flo_name);
150 	return NULL;
151     }
152     flo_off_cur = off;
153 
154     /* Read next line */
155     if( ! (ret = fgets(s, len, flo_fp)) )
156     {
157 	/* EOF or error */
158 	if(ferror(flo_fp))
159 	{
160 	    logit("$reading FLO file %s failed", flo_name);
161 	    return NULL;
162 	}
163     }
164 
165     /* New offset == offset of next entry line */
166     if( (off = ftell(flo_fp)) == -1 )
167     {
168 	logit("$ftell FLO file %s failed", flo_name);
169 	return NULL;
170     }
171     flo_off_next = off;
172 
173     /* Remove CR/LF */
174     strip_crlf(s);
175 
176     return ret;
177 }
178 
179 
180 
181 /*
182  * Close FLO file
183  */
flo_close(Node * node,int bsy,int del)184 int flo_close(Node *node, int bsy, int del)
185 {
186     int ret = OK;
187 
188     if(flo_fp)
189     {
190 	if(del)
191 	    if(unlink(flo_name) == -1)
192 	    {
193 		logit("$removing FLO file %s failed", flo_name);
194 		ret = ERROR;
195 	    }
196 	fclose(flo_fp);
197 	flo_fp = NULL;
198     }
199 
200     if(bsy)
201 	bink_bsy_delete(node);
202 
203     return ret;
204 }
205 
206 
207 
208 /*
209  * Mark entry line in FLO file as sent
210  */
flo_mark(void)211 int flo_mark(void)
212 {
213     char tilde = '~';
214 
215     if(flo_fp==NULL || flo_off_cur==-1 || flo_off_next==-1)
216 	return ERROR;
217 
218     /* Seek to beginning of line last read */
219     if(fseek(flo_fp, flo_off_cur, SEEK_SET) == -1)
220     {
221 	logit("$seeking to offset %ld in FLO file %s failed",
222 	    flo_off_cur, flo_name);
223 	return ERROR;
224     }
225 
226     /* Write ~ char */
227     if( fwrite(&tilde, 1, 1, flo_fp) != 1 )
228     {
229 	logit("$writing ~ to FLO file %s failed", flo_name);
230 	return ERROR;
231     }
232 
233     /* Seek to beginning of next line */
234     if(fseek(flo_fp, flo_off_next, SEEK_SET) == -1)
235     {
236 	logit("$seeking to offset %ld in FLO file %s failed",
237 	    flo_off_next, flo_name);
238 	return ERROR;
239     }
240 
241     return OK;
242 }
243 
244 
245 
246 /*****************************************************************************/
247 #ifdef TEST
248 
249 #include "getopt.h"
250 
251 
252 #define CONFIG		DEFAULT_CONFIG_MAIN
253 
254 
main(int argc,char * argv[])255 int main(int argc, char *argv[])
256 {
257     Node node;
258     int c;
259     char *c_flag=NULL;
260     char *S_flag=NULL, *L_flag=NULL;
261     char mode[] = "-";
262     char *line;
263 
264     int option_index;
265     static struct option long_options[] =
266     {
267 	{ "verbose",      0, 0, 'v'},	/* More verbose */
268 	{ "config",       1, 0, 'c'},	/* Config file */
269 	{ "spool-dir",    1, 0, 'S'},	/* Set FIDOGATE spool directory */
270 	{ "lib-dir",      1, 0, 'L'},	/* Set FIDOGATE lib directory */
271 	{ 0,              0, 0, 0  }
272     };
273 
274     /* Init configuration */
275     cf_initialize();
276 
277     while ((c = getopt_long(argc, argv, "vc:S:L:",
278 			    long_options, &option_index     )) != EOF)
279 	switch (c) {
280 	/***** Common options *****/
281 	case 'v':
282 	    verbose++;
283 	    break;
284 	case 'c':
285 	    c_flag = optarg;
286 	    break;
287 	case 'S':
288 	    S_flag = optarg;
289 	    break;
290 	case 'L':
291 	    L_flag = optarg;
292 	    break;
293 	}
294 
295     /*
296      * Read config file
297      */
298     if(L_flag)				/* Must set libdir beforehand */
299 	cf_s_libdir(L_flag);
300     cf_read_config_file(c_flag ? c_flag : CONFIG);
301 
302     /*
303      * Process config options
304      */
305     if(L_flag)
306 	cf_s_libdir(L_flag);
307     if(S_flag)
308 	cf_s_spooldir(S_flag);
309 
310     /***** Test **************************************************************/
311     if(optind >= argc)
312     {
313 	fprintf(stderr,
314 		"usage: testflo [-v] [-c CONFIG] "
315 		"[-L LIBDIR] [-S SPOOLDIR] Z:N/F.P\n");
316 	exit(1);
317     }
318 
319     if(asc_to_node(argv[optind], &node, FALSE) == ERROR)
320     {
321 	fprintf(stderr, "testflo: %s is not an FTN address\n", argv[optind]);
322 	exit(1);
323     }
324 
325     if(flo_open(&node, TRUE) == ERROR)
326     {
327 	printf("No FLO file for %s\n", znfp1(&node));
328 	exit(0);
329     }
330 
331     printf("Contents of FLO file:\n");
332     str_printf(buffer, sizeof(buffer), "cat -v %s", flo_name);
333     system(buffer);
334 
335     while( (line = flo_gets(buffer, sizeof(buffer))) )
336     {
337 	mode[0] = '-';
338 	printf("Line  :   %s\n", line);
339 	if(*line=='^' || *line=='#')
340 	    mode[0] = *line++;
341 	printf("  DOS : %s %s\n", mode, line);
342 	if(cf_dos())
343 	    printf("  UNIX: %s %s\n", mode, cf_unix_xlate(line));
344 	flo_mark();
345     }
346 
347     printf("Modified contents of FLO file:\n");
348     str_printf(buffer, sizeof(buffer), "cat -v %s", flo_name);
349     system(buffer);
350 
351     flo_close(&node, TRUE, TRUE);
352 
353     exit(0);
354 
355     /**NOT REACHED**/
356     return 0;
357 }
358 
359 #endif /**TEST**/
360