/* 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 #endif #ifdef HAVE_ASSERT_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #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 ); }