/*
 * hoz - Hacha Open Zource
 * Copyright (C) 2004 Gustavo Picon (http://hoz.sourceforge.net/)
 *
 * 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
 *
 */



#if defined(WIN32)
#define HOZ_PATHSEP '\\'
#else
#define HOZ_PATHSEP '/'
#endif

#include "hoz.h"

char outpath[MAXLEN];
size_t fullsize, partsize, headersize;
int showprogress, forceow, simulate;


/**
 * hoz_echo - displays something based on a code
 * @code: the event code
 * @xtra: extra information about an event
 *
 * not all the events have a xtra parameter
 */
void hoz_echo(const int code, const char *xtra)
{
    char foo[1024];
    foo[0] = 0;
    switch (code) {
    case 301:
        hoz_print(HOZ_COPYRIGHT1);
        hoz_lf();
        hoz_print(HOZ_COPYRIGHT2);
        hoz_lf();
        break;
    case 401:
        hoz_echo(301, NULL);
        hoz_lf();
        sprintf(foo, HOZ_USAGE_1, xtra);
        hoz_print(foo);
        hoz_lf();
        hoz_print(HOZ_USAGE_2);
        hoz_lf();
        hoz_print(HOZ_USAGE_3);
        hoz_lf();
        hoz_print(HOZ_USAGE_4);
        hoz_lf();
        hoz_print(HOZ_USAGE_5);
        hoz_lf();
        hoz_print(HOZ_USAGE_6);
        hoz_lf();
        hoz_print(HOZ_USAGE_7);
        hoz_lf();
        hoz_print(HOZ_USAGE_8);
        hoz_lf();
        hoz_print(HOZ_USAGE_9);
        hoz_lf();
        break;
    case 402:
        /*
         * it's gone
         */
        break;
    case 403:
        hoz_lf();
        hoz_print(HOZ_ENDDOTO);
        hoz_lf();
        break;
    case 404:
        hoz_lf();
        sprintf(foo, HOZ_NOFILE, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 405:
        hoz_lf();
        sprintf(foo, HOZ_BADHEADER, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 406:
        hoz_lf();
        sprintf(foo, HOZ_BADPARTS, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 407:
        hoz_lf();
        sprintf(foo, HOZ_ERROPENWRITE, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 408:
        hoz_lf();
        sprintf(foo, HOZ_ERROPENREAD, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 409:
        hoz_lf();
        sprintf(foo, HOZ_ERRPARTSIZE, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 410:
        hoz_lf();
        sprintf(foo, HOZ_ERRPROCESS, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 411:
        hoz_lf();
        sprintf(foo, HOZ_ERROUTNODIR, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 412:
        hoz_lf();
        sprintf(foo, HOZ_ERRWRITE, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 413:
        sprintf(foo, HOZ_BADARGSOPT, xtra);
        hoz_print(foo);
        hoz_lf();
        sprintf(foo, HOZ_HMOREINFO, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 414:
        sprintf(foo, HOZ_BADARGSFILE, xtra);
        hoz_print(foo);
        hoz_lf();
        sprintf(foo, HOZ_HMOREINFO, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    case 415:
        sprintf(foo, HOZ_HMOREINFO, xtra);
        hoz_print(foo);
        hoz_lf();
        break;
    }
}


/**
 * hoz_cut_main - cut files main function
 * @ifname: "file.ext" file name
 */
int hoz_cut_main(const char *ifname)
{
    FILE *f_in, *f_out;         /* file handles */
    clock_t initime;            /* to calculate the time spent */
    unsigned char buf[FILESTREAMSIZE + 1],      /* buffer to copy */
     foo[MAXLEN],               /* current 'file.n' filename */
     bar[MAXLEN],               /* "?????" */
     baz[MAXLEN], qux;          /* useless byte in the header,
                                 * must be included for compat with hacha
                                 */
    size_t i,                   /* foobar */
     len,                       /* bytes read */
     bfile,                     /* bytes read in current file file.n */
     btotal,                    /* total bytes read */
     dif;
    double elapsed;             /* total time elapsed */
    char *ifnopath;             /* input fname without path */

    f_in = fopen(ifname, "rb");
    if (!f_in) {
        hoz_echo(408, NULL);
        return 408;
    }
    i = bfile = btotal = 0;
    ifnopath = hoz_nopath(ifname);
    sprintf(baz, "%s.%u", ifnopath, i);
    mergepath(outpath, baz, foo);
    remove(foo);
    f_out = fopen(foo, "ab");
    if (!f_out) {
        fclose(f_in);
        hoz_echo(407, foo);
        return 407;
    }

    fullsize = fsize(ifname);

    /* store the time */
    initime = clock();

    /* begin control byte */
    /*
     * This code was broken, thanks Eric for reporting this
     *   sprintf(buf, "%u", partsize);
     *   len = strlen(buf);
     *   qux = 24 + len + strlen(ifnopath) + ((len <= 4) ? 1 : 3);
     */
    sprintf(buf, "%u%u%s", partsize, fullsize, ifnopath);
    qux = 20 + strlen(buf);
    /* end control byte */

    strcpy(bar, "?????");
    sprintf(buf, "%s%c   %s%s%s%u%s%u%s", bar, qux, bar,
            hoz_nopath(ifname), bar, fullsize, bar, partsize, bar);
    len = (size_t) strlen(buf);
    buf[6] = buf[7] = buf[8] = 0;
    if (fwrite(buf, sizeof(char), len, f_out) != len) {
        fclose(f_in);
        fclose(f_out);
        hoz_echo(412, foo);
        return 412;
    }

    sprintf(bar, HOZ_CUTTOFILE, hoz_nopath(foo));
    hoz_print(bar);

    for (;;) {
        if (partsize <= FILESTREAMSIZE) {
            len = (size_t) fread(buf, sizeof(char), FILESTREAMSIZE, f_in);
            if (fwrite(buf, sizeof(char), len, f_out) != len) {
                fclose(f_in);
                fclose(f_out);
                hoz_echo(412, foo);
                return 412;
            }
            if (showprogress) {
                hoz_print(PROGRMETERSTR);       /* progress meter? */
            }
            bfile = len;
            btotal += len;
            fclose(f_out);

            hoz_lf();
            sprintf(bar, HOZ_PROGRESS, btotal,
                    fullsize,
                    (float) ((float) btotal / (float) fullsize) * 100);
            hoz_print(bar);
            hoz_lf();

            if (feof(f_in)) {
                break;
            }
            ++i;
            sprintf(baz, "%s.%u", ifnopath, i);
            mergepath(outpath, baz, foo);
            remove(foo);
            f_out = fopen(foo, "ab");
            if (!f_out) {
                fclose(f_in);
                hoz_echo(407, foo);
                return 407;
            }
            sprintf(bar, HOZ_CUTTOFILE, hoz_nopath(foo));
            hoz_print(bar);
        } else {
            len = (size_t) fread(buf, sizeof(char), FILESTREAMSIZE, f_in);
            if (bfile + len < partsize) {
                if (fwrite(buf, sizeof(char), len, f_out) != len) {
                    fclose(f_in);
                    fclose(f_out);
                    hoz_echo(412, foo);
                    return 412;
                }
                if (showprogress) {
                    hoz_print(PROGRMETERSTR);   /* progress meter? */
                }
                bfile += len;
            } else {
                dif = partsize - bfile;
                if (fwrite(buf, sizeof(char), dif, f_out) != dif) {
                    fclose(f_in);
                    fclose(f_out);
                    hoz_echo(412, foo);
                    return 412;
                }
                if (showprogress) {
                    hoz_print(PROGRMETERSTR);   /* progress meter? */
                }
                bfile += dif;
                fclose(f_out);

                hoz_lf();
                sprintf(bar, HOZ_PROGRESS, btotal,
                        fullsize,
                        (float) ((float) btotal / (float) fullsize) * 100);
                hoz_print(bar);
                hoz_lf();

                ++i;
                bfile = 0;
                sprintf(baz, "%s.%u", ifnopath, i);
                mergepath(outpath, baz, foo);
                remove(foo);
                f_out = fopen(foo, "ab");
                if (!f_out) {
                    fclose(f_in);
                    hoz_echo(407, foo);
                    return 407;
                }
                sprintf(bar, HOZ_CUTTOFILE, hoz_nopath(foo));
                hoz_print(bar);
                if (fwrite(buf + dif, sizeof(char), len - dif, f_out) !=
                    (len - dif)) {
                    fclose(f_in);
                    fclose(f_out);
                    hoz_echo(412, foo);
                    return 412;
                }
                if (showprogress) {
                    hoz_print(PROGRMETERSTR);   /* progress meter? */
                }
                bfile += (len - dif);
            }
            btotal += len;
            if (feof(f_in)) {
                hoz_lf();
                sprintf(bar, HOZ_PROGRESS, btotal, fullsize,
                        (float) ((float) btotal / (float) fullsize) * 100);
                hoz_print(bar);
                hoz_lf();
                break;
            }
        }
    }
    sprintf(foo, "%s.%u", ifname, ++i);
    remove(foo);
    fclose(f_in);
    fclose(f_out);

    /* if the sum of the file sizes isn't the same as the original file size
     * then the operation failed
     */
    if (btotal != fullsize) {
        sprintf(foo, "%u/%u", btotal, fullsize);
        hoz_echo(410, foo);
        return 410;
    }

    /* calculate the time spent in this operation */
    elapsed = (double) (clock() - initime) / CLOCKS_PER_SEC;
    elapsed = (elapsed) ? elapsed : 0.001;      /* can't be 0 seconds! */

    /* yes */
    hoz_lf();
    sprintf(bar, HOZ_CUTEND, hoz_nopath(ifname), btotal, elapsed,
            (size_t) ((double) btotal / elapsed), outpath);
    hoz_print(bar);
    hoz_lf();
    return 0;
}

/**
 * hoz_paste_main - paste files main function
 * @ifname: "file.0" file name
 */
int hoz_paste_main(const char *ifname)
{
    FILE *f_in, *f_out;         /* file handles */
    clock_t initime;            /* to calculate the time spent */
    unsigned char buf[FILESTREAMSIZE + 1],      /* buffer to copy */
     foo[MAXLEN],               /* current 'file.n' filename */
     bar[MAXLEN],               /* blah */
     basename[MAXLEN],          /* base filename (file.*) */
     origfname[MAXLEN], *outfname;
    size_t i,                   /* foobar */
     len,                       /* bytes read */
     bfile,                     /* bytes read in current file file.n */
     btotal;                    /* total bytes read */
    double elapsed;             /* total time elapsed */

    /* verifying that the input filename ends in ".0" */
    if (ifname[strlen(ifname) - 1] != '0'
        || ifname[strlen(ifname) - 2] != '.') {
        hoz_echo(403, NULL);
        return 403;
    }

    /* error if the input file can't be opened */
    f_in = fopen(ifname, "r");
    if (!f_in) {
        hoz_echo(404, ifname);
        return 404;
    }
    fclose(f_in);

    /* retrieving header info */
    i = hoz_paste_hr(ifname, origfname);

    /* if hoz_paste_hr() returns an error, end process */
    if (i) {
        return i;
    }

    /* storing the base file name, just removing the "0" from "file.0" */
    strcpy(basename, ifname);
    basename[strlen(basename) - 1] = 0;

    /* total bytes read = 0 */
    btotal = 0;

    outfname =
        (char *) malloc(sizeof(char) *
                        (strlen(origfname) + strlen(outpath) + 3));
    mergepath(outpath, origfname, outfname);
    /* if the file exists and !forceow, ask what to do */
    if (!forceow && isfile(outfname) && !hoz_replace_ask(outfname)) {
        free(outfname);
        return 302;
    }

    /* removing the output file if it already exists */
    remove(outfname);

    /* opening the output file: (b)inary (w)rite */
    f_out = fopen(outfname, "wb");
    /* error if can't be openned */
    if (!f_out) {
        hoz_echo(407, outfname);
        free(outfname);
        return 407;
    }

    /* telling the user what are we doing */
    hoz_lf();
    sprintf(bar, HOZ_BEGINPASTE, origfname, fullsize);
    hoz_print(bar);
    hoz_lf();
    hoz_lf();

    /* store the time */
    initime = clock();

    for (i = 0;; i++) {
        /* generating the "file.n" string, storing it in foo */
        sprintf(foo, "%s%d", basename, i);
        /* openning the input file: (b)inary (r)ead */
        f_in = fopen(foo, "rb");
        /* bytes read in file = 0 */
        bfile = 0;

        if (!f_in) {
            break;              /* last file, end */
        } else {
            /* extracting file.n... */
            sprintf(bar, HOZ_PASTEFILE, hoz_nopath(foo));
            hoz_print(bar);
            if (i == 0) {
                /* if we are extracting the first file (*.0),
                 * discard the header
                 */
                fread(buf, sizeof(char), headersize, f_in);
            }
            for (;;) {
                /* appending file.n to the output file */
                len =
                    (size_t) fread(buf, sizeof(char), FILESTREAMSIZE,
                                   f_in);
                if (len) {
                    if (fwrite(buf, sizeof(char), len, f_out) != len) {
                        fclose(f_in);
                        fclose(f_out);
                        hoz_echo(412, outfname);
                        free(outfname);
                        return 412;
                    }
                    /* fwrite(buf, sizeof(char), len, f_out); *//* argh! */
                    btotal += len;
                    bfile += len;
                }
                if (showprogress) {
                    hoz_print(PROGRMETERSTR);   /* progress meter? */
                }
                if (feof(f_in)) {
                    break;
                }
            }
            /* displays info... */
            hoz_lf();
            sprintf(bar, HOZ_PROGRESS, btotal,
                    fullsize,
                    (float) ((float) btotal / (float) fullsize) * 100);
            hoz_print(bar);
            hoz_lf();
        }
        /* close the file.n handle */
        fclose(f_in);
        if (bfile < partsize) {
            /* if the current file.n file is smaller than the size defined in
             * the file.0 header for a partial file, end process
             */
            break;
        }
    }
    /* close file handles */
    fclose(f_out);

    /* if the extracted file size isn't the same as the file defined in the
     * file.0  header, then the operation failed
     */
    if (btotal != fullsize) {
        if (btotal < fullsize) {
            hoz_lf();
            sprintf(bar, HOZ_PASTEMISSING, foo);
            hoz_print(bar);
            hoz_lf();
        }
        sprintf(foo, "%u/%u", btotal, fullsize);
        hoz_echo(406, foo);
        free(outfname);
        return 406;
    }

    /* calculate the time spent in this operation */
    elapsed = (double) (clock() - initime) / CLOCKS_PER_SEC;
    elapsed = (elapsed) ? elapsed : 0.001;      /* can't be 0 seconds! */

    /* yes */
    hoz_lf();
    sprintf(bar, HOZ_PASTEEND, origfname, btotal, elapsed,
            (size_t) ((double) btotal / elapsed), outpath);
    hoz_print(bar);
    hoz_lf();
    free(outfname);
    return 0;
}

/**
 * hoz_paste_hr - reads the header from the file.0 file
 * @ifname: "file.0" filename
 */
int hoz_paste_hr(const char *ifname, const char *origfname)
{
    int i, read, ssize;
    char buf[FILESTREAMSIZE + 1], aux[MAXLEN], *foo, *bar;
    FILE *f;

    bar = (char *) origfname;
    headersize = 0;
    ssize = FILESTREAMSIZE;
    if (ssize < 512) {
        ssize = 512;
    }
    f = fopen(ifname, "rb");
    read = (int) fread(buf, sizeof(char), ssize, f);
    foo = buf;
    if (!read || strncmp(foo, "?????", 5)) {
        hoz_echo(405, ifname);
        return 405;
    }
    foo += 5;
    headersize += 5;
    i = 0;
    for (i = 0; *foo != '?'; foo++, i++, headersize++) {
        if (i == 20) {
            hoz_echo(405, ifname);
            return 405;
        }
    }
    if (strncmp(foo, "?????", 5)) {
        hoz_echo(405, ifname);
        return 405;
    }
    foo += 5;
    headersize += 5;
    if (*foo == '?') {
        hoz_echo(405, ifname);
        return 405;
    }
    for (i = 0; *foo != '?'; foo++, i++, headersize++) {
        if (i == 255) {
            hoz_echo(405, ifname);
            return 405;
        }
        *bar++ = *foo;
    }
    *bar = '\0';
    if (strncmp(foo, "?????", 5)) {
        hoz_echo(405, ifname);
        return 405;
    }
    foo += 5;
    headersize += 5;
    if (*foo == '?') {
        hoz_echo(405, ifname);
        return 405;
    }
    for (i = 0; *foo != '?'; foo++, i++, headersize++) {
        if (i == 255) {
            hoz_echo(405, ifname);
            return 405;
        }
        aux[i] = *foo;
    }
    aux[i] = 0;
    fullsize = (int) atol(aux);
    if (!fullsize) {
        hoz_echo(405, ifname);
        return 405;
    }
    if (strncmp(foo, "?????", 5)) {
        hoz_echo(405, ifname);
        return 405;
    }
    foo += 5;
    headersize += 5;
    if (*foo == '?') {
        hoz_echo(405, ifname);
        return 405;
    }
    for (i = 0; *foo != '?'; foo++, i++, headersize++) {
        if (i == 255) {
            hoz_echo(405, ifname);
            return 405;
        }
        aux[i] = *foo;
    }
    aux[i] = 0;
    partsize = (int) atol(aux);
    if (!partsize) {
        hoz_echo(405, ifname);
        return 405;
    }
    if (strncmp(foo, "?????", 5)) {
        hoz_echo(405, ifname);
        return 405;
    }
    foo += 5;
    headersize += 5;
    fclose(f);
    return 0;
}

/**
 * fsize - Retrieves the size of a file
 * @path: filename
 */
size_t fsize(const char *path)
{
    struct stat stats;
    stat(path, &stats);
    return (size_t) stats.st_size;
}

/**
 * isfile - a file exists?
 * @path: path to file
 */
int isfile(const char *path)
{
    struct stat stats;
    return (!stat(path, &stats) && S_ISREG(stats.st_mode));
}

/**
 * isdir - a directory exists?
 * @path: path to dir
 */
int isdir(const char *path)
{
    struct stat stats;
    return (!stat(path, &stats) && S_ISDIR(stats.st_mode));
}

/**
 * hoz_nopath - returns a file name, without the path
 * @file: the full filename
 */
char *hoz_nopath(const char *file)
{
    char *aux;
    aux = (char *) (file + strlen(file));
    while (*aux != HOZ_PATHSEP) {
        if (aux == file) {
            return aux;
        }
        aux--;
    }
    return aux + 1;
}

/**
 * mergepath - returns a file name, without the path
 * @dir: the full diectory
 * @fname: the full filename
 * @out: the output
 */
int mergepath(const char *dir, const char *fname, char *out)
{
    const char *dirp;
    dirp = dir;

    if (!fname || !*fname) {
        return -1;
    }
    if (strcmp(dir, ".")) {
        while (*dirp) {
            *out++ = *dirp++;
        }
        if (dirp > dir && *(dirp - 1) != HOZ_PATHSEP) {
            *out++ = HOZ_PATHSEP;
        }
    }
    while (*fname) {
        *out++ = *fname++;
    }
    *out = '\0';
    return 0;
}

/*
 * atolp(string)
 *   returns a _positive_ number extracted from the string
 *   if the string wasn't a number a 0 will be returned
 */
int atolp(const char *s)
{
    int n = 0;
    char *c = (char*)s;
    while (*c) {
        if (*c >= '0' && *c <= '9') {
            n *= 10;
            n += (*c++ - '0');
        } else {
            return 0;
        }
    }
    return n;
}

/*
 * atolmp(string, multiplier)
 *   returns a _positive_ number extracted from the string and multiplies it
 *   always returns an integer, 0 if the string wasn't a number
 */

int atolmp(const char *s, const int mult)
{
    size_t n = 0, p = 0, d = 1;
    char *c = (char*)s;
    while (*c) {
	if (*c == '.') {
	    if (p) {
		return 0; /* more than one '.' in the string? error */
	    }
	    p = 1;
	    *c++;
	} else if (*c >= '0' && *c <= '9') {
	    if (p) {
		d *= 10; /* final decimal division */
	    }
            n *= 10;
            n += (*c++ - '0');
        } else {
            return 0;
        }
    }
    if (d) {
	n /= d;
    }
    n *= (size_t)mult;
    if (n < 0) {
	printf("DA FOC!\n");
	/* number is too big for size_t, error */
	return 0;
    }
    return n;
}


syntax highlighted by Code2HTML, v. 0.9.1