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