/*****************************************************************************
 *
 * $Id$
 * Purpose ...............: Create Message Area
 *
 *****************************************************************************
 * 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 "../config.h"
#include "../lib/libs.h"
#include "../lib/memwatch.h"
#include "../lib/structs.h"
#include "../lib/users.h"
#include "../lib/records.h"
#include "../lib/common.h"
#include "../lib/clcomm.h"
#include "../lib/msg.h"
#include "mgrutil.h"
#include "createm.h"


#define MCHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"


int create_msgarea(char *marea, faddr *p_from)
{
    char	*temp;
    FILE	*gp;

    Syslog('m', "create_msgarea(%s)", marea);
    temp = calloc(PATH_MAX, sizeof(char));
    sprintf(temp, "%s/etc/mgroups.data", getenv("MBSE_ROOT"));
    if ((gp = fopen(temp, "r")) == NULL) {
	WriteError("Can't open %s", temp);
	free(temp);
	return FALSE;
    }
    fread(&mgrouphdr, sizeof(mgrouphdr), 1, gp);
    free(temp);

    fseek(gp, mgrouphdr.hdrsize, SEEK_SET);
    while ((fread(&mgroup, mgrouphdr.recsize, 1, gp)) == 1) {
	if ((mgroup.UpLink.zone  == p_from->zone) && (mgroup.UpLink.net   == p_from->net) &&
	    (mgroup.UpLink.node  == p_from->node) && (mgroup.UpLink.point == p_from->point) &&
	    strlen(mgroup.AreaFile)) {
	    if (CheckEchoGroup(marea, FALSE, p_from) == 0) {
		fclose(gp);
		return TRUE;
	    }
	}
    }
    fclose(gp);
    return FALSE;
}



/*
 * Check echomail group AREAS file if requested area exists.
 * If so, create echomail area and if SendUplink is TRUE,
 * send the uplink a AreaMgr request to connect this area.
 * The echomail group record (mgroup) must be in memory.
 * Return codes:
 *  0  - All Seems Well
 *  1  - Some error
 *
 * The current nodes record may be destroyed after this,
 * make sure it is saved.
 */
