/*****************************************************************************
 *
 * $Id$
 * Purpose ...............: Fidonet mailer
 *
 *****************************************************************************
 * Copyright (C) 1997-2005
 *   
 * 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, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/

#include "../config.h"
#include "../lib/mbselib.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;
extern char	*tempinbound;


/*
 * 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, *p, x, ctt[32], tmpfname[16];
    int		    rc, rsc, ncount;
    struct stat	    st;

    strcpy(ctt,date(remtime));

    Syslog('s', "openfile(\"%s\",%s,%lu,...)", MBSE_SS(fname), MBSE_SS(ctt), (unsigned int)remsize);

    if ((fname == NULL) || (fname[0] == '\0')) {
	snprintf(tmpfname,16,"%08x.pkt",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 inbound directory.
     * If it's there, resoffs will be set equal to remsize to signal the
     * receiving protocol to skip the file.
     */
    if (tempinbound == NULL) {
	/*
	 * This is when we get a FTS-0001 handshake packet
	 */
	infpath = xstrcpy(CFG.inbound);
	infpath = xstrcat(infpath, (char *)"/tmp/");
	mkdirs(infpath, 0700);
    } else {
	infpath = xstrcpy(tempinbound);
	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 in the inbound with a zero length, erase the
     * file as if it wasn't there at all.
     */
    if (((rc = stat(infpath, &st)) == 0) && (st.st_size == 0)) {
	Syslog('+', "Zero bytes file in the inbound, unlinking");
	unlink(infpath);
    }

    /*
     * 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
     * has another timestamp as the file we expect.
     *
     * 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.
     */
    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';
	snprintf(ctt,32,"%08x.doe",sequencer());
	free(infpath);
	infpath = xstrcpy(p);
	infpath = xstrcat(infpath, ctt);
    }
    if (ncount)
	Syslog('s', "File renamed to %s", infpath);
    
    *resofs = 0L;
    opentype = (char *)"w";
    if ((rc == 0) && (remsize != 0)) {
	rsc = resync(st.st_size);
	Syslog('s', "resync(%d) rsc=%d", (int)st.st_size, rsc);
	switch (rsc) {
	    case 0:	/* Success  */
			opentype = (char *)"a+";
			*resofs = st.st_size;
			Syslog('+', "Resyncing at offset %lu of \"%s\"", (unsigned int)st.st_size, infpath);
			break;
	    case -1:	/* Binkp did send a GET, return here and do not open file */
			free(infpath);
			infpath = NULL;
			return NULL;
	    default:	/* Error from xmrecv, do nothing    */
			break;
	}
    }
    Syslog('s', "try fopen(\"%s\",\"%s\")", infpath, opentype);

    if ((infp = fopen(infpath, opentype)) == NULL) {
	WriteError("$Cannot open local file \"%s\" for \"%s\"", infpath,opentype);
	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 int)*resofs);
    return infp;
}



/*
 *  close file, even if the file is partial received, we set the date on the
 *  file so that in a next session we know we must append to that file instead of
 *  trying to get the file again.
 */
int closefile(void)
{
    int		    rc = 0;
    struct utimbuf  ut;

    Syslog('s', "closefile(), for file \"%s\"", MBSE_SS(infpath));

    if ((infp == NULL) || (infpath == NULL)) {
	Syslog('+', "closefile(), nothing to close");
	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) {
	    Syslog('+', "Removing unsuccessfuly received wazoo freq");
	    unlink(freqname);
	    free(freqname);
	    freqname=NULL;
	}
	isfreq = FALSE;
    } 
	
    free(infpath);
    infpath = NULL;
    return rc;
}