/*
From: wang@apache          Article 982 of alt.binaries.pictures.utilities
Article: 982 of alt.binaries.pictures.utilities
From: wang@apache (Wang Gang)
Newsgroups: alt.binaries.pictures.utilities
Subject: wang.c Version 3.1
Message-ID: <1992Oct17.161357.3741@udel.edu>
Date: 17 Oct 92 16:13:57 GMT
Sender: usenet@udel.edu (USENET News Service)
Distribution: usa
Organization: Delaware Technical & Community College
Lines: 465
Nntp-Posting-Host: apache.dtcc.edu

Thanks to my friend Robert Jen, who rewrote wang.c into a neat documented
program.

Also fixed in this version, pictures without a proper "part" indication
are recognizable by wang.c thus wang.c can decode a little bit more files.
*/
 /* NAME         : wang.c
 * DESCRIPTION  : Extracts any number of multiple section uuencoded files
 *              :   from a single file.
 * SYNOPSIS     : wang <datafile>
 * WRITTEN BY   : wang@apache.dtcc.edu
 * MODIFIED BY  : Robert Jen (rjen@ctp.com, 10/16/92) -- Completely cleaned up.
 *              :   Changed system("rm wang.temp") to unlink() call.
 *              :   Changed close() and [re]open() to call to lseek().
 *              :   Removed trailing space from search string "Article".
 */

#include <ctype.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>

#define LENGTH      70
#define LINELEN     256
#define FILENAMEMAX 256
#define MAXFILES    2048

struct superblock
{
    char        Filename[FILENAMEMAX];
    int         Partno;
    int         Parts;
    long int    Offsetbegin;
    long int    Offsetend;
} filereg[MAXFILES];

int filecount = 0;
long int lpt = 0;

#define TRUE 1
#define FALSE 0

int copyone();
int exportone();
int whereispart();
struct superblock nextfilereg();
void out();
void writeto();
void getinfo();
char *parse();


/******************************************************************/
main(argc, argv)
int argc;
char **argv;
{
    int num, fd;
    char *filename = "wang.temp";
    struct superblock reg;
    FILE *fpt;

    if (argc != 2)
    {
        fprintf(stderr, "\nUsage: %s filename\n", argv[0]);
        exit(1);
    }

    if ((fpt = fopen(argv[1], "r")) == NULL)
    {
        fprintf(stderr, "\nUnable to open file %s to read", argv[1]);
        exit(2);
     }

    if ((fd = open(filename, O_RDWR | O_CREAT, 0600)) == -1)
    {
        fprintf(stderr, "\nUnable to open temporary file %s (errno %d)\n",
                filename, errno);
        exit(3);
    }

    /* remove file from directory.  It won't really go away until we */
    /*  close it. */
    unlink(filename);

    for (num = 0; ; num++)
    {
        printf("\nExtracting file: %d", num);
        fflush(stdout);
        if (copyone(fpt, fd)) /* reach file end */
            break;
        printf("Done");
    }

    /*-----------------decoding-------------------*/
    /* rewind to beginning of file */
    lseek(fd, 0L, 0);

    reg = nextfilereg();
    while (*(reg.Filename))
    {
        fprintf(stderr, "\nDecoding file %s ...", reg.Filename);
        if (exportone(reg, fd) == 0) /*successful return */
        {
            fprintf(stderr, "Done    ");
        }
        reg = nextfilereg();
    }

    printf("\n\7:-) Job Done.\n");
    close(fd);
}  /* end of main */



/**********************************************************************
 * copy one piece file (extracted from BEGIN to END) from source file *
 * to temp                                                            *
 * return 1:reach source file end;  return 0: one piece extracted     *
 *********************************************************************/
