/*****************************************************************************
 *
 * $Id$
 * Purpose ...............: Fidonet mailer, inbound functions 
 *
 *****************************************************************************
 * 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 "dirlock.h"
#include "inbound.h"


extern char	*inbound;
extern char	*tempinbound;
extern int	gotfiles;
extern int	laststat;


/*
 * Open the inbound directory, set the temp inbound for the node
 * so that this is true multiline safe. All files received from
 * the node during the session are stored here.
 * For binkp we add one extra directory to queue incoming files.
 */
int inbound_open(faddr *addr, int protected, int binkp_mode)
{
    char    *temp;
    DIR	    *dp;

    if (inbound)
	free(inbound);
    inbound = NULL;
    if (protected)
	inbound = xstrcpy(CFG.pinbound);
    else
	inbound = xstrcpy(CFG.inbound);

    temp = calloc(PATH_MAX, sizeof(char));
    snprintf(temp, PATH_MAX -1, "%s/tmp.%d.%d.%d.%d", inbound, addr->zone, addr->net, addr->node, addr->point);

    /*
     * Check if this directory already exist, it should not unless the previous
     * session with this node failed for some reason.
     */
    if ((dp = opendir(temp))) {
	Syslog('s', "Binkp: dir %s already exists, previous session failed", temp);
	laststat++;
	closedir(dp);
    }

    tempinbound = xstrcpy(temp);
    if (binkp_mode)
	snprintf(temp, PATH_MAX, "%s/tmp/foobar", tempinbound);
    else
	snprintf(temp, PATH_MAX, "%s/foobar", tempinbound);
    mkdirs(temp, 0700);
    free(temp);

    Syslog('s', "Inbound set to \"%s\"", tempinbound);
    return 0;
}



/*
 * Close the temp inbound, if the session is successfull, move all
 * received files to the real inbound, else leave them there for
 * the next attempt. Set a semafore if we did receive anything.
 * Clean and remove the temp inbound if it is empty.
 */
int inbound_close(int success)
{
    DIR		    *dp;
    struct dirent   *de;
    char	    *source, *dest;
    struct stat	    stb;
    int		    i, rc;

    Syslog('s', "Closing temp inbound after a %s session", success?"good":"failed");
    if (! success) {
	if (tempinbound)
	    free(tempinbound);
	return 0;
    }

    if (tempinbound == NULL) {
	Syslog('!', "Temp inbound was not open");
	return 0;
    }

    /*
     * Try to lock the inbound so we can safely move the files
     * to the inbound.
     */
    i = 30;
    while (TRUE) {
	if (lockdir(inbound))
	    break;
	i--;
	if (! i) {
	    WriteError("Can't lock %s", inbound);
	    return 1;
	}
	sleep(20);
	Nopper();
    }
    Syslog('s', "inbound_close(): %s locked", inbound);

    if ((dp = opendir(tempinbound)) == NULL) {
	WriteError("$Can't open %s", tempinbound);
	return 1;
    }
 
    source = calloc(PATH_MAX, sizeof(char));
    dest   = calloc(PATH_MAX, sizeof(char));

    while ((de = readdir(dp))) {
	snprintf(source, PATH_MAX, "%s/%s", tempinbound, de->d_name);
	snprintf(dest, PATH_MAX, "%s/%s", inbound, de->d_name);
	if ((lstat(source, &stb) == 0) && (S_ISREG(stb.st_mode))) {
	    if (file_exist(dest, F_OK) == 0) {
		Syslog('!', "Cannot move %s to %s, file exists", de->d_name, inbound);
	    } else {
		if ((rc = file_mv(source, dest))) {
		    WriteError("Can't move %s to %s: %s", source, dest, strerror(rc));
		} else {
		    Syslog('s', "inbound_close(): moved %s to %s", de->d_name, inbound);
		    gotfiles = TRUE;
		}
	    }
	}
    }

    closedir(dp);
    ulockdir(inbound);
    Syslog('s', "inbound_close(): %s unlocked", inbound);

    /*
     * Try to remove binkp tmp queue. Only log if not empty, else
     * don't log anything, this directory doesn't exist for normal
     * sessions.
     */
    snprintf(source, PATH_MAX, "%s/tmp", tempinbound);
    if ((rc = rmdir(source))) {
	if (errno == ENOTEMPTY) {
	    Syslog('+', "Keep binkp temp incoming directory, partial file");
	}
    } else {
	Syslog('s', "inbound_close(): removed %s", source);
    }
    
    /*
     * Try to clean the temp inbound, if it fails log this, maybe the
     * next time it will work.
     */
    if ((rc = rmdir(tempinbound))) {
	WriteError("$Can't remove %s", tempinbound);
    } else {
	Syslog('s', "inbound_close(): removed %s", tempinbound);
    }

    free(source);
    free(dest);
    free(tempinbound);
    tempinbound = NULL;

    return 0;
}



/*
 * Get the free space size in the temp inbound directory.
 */
int inbound_space(void)
{
    struct statfs   sfs;

    if (statfs(tempinbound, &sfs) != 0) {
	Syslog('!', "Cannot statfs \"%s\", assume enough space", tempinbound);
	return -1L;
    } else
	return (sfs.f_bsize * sfs.f_bfree);
}