/*
    gutenfetch - a small utility to list and fetch books available through
	project gutenberg

    Copyright (C) 2001, 2002, 2003, 2004 Russell Francis 

    This program 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 of the License, or
    (at your option) any later version.

    This program 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 this program; if not, write to the

	Free Software Foundation, Inc.
	59 Temple Place, Suite 330
	Boston, MA  02111-1307  USA

Last updated on $Date: 2004/07/07 02:41:22 $ by $Author: johntabularasa $.
*/
#include "stddefs.h"
#include "libgutenfetch_fileinfo.h"
#include "libgutenfetch_etext.h"
#include "libgutenfetch_utility.h"
#include "libgutenfetch_cache.h"
#ifdef HAVE_STDLIB_H
#	include <stdlib.h>
#endif
#ifdef HAVE_ASSERT_H
#	include <assert.h>
#endif
#ifdef HAVE_STRING_H
#	include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#	include <strings.h>
#endif
#include "list.h"

void
gutenfetch_etext_entry_set_format(gutenfetch_etext_entry_t *entry)
{
	char *base, *ext;

	assert(entry != NULL);
	
	base = entry->filebase;
	ext = entry->file_ext;

	if (strcmp(ext, "txt") == 0) {    /* ASCII  ||
								 	   * 8-bit  ||
									   * Big-5  ||
									   * Unicode
									   */
		/*   To distinguish the different types requires
		 *	some investigation and good guess work. 
		 *
		 *	On etexts >= 10000, The difference is shown
		 *	in the basename,  base-8.txt being 8-bit,
		 *	base-5.txt being big5 and base-0.txt being
		 *	Unicode anything else is plain vanilla. 
		 *
		 *	On etexts less than 10000, If the first byte
		 *	is a 7, it is 7-bit, 8 it is 8-bit, I know
		 *	of no way to determine Big-5 or Unicode without
		 *	opening the file on the first 10000 etexts.
		 */
					
		/* Lets treat it as though it is a new etext. */
		if (	(base[strlen(base)-2] == '-') &&
				(base[strlen(base)-1] == '8')
		){
			entry->format.eight_bit_text = 1;
		} else if( 	(base[strlen(base)-2] == '-') &&
					(base[strlen(base)-1] == '5')
		) {
			entry->format.big5_text = 1;
		} else if(	(base[strlen(base)-2] == '-') &&
					(base[strlen(base)-1] == '0')
		) {
			entry->format.unicode = 1;
		} 
		/* We weren't able to determine the type using the new
		   method, lets try  the old way. */
		else if (	(base[0] == '8')) {
			entry->format.eight_bit_text = 1;
		} else { /* Lets assume it is plain vanilla. */
			entry->format.plain_text = 1;
		}
	} else if (strcmp(ext, "htm") == 0) { /* HTML file */
		entry->format.html = 1;
	} else if (strcmp(ext, "pdf") == 0) { /* PDF file */
		entry->format.pdf = 1;
	} else if (strcmp(ext, "pdb") == 0) { /* Protein Data Bank file */
		entry->format.pdb = 1;
	} else if (strcmp(ext, "doc") == 0) { /* MS-WORD file. */
		entry->format.doc = 1;
	} else if (strcmp(ext, "lit") == 0) { /* .lit file? */
		entry->format.lit = 1;
	} else if (strcmp(ext, "rtf") == 0) { /* Rich text file */
		entry->format.rtf = 1;
	} else if (strcmp(ext, "mp3") == 0) { /* Audio file. */
		entry->format.mp3 = 1;
	} else if (strcmp(ext, "xml") == 0) { /* XML file. */
		entry->format.xml = 1;
	} else if (strcmp(ext, "tex") == 0) { /* Latex file. */
		entry->format.tex = 1;
	} else if (strcmp(ext, "prc") == 0) { /* Palm Resource ? */
		entry->format.prc = 1;
	}
}

/**
 * gutenfetch_etext_entry_new
 *
 * This will create an empty gutenfetch_etext_entry_t
 * structure.
 *
 * @return A pointer to an allocated and initialized 
 *	gutenfetch_etext_entry_t structure.
 */
