/*
 # $Id: index.c,v 1.11 1998/04/10 10:27:18 fbm Exp fbm $
 # Copyright (C) 1997,1998 Farrell McKay
 # All rights reserved.
 #
 # This file is part of the Fortify distribution, a toolkit for
 # upgrading the cryptographic strength of the Netscape Navigator
 # web browser, authored by Farrell McKay.
 #
 # This toolkit is provided to the recipient under the
 # following terms and conditions:-
 #   1.  This copyright notice must not be removed or modified.
 #   2.  This toolkit may not be reproduced or included in any commercial
 #       media distribution, or commercial publication (for example CD-ROM,
 #       disk, book, magazine, journal) without first obtaining the author's
 #       express permission.
 #   3.  This toolkit, or any component of this toolkit, may not be
 #       commercially resold, redeveloped, rewritten, enhanced or otherwise
 #       used as the basis for commercial venture, without first obtaining
 #       the author's express permission.
 #   4.  Subject to the above conditions being observed (1-3), this toolkit
 #       may be freely reproduced or redistributed.
 #   5.  This software is provided "as-is", without express or implied
 #       warranty.  In no event shall the author be liable for any direct,
 #       indirect or consequential damages however caused.
 #   6.  Subject to the above conditions being observed (1-5),
 #       this toolkit may be used at no cost to the recipient.
 #
 # Farrell McKay			contact@fortify.net
 */

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "misc.h"
#include "index.h"
#include "morpher.h"
#include "md5_calc.h"
#include "os2lx.h"
#include "os2obj.h"
#include "os2page.h"
#include "trace.h"

#define VERN_STR	"version"

static int		idx_sz;
static index_entry_t	**idx_ents;

int
have_morphs(index_entry_t *ent)
{
	return (ent->flds[IDX_MORPHS] && ent->flds[IDX_MORPHS][0] != '\0');
}

int
build_index(char *indexfile, char **vern)
{
	char		buf[1024];
	FILE		*ifp;
	int		i, len, nflds;
	int		vern_seen	= 0;
	char		*p;
	index_entry_t	*ent;

	idx_sz = 0;

	ifp = fopen(indexfile, "r");
	if (ifp == NULL) {
		fprintf(stderr, "Cannot open \"%s\": ", indexfile);
		perror("");
		return -1;
	}

	while (fgets(buf, sizeof(buf), ifp)) {
		if (*buf == '#' || *buf == '\n')
			continue;
		len = strlen(buf);
		if (len <= 1)
			continue;
		
		if (!vern_seen && strncmp(buf, VERN_STR, strlen(VERN_STR)) == 0) {
			p = buf + strlen(VERN_STR);
			while (isspace(*p))
				p++;
			*vern = _strndup(p, strlen(p)-1);
			vern_seen++;
			continue;
		}

		ent = (index_entry_t *) _calloc(1, sizeof(index_entry_t));

		ent->raw = p = _strndup(buf, len);

		for (i = nflds = 0; i < IDX_NFLDS; i++) {
			while (isspace(*p))
				p++;
			ent->flds[i] = p;
			while (*p && !isspace(*p))
				p++;
			*p = '\0';
			if (strlen(ent->flds[i]) > 0)
				nflds++;
			if (strcmp(ent->flds[i], "-") == 0)
				ent->flds[i] = p;

			if (p < ent->raw + len)
				p++;
		}

		if (nflds != IDX_NFLDS) {
			free(ent->raw);
			free(ent);
			continue;
		}

		ent->size = atoi(ent->flds[IDX_SZ]);
		ent->grade = atoi(ent->flds[IDX_GRADE]);
		ent->max_grade = atoi(ent->flds[IDX_MAX_GRADE]);

		if (ent->grade == 0) {
			ent->flds[IDX_GRADE] = "Export grade";
		}
		else if (ent->grade == ent->max_grade) {
			ent->flds[IDX_GRADE] = "Fully Fortified";
		}
		else if (ent->grade == 1) {
			ent->flds[IDX_GRADE] = "Fortified-SSL grade";
		}
		else {
			ent->flds[IDX_GRADE] = "?? Unknown grade ??";
		}

		idx_sz++;
		idx_ents = (index_entry_t **) _realloc((void *) idx_ents,
				idx_sz * sizeof(index_entry_t *));
		idx_ents[idx_sz - 1] = ent;
	}

	fclose(ifp);
	return idx_sz;
}

int
is_lx_entry(index_entry_t *ip)
{
	return (strcmp(ip->flds[IDX_SZ], "lx") == 0);
}

index_entry_t *
index_lookup(char *tgt, int *err)
{
	int		i, ifd;
	lxfile_t	*lx;
	struct stat	st;
	index_entry_t	*ip;
	char		*md5 = NULL;
	char		*md5span = NULL;

	trace(2, ("\nt2>> Index lookup:\n"));
	*err = 0;

	if ((ifd = open(tgt, OPENFL(O_RDONLY), 0666)) == -1
		|| fstat(ifd, (struct stat *) &st) == -1) {
		trace(2, ("t2>> error ERR_OPEN\n"));
		close(ifd);
		*err = ERR_OPEN;
		return NULL;
	}

	lx = lxFile_is_lx(ifd);
	trace(2, ("t2>> file size = %ld\n", (long) st.st_size));
	trace(2, ("t2>> file is%s LX format\n", lx? "": " not"));
	if (lx) {
		lxFile_print_hdr(lx);
		lxObj_print(lx);
		lxPages_print(lx);
	}

	for (i = 0; i < idx_sz; i++) {
		ip = idx_ents[i];
		if (lx && is_lx_entry(ip)) {
			if (md5 == NULL || strcmp(ip->flds[IDX_MD5SPAN], md5span) != 0) {
				md5 = lxFile_md5_calc(lx, ifd, ip->flds[IDX_MD5SPAN], err);
				md5span = ip->flds[IDX_MD5SPAN];
				if (*md5 == '\0' && *err == ERR_LXCOMPR) {
					close(ifd);
					lxFile_free(lx);
					return NULL;
				}
				trace(3, ("t3>> md5_calc = %s\n", md5));
				trace(3, ("t3>> md5_span = %s\n", md5span));
			}
			trace(3, ("t3>> match against %s\n", ip->flds[IDX_MD5]));
			if (strcmp(ip->flds[IDX_MD5], md5) == 0) {
				close(ifd);
				lxFile_free(lx);
				return ip;
			}
		}
		else if (ip->size == st.st_size) {
			if (md5 == NULL || strcmp(ip->flds[IDX_MD5SPAN], md5span) != 0) {
				md5 = md5_calc(ifd, ip->flds[IDX_MD5SPAN]);
				md5span = ip->flds[IDX_MD5SPAN];
				trace(3, ("t3>> md5_calc = %s\n", md5));
				trace(3, ("t3>> md5_span = %s\n", md5span));
			}
			trace(3, ("t3>> match against %s\n", ip->flds[IDX_MD5]));
			if (strcmp(ip->flds[IDX_MD5], md5) == 0) {
				close(ifd);
				return ip;
			}
		}
	}

	close(ifd);
	lxFile_free(lx);

	trace(2, ("t2>> no matches\n"));
	*err = ERR_NOMATCH;
	return NULL;
}
