/* * This module is called by the webbook main routine sees a path_info * string ending in slash, implying that the the atarget is a shelf. * The main routine deletes the trailing slash and passes the path as an * argument to webbook_shelf(). This 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. * * Conditional compilation symbols: * NOCGILIB * * Revised: 29-JUN-1996 Incorporate bug fixes supplied by Jose Baars, * baarsj@abnamro.nl. * Revsied: 12-JUL-1999 Update for ODL/BKB. * */ #include #include #include #include #include "cgilib.h" #define SHELF_ICON "" #define BOOK_ICON "" #define HTML_ICON "" #define DEFAULT_ICON_DIR "/demo" static char *icon_dir; struct shelf_rec { struct shelf_rec *next; char *type; /* first element. */ char *fname; char *desc; int is_odl; /* true if newer ODL format */ }; 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 webbook_shelf ( char *path, char *software_version ) { char *title, *script_name, *elem[20]; int status, i, j, lvl; FILE *sf; struct shelf_rec *rec, first_rec; char *default_library; char title_spec[256]; char shelf_spec[256]; char dna_spec[260]; char shelf_history[2048]; char icon_image[300]; /* * 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; } /* * Determine approiate default name for open based upon existence * of odlibrary logical. */ default_library = getenv("odlibrary"); if (!default_library) default_library = "decw$book:library.decw$bookshelf"; else if (strlen(default_library) > sizeof(dna_spec)-5 ) default_library = "library.odl"; sprintf ( dna_spec, "dna=%s", default_library ); /* * Attempt to open the shelf file and parse. */ first_rec.next = (shelf_recp) 0; first_rec.type = ""; rec = &first_rec; title = path; #ifdef VERBOSE printf("\n", path, j, elem[j] ); #endif sf = fopen ( elem[j], "r", dna_spec, "mbc=64" ); if ( sf ) { while ( rec = get_shelf_rec ( sf, rec ) ) { if ( 0 == strcmp ( rec->type, "TITLE" ) ) { title = rec->desc; if ( rec->is_odl ) { if ( (strlen(rec->fname)+strlen(rec->desc)+2) < 256) { sprintf(title_spec, "%s %s", rec->fname, rec->desc ); title = title_spec; } } } } fgetname(sf, shelf_spec, 1); /* full file name of bookshelf */ fclose ( sf ); } /* * Generate HTML header. */ send_http_header ( "200 Sending generated HTML", "Text/html" ); cgi_printf("\n%s\n", entify_string(title) ); cgi_printf("\n", software_version ); cgi_printf("\n

%s

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