int CheckEchoGroup(char *Area, int SendUplink, faddr *f)
{
    char	*temp, *buf, *tag, *desc, *p;
    FILE	*ap, *mp;
    long	offset;
    int		i, rc = 0;
    sysconnect	System;
    faddr	*From, *To;

    temp = calloc(PATH_MAX, sizeof(char));
    Syslog('m', "Checking echogroup %s %s", mgroup.Name, mgroup.Comment);
    sprintf(temp, "%s/%s", CFG.alists_path , mgroup.AreaFile);
    if ((ap = fopen(temp, "r")) == NULL) {
	WriteError("Echogroup %s: area taglist %s not found", mgroup.Name, temp);
	free(temp);
	return 1;
    }

    buf = calloc(4097, sizeof(char));
    while (fgets(buf, 4096, ap)) {
	if (strlen(buf) && isalnum(buf[0])) {
	    tag = strtok(buf, "\t \r\n\0");
	    p = strtok(NULL, "\r\n\0");
	    if (p == NULL)
		p = tag; /* If no description after the TAG, use TAG as description */
	    desc = p;
	    while ((*desc == ' ') || (*desc == '\t'))
		desc++;
	    if (strcmp(tag, Area) == 0) {
		Syslog('m', "Found tag \"%s\" desc \"%s\"", tag, desc);

		/*
		 * Area is in AREAS file, now create area.
		 * If needed, connect at uplink.
		 */
		if (SendUplink) {
		    sprintf(temp, "+%s", Area);
		    From = fido2faddr(mgroup.UseAka);
		    To   = fido2faddr(mgroup.UpLink);
		    if (UplinkRequest(To, From, FALSE, temp)) {
			WriteError("Can't send netmail to uplink");
			fclose(ap);
			free(buf);
			free(temp);
			tidy_faddr(From);
			tidy_faddr(To);
			return 1;
		    }
		    tidy_faddr(From);
		    tidy_faddr(To);
		}

		sprintf(temp, "%s/etc/mareas.data", getenv("MBSE_ROOT"));
		if ((mp = fopen(temp, "r+")) == NULL) {
		    WriteError("$Can't open %s", temp);
		    fclose(ap);
		    free(buf);
		    free(temp);
		    return 1;
		}
		fread(&msgshdr, sizeof(msgshdr), 1, mp);

		/*
		 * Verify the file is large enough
		 */
		fseek(mp, 0, SEEK_END);
		offset = msgshdr.hdrsize + ((mgroup.StartArea -1) * (msgshdr.recsize + msgshdr.syssize));
		Syslog('m', "file end at %ld, start area offset at %ld", ftell(mp), offset);

		if (ftell(mp) < offset) {
		    /*
		     * Start area record not in database, expand until start record exists.
		     */
		    Syslog('m', "Database too small, expanding...");
		    memset(&msgs, 0, sizeof(msgs));
		    memset(&System, 0, sizeof(System));
		    while (TRUE) {
			fwrite(&msgs, sizeof(msgs), 1, mp);
			for (i = 0; i < (msgshdr.syssize / sizeof(System)); i++)
			    fwrite(&System, sizeof(System), 1, mp);
			if (ftell(mp) >= msgshdr.hdrsize + ((mgroup.StartArea -1) * (msgshdr.recsize + msgshdr.syssize)))
			    break;
		    }
		}

		if (fseek(mp, offset, SEEK_SET)) {
		    WriteError("$Can't seek in %s to position %ld", temp, offset);
		    fclose(ap);
		    fclose(mp);
		    free(buf);
		    free(temp);
		    return 1;
		}

		/*
		 * Search a free record
		 */
		while (fread(&msgs, sizeof(msgs), 1, mp) == 1) {
		    if (!msgs.Active) {
			fseek(mp, - msgshdr.recsize, SEEK_CUR);
			offset = ((ftell(mp) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize)) + 1;
			Syslog('m', "Found free slot at %ld", offset);
			rc = 1;
			break;
		    }
		    /*
		     * Skip systems
		     */
		    fseek(mp, msgshdr.syssize, SEEK_CUR);
		}

		if (!rc) {
		    Syslog('m', "No free slot, append after last record");
		    fseek(mp, 0, SEEK_END);
		    if (ftell(mp) < msgshdr.hdrsize + ((mgroup.StartArea -1) * (msgshdr.recsize + msgshdr.syssize))) {
			Syslog('m', "Database too small, expanding...");
			memset(&msgs, 0, sizeof(msgs));
			memset(&System, 0, sizeof(System));
			while (TRUE) {
			    fwrite(&msgs, sizeof(msgs), 1, mp);
			    for (i = 0; i < (msgshdr.syssize / sizeof(System)); i++)
				fwrite(&System, sizeof(System), 1, mp);
			    if (ftell(mp) >= msgshdr.hdrsize + ((mgroup.StartArea -1) * (msgshdr.recsize + msgshdr.syssize)))
				break;
			}
		    }
		    rc = 1;
		}

		/*
		 * Create the record with the defaults from the group record.
		 */
		offset = ((ftell(mp) - msgshdr.hdrsize) / (msgshdr.recsize + msgshdr.syssize)) + 1;
		memset(&msgs, 0, sizeof(msgs));
		strncpy(msgs.Tag, tag, 50);
		strncpy(msgs.Name, desc, 40);
		strncpy(msgs.QWKname, tag, 20);
		msgs.MsgKinds = PUBLIC;
		msgs.Type = ECHOMAIL;
		msgs.DaysOld = CFG.defdays;
		msgs.MaxMsgs = CFG.defmsgs;
		msgs.UsrDelete = mgroup.UsrDelete;
		msgs.RDSec = mgroup.RDSec;
		msgs.WRSec = mgroup.WRSec;
		msgs.SYSec = mgroup.SYSec;
		msgs.LinkSec = mgroup.LinkSec;
		strncpy(msgs.Group, mgroup.Name, 12);
		msgs.Aka = mgroup.UseAka;
		strncpy(msgs.Origin, CFG.origin, 50);
		msgs.Aliases = mgroup.Aliases;
		msgs.NetReply = mgroup.NetReply;
		msgs.Active = TRUE;
		msgs.Quotes = mgroup.Quotes;
		msgs.Rfccode = 0; // CHRS_DEFAULT_RFC;
		msgs.Ftncode = 0; // CHRS_DEFAULT_FTN;
		msgs.MaxArticles = CFG.maxarticles;
		tag = tl(tag);
		for (i = 0; i < strlen(tag); i++)
		    if (tag[i] == '.')
			tag[i] = '/';
		sprintf(msgs.Base, "%s/%s", mgroup.BasePath, tag);
		fwrite(&msgs, sizeof(msgs), 1, mp);
		mkdirs(msgs.Base, 0770);
		if (Msg_Open(msgs.Base))
		    Msg_Close();
		
		memset(&System, 0, sizeof(System));
		System.aka = mgroup.UpLink;
		System.sendto = System.receivefrom = TRUE;
		fwrite(&System, sizeof(System), 1, mp);
		memset(&System, 0, sizeof(System));
		for (i = 1; i < (msgshdr.syssize / sizeof(System)); i++)
		    fwrite(&System, sizeof(System), 1, mp);
		
		fclose(mp);
		fclose(ap);
		free(buf);
		free(temp);
		if (f == NULL)
		    Mgrlog("Auto created echo %s, group %s, area %ld", msgs.Tag, msgs.Group, offset);
		else
		    Mgrlog("Auto created echo %s, group %s, area %ld, for node %s",
			msgs.Tag, msgs.Group, offset, ascfnode(f , 0x1f));
		return 0;
	    } /* if (strcmp(tag, Area) == 0) */
	} /* if (strlen(buf) && isalnum(buf[0])) */
    } /* while (fgets(buf, 4096, ap)) */

    Syslog('m', "Area %s not found in taglist", Area);
    free(buf);
    fclose(ap);
    free(temp);
    return 1;
}


