/*****************************************************************************
 *
 * File ..................: mbaff/filefind.c
 * Purpose ...............: Announce new files and FileFind
 * Last modification date : 10-Aug-2001
 *
 *****************************************************************************
 * Copyright (C) 1997-2001
 *   
 * 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/records.h"
#include "../lib/common.h"
#include "../lib/clcomm.h"
#include "../lib/dbcfg.h"
#include "../lib/msg.h"
#include "../lib/msgtext.h"
#include "fflist.h"
#include "filefind.h"
#include "msgutil.h"

/*
 *  The next constants are to prevent overflowing the echomail areas
 *  with huge replies. MAX_DESC_LINES limits the number of file description
 *  lines, 5 should be enough. The other two are the maximum files to report
 *  if in the same area or different area.
 *  For netmail replies there is a different limit.
 */
#define	MAX_DESC_LINES		5
#define	MAX_FILES_SAMEBOARD	15
#define	MAX_FILES_OTHERBOARD	50
#define MAX_FILES_NETMAIL	100


extern int		do_quiet;		/* Supress screen output    */
struct _filerecord	T_File;			/* Internal announce record */
int			Requests = 0;		/* Total found request      */
int			Replies = 0;		/* Total generated replies  */


void Back(int);
void Back(int count)
{
	int	i;

	if (do_quiet)
		return;

	for (i = 0; i < count; i++)
		printf("\b");
	fflush(stdout);
}



void Clean(int);
void Clean(int count)
{
	int	i;

	if (do_quiet)
		return;

	for (i = 0; i < count; i++)
		printf(" ");
	Back(count);
}



void ScanArea(ff_list **);
void ScanArea(ff_list **ffl)
{
	unsigned long	Number, Highest;

	if (!do_quiet) {
		colour(3, 0);
		printf("\r  %-40s", scanmgr.Comment);
		colour(12, 0);
		printf(" (Scanning) ");
		colour(13, 0);
		fflush(stdout);
	}
	Syslog('+', "Scanning %s", scanmgr.Comment);
	if (Msg_Open(scanmgr.ScanBoard)) {
		Number  = Msg_Lowest();
		Highest = Msg_Highest();

		do {
			if (!do_quiet) {
				printf("%6lu / %6lu", Number, Highest);
				Back(15);
			}

			if (CFG.slow_util && do_quiet)
				usleep(1);

			if (Msg_ReadHeader(Number) == TRUE) {
				if (((!strcasecmp(Msg.To, "allfix")) ||
				    (!strcasecmp(Msg.To, "filefind"))) &&
				    (!Msg.Received)) {
					Syslog('m', "Msg: %s (%lu) [%s]", Msg.From, Number, Msg.Subject);
					Msg.Received = TRUE;
					Msg.Read = time(NULL);
					if (Msg_Lock(30L)) {
						Msg_WriteHeader(Number);
						Msg_UnLock();
						Syslog('m', "Marked message received");
					}
					if (strlen(Msg.Subject) && strlen(Msg.FromAddress)) {
						fill_fflist(ffl);
						Requests++;
					}
				}
			}

		} while (Msg_Next(&Number) == TRUE);

		Msg_Close();
		Clean(15);
	} else
		WriteError("$Can't open %s", scanmgr.ScanBoard);

	Back(54);
	Clean(54);
}



int StartReply(ff_list *);
int StartReply(ff_list *ffl)
{
	char		*temp;
	unsigned long	crc = -1;

	if (strlen(scanmgr.ReplBoard)) {
		if (!Msg_Open(scanmgr.ReplBoard))
			return FALSE;
		else
			CountPosted(scanmgr.ReplBoard);
	} else {
		if (!Msg_Open(scanmgr.ScanBoard))
			return FALSE;
		else
			CountPosted(scanmgr.ScanBoard);
	}

	if (!Msg_Lock(30L)) {
		Msg_Close();
		return FALSE;
	}
	Msg_New();

	temp = calloc(PATH_MAX, sizeof(char));

	sprintf(Msg.From, "%s", CFG.sysop_name);
	sprintf(Msg.To, "%s", ffl->from);
	sprintf(Msg.Subject, "Re: %s", ffl->subject);
	sprintf(Msg.FromAddress, "%s", aka2str(scanmgr.Aka));
	Msg.Written = time(NULL);
	Msg.Arrived = time(NULL);
	Msg.Local   = TRUE;
	if (scanmgr.NetReply)
		Msg.Netmail = TRUE;
	else
		Msg.Echomail = TRUE;

	/*
	 *  Start message text including kludges
	 */
	Msg_Id(scanmgr.Aka);
	sprintf(temp, "\001REPLY: %s", ffl->msgid);
	MsgText_Add2(temp);
	Msg.ReplyCRC = upd_crc32(temp, crc, strlen(temp));
	Msg_Pid();
	Msg_Top();

	return TRUE;
}



