/**
 * Because of export restrictions encryption is done via an 
 * addon plugin which can be dropped in Yudit plugin directory.
 *
 * This sample sedy encrytpion plugin should be compiled as a dynamic 
 * library:
 *  - libsedy.so (Linux/Unix)
 *  - libsedy.dll (Window)
 *  - libsedy.dylib (Mac).
 *
 * Linux
 *  gcc -c -Wall -Werror -fpic sedy.c
 *  gcc -shared -o libsedy.so sedy.o
 * 
 * Mac  
 * gcc -c -Wall -Werror -fpic sedy.c
 * gc -shared -o libsedy.dylib sedy.o
 *
 * Windows
 * cl /Zi -c -nologo  /D_USRDLL /D_WINDLL  sedy.c
 * link -nologo /DLL /OUT:libsedy.dll sedy.obj
 *
 * Gaspar Sinai <gaspar@yudit.org> 2020-05-02, Tokyo
 */ 
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "yudit_sedy.h"


#define SAMPLE_ENCRYPT "Sey Encrypted\n"
#define SAMPLE_DECRYPT "Sey Decrypted\n"

char* last_cypher = "TDES-168-bit";

typedef struct _sedy_context {
    char* result;  
    unsigned long result_size;
    char* cypher;
    char* password;
} sedy_context;

void* object;

// If cypher is null, it will be guessed from decrypted data.
// return the context.
SEDY_EXPORT void* sedy_create (char* password, char* cypher) {

    sedy_context* ret = (sedy_context*) malloc(sizeof(sedy_context));
    if (ret == 0) return 0;
    ret->result = 0;
    ret->result_size = 0;
    ret->cypher = (char*) malloc(strlen (cypher)+1);
    if (ret->cypher == 0) {
        free(ret);
        return 0;
    }
    if(cypher) {
        strcpy(ret->cypher, cypher);
    } else {
        ret->cypher[0] = '0';
    }
    ret->password = (char*) malloc(strlen (password)+1);
    if (ret->password == 0) {
        free(ret->cypher);
        free(ret);
        return 0;
    }
    strcpy(ret->password, password);
    return ret;
}

SEDY_EXPORT void sedy_destroy (void* sedy) {
    sedy_context* sc = (sedy_context*) sedy;
    if (sc->result) free (sc->result);
    if (sc->password) free (sc->password);
    if (sc->cypher) free (sc->cypher);
    free(sc);
}

SEDY_EXPORT char* sedy_get_result (void* sedy) {
    sedy_context* sc = (sedy_context*) sedy;
    return sc->result;
}

SEDY_EXPORT unsigned long sedy_get_result_size (void* sedy) {
    sedy_context* sc = (sedy_context*) sedy;
    return sc->result_size;
}

// When cypher is guessed.
SEDY_EXPORT char* sedy_get_cypher (void* sedy) {
    sedy_context* sc = (sedy_context*) sedy;
    return sc->cypher;
}

SEDY_EXPORT int sedy_encrypt (void* sedy, char* buffer, unsigned long buffer_size) {
    sedy_context* sc = (sedy_context*) sedy;
    char* ret;
    if (sc->result) {
        free (sc->result);
        sc->result = 0;
        sc->result_size = 0;
    }
    if (strcmp(sc->cypher, "TDES-168-bit")!=0) {
        return SEDY_UNSOPPORTED_CYPHER;
    }
    if (strcmp(sc->password, "1234")!=0) {
        return SEDY_BAD_PASSWORD;
    }
    ret = (char*) malloc(strlen (SAMPLE_ENCRYPT) + 1);
    if (!ret) return SEDY_OUT_OF_MEMORY;
    strcpy (ret, SAMPLE_ENCRYPT);
    sc->result_size = strlen (SAMPLE_ENCRYPT);
    sc->result = ret;
    return SEDY_NO_ERROR;
}

/* you can pass NULL as cypher and it will guess the cypher. */
SEDY_EXPORT int sedy_decrypt (void* sedy, char* buffer, unsigned long buffer_size) {
    sedy_context* sc = (sedy_context*) sedy;
    char* ret;
    if (sc->result) {
        free (sc->result);
        sc->result = 0;
        sc->result_size = 0;
    }
    if (strcmp(sc->cypher, "TDES-168-bit")!=0) {
        return SEDY_UNSOPPORTED_CYPHER;
    }
    if (strcmp(sc->password, "1234")!=0) {
        return SEDY_BAD_PASSWORD;
    }
    ret = (char*) malloc(strlen (SAMPLE_DECRYPT) + 1);
    if (!ret) return SEDY_OUT_OF_MEMORY;
    strcpy (ret, SAMPLE_DECRYPT);
    sc->result_size = strlen (SAMPLE_DECRYPT);
    sc->result = ret;
    return SEDY_NO_ERROR;
}