gutenfetch_etext_entry_t *
gutenfetch_etext_entry_new(void)
{
	gutenfetch_etext_entry_t *entry;
	entry = (gutenfetch_etext_entry_t*)
		malloc(sizeof(gutenfetch_etext_entry_t));
	if (entry == NULL)
		return NULL;
	entry->directory = NULL;	
	entry->filebase = NULL;
	entry->file_ext = NULL;
	entry->mime = NULL;
	entry->format.verified = 0;
	entry->format.plain_text = 0;
	entry->format.eight_bit_text = 0;
	entry->format.big5_text = 0;
	entry->format.unicode = 0;
	entry->format.html = 0;
	entry->format.tex = 0;
	entry->format.xml = 0;
	entry->format.mp3 = 0;
	entry->format.rtf = 0;
	entry->format.pdf = 0;
	entry->format.lit = 0;
	entry->format.doc = 0;
	entry->format.pdb = 0;
	entry->format.prc = 0;
	entry->available_as_zip = 0;
	return entry;
}

/**
 * gutenfetch_etext_entry_free
 *
 * Free a gutenfetch_etext_entry structure.
 *
 * @param entry A pointer to a gutenfetch_etext_entry_t to free.
 */
void
gutenfetch_etext_entry_free(gutenfetch_etext_entry_t *entry)
{
	if (entry != NULL) {
		FREE_NULL(entry->directory);
		FREE_NULL(entry->filebase);
		FREE_NULL(entry->file_ext);
		FREE_NULL(entry->mime);
		FREE_NULL(entry);
	}
}

/**
 * gutenfetch_etext_entry_build_new
 *
 * Create an new etext_entry_t from the provided
 * parameters.
 *
 * @param dir The directory relative to the server which this file
 *		can be found.
 * @param file The file name it is known as.
 * @param size The size of the file [bytes].
 * @param flt A list of zipfiles in the same directory which
 *		may be the same file only compressed.
 * @return NULL on failure, or a valid gutenfetch_etext_entry_t *.
 */
gutenfetch_etext_entry_t *
gutenfetch_etext_entry_build_new(
	const char *dir,
	const char *file,
	size_t size,
	list_t *flt)
{
	char *base = NULL, *ext = NULL;
	gutenfetch_etext_entry_t *entry;
	list_t *zip_lt;
	file_info_t *file_info;

	assert(dir != NULL);
	assert(file != NULL);
		
	/* Allocate an etext_entry for us. */
	entry = gutenfetch_etext_entry_new();
	assert(entry != NULL);

	entry->directory = strdup(dir);
	assert(entry->directory != NULL);

	/* break apart the filename into base and extension. */
	gutenfetch_util_get_base_ext(&base, &ext, file);
	entry->file_ext = ext;
	entry->filebase = base;
	entry->mime = gutenfetch_util_get_mime_from_filename(file);
	entry->filesize = size;
	entry->available_as_zip = 0;
	gutenfetch_etext_entry_set_format(entry);
							
	/* Determine if the available_as_zip flag should be set. */
	zip_lt = list_first(flt);
	while (zip_lt != NULL) {
		file_info = (file_info_t*)zip_lt->data;
		if (strncmp(entry->filebase, file_info->filename, strlen(entry->filebase)) == 0) {
			entry->available_as_zip = 1;
			break;
		}
		zip_lt = list_next(zip_lt);
	}
	return entry;
}


/**
 * gutenfetch_etext_new
 *
 * Allocate space for and initialize a new etext.
 *
 * @return NULL on failure otherwise an initialized and
 *		empty etext.
 */
