/*
 * Tcl Source Code Encryption Package
 *
 * Copyright (C) 1992-1997 Karl Lehenbauer, All Rights Reserved
 * Copyright (C) 1998 NeoSoft, Inc., All Rights Reserved
 *
 * $Id: neoXcrypt.c,v 1.1.1.1 1999/03/31 20:34:37 damon Exp $
 *
 */

#ifdef NEOSOFT_TCL_ENCRYPTION

#include "neo.h"

#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif

char *fileEncryptionKey = "NeoSoft Tcl";

/* encrypt/decrypt string in place using key, mode = 1 to encrypt and
 * 0 to decrypt
 */
static void
neo_encrypt(string, key, offset, mode)
char *string;
const char *key;
long offset;
int mode;
{
    const char *kp = key;

    offset = offset % strlen(key);
    while (offset--) kp++;

    /* printf("encrypt '%s' with key '%s', mode %d\n",string,key,mode); */

    while (*string != '\0')
    {
	if (*string >= 32 && *string <= 126)
	{
	    if (mode)
		*string = (((*string - 32) + (*kp - 32)) % 94) + 32;
	    else
		*string = (((*string - 32) - (*kp - 32) + 94) % 94) + 32;
	}

	string++;
	kp++;
	if (*kp == '\0')
		kp = key;
    }
}

void
NeoSoft_DecryptFile(interp, fileName, dataBuffer, fileOffset)
Tcl_Interp *interp;
char *fileName;
char *dataBuffer;
long fileOffset;
{
    char *baseFileName, *workFileName;
    char *encryptedFileVarValue;

    baseFileName = workFileName = fileName;
    while (*workFileName != '\0') {
	if (*workFileName == '/') baseFileName = workFileName + 1;
	workFileName++;
    }

    /* See if it's in the array of encrypted filenames.  If not, we're done. */
    encryptedFileVarValue = Tcl_GetVar2(interp, "ef", baseFileName, TCL_GLOBAL_ONLY);
    if (encryptedFileVarValue == NULL) return;

    neo_encrypt(dataBuffer, encryptedFileVarValue, fileOffset, 0L);
    neo_encrypt(dataBuffer, baseFileName, fileOffset, 0L);
    neo_encrypt(dataBuffer, fileEncryptionKey, fileOffset, 0L);

    return;
}

static int
NeoSoft_EncryptCmd (clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int         argc;
    char      **argv;
{
    char *resultBuffer;
    int mode;
    int keyIndex;

    if (argc < 3) {
        Tcl_AppendResult (interp, " bad # arg: ", argv[0], 
			    " data key", (char *)NULL);
        return TCL_ERROR;
    }

    resultBuffer = (char *)ckalloc (strlen (argv[1]) + 1);
    strcpy (resultBuffer, argv[1]);

    mode = (STREQU (argv[0], "neo_encrypt"));

    for (keyIndex = 2; keyIndex < argc; keyIndex++) {
        neo_encrypt (resultBuffer, argv[keyIndex], 0L, mode);
    }

    Tcl_SetResult (interp, resultBuffer, TCL_DYNAMIC);
    return TCL_OK;
}

static int
NeoSoft_CryptCmd (clientData, interp, argc, argv)
    ClientData  clientData;
    Tcl_Interp *interp;
    int         argc;
    char      **argv;
{
    char *resultBuffer;

    if (argc != 3) {
        Tcl_AppendResult (interp, " bad # arg: ", argv[0], 
			    " key setting", (char *)NULL);
        return TCL_ERROR;
    }

    resultBuffer = crypt (argv[1], argv[2]);

    if (resultBuffer == NULL) {
	Tcl_AppendResult (interp, "crypt function failed: ", argv[0],
	    (char *)NULL);
	return TCL_ERROR;
    }
    Tcl_SetResult (interp, resultBuffer, TCL_VOLATILE);
    return TCL_OK;
}

int
NeoSoft_InitEncrypt (interp)
Tcl_Interp *interp;
{
    Tcl_CreateCommand (interp, "neo_encrypt", NeoSoft_EncryptCmd,
                      (ClientData)NULL, (void (*)())NULL);

    Tcl_CreateCommand (interp, "neo_decrypt", NeoSoft_EncryptCmd,
                      (ClientData)NULL, (void (*)())NULL);

    Tcl_CreateCommand (interp, "neo_crypt", NeoSoft_CryptCmd,
                      (ClientData)NULL, (void (*)())NULL);

    return TCL_OK;
}

#endif /* NEOSOFT_TCL_ENCRYPTION */
