/* * This program is a CGI script for presenting a bookreader bookshelf * heirarchy as HTML. * * The first element path_info string is assumed to be the name of * the bookshelf file to read (default decw$book:library.decw$bookshelf). * Succeeding elements are used to hold the history of which shelves were * travered to get to the current shelf. */ #include #include #include #include #include "cgilib.h" #define SHELF_ICON "" #define BOOK_ICON "" #define BOOK_SCRIPT "/htbin/webbook/" struct shelf_rec { struct shelf_rec *next; char *type; /* first element. */ char *fname; char *desc; }; typedef struct shelf_rec *shelf_recp; static shelf_recp get_shelf_rec ( FILE *sf, shelf_recp prev ); static char *escape_string ( char * ); static char *entify_string ( char * ); static char *apply_default ( char *fname, char *defname, char *out ); static int send_http_header ( char *stsline, char *content ); int main ( int argc, char **argv ) { char *path, *title, *elem[20]; int status, i, j, lvl; FILE *sf; struct shelf_rec *rec, first_rec; char shelf_spec[256]; char shelf_history[2048]; /* * Establish communication with http server and set up CGI environment */ status = cgi_init ( argc, argv ); if ( (status&1) == 0 ) exit ( status ); path = cgi_info ( "PATH_INFO" ); if ( !path ) { send_http_header ( "500 bad path info", "text/plain" ); return 20; } /* * Parse the path elements. */ strncpy ( shelf_history, path, sizeof(shelf_history)-1 ); path = shelf_history; path[sizeof(shelf_history)-1] = '\0'; if ( *path == '/' ) path++; elem[0] = path; for ( j = i = 0; path[i]; i++ ) if ( path[i] == '/' ) { path[i] = '\0'; j++; elem[j] = &path[i+1]; if ( j > 19 ) break; } /* * Attempt to open the shelf file and parse. */ first_rec.next = (shelf_recp) 0; first_rec.type = ""; rec = &first_rec; title = path; sf = fopen ( elem[j], "r", "dna=decw$book:.decw$bookshelf", "mbc=64" ); if ( sf ) { while ( rec = get_shelf_rec ( sf, rec ) ) { if ( 0 == strcmp ( rec->type, "TITLE" ) ) { title = rec->desc; } } fgetname(sf, shelf_spec, 1); /* full file name of bookshelf */ fclose ( sf ); } /* * Generate HTML header. */ send_http_header ( "200 Sending generated HTML\n", "Text/html" ); cgi_printf("\n%s\n", entify_string(title) ); cgi_printf("\n

%s

\n", path); /* * Generate history path. */ lvl = 2; for ( i = 0; i < j; i++ ) { lvl++; if ( lvl > 6 ) lvl = 6; cgi_printf ( "%s\n", lvl, entify_string(elem[i]), lvl ); } cgi_printf("