void FinishReply(int, int);
void FinishReply(int Reported, int Total)
{
	char	*temp;
	FILE	*fp;

	temp = calloc(PATH_MAX, sizeof(char));

	MsgText_Add2((char *)"");
	if (Reported < Total) {
		sprintf(temp, "Listed %d out of %d files matching your search request", Reported, Total);
		MsgText_Add2(temp);
		MsgText_Add2((char *)"For more information, visit our BBS");
	} else {
		sprintf(temp, "Found %d files matching your search request", Reported);
		MsgText_Add2(temp);
	}

	if (strlen(scanmgr.Origin))
		Msg_Bot(scanmgr.Aka, scanmgr.Origin);
	else
		Msg_Bot(scanmgr.Aka, CFG.origin);
	Msg_AddMsg();
	Msg_UnLock();
	Syslog('+', "Posted message %ld", Msg.Id);

	sprintf(temp, "%s/tmp/echomail.jam", getenv("MBSE_ROOT"));
	if ((fp = fopen(temp, "a")) != NULL) {
		if (strlen(scanmgr.ReplBoard))
			fprintf(fp, "%s %lu\n", scanmgr.ReplBoard, Msg.Id);
		else
			fprintf(fp, "%s %lu\n", scanmgr.ScanBoard, Msg.Id);
		fclose(fp);
	}

	Msg_Close();
	free(temp);
}



/*
 *  Scan for files for one request.
 */
void ScanFiles(ff_list *);
void ScanFiles(ff_list *tmp)
{
	char		*temp, *kwd, *BigDesc;
	FILE		*pAreas, *pFile;
	unsigned long	areanr = 0, found = 0;
	int		i, j, k, keywrd, Found;
	rf_list		*rfl = NULL, *rft;
	int		Rep = 0, Sub = 0, Stop = FALSE;

	/*
	 *  Check for local generated requests.
	 */
	if (!CFG.ct_LocalRep) {
	}

	kwd  = calloc(81, sizeof(char));
	temp = calloc(1024, sizeof(char));
	BigDesc = calloc(1230, sizeof(char));

	sprintf(temp, "%s (%d:%d/%d.%d)", tmp->from, tmp->zone, tmp->net, tmp->node, tmp->point);
	Syslog('+', "ff: %s [%s]", temp, tmp->subject);

	if (!do_quiet) {
		colour(3, 0);
		temp[40] = '\0';
		printf("\r  %-40s", temp);
		colour(12, 0);
		printf(" (Searching)");
		colour(13, 0);
		fflush(stdout);
	}

	sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT"));
	if ((pAreas = fopen(temp, "r")) != NULL) {
		fread(&areahdr, sizeof(areahdr), 1, pAreas);

		while (fread(&area, areahdr.recsize, 1, pAreas) == 1) {
			areanr++;

			if (CFG.slow_util && do_quiet)
				usleep(1);

			if (!do_quiet) {
				printf("%6lu / %6lu", areanr, found);
				Back(15);
			}
			if (area.Available && area.FileFind) {
				sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), areanr);
				if ((pFile = fopen(temp, "r")) != NULL) {

					while (fread(&file, sizeof(file), 1, pFile) == 1) {
						for (i = 0; i < 25; i++)
							sprintf(BigDesc, "%s%s", BigDesc, *(file.Desc + i));
						sprintf(temp, "%s", tmp->subject);

						Found = FALSE;
						while (strlen(temp) && (!Found)) {
							/*
							 *  Split the search request in
							 *  separate words.
							 */
							k = strlen(temp);
							for (i = 0; i < k; i++)
								if (temp[i] == ' ')
									break;
							if (i < k) {
								strncpy(kwd, temp, i);
								kwd[i] = '\0';
								for (j = 0; j < (k - i -1); j++)
									temp[j] = temp[j+i+1];
								temp[j] = '\0';
							} else {
								sprintf(kwd, "%s", temp);
								temp[0] = '\0';
							}

							/*
							 *  Check if it's a filename search
							 *  or a keyword search.
							 */
							keywrd = FALSE;
							if ((kwd[0] == '/') || (kwd[0] == '\\')) {
								keywrd = TRUE;
								for (i = 1; i < strlen(kwd); i++)
									kwd[i-1] = kwd[i];
								kwd[i-1] = '\0';
							}
							tl(kwd);

							if (strlen(kwd) > 3) {
								if (strstr(file.Name, kwd) != NULL) {
									Found = TRUE;
									Syslog('m', "Found %s in %s in filename", kwd, file.Name);
								}
								if (keywrd && (strstr(tl(BigDesc), kwd) != NULL)) {
									Found = TRUE;
									Syslog('m', "Found %s in %s in description", kwd, file.Name);
								}
							}
						}
						if (Found) {
							found++;
							Syslog('m', "Found %s area %d", file.Name, areanr);
							fill_rflist(&rfl, file.Name, areanr);
						}
						strcpy(BigDesc, "");
					}

					fclose(pFile);
				} else
					WriteError("$Can't open %s", temp);
			}
		}
		fclose(pAreas);
		Clean(15);
	} else
		WriteError("$Can't open %s", temp);

	Back(12);
	Clean(12);

	if (found) {
		if (!do_quiet) {
			colour(14, 0);
			printf(" (Replying)");
			fflush(stdout);
		}

		if (StartReply(tmp)) {
			areanr = 0;
			sprintf(temp, "%s/etc/fareas.data", getenv("MBSE_ROOT"));
			if ((pAreas = fopen(temp, "r")) != NULL) {
				fread(&areahdr, sizeof(areahdr), 1, pAreas);

				for (rft = rfl; rft; rft = rft->next) {

					if ((areanr != rft->area) && (Sub)) {
						MsgText_Add2((char *)"------------------------------------------------------------------------");
						sprintf(temp, "Found %d file(s)", Sub);
						MsgText_Add2(temp);
						MsgText_Add2((char *)"");
						MsgText_Add2((char *)"");
						Sub = 0;
					}

					if (areanr != rft->area) {
						fseek(pAreas, ((rft->area - 1) * areahdr.recsize) + areahdr.hdrsize, SEEK_SET);
						fread(&area, areahdr.recsize, 1, pAreas);
						sprintf(temp, "Area %lu - %s", rft->area, area.Name);
						MsgText_Add2(temp);
						MsgText_Add2((char *)"------------------------------------------------------------------------");
						areanr = rft->area;
					}

					sprintf(temp, "%s/fdb/fdb%lu.data", getenv("MBSE_ROOT"), rft->area);
					if ((pFile = fopen(temp, "r")) != NULL) {
						while (fread(&file, sizeof(file), 1, pFile) == 1)
							if (!strcmp(rft->filename, file.Name))
								break;
						fclose(pFile);
						sprintf(temp, "%-12s %5lu Kb. %s", tu(file.Name), (long)(file.Size / 1024), 
								To_Low(file.Desc[0],scanmgr.HiAscii));
						MsgText_Add2(temp);

						/*
						 * We add no more then 5 description lines
						 * to prevent unnecesary long messages.
						 */
						for (i = 1; i < MAX_DESC_LINES; i++)
							if (strlen(file.Desc[i])) {
								sprintf(temp, "                       %s", To_Low(file.Desc[i],scanmgr.HiAscii));
								MsgText_Add2(temp);
							}
					}
					Rep++;
					Sub++;

					if (!scanmgr.NetReply) {
						if (strlen(scanmgr.ReplBoard)) {
							if (Rep >= MAX_FILES_OTHERBOARD) 
								Stop = TRUE;
						} else {
							if (Rep >= MAX_FILES_SAMEBOARD)
								Stop = TRUE;
						}
					} else {
						if (Rep >= MAX_FILES_NETMAIL)
							Stop = TRUE;
					}
					if (Stop)
						break;
				}

				if (Sub) {
					MsgText_Add2((char *)"------------------------------------------------------------------------");
					sprintf(temp, "Found %d file(s)", Sub);
					MsgText_Add2(temp);
					MsgText_Add2((char *)"");
					MsgText_Add2((char *)"");
				}

				fclose(pAreas);
			}
			FinishReply(Rep, found);
			Replies++;
		}

		Back(11);
		Clean(11);
	}

	Back(42);
	Clean(42);

	tidy_rflist(&rfl);
	free(BigDesc);
	free(temp);
	free(kwd);
}