int
copyone(from, to)
FILE    *from;
int     to; /* filedescriber */
{
    int len;
    char buf[LINELEN + 1], a[LINELEN + 1], b[LINELEN + 1];
    char *res;
    static int linenum = 0; /* mainly for debugging purposes */

    /* wait for either file end or meaningful string:Subject, BEGIN */
    while (res = fgets(buf, LINELEN, from))
    {
        linenum++;
        if (strncmp(buf, "Subject", 7) == 0) /*equals*/
            getinfo(buf);
        else if (((strncmp(buf, "begin ", 6) == 0) && isdigit(buf[6]))
                || ((buf[0] == 'M')
                 && ((strlen(buf) > 59) && (strlen(buf) < 71))
                && (strncmp(buf, "Message-Id", 10) != 0)))
        {
            a[0] = '\0';
            b[0] = '\0';
            writeto(buf, to);
            break;
        }
    }

    if (!res)
        return(1); /* reach file end */

    while (res = fgets(buf, LINELEN, from))
    {
        linenum++;
        if (strncmp(buf, "end", 3) == 0)
        {
            if (b[0])
            { /* fprintf(stderr, "Restoring \"%s\"\n", b); */
                writeto(b, to);
            }
            if (a[0])
            { /* fprintf(stderr, "Restoring \"%s\"\n", a);*/
                writeto(a, to);
            }
            writeto(buf, to);
            break;
        }
        else if (strncmp(buf, "END", 3) == 0)
            break; /* successful, return 0 */
        /* else if (strncmp(buf, "Article ", 8) == 0) */
        else if (strncmp(buf, "Article", 7) == 0)
            break;
        else
        {
            len = strlen(buf);
            if ((buf[0] != 'M' ||
                    len < 60 ||
                    len > 70 ||
                    (strncmp(buf, "Message-ID", 10) == 0))
                    && (strncmp(buf, "begin", 5)))
            {
                /* fprintf(stderr, "Rejecting \"%s\"\n", buf);*/
                strcpy(b, a);
                strcpy(a, buf);
                continue;
            }
            a[0] = '\0';
            b[0] = '\0';
            writeto(buf, to);
        }
    }

    /* if (!res)    fprintf(stderr, "warning:reach file end without end"); */

    return(0);
} /* end of copyone */



/*******************************************************************
 * pipe all parts of a file  from temp in proper order to uudecode *
 * return 0:sucessful;  return 1:part not found                    *
 *******************************************************************/
int
exportone(reg, fd)
struct superblock reg;
int fd; /* file descriptor */
{
    int count, where;
    int part = 0;
    FILE *uu;

    for (count = 1; count < reg.Parts + 1; count++)
    {
        if (whereispart(count, reg) == FALSE)
        {
            fprintf(stderr, "Part %d not found, decoding of file %s aborted\n",
                    count, reg.Filename);
            return(1); /* error return. */
        }
    }

    fflush(stdout);
    if ((uu = popen("uudecode", "w")) == NULL)
    {
        fprintf(stderr, "\nUnable to open the pipe to write.\n");
        exit(0);
    }

    if (!((where = whereispart(0, reg)) == FALSE))
        out(fd, where, uu);

    for (count = 1; count < reg.Parts + 1; count++) /* there can be part 0 */
    {
        where = whereispart(count, reg);
        out(fd, where, uu);
    }

    pclose(uu);
    return(0);
} /* end of exportone */



/***********************************************************/
struct superblock
nextfilereg()
{
    int count;
    static struct superblock nulblock =
    {
        "", 0, 0, 0
    };

    for (count = 1; count < filecount + 1; count++) /* filecount start at 1*/
        if (*(filereg[count].Filename))
            return(filereg[count]);

    return(nulblock); /* don't worry, when success, it won't come here*/
}/* end of nextfilereg*/



/**************************************************************/
void
writeto(buf, fd)
char buf[LINELEN];
int  fd; /* file descriptor */
{
    write(fd, buf, LENGTH);
     lpt = lpt + LENGTH; /* lpt is global, initiated as 0 */
    filereg[filecount].Offsetend = lpt - 1;
    /* filecount will not change until next getinfo */

    return;
} /* end of writeto */



/**************************************************************************/
int
whereispart(partno, reg)
int partno;
struct superblock reg;
{
    int count;

