/***************************************************************************** * * $Id$ * Purpose ...............: Fidonet mailer * ***************************************************************************** * Copyright (C) 1997-2002 * * Michiel Broek FIDO: 2:280/2802 * Beekmansbos 10 * 1971 BV IJmuiden * the Netherlands * * This file is part of MBSE BBS. * * This BBS is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * MBSE BBS is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MBSE BBS; see the file COPYING. If not, write to the Free * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. *****************************************************************************/ #include "../lib/libs.h" #include "../lib/structs.h" #include "../lib/clcomm.h" #include "../lib/common.h" #include "config.h" #include "lutil.h" #include "openfile.h" static FILE *infp=NULL; static char *infpath=NULL; static time_t intime; static int isfreq; char *freqname=NULL; int gotfiles = FALSE; /* * Try to find present (probably incomplete) file with the same timestamp * (it might be renamed), open it for append and store resync offset. * Store 0 in resync offset if the file is new. Return FILE* or NULL. * resync() must accept offset in bytes and return 0 on success, nonzero * otherwise (and then the file will be open for write). For Zmodem, * resync is always possible, but for SEAlink it is not. Do not try * any resyncs if remsize == 0. */ FILE *openfile(char *fname, time_t remtime, off_t remsize, off_t *resofs, int(*resync)(off_t)) { char *opentype; char *p, x; char ctt[32]; int rc, ncount; struct stat st; struct flock fl; char tmpfname[16]; fl.l_type = F_WRLCK; fl.l_whence = 0; fl.l_start = 0L; fl.l_len = 0L; strcpy(ctt,date(remtime)); Syslog('S', "openfile(\"%s\",%s,%lu,...)", MBSE_SS(fname), MBSE_SS(ctt),(unsigned long)remsize); if ((fname == NULL) || (fname[0] == '\0')) { sprintf(tmpfname,"%08lx.pkt",(unsigned long)sequencer()); fname=tmpfname; } if ((strlen(fname) == 12) && (strspn(fname,"0123456789abcdefABCDEF") == 8) && (strcasecmp(fname+8,".req") == 0)) { Syslog('s', "Received wazoo freq file"); isfreq = TRUE; } else isfreq = FALSE; /* * First check if the file is already in the real inbound directory. * If it's there, resoffs will be set equal to remsize to signal the * receiving protocol to skip the file. */ if (infpath) free(infpath); infpath = xstrcpy(inbound); infpath = xstrcat(infpath, (char *)"/"); infpath = xstrcat(infpath, fname); if (stat(infpath, &st) == 0) { Syslog('S', "remtine=%ld, st_time=%ld, remsize=%ld, st_size=%ld", remtime, st.st_mtime, remsize, st.st_size); if ((remtime == st.st_mtime) && (remsize == st.st_size)) { Syslog('+', "File %s is already here", fname); *resofs = st.st_size; free(infpath); infpath = NULL; return NULL; } } /* * If the file is not already in the inbound, but there is a file * with the same name, the new file will be renamed. * * If the file is 0 bytes, erase it so it can be received again. * * Renaming algorythm is as follows: start with the present name, * increase the last character of the file name, jumping from * '9' to 'a', from 'z' to 'A', from 'Z' to '0'. If _all_ these * names are occupied, create random name. */ if (infpath) free(infpath); infpath = xstrcpy(inbound); infpath = xstrcat(infpath, (char *)"/tmp/"); infpath = xstrcat(infpath, fname); if (((rc = stat(infpath, &st)) == 0) && (st.st_size == 0)) { Syslog('+', "Zero bytes file in the inbound, unlinking"); unlink(infpath); } p = infpath + strlen(infpath) -1; x = *p; ncount = 0; while (((rc = stat(infpath, &st)) == 0) && (remtime != st.st_mtime) && (ncount++ < 62)) { if (x == '9') x = 'a'; else if (x == 'z') x = 'A'; else if (x == 'Z') x = '0'; else x++; *p = x; } if (ncount >= 62) { /* names exhausted */ rc = 1; p = strrchr(infpath,'/'); *p = '\0'; sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); free(infpath); infpath = xstrcpy(p); infpath = xstrcat(infpath, ctt); } *resofs = 0L; opentype = (char *)"w"; if ((rc == 0) && (remsize != 0)) { Syslog('+', "Resyncing at offset %lu of \"%s\"", (unsigned long)st.st_size, infpath); if (resync(st.st_size) == 0) { opentype = (char *)"a"; *resofs = st.st_size; } } Syslog('S', "try fopen(\"%s\",\"%s\")",infpath,opentype); /* * If first attempt doesn't succeed, create tmp directory * and try again. */ if ((infp = fopen(infpath,opentype)) == NULL) { mkdirs(infpath, 0770); if ((infp = fopen(infpath, opentype)) == NULL) { WriteError("$Cannot open local file \"%s\" for \"%s\"", infpath,opentype); free(infpath); infpath=NULL; return NULL; } } fl.l_pid = getpid(); if (fcntl(fileno(infp),F_SETLK,&fl) != 0) { Syslog('+', "$cannot lock local file \"%s\"",infpath); fclose(infp); infp = NULL; free(infpath); infpath = NULL; return NULL; } intime=remtime; if (isfreq) { if (freqname) free(freqname); freqname = xstrcpy(infpath); } Syslog('S', "opened file \"%s\" for \"%s\", restart at %lu", infpath,opentype,(unsigned long)*resofs); return infp; } /* * close file and if (success) { move it to the final location } */ int closefile(int success) { char *newpath, *p, ctt[32]; int rc=0,ncount; char x; struct stat st; struct utimbuf ut; Syslog('S', "closefile(%d), for file \"%s\"",success, MBSE_SS(infpath)); if ((infp == NULL) || (infpath == NULL)) { WriteError("Internal error: try close unopened file!"); return 1; } rc = fclose(infp); infp = NULL; if (rc == 0) { ut.actime = intime; ut.modtime = intime; if ((rc = utime(infpath,&ut))) WriteError("$utime failed"); } if (isfreq) { if ((rc != 0) || (!success)) { Syslog('+', "Removing unsuccessfuly received wazoo freq"); unlink(freqname); free(freqname); freqname=NULL; } isfreq = FALSE; } else if ((rc == 0) && success) { newpath = xstrcpy(inbound); newpath = xstrcat(newpath, strrchr(infpath,'/')); p = newpath + strlen(newpath) - 1; x = *p; ncount = 0; while (((rc = stat(newpath, &st)) == 0) && (ncount++ < 62)) { if (x == '9') x = 'a'; else if (x == 'z') x = 'A'; else if (x == 'Z') x = '0'; else x++; *p = x; } if (ncount >= 62) { /* names exhausted */ rc = 1; p = strrchr(newpath,'/'); *p = '\0'; sprintf(ctt,"%08lx.doe",(unsigned long)sequencer()); free(newpath); newpath = xstrcpy(p); newpath = xstrcat(newpath, ctt); } Syslog('S', "moving \"%s\" -> \"%s\"", MBSE_SS(infpath), MBSE_SS(newpath)); rc = rename(infpath, newpath); if (rc) WriteError("$error renaming \"%s\" -> \"%s\"", MBSE_SS(infpath),MBSE_SS(newpath)); else gotfiles = TRUE; free(newpath); } free(infpath); infpath = NULL; return rc; }