int Filefind()
{
	char	*temp;
	int	rc = FALSE;
	FILE	*fp;
	ff_list	*ffl = NULL, *tmp;

	IsDoing("FileFind");

	if (!do_quiet) {
		colour(3, 0);
		printf("Processing FileFind requests\n");
	}
	Syslog('+', "Processing FileFind requests");
	temp = calloc(PATH_MAX, sizeof(char));

	sprintf(temp, "%s/etc/scanmgr.data", getenv("MBSE_ROOT"));
	if ((fp = fopen(temp, "r")) == NULL) {
		WriteError("$Can't open %s", temp);
		free(temp);
		return FALSE;
	}
	fread(&scanmgrhdr, sizeof(scanmgrhdr), 1, fp);

	while (fread(&scanmgr, scanmgrhdr.recsize, 1, fp) == 1) {
		if (scanmgr.Active) {
			ScanArea(&ffl);

			for (tmp = ffl; tmp; tmp = tmp->next) {
				ScanFiles(tmp);
			}
			tidy_fflist(&ffl);
		}
	}
	fclose(fp);

	free(temp);

	if (Requests) {
		Syslog('+', "Processed %d requests, created %d replies", Requests, Replies);
		if (Replies)
			rc = TRUE;
		if (!do_quiet) {
			colour(3, 0);
			printf("Processed %d requests, created %d replies\n", Requests, Replies);
		}
	}

	return rc;
}