/*
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