    /* fprintf(stderr, "\n%s == %s\n", filereg[1].Filename, reg.Filename); */
    for (count = 1; count < filecount + 1; count++)
    {
        if ((filereg[count].Partno == partno)
                && (strncmp(filereg[count].Filename, reg.Filename, 20) == 0))
            return(count);
    }

    /* partno not found */
    for (count = 1; count < filecount + 1; count++)
    {
        if ((strncmp(filereg[count].Filename, reg.Filename, 20) == 0)
                && (!(partno == 0)))
            *(filereg[count].Filename) = '\0';
    }

    return(FALSE);
} /* end of whereispart */



/*******************************************************************/
void
out(fd, filecountno, uu)
int     fd;
int     filecountno;
char    *uu;
{
    char buf[LINELEN];
    long int  count;

    for (count = filereg[filecountno].Offsetbegin;
            count < filereg[filecountno].Offsetend; count += LENGTH)
    {
        lseek(fd, count, 0);
        read(fd, buf, LENGTH);
        fputs(buf, uu);
    }

    *(filereg[filecountno].Filename) = '\0';
    /*mark it DONE, so it won't be found in nextfilereg() */

    return;
} /* end of out */



/*****************************************************/
int
atoin(string)
char string[80];
{
    int r = 0;
    int count = 0;

    while (!isdigit(string[count++]))
        ;

    r = string[count - 1] - '0';

    while (isdigit(string[count++]))
        r = r * 10 + string[count - 1] - '0';

    return(r);
} /* end of atoin */



#define END (buf[count-1]=='\0')
/*#define TRASH  {\
    fprintf(stderr, "           @@Sorry, unrecognized format.\n");\
    *(filereg[filecount].Filename) = '\0';\
    return;\
}
*/
#define TRASH {\
     filereg[filecount].Parts=1;\
     filereg[filecount].Partno=1;\
     filereg[filecount].Offsetbegin=lpt;\
     fprintf(stderr,"%s, part %d of %d, starting %d ...",\
	     filereg[filecount].Filename,filereg[filecount].Partno,\
	     filereg[filecount].Parts,   filereg[filecount].Offsetbegin);\
     return;\
}
/************************************************************************/
void
getinfo(buf)
char buf[LINELEN];
{

    int count = 0;
    int count1 = 0;
    char temp[LINELEN];

    fprintf(stderr, "\n <--%s", buf);

    filecount++;

    while ((buf[count++] != ':') && (!END))
        ;

    if END
        TRASH

    while ((buf[count++] == ' ') && (!END))
        ;

    if END
        TRASH;

    count--;

    while ((buf[count++] != '(')
            && (buf[count - 1] != '[')
            && (buf[count - 1] != '{')
            && (!END))
    {
        if ((buf[count - 1] == 'p')
                && (buf[count] == 'a')
                && (buf[count + 1] == 'r')
                && (buf[count + 2] == 't'))
        {
                        break;
        }

        if (buf[count - 1] == ' ')
            if (isdigit(buf[count]))
                break;

        temp[count1++] = buf[count - 1];
    }

        temp[count1] = '\0';
        strcpy(filereg[filecount].Filename, temp);

    if END
      TRASH;

    count1 = 0;
    while ((buf[count++] != '/')
            &&(!END))
    {
        if ((buf[count - 1] == 'o')
                && (buf[count] == 'f'))
            break;
        temp[count1++] = buf[count - 1];
    }

    if END
        TRASH
    else
    {
        temp[count1] = '\0';
        filereg[filecount].Partno = atoin(temp);
    }

    count1 = 0;
    while ((buf[count++] != ')')
            && (buf[count - 1] != ']')
            && (buf[count - 1] != '}')
            && (!END))
        temp[count1++] = buf[count - 1];
    temp[count1] = '\0';

    filereg[filecount].Parts = atoin(temp);

    if (filereg[filecount].Parts == 0)
        TRASH
    else
    {
        filereg[filecount].Offsetbegin = lpt;
        fprintf(stderr, "%s, part %d of %d, starting %d...",
        filereg[filecount].Filename, filereg[filecount].Partno,
        filereg[filecount].Parts, filereg[filecount].Offsetbegin);
    }

    return;
} /* end of getinfo */