gutenfetch_etext_t *
gutenfetch_etext_new(void)
{
	gutenfetch_etext_t *etext;
	etext = (gutenfetch_etext_t*)malloc(sizeof(gutenfetch_etext_t));
	if (etext == NULL) 
		return NULL;
	etext->full = NULL;
	etext->author = NULL;
	etext->title = NULL;
	etext->directory = NULL;
	etext->filebase = NULL;
	etext->extra = NULL;
	etext->id = 0;
	etext->cflag.reserved = 0;
	etext->cflag.australia = 0;
	etext->cflag.copyright = 0;
	etext->fflag.verified = 0;
	etext->fflag.plain_text = 0;
	etext->fflag.eight_bit_text = 0;
	etext->fflag.big5_text = 0;
	etext->fflag.unicode = 0;
	etext->fflag.html = 0;
	etext->fflag.tex = 0;
	etext->fflag.xml = 0;
	etext->fflag.mp3 = 0;
	etext->fflag.rtf = 0;
	etext->fflag.pdf = 0;
	etext->fflag.lit = 0;
	etext->fflag.doc = 0;
	etext->fflag.pdb = 0;
	etext->fflag.prc = 0;
	etext->entry = NULL;
	return etext;
}

/**
 * gutenfetch_etext_free
 *
 * Release all resources held by and etext.
 *
 * @param etext The etext to free.
 */
void
gutenfetch_etext_free(gutenfetch_etext_t *etext)
{
	int i;
	
	if (etext != NULL) {
		FREE_NULL(etext->full);
		FREE_NULL(etext->author);
		FREE_NULL(etext->title);
		FREE_NULL(etext->directory);
		FREE_NULL(etext->filebase);
		FREE_NULL(etext->extra);

		if (etext->entry != NULL) {
			for (i = 0;etext->entry[i] != NULL; ++i) {
				gutenfetch_etext_entry_free(etext->entry[i]);
			}
			FREE_NULL(etext->entry);
		}
		FREE_NULL(etext);
	}
}

/**
 * gutenfetch_get_etext
 *
 * Download a given etext.
 *
 * @param entry The etext entry which we would like to download.
 * @param file A pointer to an allocated file_t structure to return
 *		the downloaded file.
 * @param download_as_zip TRUE if we should try to download and
 *		return the file in .ZIP format, FALSE if we should get
 *		the unaltered file from the server.
 * @param progress_func This function will be called periodically
 *		to allow the caller to determine the progress we are making.
 * @param progress_func_data User supplied parameter to progress_func.
 * @return GUTENFETCH_OK on success, something else on failure.
 */
gutenfetch_error_t
gutenfetch_get_etext(
	gutenfetch_etext_entry_t *entry,
	gutenfetch_file_t *file,
	int download_as_zip,
	int (*progress_func)(void *, double, double, double, const char *),
	void *progress_func_data)
{
	char *filename;
	int fd;
	gutenfetch_error_t gutenerr = GUTENFETCH_OK;

	if ((entry == NULL) || (file == NULL)) {
		return GUTENFETCH_BAD_PARAM;
	}
	
	file->filename = NULL;
	file->contents = NULL;
	
	if (	(entry->directory == NULL) ||
			(entry->filebase == NULL) ||
			(entry->file_ext == NULL)
	) {
		return GUTENFETCH_BAD_PARAM;	
	}

	
	if ((entry->available_as_zip) && (download_as_zip == TRUE)) {
		filename = file->filename = 
			gutenfetch_util_strcat(entry->directory, "/",
			entry->filebase, ".zip", NULL);
		file->zipped = TRUE;	
	} else {
		filename = file->filename = 
			gutenfetch_util_strcat(entry->directory, "/", 
			entry->filebase, ".", entry->file_ext, NULL);
		file->zipped = FALSE;	
	}

	if (filename == NULL) {
		return GUTENFETCH_NOMEM;
	}	
	
	if (entry->aussie) {
		fd = gutenfetch_cache_fetch(
			AUSTRALIAN, filename, progress_func, progress_func_data);
	} else {
		fd = gutenfetch_cache_fetch(
			NON_AUSTRALIAN, filename, progress_func, progress_func_data);
	}
	
	if (fd != -1) {
		gutenerr = gutenfetch_util_read_binary_file_to_buffer(
			fd,
			&file->contents,
			&file->filesize);
		close( fd );
	} else {
		file->contents = NULL;
	}	

	return( gutenerr );	
}



syntax highlighted by Code2HTML, v. 0.9.1