/*

    Minimum Profit 5.x
    A Programmer's Text Editor

    Encrypting functions.

    Copyright (C) 1991-2012 Angel Ortega <angel@triptico.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    http://triptico.com

*/

/** ARCFOUR (encryption) class **/

arcfour = {
    i:      0,
    j:      0,
    S:      [ 0 .. 255 ],
    byte:   sub (a4) {
        i = (i + 1) & 0xff;
        j = (j + S[i]) & 0xff;

        /* swap */
        local t = S[i]; S[i] = S[j]; S[j] = t;

        return S[(S[i] + S[j]) & 0xff];
    },
    init:   sub (a4, key) {
        /* split as an array of characters */
        local k = split(key || '');
        local n = 0;

        /* scramble */
        foreach (i, [ 0 .. 255 ]) {
            local t = S[i];

            n = (n + t + ord(k[i % size(k)])) & 0xff;

            S[i] = S[n];
            S[n] = t;
        }

        /* discard 256 bytes (as recommended in many sources) */
        foreach (i, [ 0 .. 255 ])
            a4->byte();

        return a4;
    }
};


/** editor actions **/

mp_doc.actions['set_password'] = sub(d) {
    local r = mp.form(
        [
            {
                type:   'password',
                label:  L("Password:")
            },
            {
                type:   'password',
                label:  L("Password (again):")
            }
        ]
    );

    if (r != NULL) {
        if (r[0] ne r[1])
            mp.alert(L("Passwords don't match."));
        else {
            d.password  = r[0];
            d.txt.mod   = 1;
        }
    }
};


/** action descriptions **/

mp.actdesc['set_password'] = LL("Password protect...");

/** code **/

sub mp.crypt1_load(fd, password)
/* loads a crypt1 encrypted file into lines */
{
    local c;
    local l = '';
    local lines = [];

    /* the mpcrypt1\n\0 signature has already been read */

    /* init */
    local a4 = new(arcfour)->init(password);

    while ((c = getchar(fd)) != NULL) {
        /* decrypt byte and concat */
        c = chr(ord(c) ^ a4->byte());

        if (c eq "\n") {
            /* end of line; push it and restart */
            push(lines, l);
            l = '';
        }
        else
            l = l ~ c;
    }

    push(lines, l);

    return lines;
}


sub mp.crypt1_save(fd, lines, password)
/* saves the lines as a crypt1 encrypted file */
{
    local nl = 0;

    /* save first the signature */
    write(fd, "mpcrypt1\n");

    /* write a \0 */
    putchar(fd, "");

    /* init */
    local a4 = new(arcfour)->init(password);

    /* loop the lines */
    foreach (l, lines) {
        /* write a line separator if it's not the first line */
        if (nl)
            l = "\n" ~ l;

        /* split by chars */
        local lc = split(l);

        /* write each char xoring with next crypto-byte */
        foreach (c, lc)
            putchar(fd, chr(ord(c) ^ a4->byte()));

        nl++;
    }

    close(fd);

    return nl;
}


sub mp.crypt1_detect(fd)
/* detects if fd is an mpcrypt1-type file */
{
    /* is it mpcrypt1\n followed by a 0? */
    if (read(fd) eq "mpcrypt1\n" && ord(getchar(fd)) == 0)
        return 1;

    /* no; file must be reopen */
    return 0;
}
