[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
[0361]
[0362]
[0363]
[0364]
[0365]
[0366]
[0367]
[0368]
[0369]
[0370]
[0371]
[0372]
[0373]
[0374]
[0375]
[0376]
[0377]
[0378]
[0379]
[0380]
[0381]
[0382]
[0383]
[0384]
[0385]
[0386]
[0387]
[0388]
[0389]
[0390]
[0391]
[0392]
[0393]
[0394]
[0395]
[0396]
[0397]
[0398]
[0399]
[0400]
[0401]
[0402]
[0403]
[0404]
[0405]
[0406]
[0407]
[0408]
[0409]
[0410]
[0411]
[0412]
[0413]
[0414]
[0415]
[0416]
[0417]
[0418]
[0419]
[0420]
[0421]
[0422]
[0423]
[0424]
[0425]
[0426]
[0427]
[0428]
[0429]
[0430]
[0431]
[0432]
[0433]
[0434]
[0435]
[0436]
[0437]
[0438]
[0439]
[0440]
[0441]
[0442]
[0443]
[0444]
[0445]
[0446]
[0447]
[0448]
[0449]
[0450]
[0451]
[0452]
[0453]
[0454]
[0455]
[0456]
/*
 * 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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#include "cgilib.h"

#define SHELF_ICON "<IMG SRC=\"%s/shelf.xbm\">"
#define BOOK_ICON "<IMG SRC=\"%s/book.xbm\">"
#define HTML_ICON "<IMG SRC=\"%s/text.gif\">"
#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("<!-- path: '%s', shelf file (elem[%d]): '%s'-->\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("<HTML>\n<HEAD><TITLE>%s</TITLE>\n", entify_string(title) );
   cgi_printf("<!-- Software: %s -->\n</HEAD>", software_version );
   cgi_printf("<BODY>\n<H2>%s</H2><P>\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 ( "<H%d>%s</H%d>\n", lvl, entify_string(elem[i]), lvl );
   }
   cgi_printf("<BR><HR>\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 <A HREF=\"../%s/%s/\">%s</A><BR>\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 <A HREF=\"%s/%s\">%s</A><BR>\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 <A HREF=\"/%s\">%s</A><BR>\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 ( "</BODY></HTML>\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;
}