\n"); /* * Generate directory with links to each. */ if ( ! first_rec.next ) { cgi_printf ( "Error opening bookshelf file %s\n", path); } for ( rec = first_rec.next; rec; rec = rec->next ) { char *escaped, *entified; char target[256]; apply_default ( rec->fname, shelf_spec, target ); entified = entify_string(rec->desc); if ( 0 == strcmp ( rec->type, "SHELF" ) ) { escaped = escape_string(target); cgi_printf("%s%s
\n", SHELF_ICON, escape_string(rec->desc), escaped, entified ); } else if ( 0 == strcmp ( rec->type, "BOOK" ) ) { escaped = escape_string(target); cgi_printf("%s%s
\n", BOOK_ICON, BOOK_SCRIPT, escaped, entified ); } } cgi_printf ( "\n" ); } /****************************************************************************/ /* Convert strings containing punctuation characters into escaped strings. */ static char *escape_string ( char *source ) { int i, j, punct_count; char *dest; dest = source; punct_count = 0; for ( i = 0; source[i]; i++ ) if ( ispunct ( source[i] ) ) { if ( (source[i] != '.') && (source[i] != '$') )punct_count++; } else if ( isspace ( source[i] ) ) punct_count++; if ( punct_count > 0 ) { dest = malloc ( i + punct_count*3 + 1 ); if ( !dest ) return source; for ( i = j = 0; source[i]; i++ ) { if ( isspace(source[i]) || (ispunct ( source[i] ) && (source[i] != '.') && (source[i] != '$')) ) { sprintf ( &dest[j], "%%%02x", source[i] ); if ( dest[j+1] == ' ' ) dest[j+1] = '0'; j += 3; } else dest[j++] = source[i]; } dest[j] = '\0'; } return dest; } /****************************************************************************/ /* Convert strings containing punctuation characters into escaped strings. */ static char *entify_string ( char *source ) { int i, j,brack_count; char *dest; dest = source; brack_count = 0; for ( i = 0; source[i]; i++ ) { if ( (source[i] == '<') || (source[i] == '>') || (source[i] == '&') ) brack_count++; } if ( brack_count > 0 ) { dest = malloc ( i + brack_count*4 + 1 ); if ( !dest ) return source; for ( i = j = 0; source[i]; i++ ) { if ( source[i] == '<' ) { dest[j++] = '&'; dest[j++] = 'l'; dest[j++] = 't'; dest[j++] = ';'; } else if ( source[i] == '>' ) { dest[j++] = '&'; dest[j++] = 'g'; dest[j++] = 't'; dest[j++] = ';'; } else if ( source[i] == '&' ) { dest[j++] = '&'; dest[j++] = 'a'; dest[j++] = 'm'; dest[j++] = 'p'; dest[j++] = ';'; } else dest[j++] = source[i]; } dest[j] = '\0'; } return dest; } /****************************************************************************/ /* Read next record from bookshelf file and copy to structure. */ static shelf_recp get_shelf_rec ( FILE *sf, shelf_recp previous ) { int i,j; shelf_recp cur; char *line, tline[4096]; /* * Be optimistice and allocate new structure. */ cur = malloc ( sizeof(struct shelf_rec) ); if ( !cur ) return cur; cur->next = (shelf_recp) 0; cur->type = cur->fname = cur->desc = ""; if ( fgets ( tline, sizeof(tline)-1, sf ) ) { /* * Copy and Parse the record on backslashes. */ for ( i = 0; i < sizeof(tline) && tline[i] && tline[i] != '\n'; i++ ); line = malloc ( i + 1 ); strncpy ( line, tline, i ); if ( !line ) return (shelf_recp) 0; line[i] = '\0'; cur->type = line; for ( j = i = 0; line[i]; i++ ) if ( line[i] == '\\' ) { line[i] = '\0'; if ( j == 0 ) { cur->fname = &line[i+1]; j++; } else { cur->desc = &line[i+1]; /* rest of line */ break; } } /* * Unescape characters and upcase type. */ for ( i = 0; line[i]; i++ ) if ( islower(line[i]) ) line[i] = _toupper(line[i]); } else { /* * Read error, return null. */ free ( cur ); cur = (shelf_recp) 0; } /* * append new record to list. */ previous->next = cur; return cur; } /**************************************************************************/ /* Prepare to send back response. Build standard response header. */ static int send_http_header ( char *stsline, char *content ) { int status; /* */ cgi_printf ( "Content-type: %s\n", content ); cgi_printf ( "status: %s\n\n", stsline ); return 1; } /**************************************************************************/ /* Take default directory from defname and apply to fname. */ static char *apply_default ( char *fname, char *defname, char *out ) { int i, d_limit; for ( d_limit = i = 0; defname[i]; i++ ) { if ( defname[i] == ':' || defname[i] == ']' || defname[i] == '>' ) d_limit = i+1; } if ( d_limit == 0 ) { defname = "decw$book:"; d_limit = 10; } for ( i = 0; fname[i]; i++ ) { if ( fname[i] == ':' || fname[i] == ']' || fname[i] == '>' ) d_limit = 0; } if ( d_limit ) strncpy ( out, defname, d_limit ); if ( i+d_limit > 255 ) i = 255-d_limit; strncpy ( &out[d_limit], fname, i ); out[i+d_limit] = '\0'; return out; }