\n"); /* * determine icon directory from environment variable. */ icon_dir = getenv ( "WEBBOOK_ICON_PATH" ); if ( !icon_dir ) icon_dir = DEFAULT_ICON_DIR; else if ( (strlen(icon_dir)+50) > sizeof(icon_image) ) icon_dir = DEFAULT_ICON_DIR; /* * 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_target, *escaped_desc, *entified; char target[256]; if ( *rec->type == '#' ) continue; /* comment */ apply_default ( rec->fname, shelf_spec, target ); entified = entify_string(rec->desc); escaped_target = escape_string(target); if ( 0 == strcmp ( rec->type, "SHELF" ) ) { escaped_desc = escape_string(rec->desc); sprintf ( icon_image, SHELF_ICON, icon_dir ); cgi_printf("%s %s
\n", icon_image, escaped_desc, escaped_target, entified ); if ( escaped_desc != rec->desc ) free ( escaped_desc ); } else if ( 0 == strcmp ( rec->type, "BOOK" ) ) { sprintf ( icon_image, BOOK_ICON, icon_dir ); cgi_printf("%s %s
\n", icon_image, script_name, escaped_target, entified ); } else if ( 0 == strcmp ( rec->type, "TITLE" ) ) { } else { /* * convert the target back to unix format, and make direct * HREF to it. */ int state, k; for ( state = k = 0; target[k]; k++ ) switch ( state ) { case 0: if ( target[k] == ':' ) { state = 1; target[k] = '/'; } else if ( target[k] == '[' || target[k] == '<' ) { state = 4; target[k] = '/'; } break; case 1: if ( target[k] == '[' ) { state = 2; } if ( target[k] == '<' ) { state = 2; } break; case 2: if ( target[k] == '.' ) target[k] = '/'; if ( target[k] == ']' || target[k] == '>' ) { target[k] = '/'; state = 3; } target[k-1] = target[k]; break; case 3: target[k-1] = target[k]; break; case 4: if ( target[k] == '.' || target[k] == ']' || target[k] == '>' ) target[k] = '/'; break; } if ( state == 2 || state == 3 ) target[k-1] = '\0'; /* printf("rewritten target: '%s'\n", target ); */ /* * Insert proper icon for filetype. */ if ( 0 == strcmp ( rec->type, "HTML" ) ) { sprintf ( icon_image, HTML_ICON, icon_dir ); } else if ( strlen(rec->type) < (sizeof(icon_image)-3) ) { sprintf ( icon_image, "[%s]", rec->type ); } else { strcpy ( icon_image, "???" ); } cgi_printf("%s %s
\n", icon_image, target, entified ); } /* * Only free string if malloc'ed */ if ( escaped_target != target ) free ( escaped_target ); if ( entified != rec->desc ) free ( entified ); } cgi_printf ( "\n" ); return 1; } /****************************************************************************/ /* 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, backslash_count; shelf_recp cur; char *line, tline[4096]; /* * Be optimistic 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 = ""; cur->is_odl = 0; backslash_count = 0; if ( fgets ( tline, sizeof(tline)-1, sf ) ) { /* * Copy and Parse the record on backslashes or tabs. It will * also parse on the first space. */ for ( i = 0; i < sizeof(tline) && tline[i] && tline[i] != '\n'; i++ ); line = malloc ( i + 1 ); if ( !line ) return (shelf_recp) 0; strncpy ( line, tline, i ); line[i] = '\0'; cur->type = line; for ( j = i = 0; line[i]; i++ ) if ( (line[i]=='\\') || ((backslash_count==0) && (line[i] == ' ')) || (line[i] == '\t') ) { if ( line[i] == '\\' ) backslash_count++; line[i] = '\0'; if ( backslash_count == 0 ) { /* * compress whitespace. */ while ( line[i+1] && isspace(line[i+1]) ) i++; } if ( j == 0 ) { cur->fname = &line[i+1]; j++; } else { cur->desc = &line[i+1]; /* rest of line */ break; } } if ( backslash_count == 0 ) cur->is_odl = 1; /* * 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; } #ifdef DEBUG if ( cur ) printf("shelf rec parse: '%s' '%s' '%s'\n", cur->type, cur->fname, cur->desc ); #endif /* * 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 ); if ( strncmp(stsline,"200",3) != 0 ) cgi_printf ( "status: %s\n\n", stsline ); else cgi_printf("\n"); return 1; } /**************************************************************************/ /* Take default directory from defname and apply to fname. If fname * begins with a percent sign, convert ODL shelf syntax to VMS filespec. */ static char *apply_default ( char *fname, char *defname, char *out ) { int i, j, d_limit, slash_fixup; if ( *fname == '%' ) { /* * Change "%devname/dir/file" --> "devname:[dir]file" */ j = 0; /* output position */ d_limit = -1; /* position of last slash */ for ( i = 1; fname[i]; i++ ) { if ( fname[i] == '/' ) { if ( d_limit < 0 ) { /* first slash */ out[j++] = ':'; out[j++] = '['; } else { out[j++] = '.'; } d_limit = j-1; } else { out[j++] = fname[i]; } } out[j] = '\0'; if ( d_limit >= 0 ) { if ( out[d_limit] == '.' ) out[d_limit] = ']'; else for ( i = d_limit; out[i]; i++ ) out[i] = out[i+1]; } return out; } /* * Find end of directory string, default to "decw$book:". */ for ( d_limit = i = 0; defname[i]; i++ ) { if ( defname[i] == ':' || defname[i] == ']' || defname[i] == '>' ) d_limit = i+1; /* end of defname directory */ } if ( d_limit == 0 ) { defname = "decw$book:"; d_limit = 10; } /* * If fname looks like it supplies it's own directory, make defname NULL. */ for ( slash_fixup = i = 0; fname[i]; i++ ) { if ( fname[i] == ':' || fname[i] == ']' || fname[i] == '>' ) { d_limit = 0; } else if ( fname[i] == '/' ) { slash_fixup = 1; } } /* * concatenate defname//fname. */ if ( d_limit ) { strncpy ( out, defname, d_limit ); if ( slash_fixup ) { if ( defname[d_limit-1] == ':' ) { strcpy ( &out[d_limit], "[000000." ); d_limit += 8; } else { out[d_limit-1] = '.'; } } } if ( i+d_limit > 255 ) i = 255-d_limit; strncpy ( &out[d_limit], fname, i ); out[i+d_limit] = '\0'; if ( slash_fixup ) { for ( i = d_limit+i-1; i > d_limit; --i ) if ( out[i] == '/' ) { out[i] = (slash_fixup) ? ']' : '.'; slash_fixup = '\0'; } } return out; }