1 /*:ts=8*/
2 /*****************************************************************************
3  * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4  *
5  * $Id: binkley.c,v 4.20 2004/08/22 20:19:11 n0ll Exp $
6  *
7  * BinkleyTerm-style outbound directory functions
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 #include <fcntl.h>
36 
37 
38 
39 
40 /*
41  * BinkleyTerm flavors and FLO/OUT file extensions
42  */
43 #define NOUTB		5
44 
45 static struct st_outb
46 {
47     int type;
48     char flo[4];
49     char out[4];
50     char flav[8];
51     char shrt[2];
52 }
53 outb_types[NOUTB] =
54 {
55     { FLAV_NONE  , ""   , ""   , "None"  , "-" },
56     { FLAV_HOLD  , "hlo", "hut", "Hold"  , "H" },
57     { FLAV_NORMAL, "flo", "out", "Normal", "N" },
58     { FLAV_DIRECT, "dlo", "dut", "Direct", "D" },
59     { FLAV_CRASH , "clo", "cut", "Crash" , "C" }
60 };
61 
62 
63 
64 /*
65  * FLAV_* flavor code to string
66  */
flav_to_asc(int flav)67 char *flav_to_asc(int flav)
68 {
69     int i;
70 
71     for(i=0; i<NOUTB; i++)
72 	if(outb_types[i].type == flav)
73 	    return outb_types[i].flav;
74 
75     return "Normal";
76 }
77 
78 
79 
80 /*
81  * String to FLAV_* flavor code
82  */
asc_to_flav(char * flav)83 int asc_to_flav(char *flav)
84 {
85     int i;
86 
87     for(i=0; i<NOUTB; i++)
88 	if(!stricmp(outb_types[i].flav, flav))
89 	    return outb_types[i].type;
90 
91     return ERROR;
92 }
93 
94 
95 
96 /*
97  * Convert node address to outbound base name
98  */
bink_out_name(Node * node)99 char *bink_out_name(Node *node)
100 {
101     static char buf[MAXPATH];
102     char *out, *outbound;
103 
104     out = cf_zones_out(node->zone);
105     if(!out)
106 	return NULL;
107     outbound = cf_p_btbasedir();
108     if(!outbound)
109 	return NULL;
110 
111 #ifdef AMIGADOS_4D_OUTBOUND
112     str_printf(buf, sizeof(buf), "%s/%s/%d.%d.%d.%d.",
113 	       outbound, out, node->zone,
114 	       node->net, node->node, node->point);
115 #else
116     if(node->point)
117 	str_printf(buf, sizeof(buf), "%s/%s/%04x%04x.pnt/0000%04x.",
118 		   outbound, out, node->net, node->node, node->point);
119     else
120 	str_printf(buf, sizeof(buf), "%s/%s/%04x%04x.",
121 		   outbound, out, node->net, node->node);
122 #endif /**AMIGADOS_4D_OUTBOUND**/
123 
124     return buf;
125 }
126 
127 
128 
129 /*
130  * Name of BSY file for a node
131  */
bink_bsy_name(Node * node)132 char *bink_bsy_name(Node *node)
133 {
134     static char buf[MAXPATH];
135     char *out;
136 
137     out = bink_out_name(node);
138     if(!out)
139 	return NULL;
140 
141     BUF_COPY(buf, out);
142     BUF_APPEND(buf, "bsy");
143     debug(6, "node=%s bsy file=%s", znfp1(node), buf);
144     return buf;
145 }
146 
147 
148 
149 /*
150  * Test for existing BSY file
151  */
bink_bsy_test(Node * node)152 int bink_bsy_test(Node *node)
153 {
154     char *name = bink_bsy_name(node);
155 
156     if(!name)
157 	return FALSE;
158 
159     return check_access(name, CHECK_FILE)==TRUE;
160 }
161 
162 
163 
164 /*
165  * Create BSY file for a node
166  */
bink_bsy_create(Node * node,int wait)167 int bink_bsy_create(Node *node, int wait)
168 {
169 #ifdef DO_BSY_FILES
170     char *name = bink_bsy_name(node);
171 
172     if(!name)
173 	return ERROR;
174 
175     /* Create directory if necessary */
176     if(bink_mkdir(node) == ERROR)
177 	return ERROR;
178 
179     /* Create BSY file */
180 # ifdef NFS_SAFE_LOCK_FILES
181     return lock_lockfile_nfs(name, wait, NULL);
182 # else
183     return lock_lockfile_id(name, wait, NULL);
184 # endif
185 #else
186     return OK;
187 #endif
188 }
189 
190 
191 
192 /*
193  * Delete BSY file for a node
194  */
bink_bsy_delete(Node * node)195 int bink_bsy_delete(Node *node)
196 {
197 #ifdef DO_BSY_FILES
198     char *name = bink_bsy_name(node);
199     int ret;
200 
201     if(!name)
202 	return ERROR;
203 
204     ret = unlink(name);
205     debug(5, "Deleting BSY file %s %s.",
206 	  name, ret==-1 ? "failed" : "succeeded");
207 
208     return ret==-1 ? ERROR : OK;
209 #else
210     return OK;
211 #endif
212 }
213 
214 
215 
216 /*
217  * Find FLO file for node
218  *
219  * flav==NULL: only return non-NULL if existing FLO file found.
220  * flav!=NULL: return existing FLO file or name of new FLO file according
221  *             to flav.
222  */
bink_find_flo(Node * node,char * flav)223 char *bink_find_flo(Node *node, char *flav)
224 {
225     static char buf[MAXPATH];
226     char *outb, *flo=NULL;
227     int i;
228 
229     outb = bink_out_name(node);
230     if(!outb)
231 	return NULL;
232 
233     /*
234      * Search existing FLO files first
235      */
236     for(i=1; i<NOUTB; i++)
237     {
238 	BUF_COPY(buf, outb);
239 	BUF_APPEND(buf, outb_types[i].flo);
240 	if(access(buf, F_OK) == 0)
241 	{
242 	    /* FLO file exists */
243 	    debug(5, "found FLO file %s", buf);
244 	    return buf;
245 	}
246     }
247 
248     if(!flav)
249 	return NULL;
250 
251     /*
252      * No FLO file exists, new one with flavor from arg
253      */
254     for(i=1; i<NOUTB; i++)
255     {
256 	if(!stricmp(outb_types[i].flav, flav) ||
257 	   !stricmp(outb_types[i].shrt, flav) ||
258 	   !stricmp(outb_types[i].flo , flav)   )
259 	    flo = outb_types[i].flo;
260     }
261     if(!flo)
262 	return NULL;
263 
264     BUF_COPY(buf, outb);
265     BUF_APPEND(buf, flo);
266     debug(5, "new FLO file %s", buf);
267     return buf;
268 }
269 
270 
271 
272 /*
273  * Find OUT file for node
274  *
275  * flav==NULL: only return non-NULL if existing OUT file found.
276  * flav!=NULL: return existing OUT file or name of new OUT file according
277  *             to flav.
278  */
bink_find_out(Node * node,char * flav)279 char *bink_find_out(Node *node, char *flav)
280 {
281     static char buf[MAXPATH];
282     char *outb, *out=NULL;
283     int i;
284 
285     outb = bink_out_name(node);
286     if(!outb)
287 	return NULL;
288 
289     /*
290      * Search existing OUT files first
291      */
292     for(i=1; i<NOUTB; i++)
293     {
294 	BUF_COPY(buf, outb);
295 	BUF_APPEND(buf, outb_types[i].out);
296 	if(access(buf, F_OK) == 0)
297 	{
298 	    /* OUT file exists */
299 	    debug(5, "found OUT file %s", buf);
300 	    return buf;
301 	}
302     }
303 
304     if(!flav)
305 	return NULL;
306 
307     /*
308      * No OUT file exists, new one with flavor from arg
309      */
310     for(i=1; i<NOUTB; i++)
311     {
312 	if(!stricmp(outb_types[i].flav, flav) ||
313 	   !stricmp(outb_types[i].shrt, flav) ||
314 	   !stricmp(outb_types[i].out , flav)   )
315 	    out = outb_types[i].out;
316     }
317     if(!out)
318 	return NULL;
319 
320     BUF_COPY(buf, outb);
321     BUF_APPEND(buf, out);
322     debug(5, "new OUT file %s", buf);
323     return buf;
324 }
325 
326 
327 
328 /*
329  * Attach file to FLO control file
330  */
bink_attach(Node * node,int mode,char * name,char * flav,int bsy)331 int bink_attach(Node *node, int mode, char *name, char *flav, int bsy)
332 {
333     FILE *fp;
334     char *n;
335     char *line;
336     int lmode, found;
337     static char buf[MAXPATH];
338 
339     if(mode)
340 	debug(4, "attach mode=%c (^=delete, #=trunc)", mode);
341     debug(4, "attach name=%s", name);
342 
343     if(cf_dos())			/* MSDOS translation enabled? */
344     {
345 	n = cf_dos_xlate(name);
346 	if(!n)
347 	{
348 	    logit("can't convert file name to MSDOS: %s", name);
349 	    return ERROR;
350 	}
351 	debug(4, "attach MSDOS name=%s", n);
352     }
353     else
354 	n = name;
355 
356     if(flo_openx(node, bsy, flav, TRUE) == ERROR)
357 	return ERROR;
358     fp = flo_file();
359 
360     /* seek to start of flo file */
361     if(fseek(fp, 0L, SEEK_SET) == ERROR)
362     {
363 	logit("$fseek EOF FLO file node %s failed", znfp1(node));
364 	flo_close(node, TRUE, FALSE);
365 	return ERROR;
366     }
367 
368     /* read FLO entries, check if file attachment exists */
369     found = FALSE;
370     while( (line = flo_gets(buf, sizeof(buf))) )
371     {
372 	if(*line == '~')
373 	    continue;
374 	lmode = ' ';
375 	if(*line == '^' || *line == '#')
376 	    lmode = *line++;
377 
378 	debug(5, "FLO entry: %c %s", lmode, line);
379 	if(streq(line, n))
380 	{
381 	    found = TRUE;
382 	    debug(5, "           found entry");
383 	}
384     }
385 
386     /* We're there ...  */
387     if(found)
388 	debug(4, "FLO file already contains an entry, not attaching file");
389     else
390     {
391 	debug(4, "FLO file open and locking succeeded, attaching file");
392 	if(mode)
393 	    fprintf(fp, "%c%s%s", mode, n, cf_dos() ? "\r\n" : "\n" );
394 	else
395 	    fprintf(fp, "%s%s"  ,       n, cf_dos() ? "\r\n" : "\n" );
396     }
397 
398     flo_close(node, bsy, FALSE);
399 
400     return OK;
401 }
402 
403 
404 
405 /*
406  * Check access for file/directory
407  */
check_access(char * name,int check)408 int check_access(char *name, int check)
409 {
410     struct stat st;
411 
412     if(stat(name, &st) == -1)
413 	return ERROR;
414 
415     if(check==CHECK_FILE && S_ISREG(st.st_mode))
416 	return TRUE;
417     if(check==CHECK_DIR  && S_ISDIR(st.st_mode))
418 	return TRUE;
419 
420     return FALSE;
421 }
422 
423 
424 
425 /*
426  * Create directory for zone/points if needed
427  */
bink_mkdir(Node * node)428 int bink_mkdir(Node *node)
429 {
430     char buf[MAXPATH];
431     char *base;
432     size_t rest;
433 
434     /*
435      * Outbound dir + zone dir
436      */
437     BUF_COPY(buf, cf_p_btbasedir());
438     BUF_APPEND(buf, "/");
439     if((base = cf_zones_out(node->zone)) == NULL)
440 	return ERROR;
441     BUF_APPEND(buf, base);
442     base = buf + strlen(buf);
443     rest = sizeof(buf) - strlen(buf);
444 
445     if(check_access(buf, CHECK_DIR) == ERROR)
446     {
447 	if(mkdir(buf, DIR_MODE) == -1)
448 	{
449 	    logit("$WARNING: can't create dir %s", buf);
450 	    return ERROR;
451 	}
452 	chmod(buf, DIR_MODE);
453     }
454 
455     /*
456      * Point directory for point addresses
457      */
458     if(node->point)
459     {
460 	str_printf(base, rest, "/%04x%04x.pnt", node->net, node->node);
461 	if(check_access(buf, CHECK_DIR) == ERROR)
462 	{
463 	    if(mkdir(buf, DIR_MODE) == -1)
464 	    {
465 		logit("$WARNING: can't create dir %s", buf);
466 		return ERROR;
467 	    }
468 	    chmod(buf, DIR_MODE);
469 	}
470     }
471 
472     return OK;
473 }
474 
475 
476 
477 /*
478  * Get file size
479  */
check_size(char * name)480 long check_size(char *name)
481 {
482     struct stat st;
483 
484     if(stat(name, &st) == -1)
485 	return ERROR;
486     else
487 	return st.st_size;
488 }
489 
490 
491 
492 /*
493  * Check for old archive (m_time older than dt)
494  */
check_old(char * name,time_t dt)495 int check_old(char *name, time_t dt)
496 {
497     struct stat st;
498     TIMEINFO ti;
499     time_t t;
500 
501     GetTimeInfo(&ti);
502     t = ti.time;
503 
504     if(stat(name, &st) == -1)
505 	return ERROR;
506 
507     return t - st.st_mtime > dt;
508 }
509