/*
 * Dynamically loaded map routine.  Scan translation for characters that
 * need escaped in VMS ODS-5 filenames and escape them.
 *
 */
#include "access.h"			/* Access structure. */
#include "ident_map.h"
#include "tutil.h"
#include <stdio.h>

static int is_special[256];
static char *ods2set = 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_-.~";
static char *disallowedset = "\"*\\:<>/?|";

int init_escape_special ( )
{
    int i;
    for ( i = 0; i < 32; i++ ) is_special[i] = 0;	/* control chars */
    for ( i = 32; i < 256; i++ ) is_special[i] = 1;
    for ( i = 0; ods2set[i]; i++ ) is_special[ods2set[i]] = 0;
    for ( i = 0; disallowedset[i]; i++ ) is_special[disallowedset[i]] = -1;
    return 1;
}

/***************************************************************************/
/* Convert /$username/.... specification to /device/home-dir/... according
 * to information in the user authorization file.  The sysuaf file may need to
 * be modified to granted read access.
 *
 * Return values:
 *   IDENT_MAP_TRANSLATED	Translation failed (username not found)
 */
int escape_special ( info_ptr blk, char *translation, int maxlen,
	access_info acc, char **case_preserved, int cp_len )
{
    int i, j, user_len, login_len, delta, status, length;
    int last_slash, last_special, special_count, new_len;
    char c, *cp_buf;
    /*
     * Scan the current translation string for characters that needs
     * escaped.
     */
    last_slash = last_special = -1;
    special_count = 0;
    for ( i = 0; translation[i]; i++ ) {
	c = translation[i];
	if ( c == '/' ) {
	    last_slash = i;
	    special_count = 0;
	} else if ( is_special[c] > 0 ) {
	    last_special = i;
	    special_count++;
	}
    }
    length = i;
    /*
     * we are done if no special characters found.
     */
    if ( last_special <= last_slash ) return IDENT_MAP_LOOP;
    /*
     * Check if characters have already been escaped.
     */
    if ( translation[last_special] == '^' ) {
	/*
	 * We should do some fancy error-prone heuristic to check that
         * every '^' is followed by a special character or '_'.
	 */
	return IDENT_MAP_LOOP;
    }
    /*
     * Re-write the portion of the translation buffer after the
     * the escaped characters.  Each special character will be replaced
     * by ^XX.
     */
    new_len = length + (special_count*2);
    if ( new_len >= maxlen ) return IDENT_MAP_LOOP;
    if ( new_len >= cp_len ) {
	/* Encoded result too big to fit in case-preserved buffer, discard it.
	 */
	cp_buf = (char *) 0;
        *case_preserved = translation;
    } else cp_buf = *case_preserved;

    translation[new_len] = '\0';
    if ( cp_buf ) cp_buf[new_len] = '\0';

    j = new_len;
    for ( i = length-1; i > last_slash; i-- ) {
	j--;
	c = translation[i];
	if ( is_special[c] > 0 ) {
	    char hex_str[12];
	    sprintf ( hex_str, "%02x", c );
	    j = j - 2;
	    translation[j] = '^';
	    translation[j+1] = hex_str[0];
	    translation[j+2] = hex_str[1];
	    if ( cp_buf ) {
		cp_buf[j] = '^';
		cp_buf[j+1] = hex_str[0];
		cp_buf[j+2] = hex_str[1];
	    }
	} else {
	    translation[j] = translation[i];
	    if ( cp_buf ) cp_buf[j] = cp_buf[i];
	}
    }

    *case_preserved = cp_buf;
    return IDENT_MAP_TRANSLATED;
}
