/*
 * This file is part of uudeview, the simple and friendly multi-part multi-
 * file uudecoder  program  (c) 1994-2001 by Frank Pilhofer. The author may
 * be contacted at fp@fpx.de
 *
 * 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.
 */

/*
 * These are very central functions of UUDeview. Here, we scan a file
 * and decide whether it contains encoded data or not. ScanPart() must
 * be called repeatedly on the same file until feof(file). Each time,
 * it returns information about the next part found within.
 */

#ifdef HAVE_CONFIG_H
    #include "config.h"
#endif

#ifdef SYSTEM_WINDLL
    #include <windows.h>
#endif
#ifdef SYSTEM_OS2
    #include <os2.h>
#endif

#include <stdio.h>

#ifdef STDC_HEADERS
    #include <stdlib.h>
    #include <string.h>
#endif
#ifdef HAVE_MALLOC_H
    #include <malloc.h>
#endif
#ifdef HAVE_UNISTD_H
    #include <unistd.h>
#endif
#ifdef HAVE_MEMORY_H
    #include <memory.h>
#endif
#ifdef HAVE_ERRNO_H
    #include <errno.h>
#endif

#include <gdefs.h>
#include <gctype.h>
#include <uudeview.h>
#include <uuint.h>
#include <fptools.h>
#include <uustring.h>

char * uuscan_id = "$Id$";

/*
 * Header fields we recognize as such. See RFC822. We add "From ",
 * the usual marker for a beginning of a new message, and a couple
 * of usual MDA, News and MIME headers.
 * We make a distinction of MIME headers as we need the difference
 * to scan the bodies from partial multipart messages.
 */

static char *knownmsgheaders[] =
{
    "From ", "Return-Path:", "Received:", "Reply-To:",
    "From:", "Sender:", "Resent-Reply-To:", "Resent-From:",
    "Resent-Sender:", "Date:", "Resent-Date:", "To:",
    "Resent-To:", "Cc:", "Bcc:", "Resent-bcc:",
    "Message-ID:", "Resent-Message-Id:", "In-Reply-To:",
    "References:", "Keywords:", "Subject:", "Comments:",

    "Delivery-Date:", "Posted-Date:", "Received-Date:",
    "Precedence:",

    "Path:", "Newsgroups:", "Organization:", "Lines:",
    "NNTP-Posting-Host:",
    NULL
};

static char *knownmimeheaders[] =
{
    "Mime-Version:",  "Content-Transfer-Encoding:",
    "Content-Type:", "Content-Disposition:",
    "Content-Description:", "Content-Length:",
    NULL
};

/*
 * for MIME (plaintext) parts without filename
 */
int mimseqno;

/*
 * how many lines do we read when checking for headers
 */
#define WAITHEADER  10

/*
 * The stack for encapsulated Multipart messages
 */
#define MSMAXDEPTH  3

int       mssdepth = 0;
scanstate multistack[MSMAXDEPTH+1];

/*
 * The state and the local envelope
 */
headers   localenv;
scanstate sstate;

/*
 * mallocable areas
 */

char *uuscan_shlline;
char *uuscan_pvvalue;
char *uuscan_phtext;
char *uuscan_sdline;
char *uuscan_sdbhds1;
char *uuscan_sdbhds2;
char *uuscan_spline;

/*
 * Macro: print cancellation message in UUScanPart
 */

#define SPCANCEL()  {UUMessage(uuscan_id,__LINE__,UUMSG_NOTE,uustring(S_SCAN_CANCEL));*errcode=UURET_CANCEL;goto ScanPartEmergency;}

/*
 * Is line empty? A line is empty if it is composed of whitespace.
 */

static int
IsLineEmpty (char *data)
{
    if (data == NULL) return 0;
    while (*data && isspace (*data)) data++;
    return ((*data)?0:1);
}

/*
 * Scans a potentially folded header line from the input file. If
 * initial is non-NULL, it is the first line of the header, useful
 * if the calling function just coincidentally noticed that this is
 * a header.
 * RFC0822 does not specify a maximum length for headers, but we
 * truncate everything beyond an insane value of 1024 characters.
 */

static char *
ScanHeaderLine (FILE *datei, char *initial)
{
    char *ptr=uuscan_shlline;
    int llength, c;
    long curpos;
    int hadcr;

    if (initial)
    {
        _FP_strncpy (uuscan_shlline, initial, 1024);
    }
    else
    {
        /* read first line */
        if (feof (datei) || ferror (datei))
            return NULL;
        if (_FP_fgets (uuscan_shlline, 1023, datei) == NULL)
            return NULL;
        uuscan_shlline[1023] = '\0';
    }

    llength = strlen (uuscan_shlline);
    hadcr   = 0;

    /* strip whitespace at end */
    ptr = uuscan_shlline + llength;
    while (llength && isspace(*(ptr-1)))
    {
        if (*(ptr-1) == '\012' || *(ptr-1) == '\015')
            hadcr = 1;
        ptr--;
        llength--;
    }
    if (llength == 0)
    {
        uuscan_shlline[0] = '\0';
        return uuscan_shlline;
    }

    while (!feof (datei))
    {
        c = fgetc (datei);
        if (feof (datei))
            break;

        /*
         * If the line didn't have a CR, it was longer than 256 characters
         * and is continued anyway.
         */

        if (hadcr==1 && c != ' ' && c != '\t')
        {
            /* no LWSP-char, header line does not continue */
            ungetc (c, datei);
            break;
        }
        while (!feof (datei) && (c == ' ' || c == '\t'))
            c = fgetc (datei);

        if (!feof (datei))
            ungetc (c, datei);    /* push back for fgets() */

        /* insert a single LWSP */
        if (hadcr==1 && llength < 1023)
        {
            *ptr++ = ' ';
            llength++;
        }
        *ptr = '\0'; /* make lint happier */

        if (feof (datei))
            break;

        /* read next line */
        curpos = ftell (datei);
        if (_FP_fgets (uugen_inbuffer, 255, datei) == NULL)
            break;
        uugen_inbuffer[255] = '\0';

        if (IsLineEmpty (uugen_inbuffer))   /* oops */
        {
            fseek (datei, curpos, SEEK_SET);
            break;
        }

        _FP_strncpy (ptr, uugen_inbuffer, 1024-llength);

        /*
         * see if line was terminated with CR. Otherwise, it continues ...
         */
        c = strlen (ptr);
        if (c>0 && (ptr[c-1] == '\012' || ptr[c-1] == '\015'))
            hadcr = 1;
        else
            hadcr = 0;

        /*
         * strip whitespace
         */

        ptr     += c;
        llength += c;
        while (llength && isspace(*(ptr-1)))
        {
            ptr--;
            llength--;
        }
    }
    *ptr = '\0';

    if (llength == 0)
        return NULL;

    return uuscan_shlline;
}

/*
 * Extract the value from a MIME attribute=value pair. This function
 * receives a pointer to the attribute.
 */
static char *
ParseValue (char *attribute)
{
    char *ptr=uuscan_pvvalue;
    int length=0;

    if (attribute == NULL)
        return NULL;

    while ((isalnum(*attribute) || *attribute=='_') && *attribute != '=')
        attribute++;

    while (isspace(*attribute))
        attribute++;

    if (*attribute == '=')
    {
        attribute++;
        while (isspace (*attribute))
            attribute++;
    }
    else
        return NULL;

    if (*attribute == '"')
    {
        /* quoted-string */
        attribute++;
        while (*attribute && *attribute != '"' && length < 255)
        {
            if (*attribute == '\\')
                *ptr++ = *++attribute;
            else
                *ptr++ = *attribute;
            attribute++;
            length++;
        }
        *ptr = '\0';
    }
    else
    {
        /* tspecials from RFC1521 */

        while (*attribute && !isspace (*attribute) &&
                *attribute != '(' && *attribute != ')' &&
                *attribute != '<' && *attribute != '>' &&
                *attribute != '@' && *attribute != ',' &&
                *attribute != ';' && *attribute != ':' &&
                *attribute != '\\' &&*attribute != '"' &&
                *attribute != '/' && *attribute != '[' &&
                *attribute != ']' && *attribute != '?' &&
                *attribute != '=' && length < 255)
            *ptr++ = *attribute++;

        *ptr = '\0';
    }
    return uuscan_pvvalue;
}

/*
 * Extract the information we need from header fields
 */

static headers *
ParseHeader (headers *theheaders, char *line)
{
    char **variable=NULL;
    char *value = NULL, *ptr, *thenew;
    int delimit = 0, length;

    if (line == NULL)
        return theheaders;

    if (_FP_strnicmp (line, "From:", 5) == 0)
    {
        if (theheaders->from) return theheaders;
        variable = &theheaders->from;
        value    = line+5;
        delimit  = 0;
    }
    else if (_FP_strnicmp (line, "Subject:", 8) == 0)
    {
        if (theheaders->subject) return theheaders;
        variable = &theheaders->subject;
        value    = line+8;
        delimit  = 0;
    }
    else if (_FP_strnicmp (line, "To:", 3) == 0)
    {
        if (theheaders->rcpt) return theheaders;
        variable = &theheaders->rcpt;
        value    = line+3;
        delimit  = 0;
    }
    else if (_FP_strnicmp (line, "Date:", 5) == 0)
    {
        if (theheaders->date) return theheaders;
        variable = &theheaders->date;
        value    = line+5;
        delimit  = 0;
    }
    else if (_FP_strnicmp (line, "Mime-Version:", 13) == 0)
    {
        if (theheaders->mimevers) return theheaders;
        variable = &theheaders->mimevers;
        value    = line+13;
        delimit  = 0;
    }
    else if (_FP_strnicmp (line, "Content-Type:", 13) == 0)
    {
        if (theheaders->ctype) return theheaders;
        variable = &theheaders->ctype;
        value    = line+13;
        delimit  = ';';

        /* we can probably extract more information */
        if ((ptr = _FP_stristr (line, "boundary")) != NULL)
        {
            if ((thenew = ParseValue (ptr)))
            {
                if (theheaders->boundary) free (theheaders->boundary);
                theheaders->boundary = _FP_strdup (thenew);
            }
        }
        if ((ptr = _FP_stristr (line, "name")) != NULL)
        {
            if ((thenew = ParseValue (ptr)))
            {
                if (theheaders->fname) free (theheaders->fname);
                theheaders->fname = _FP_strdup (thenew);
            }
        }
        if ((ptr = _FP_stristr (line, "id")) != NULL)
        {
            if ((thenew = ParseValue (ptr)))
            {
                if (theheaders->mimeid) free (theheaders->mimeid);
                theheaders->mimeid = _FP_strdup (thenew);
            }
        }
        if ((ptr = _FP_stristr (line, "number")) != NULL)
        {
            if ((thenew = ParseValue (ptr)))
            {
                theheaders->partno = atoi (thenew);
            }
        }
        if ((ptr = _FP_stristr (line, "total")) != NULL)
        {
            if ((thenew = ParseValue (ptr)))
            {
                theheaders->numparts = atoi (thenew);
            }
        }
    }
    else if (_FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0)
    {
        if (theheaders->ctenc) return theheaders;
        variable = &theheaders->ctenc;
        value    = line+26;
        delimit  = ';';
    }
    else if (_FP_strnicmp (line, "Content-Disposition:", 20) == 0)
    {
        /*
         * Some encoders mention the original filename as parameter to
         * Content-Type, others as parameter to Content-Disposition. We
         * do prefer the first solution, but accept this situation, too.
         * TODO: Read RFC1806
         */
        if ((ptr = _FP_stristr (line, "name")) != NULL)
        {
            if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL)
            {
                theheaders->fname = _FP_strdup (thenew);
            }
        }
        variable = NULL;
    }
    else
    {
        /*
         * nothing interesting
         */
        return theheaders;
    }

    /*
     * okay, so extract the actual data
     */
    if (variable)
    {
        length = 0;
        ptr = uuscan_phtext;

        while (isspace (*value))
            value++;
        while (*value && (delimit==0 || *value!=delimit) &&
                *value != '\012' && *value != '\015' && length < 255)
        {
            *ptr++ = *value++;
            length++;
        }
        while (length && isspace(*(ptr-1)))
        {
            ptr--;
            length--;
        }
        *ptr = '\0';

        if ((*variable = _FP_strdup (uuscan_phtext)) == NULL)
            return NULL;
    }

    return theheaders;
}

/*
 * is this a header line we know about?
 */

static int
IsKnownHeader (char *line)
{
    char **iter = knownmsgheaders;

    while (iter && *iter)
    {
        if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
            return 1;
        iter++;
    }

    iter = knownmimeheaders;

    while (iter && *iter)
    {
        if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
            return 2;
        iter++;
    }

    return 0;
}

/*
 * Scan a header
 */

int
UUScanHeader (FILE *datei, headers *envelope)
{
    char *ptr;

    while (!feof (datei))
    {
        if ((ptr = ScanHeaderLine (datei, NULL)) == NULL)
            break;
        if (*ptr == '\0' || *ptr == '\012' || *ptr == '\015')
            break;
        ParseHeader (envelope, ptr);
    }
    return 0;
}

/*
 * Scan something for encoded data and fill the fileread* structure.
 * If boundary is non-NULL, we stop after having read it. If Check-
 * Headers != 0, we also stop after we've found uu_headercount recog-
 * nized header lines.
 * If we have a boundary, then we also don't accept Base64; MIME mails
 * really should handle this properly.
 * We return -1 if something went wrong, 0 if everything is normal,
 * 1 if we found a new header and 2 if we found a boundary.
 * In MIME message bodies (not multiparts), we also disable our reduced
 * MIME handling.
 */

static int
ScanData (FILE *datei, int *errcode, char *boundary, int ismime,
          int checkheaders, fileread *result)
{
    char *line=uuscan_sdline, *bhds1=uuscan_sdbhds1, *bhds2=uuscan_sdbhds2;
    static char *ptr, *p2, *p3=NULL, *bhdsp, bhl;
    int isb64[10], isuue[10], isxxe[10], isbhx[10], iscnt;
    int cbb64, cbuue, cbxxe, cbbhx;
    int bhflag=0, vflag, haddh=0, hadct=0;
    int bhrpc=0, bhnf=0, c, hcount, lcount, blen=0;
    int encoding=0, dflag=0, ctline=42;
    int dontcare=0, hadnl=0;
    long preheaders=0, oldposition;
    long yefilesize=0, yepartends=0;
    size_t dcc, bhopc;
    char prevlinefirstchar;

    *errcode = UURET_OK;
    (void) UUDecodeLine (NULL, NULL, 0);          /* init */
    bhdsp = bhds2;

    if (datei == NULL || feof (datei))
        return -1;

    result->startpos = ftell (datei);
    hcount = lcount  = 0;

    for (iscnt=0; iscnt<10; iscnt++)
    {
        isb64[iscnt] = isuue[iscnt] = isxxe[iscnt] = isbhx[iscnt] = 0;
    }

    iscnt = 0;

    if (boundary)
        blen = strlen (boundary);

    line[0] = '\0';
    while (!feof (datei))
    {
        prevlinefirstchar = line[0];
        oldposition = ftell (datei);
        if (_FP_fgets (line, 299, datei) == NULL)
            break;
        if (ferror (datei))
            break;

        line[299] = '\0'; /* For Safety of string functions */

        /*
         * Make Busy Polls
         */

        if (UUBUSYPOLL(ftell(datei),progress.fsize))
        {
            UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
                       uustring (S_SCAN_CANCEL));
            *errcode = UURET_CANCEL;
            break;
        }

        if (IsLineEmpty (line))   /* line empty? */
        {
            hcount = 0;
            hadnl  = 1;
            continue;               /* then ignore */
        }

        if (checkheaders)
        {
            if (IsKnownHeader (line))
            {
                (void) ScanHeaderLine (datei, line);

                if (hcount == 0)
                {
                    preheaders = oldposition;
                    lcount     = 0;
                }
                hcount++;
                lcount++;

                /*
                 * check for the various restart counters
                 */

                if ((hcount >= hlcount.restart) ||
                        (hcount >= hlcount.afterdata && ismime == 0) ||
                        (hcount >= hlcount.afterdata && result->uudet) ||
                        (hcount >= hlcount.afternl   && result->uudet && hadnl))
                {
                    /*
                     * Hey, a new header starts here
                     */
                    fseek (datei, preheaders, SEEK_SET);
                    break;
                }
                /* continue; */
            }
            else if (lcount > WAITHEADER)
            {
                hcount = 0;
                lcount = 0;
                dontcare=0;
            }
            else if (hcount)
            {
                lcount++;
                dontcare=1;
            }
            else
            {
                dontcare=0;
            }
        }
        else
        {
            dontcare=0;
        }

        if (boundary != NULL &&
                line[0] == '-' && line[1] == '-' &&
                strncmp (line+2, boundary, blen) == 0)
        {
            fseek (datei, oldposition, SEEK_SET);
            break;
        }
        if (boundary != NULL && line[0] == 'C' && line[1] == 'o' &&
                _FP_strnicmp (line, "Content-Type:", 13) == 0)
        {
            ptr = ScanHeaderLine (datei, line);
            p2  = (ptr)?_FP_stristr(ptr,"boundary"):NULL;
            p3  = (p2)?ParseValue(p2):NULL;

            if (p3 && strcmp (p3, boundary) == 0)
            {
                fseek (datei, oldposition, SEEK_SET);
                break;
            }
            else
            {
                p3 = NULL;
            }
        }

        if (strncmp      (line, "begin ",       6) == 0 ||
                _FP_strnicmp (line, "<pre>begin ", 11) == 0)
        {
            if ((result->begin || result->end ||
                    result->uudet == B64ENCODED ||
                    result->uudet == BH_ENCODED) && !uu_more_mime)
            {
                fseek (datei, oldposition, SEEK_SET);
                break;
            }

            if (*line == '<')
                ptr = line + 10;
            else
                ptr = line + 5;

            while (*ptr == ' ') ptr++;
            while (isdigit (*ptr))
                result->mode = result->mode * 8 + *ptr++ - '0';
            while (*ptr == ' ') ptr++;

            /*
             * We may have picked up a filename from a uuenview-style header
             */
            _FP_free (result->filename);
            result->filename = _FP_strdup (ptr);
            result->begin    = 1;

            while (isspace (result->filename[strlen(result->filename)-1]))
                result->filename[strlen(result->filename)-1] = '\0';

            continue;
        }

        if ((strncmp (line, "end", 3) == 0) &&
                result->uudet != BH_ENCODED &&
                result->uudet != YENC_ENCODED)
        {
            if (result->uudet == B64ENCODED && result->begin)
                result->uudet = XX_ENCODED;

            if (result->uudet != B64ENCODED)
            {
                if (result->uudet == XX_ENCODED)
                {
                    if (prevlinefirstchar == '+')
                        result->end = 1;
                }
                if (result->uudet == UU_ENCODED)
                {
                    if (prevlinefirstchar == '`')
                        result->end = 1;
                }
                else
                {
                    result->end = 1;
                }
                if (dflag && encoding)
                    result->uudet = encoding;
                continue;
            }
        }

        hadnl = 0;

        /*
         * Detect a UUDeview-Style header
         */

        if ((_FP_strnicmp (line, "_=_ Part ", 9) == 0 ||
                _FP_strnicmp (line, "section ", 8) == 0) &&
                result->uudet != YENC_ENCODED)
        {
            if (result->uudet)
            {
                fseek (datei, oldposition, SEEK_SET);
                break;
            }
            result->partno = atoi (line + 8);
            if ((ptr = _FP_stristr (line, " of ")) != NULL)
            {
                int maxpno = atoi (ptr + 4);
                if(maxpno != 0) result->maxpno = maxpno;
            }
            if ((ptr = _FP_stristr (line, "of file ")) != NULL)
            {
                ptr += 8;
                while (isspace (*ptr)) ptr++;
                p2 = ptr;
                while (isalnum(*p2) || (strchr(uufnchars, *p2)!=NULL))
                    p2++;
                c = *p2;
                *p2 = '\0';
                if (p2 != ptr && result->filename == NULL)
                    result->filename = _FP_strdup (ptr);
                else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL)
                {
                    /*
                     * This file name looks good, too. Let's use it
                     */
                    _FP_free (result->filename);
                    result->filename = _FP_strdup (ptr);
                }
                *p2 = c;
            }
        }

        /*
         * Some reduced MIME handling. Only use if boundary == NULL. Also
         * accept the "X-Orcl-Content-Type" used by some braindead program.
         */
        if (boundary == NULL && !ismime && !uu_more_mime &&
                result->uudet != YENC_ENCODED)
        {
            if (_FP_strnicmp (line, "Content-Type", 12) == 0 ||
                    _FP_strnicmp (line, "X-Orcl-Content-Type", 19) == 0)
            {
                /*
                 * We use Content-Type to mark a new attachment and split the file.
                 * However, we do not split if we haven't found anything encoded yet.
                 */
                if (result->uudet)
                {
                    fseek (datei, oldposition, SEEK_SET);
                    break;
                }
                if ((ptr = strchr (line, ':')) != NULL)
                {
                    ptr++;
                    while (isspace (*ptr)) ptr++;
                    p2 = ptr;
                    while (!isspace (*p2) && *p2 != ';') p2++;
                    c = *p2;
                    *p2 = '\0';
                    if (p2 != ptr)
                    {
                        _FP_free (result->mimetype);
                        result->mimetype = _FP_strdup (ptr);
                    }
                    *p2 = c;
                }
                ctline=0;
                hadct=1;
            }
            if ((ptr = _FP_stristr (line, "number=")) && ctline<4)
            {
                ptr += 7;
                if (*ptr == '"') ptr++;
                result->partno = atoi (ptr);
            }
            if ((ptr = _FP_stristr (line, "total=")) && ctline<4)
            {
                ptr += 6;
                if (*ptr == '"') ptr++;
                result->maxpno = atoi (ptr);
            }
            if ((ptr = _FP_stristr (line, "name=")) && ctline<4)
            {
                ptr += 5;
                while (isspace (*ptr)) ptr++;
                if (*ptr == '"' && *(ptr+1) && (p2 = strchr (ptr+2, '"')) != NULL)
                {
                    c = *p2;
                    *p2 = '\0';
                    _FP_free (result->filename);
                    result->filename = _FP_strdup (ptr+1);
                    *p2 = c;
                }
                else if (*ptr=='\''&&*(ptr+1)&&(p2 = strchr(ptr+2, '\'')) != NULL)
                {
                    c = *p2;
                    *p2 = '\0';
                    _FP_free (result->filename);
                    result->filename = _FP_strdup (ptr+1);
                    *p2 = c;
                }
                else
                {
                    p2 = ptr;
                    while (isalnum(*p2) ||
                            *p2 == '.' || *p2=='_' || *p2 == '-' ||
                            *p2 == '!' || *p2=='@' || *p2 == '$')
                        p2++;
                    c = *p2;
                    *p2 = '\0';
                    if (p2 != ptr && result->filename == NULL)
                        result->filename = _FP_strdup (ptr);
                    else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL)
                    {
                        /*
                         * This file name looks good, too. Let's use it
                         */
                        _FP_free (result->filename);
                        result->filename = _FP_strdup (ptr);
                    }
                    *p2 = c;
                }
            }
            if ((ptr = _FP_stristr (line, "id=")) && ctline<4)
            {
                p2 = ptr += 3;
                if (*p2 == '"')
                {
                    p2 = strchr (++ptr, '"');
                }
                else
                {
                    while (*p2 && isprint(*p2) && !isspace(*p2) && *p2 != ';')
                        p2++;
                }
                if (p2 && *p2 && p2!=ptr)
                {
                    c = *p2;
                    *p2 = '\0';
                    if (result->mimeid)
                        _FP_free (result->mimeid);
                    result->mimeid = _FP_strdup (ptr);
                    *p2 = c;
                }
            }

            /*
             * Handling for very short Base64 files.
             */
            if (uu_tinyb64 && !ismime && !uu_more_mime)
            {
                if (line[0] == '-' && line[1] == '-')
                {
                    if (dflag && (encoding==B64ENCODED || result->uudet==B64ENCODED))
                    {
                        if (encoding==B64ENCODED && result->uudet==0 && (haddh||hadct))
                        {
                            result->uudet = encoding;
                            encoding = dflag = 0;
                        }
                        haddh = 1;
                        continue;
                    }
                    hadct = 0;
                }
            }
        } /* end of reduced MIME handling */

        /*
         * If we're in "freestyle" mode, have not encountered anything
         * interesting yet, and stumble upon something that looks like
         * a boundary, followed by a Content-* line, try to use it.
         */

        if (boundary == NULL && !ismime && !uu_more_mime && dflag <= 1 &&
                line[0] == '-' && line[1] == '-' && strlen(line+2)>10 &&
                (((ptr = _FP_strrstr (line+2, "--")) == NULL) ||
                 (*(ptr+2) != '\012' && *(ptr+2) != '\015')) &&
                _FP_strstr (line+2, "_=_") != NULL)
        {
            prevlinefirstchar = line[0];
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                break;
            }
            if (_FP_strnicmp (line, "Content-", 8) == 0)
            {
                /*
                 * Okay, let's do it. This breaks out of ScanData. ScanPart will
                 * recognize the boundary on the next call and use it.
                 */
                fseek (datei, oldposition, SEEK_SET);
                break;
            }
        }

        /*
         * Detection for yEnc encoding
         */

        if (strncmp (line, "=ybegin ", 8) == 0 &&
                _FP_strstr (line, " name=") != NULL)
        {
            if ((result->begin || result->end) && !uu_more_mime)
            {
                fseek (datei, oldposition, SEEK_SET);
                break;
            }

            /*
             * name continues to the end of the line
             */

            _FP_free (result->filename);
            ptr = _FP_strstr (line, " name=") + 6;
            result->filename = _FP_strdup (ptr);

            while (isspace (result->filename[strlen(result->filename)-1]))
                result->filename[strlen(result->filename)-1] = '\0';

            /*
             * Determine size
             */

            if ((ptr = _FP_strstr (line, " size=")) != NULL)
            {
                ptr += 6;
                yefilesize = atoi (ptr);
            }
            else
            {
                yefilesize = -1;
            }

            /*
             * check for multipart file and read =ypart line
             */

            if ((ptr = _FP_strstr (line, " part=")) != NULL)
            {
                result->partno = atoi (ptr + 6);

                if (result->partno == 1)
                {
                    result->begin = 1;
                }

                if (_FP_fgets (line, 255, datei) == NULL)
                {
                    break;
                }

                line[255] = '\0';

                if (strncmp (line, "=ypart ", 7) != 0)
                {
                    break;
                }

                if ((ptr = _FP_strstr (line, " end=")) == NULL)
                {
                    break;
                }

                yepartends = atoi (ptr + 5);
            }
            else
            {
                result->partno = 1;
                result->begin = 1;
            }

            /*
             * Don't want auto-detection
             */

            result->uudet = YENC_ENCODED;
            continue;
        }

        if (strncmp (line, "=yend ", 6) == 0 &&
                result->uudet == YENC_ENCODED)
        {
            if (yepartends == 0 || yepartends >= yefilesize)
            {
                result->end = 1;
            }
            if (!uu_more_mime)
                break;
        }

        /*
         * if we haven't yet found anything encoded, try to find something
         */

        if (!(result->uudet))
        {
            /*
             * Netscape-Repair code is the same as in uunconc.c
             */

            if ((vflag = UUValidData (line, 0, &bhflag)) == 0 && !ismime)
                vflag = UURepairData (datei, line, 0, &bhflag);

            /*
             * Check data against all possible encodings
             */

            isb64[iscnt%10] = (UUValidData (line, B64ENCODED, &bhflag)==B64ENCODED);
            isuue[iscnt%10] = (UUValidData (line, UU_ENCODED, &bhflag)==UU_ENCODED);
            isxxe[iscnt%10] = (UUValidData (line, XX_ENCODED, &bhflag)==XX_ENCODED);
            isbhx[iscnt%10] = (UUValidData (line, BH_ENCODED, &bhflag)==BH_ENCODED);

            /*
             * If we've got a first valid encoded line, we get suspicious if
             * it's shorter than, say, 40 characters.
             */

            if (vflag == B64ENCODED &&
                    (dflag == 0 || encoding != B64ENCODED) &&
                    strlen (line) < 40 && !result->begin && !uu_tinyb64)
            {
                isb64[iscnt%10] = 0;
                vflag = 0;
            }

            if ((vflag == UU_ENCODED || vflag == XX_ENCODED) &&
                    (dflag == 0 || encoding != vflag) &&
                    strlen (line) < 40 && !result->begin)
            {
                isuue[iscnt%10] = isxxe[iscnt%10] = 0;
                vflag = 0;
            }

            iscnt++;

            /*
             * Ah, so we got an encoded line? How interesting!
             */

            if (vflag)
            {
                /*
                 * For BinHex data, we can use the initial colon ':' as begin
                 * and the terminating colon as ':'.
                 * If (vflag && !bhflag), this is the last line,
                 */
                if (vflag == BH_ENCODED)
                {
                    if (line[0] == ':' && result->end)
                    {
                        fseek (datei, oldposition, SEEK_SET);
                        break;
                    }
                    if (line[0] == ':')
                        result->begin = 1;
                    if (bhflag == 0)
                    {
                        result->uudet = BH_ENCODED;
                        result->end   = 1;
                    }
                }
                /*
                 * For BinHex files, the file name is encoded in the first encoded
                 * data bytes. We try to extract it here
                 */
                if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL)
                {
                    if (bhdsp == bhds2 ||
                            ((bhdsp-bhds2) <= (int) bhds2[0] &&
                             (bhdsp-bhds2) <  256))
                    {
                        dcc = UUDecodeLine (line, bhds1, BH_ENCODED);
                        UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc,
                                    dcc, 256-(bhdsp-bhds2), &bhopc);
                        bhdsp += bhopc;
                    }
                    if ((bhdsp-bhds2) > (int) bhds2[0] && bhds2[0]>0 &&
                            result->filename==NULL)
                    {
                        memcpy (bhds1, bhds2+1, (int) bhds2[0]);
                        bhds1[(int)bhds2[0]]='\0';
                        result->filename = _FP_strdup (bhds1);
                        bhnf             = 1;
                    }
                    else if (bhdsp-bhds2 >= 256 && bhds2[0]>0)
                    {
                        memcpy (bhds1, bhds2+1, 255);
                        bhds1[255]       = '\0';
                        result->filename = _FP_strdup (bhds1);
                        bhnf             = 1;
                    }
                    else if (bhds2[0] <= 0)
                        bhnf = 1;
                }

                /*
                 * We accept an encoding if it has been true for four consecutive
                 * lines. Check the is<enc> arrays to avoid mistaking one encoding
                 * for the other. Uuencoded data is rather easily mistaken for
                 * Base 64. If the data matches more than one encoding, we need to
                 * scan further.
                 */

                if (iscnt > 3)
                {
                    cbb64 = (isb64[(iscnt-1)%10] && isb64[(iscnt-2)%10] &&
                             isb64[(iscnt-3)%10] && isb64[(iscnt-4)%10]);
                    cbuue = (isuue[(iscnt-1)%10] && isuue[(iscnt-2)%10] &&
                             isuue[(iscnt-3)%10] && isuue[(iscnt-4)%10]);
                    cbxxe = (isxxe[(iscnt-1)%10] && isxxe[(iscnt-2)%10] &&
                             isxxe[(iscnt-3)%10] && isxxe[(iscnt-4)%10]);
                    cbbhx = (isbhx[(iscnt-1)%10] && isbhx[(iscnt-2)%10] &&
                             isbhx[(iscnt-3)%10] && isbhx[(iscnt-4)%10]);
                }
                else
                {
                    cbb64 = cbuue = cbxxe = cbbhx = 0;
                }

                if (cbb64 && !cbuue && !cbxxe && !cbbhx)
                {
                    result->uudet = B64ENCODED;
                }
                else if (!cbb64 && cbuue && !cbxxe && !cbbhx)
                {
                    result->uudet = UU_ENCODED;
                }
                else if (!cbb64 && !cbuue && cbxxe && !cbbhx)
                {
                    result->uudet = XX_ENCODED;
                }
                else if (!cbb64 && !cbuue && !cbxxe && cbbhx)
                {
                    result->uudet = BH_ENCODED;
                }

                if (result->uudet)
                {
                    encoding = dflag = 0;

                    /*
                     * If we're in fast mode, we're told we don't have to look
                     * for anything below, so we can as well break out of every-
                     * thing
                     * We cannot fast-scan if we have a boundary to look after.
                     */

                    if (uu_fast_scanning && boundary == NULL)
                        break;

                    /*
                     * Skip the encoded data. We simply wait for a boundary, for
                     * a header or for an empty line. But we also try to pick up
                     * an "end"
                     */

                    hcount = lcount = 0;

                    while (!feof (datei))
                    {
                        /*
                         * Make Busy Polls
                         */
                        if (UUBUSYPOLL(ftell(datei),progress.fsize))
                        {
                            UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
                                       uustring (S_SCAN_CANCEL));
                            *errcode = UURET_CANCEL;
                            break;
                        }

                        prevlinefirstchar = line[0];
                        oldposition = ftell (datei);
                        if (_FP_fgets (line, 255, datei) == NULL)
                            break;
                        if (ferror (datei))
                            break;

                        line[255] = '\0';

                        /*
                         * Stop scanning at an empty line or a MIME-boundary.
                         */
                        if (IsLineEmpty (line))
                            break;
                        if (boundary && line[0] == '-' && line[1] == '-' &&
                                strncmp (line+2, boundary, blen) == 0)
                        {
                            fseek (datei, oldposition, SEEK_SET);
                            break;
                        }
                        else if (line[0] == 'e' && (result->uudet == UU_ENCODED ||
                                                    result->uudet == XX_ENCODED))
                        {
                            if (strncmp (line, "end", 3) == 0)
                            {
                                if (result->uudet == XX_ENCODED)
                                {
                                    if (prevlinefirstchar == '+')
                                    {
                                        result->end = 1;
                                        break;
                                    }
                                }
                                else
                                {
//          if (prevlinefirstchar == '`') {
                                    result->end = 1;
                                    break;
//          }
                                }
                            }
                        }
                        else if (line[0] == 'b')
                        {
                            if (strncmp (line, "begin ", 6) == 0)
                            {
                                fseek (datei, oldposition, SEEK_SET);
                                break;
                            }
                        }

                        if (checkheaders)
                        {
                            if (IsKnownHeader (line))
                            {
                                (void) ScanHeaderLine (datei, line);
                                if (hcount == 0)
                                    preheaders = oldposition;
                                hcount++;
                                lcount++;
                                if ((hcount >= hlcount.restart) ||
                                        (hcount >= hlcount.afterdata && result->uudet))
                                {
                                    /*
                                     * Hey, a new header starts here
                                     */
                                    fseek (datei, preheaders, SEEK_SET);
                                    break;
                                }
                            }
                            else if (lcount > WAITHEADER)
                            {
                                hcount = 0;
                                lcount = 0;
                            }
                            else if (hcount)
                            {
                                lcount++;
                            }
                        }
                        if (result->uudet == BH_ENCODED)
                        {
                            /* pick up ``EOF'' for BinHex files. Slow :-< */
                            if (line[0] && strchr (line+1, ':') != NULL)
                            {
                                result->end = 1;
                                bhflag      = 0;
                                break;
                            }
                        }
                    }

                    if (ferror (datei) || *errcode == UURET_CANCEL)
                        break;

                    if (line[0] == '-' && line[1] == '-')
                        haddh = 1;

                    /*
                     * Okay, got everything we need. If we had headers or a
                     * boundary, we break out of the outer loop immediately.
                     */

                    if (IsKnownHeader (line) ||
                            (boundary && line[0] == '-' && line[1] == '-' &&
                             strncmp (line+2, boundary, blen) == 0))
                    {
                        break;
                    }

                    /*
                     * Otherwise, we wait until finding something more interesting
                     * in the outer loop
                     */

                    continue;
                }

                /*
                 * Select the encoding with the best "history"
                 */

                cbb64 = isb64[(iscnt-1)%10];
                cbuue = isuue[(iscnt-1)%10];
                cbxxe = isxxe[(iscnt-1)%10];
                cbbhx = isbhx[(iscnt-1)%10];
                dflag = 0;

                if (cbb64 || cbuue || cbxxe || cbbhx)
                {
                    for (dflag=2; dflag<iscnt && dflag<4; dflag++)
                    {
                        if ((!cbb64 || !isb64[(iscnt-dflag)%10]) &&
                                (!cbuue || !isuue[(iscnt-dflag)%10]) &&
                                (!cbxxe || !isxxe[(iscnt-dflag)%10]) &&
                                (!cbbhx || !isbhx[(iscnt-dflag)%10]))
                        {
                            dflag--;
                            break;
                        }
                        cbb64 &= isb64[(iscnt-dflag)%10];
                        cbuue &= isuue[(iscnt-dflag)%10];
                        cbxxe &= isxxe[(iscnt-dflag)%10];
                        cbbhx &= isbhx[(iscnt-dflag)%10];
                    }
                }

                /*
                 * clear-cut cases
                 */

                if (cbb64 && !cbuue && !cbxxe && !cbbhx)
                {
                    encoding = B64ENCODED;
                }
                else if (!cbb64 && cbuue && !cbxxe && !cbbhx)
                {
                    encoding = UU_ENCODED;
                }
                else if (!cbb64 && !cbuue && cbxxe && !cbbhx)
                {
                    encoding = XX_ENCODED;
                }
                else if (!cbb64 && !cbuue && !cbxxe && cbbhx)
                {
                    encoding = BH_ENCODED;
                }
                else
                {
                    encoding = 0;
                }

                /*
                 * Check a few common non-clear-cut cases
                 */

                if (!encoding && cbuue && result->begin)
                {
                    encoding = UU_ENCODED;
                }
                else if (!encoding && cbxxe && result->begin)
                {
                    encoding = XX_ENCODED;
                }
                else if (!encoding && cbb64)
                {
                    encoding = B64ENCODED;
                }
                else if (!encoding && cbuue)
                {
                    encoding = UU_ENCODED;
                }
                else if (!encoding && cbxxe)
                {
                    encoding = XX_ENCODED;
                }
                else if (!encoding && cbbhx)
                {
                    encoding = BH_ENCODED;
                }
            }
            else if (!dontcare)
            {
                encoding = 0;
                dflag = 0;
                haddh = 0;
            }
        } /* if (!uudet) */
        /*
         * End of scanning loop
         */
    } /* while (!feof (datei)) */

    if (feof (datei))
        oldposition = ftell (datei);

    if (dflag && encoding == B64ENCODED && haddh)
        result->uudet = B64ENCODED;
    else if (dflag && encoding == BH_ENCODED)
        result->uudet = BH_ENCODED;

    /* Base64 doesn't have begin or end, so it was probably XX */
    if (result->uudet == B64ENCODED && result->begin && result->end)
        result->uudet = XX_ENCODED;

    /* Base64 doesn't have begin or end */
    if (result->uudet == B64ENCODED)
        result->begin = result->end = 0;

    /* Base64 and BinHex don't have a file mode */
    if (result->uudet == B64ENCODED || result->uudet == BH_ENCODED ||
            result->uudet == YENC_ENCODED)
        result->mode  = 6*64+4*8+4;

    /*
     * When strict MIME adherance is set, throw out suspicious attachments
     */

    if (uu_more_mime)
    {
        /*
         * In a MIME message, Base64 should be appropriately tagged
         */

        if (result->uudet == B64ENCODED)
        {
            result->uudet = 0;
        }

        /*
         * Do not accept incomplete UU or XX encoded messages
         */

        if ((result->uudet != 0 && result->uudet != B64ENCODED) &&
                (!result->begin || !result->end))
        {
            result->uudet = 0;
        }
    }

    /*
     * In fast mode, this length will yield a false value. We don't care.
     * This must be checked for in uunconc(), where we usually stop decoding
     * after reaching startpos+length
     */

    if (uu_fast_scanning)
        result->length = progress.fsize-result->startpos;
    else
        result->length = ftell(datei)-result->startpos;

    if (ferror (datei))
    {
        *errcode = UURET_IOERR;
        uu_errno = errno;
        return -1;
    }
    if (*errcode != UURET_OK)
    {
        return -1;
    }

    if (boundary && line[0] == '-' && line[1] == '-' &&
            strncmp (line+2, boundary, blen) == 0)
        return 2;
    else if (boundary && p3 &&
             line[0] == 'C' && line[1] == 'o' &&
             _FP_strnicmp (line, "Content-Type:", 13) == 0 &&
             strcmp (p3, boundary) == 0)
        return 2;
    else if (IsKnownHeader (line))
        return 1;

    return 0;
}

/*
 * This is the main scanning function.
 */

fileread *
ScanPart (FILE *datei, char *fname, int *errcode)
{
    int ecount, hcount, lcount;
    int bhflag, begflag, vflag, blen=0, res;
    long preheaders, prevpos=0, preenc, before;
    char *line=uuscan_spline;
    fileread *result;
    char *ptr1, *ptr2;

    (void) UUDecodeLine (NULL, NULL, 0);          /* init */
    if (datei == NULL || feof (datei))
    {
        *errcode = UURET_OK;
        return NULL;
    }

    *errcode = UURET_OK;

    if ((result = (fileread *) malloc (sizeof (fileread))) == NULL)
    {
        *errcode = UURET_NOMEM;
        return NULL;
    }
    memset (result, 0, sizeof (fileread));
    result->startpos = ftell (datei);
    preheaders       = result->startpos;
    before           = result->startpos;

    /* if this is a new file, reset our scanning state */
    if (sstate.source == NULL || strcmp (fname, sstate.source) != 0)
    {
        sstate.isfolder  = 1;       /* assume yes            */
        sstate.ismime    = 0;       /* wait for MIME-Version */
        sstate.mimestate = MS_HEADERS;  /* assume headers follow */
        /* mimseqno      = 1; */

        while (mssdepth)
        {
            mssdepth--;
            UUkillheaders (&(multistack[mssdepth].envelope));
            _FP_free (multistack[mssdepth].source);
        }

        UUkillheaders (&sstate.envelope);
        memset (&sstate.envelope, 0, sizeof (headers));

        _FP_free (sstate.source);
        if ((sstate.source = _FP_strdup (fname)) == NULL)
        {
            *errcode = UURET_NOMEM;
            _FP_free (result);
            return NULL;
        }

        /* ignore empty lines at the beginning of a file */
        preheaders = ftell (datei);
        while (!feof (datei))
        {
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            if (_FP_fgets (line, 255, datei) == NULL)
                break;
            if (!IsLineEmpty (line))
            {
                fseek (datei, preheaders, SEEK_SET);
                line[255] = '\0';
                break;
            }
            preheaders = ftell (datei);
        }
    }

    if (ferror(datei) || feof(datei))
    {
        _FP_free (result);
        return NULL;
    }

    /*
     * If we are confident that this is a mail folder and are at the
     * beginning of the file, expecting to read some headers, scan
     * the envelope.
     */

    if (sstate.isfolder && sstate.mimestate == MS_HEADERS)
    {
        hcount = 0;
        lcount = 0;
        UUkillheaders (&sstate.envelope);

        /*
         * clean up leftovers from invalid messages
         */

        while (mssdepth)
        {
            mssdepth--;
            UUkillheaders (&(multistack[mssdepth].envelope));
            _FP_free (multistack[mssdepth].source);
        }

        if (_FP_fgets (line, 255, datei) == NULL)
        {
            _FP_free (result);
            return NULL;
        }
        line[255] = '\0';

        /*
         * Special handling for AOL folder files, which start off with a boundary.
         * We recognize them by a valid boundary line as the first line of a file.
         * Note that the rest of the scanning code becomes suspicious if a boun-
         * dary does never appear in a file -- this should save us from grave
         * false detection errors
         */

        if (!feof (datei) && line[0] == '-' && line[1] == '-' && line[2])
        {
            while (line[strlen(line)-1] == '\012' ||
                    line[strlen(line)-1] == '\015')
            {
                line[strlen(line)-1] = '\0';
            }

            sstate.ismime            = 1;
            sstate.envelope.mimevers = _FP_strdup ("1.0");
            sstate.envelope.boundary = _FP_strdup (line+2);
            sstate.envelope.ctype    = _FP_strdup ("multipart/mixed");
            sstate.mimestate         = MS_SUBPART;

            *errcode = UURET_CONT;
            _FP_free (result);
            return NULL;
        }

        /*
         * Normal behavior: look for a RFC 822 header
         */

        while (!feof (datei) && !IsLineEmpty (line))
        {
            if (IsKnownHeader (line))
                hcount++;
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            ptr1 = ScanHeaderLine (datei, line);
            if (ParseHeader (&sstate.envelope, ptr1) == NULL)
            {
                *errcode = UURET_NOMEM;
                _FP_free (result);
                return NULL;
            }
            /*
             * if we've read too many lines without finding headers, then
             * this probably isn't a mail folder after all
             */
            lcount++;
            if (lcount > WAITHEADER && hcount < hlcount.afternl)
                break;

            if (_FP_fgets (line, 255, datei) == NULL)
                break;
            line[255] = '\0';
        }
        /* skip empty lines */
        prevpos = ftell (datei);
        while (!feof (datei))
        {
            if (_FP_fgets (line, 255, datei) == NULL)
                break;
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            if (!IsLineEmpty (line))
            {
                fseek (datei, prevpos, SEEK_SET);
                line[255] = '\0';
                break;
            }
            prevpos = ftell (datei);
        }
        /*
         * If we don't have all valid MIME headers yet, but the following
         * line is a MIME header, accept it anyway.
         */

        if (!uu_more_mime &&
                sstate.envelope.mimevers == NULL &&
                sstate.envelope.ctype    == NULL &&
                sstate.envelope.ctenc    == NULL &&
                IsKnownHeader (line))
        {
            /*
             * see above
             */
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                line[0] = '\012';
                line[1] = '\0';
            }
            line[255] = '\0';

            while (!feof (datei) && !IsLineEmpty (line))
            {
                if (IsKnownHeader (line))
                    hcount++;
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                ptr1 = ScanHeaderLine (datei, line);
                if (ParseHeader (&sstate.envelope, ptr1) == NULL)
                {
                    *errcode = UURET_NOMEM;
                    _FP_free (result);
                    return NULL;
                }
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                line[255] = '\0';
            }
            /* skip empty lines */
            prevpos = ftell (datei);
            while (!feof (datei))
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                if (!IsLineEmpty (line))
                {
                    fseek (datei, prevpos, SEEK_SET);
                    line[255] = '\0';
                    break;
                }
                prevpos = ftell (datei);
            }
        }

        /*
         * A partial multipart message probably has only a Content-Type
         * header but nothing else. In this case, at least simulate a
         * MIME message
         * if mimevers is not set but there are other well-known MIME
         * headers, don't be too picky about it.
         */
        if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL  &&
                _FP_stristr (sstate.envelope.ctype, "multipart") != NULL &&
                sstate.envelope.boundary != NULL)
        {
            sstate.envelope.mimevers = _FP_strdup ("1.0");
            hcount = hlcount.afternl;
        }
        else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype &&
                 sstate.envelope.fname && sstate.envelope.ctenc)
        {
            sstate.envelope.mimevers = _FP_strdup ("1.0");
            hcount = hlcount.afternl;
        }

        if (hcount < hlcount.afternl)
        {
            /* not a folder after all */
            fseek (datei, preheaders, SEEK_SET);
            sstate.isfolder = 0;
            sstate.ismime   = 0;
        }
        else if (sstate.envelope.mimevers != NULL)
        {
            /* this is a MIME file. check the Content-Type */
            sstate.ismime = 1;
            if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL)
            {
                if (sstate.envelope.boundary == NULL)
                {
                    UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                               uustring (S_MIME_NO_BOUNDARY));
                    sstate.mimestate = MS_BODY;
                    _FP_free (sstate.envelope.ctype);
                    sstate.envelope.ctype = _FP_strdup ("text/plain");
                }
                else
                {
                    sstate.mimestate = MS_PREAMBLE;
                }
            }
            else
            {
                sstate.mimestate = MS_BODY; /* just a `simple' message */
            }
        }
    }

    if (feof (datei) || ferror (datei))   /* oops */
    {
        _FP_free (result);
        return NULL;
    }

    /*
     * Handle MIME stuff
     */

    /*
     * Read Preamble. This must be ended by a sstate.envelope.boundary line.
     * If uu_usepreamble is set, we produce a result from this one
     */

    if (sstate.ismime && sstate.mimestate == MS_PREAMBLE)
    {
        result->startpos = ftell (datei);   /* remember start of preamble */
        prevpos          = ftell (datei);
        preheaders       = ftell (datei);

        blen   = strlen (sstate.envelope.boundary);
        lcount = 0;

        while (!feof (datei))
        {
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                line[0] = '\0';
                break;
            }
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            if (line[0] == '-' && line[1] == '-' &&
                    strncmp (line+2, sstate.envelope.boundary, blen) == 0)
                break;
            if (!IsLineEmpty (line))
                lcount++;

            prevpos = ftell (datei);
        }
        if (feof (datei) || ferror (datei))
        {
            UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                       uustring (S_MIME_B_NOT_FOUND));
            /*
             * restart and try again; don't restart if uu_fast_scanning
             */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
            sstate.mimestate = MS_BODY;

            if (!uu_fast_scanning)
            {
                *errcode = UURET_CONT;
                fseek (datei, preheaders, SEEK_SET);
            }
            _FP_free (result);
            return NULL;
        }
        if (line[0] == '-' && line[1] == '-' &&
                strncmp (line+2, sstate.envelope.boundary, blen) == 0)
        {
            ptr1 = line + 2 + blen;
            if (*ptr1 == '-' && *(ptr1+1) == '-')
            {
                /* Empty Multipart Message. Duh. */
                sstate.mimestate = MS_EPILOGUE;
            }
            else
            {
                sstate.mimestate = MS_SUBPART;
            }
        }
        else   /* shouldn't happen */
        {
            UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                       uustring (S_MIME_B_NOT_FOUND));
            /*
             * restart and try again; don't restart if uu_fast_scanning
             */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
            sstate.mimestate = MS_BODY;

            if (!uu_fast_scanning)
            {
                *errcode = UURET_CONT;
                fseek (datei, preheaders, SEEK_SET);
            }
            _FP_free (result);
            return NULL;
        }
        /* produce result if uu_usepreamble is set */
        if (uu_usepreamble && lcount)
        {
            sprintf (line, "%04d.txt", ++mimseqno);
            result->subject  = _FP_strdup (sstate.envelope.subject);
            result->filename = _FP_strdup (line);
            result->origin   = _FP_strdup (sstate.envelope.from);
            result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
            result->mimetype = _FP_strdup ("text/plain");
            result->mode     = 0644;
            result->uudet    = PT_ENCODED;    /* plain text */
            result->sfname   = _FP_strdup (fname);
            result->flags    = FL_SINGLE | FL_PROPER;
            /* result->startpos set from above */
            result->length   = prevpos - result->startpos;
            result->partno   = 1;

            /* MIME message, let's continue */
            *errcode = UURET_CONT;

            if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
                    result->filename == NULL || result->sfname == NULL)
            {
                *errcode = UURET_NOMEM;
            }

            return result;
        }
        /* MIME message, let's continue */
        if (*errcode == UURET_OK)
            *errcode = UURET_CONT;

        /* otherwise, just return NULL */
        _FP_free (result);
        return NULL;
    }

    /*
     * Read Epilogue, the plain text after the last boundary.
     * This can either end with new headers from the next message of a
     * mail folder or with a `parent' boundary if we are inside an
     * encapsulated Multipart message. Oh yes, and of course the file
     * may also simply end :-)
     * Another possibility is that we might find plain encoded data
     * without encapsulating message. We're not _too_ flexible here,
     * we won't detect Base64, and require a proper `begin' line for
     * uuencoding and xxencoding
     * If uu_usepreamble is set, we produce a result from this one
     */

    if (sstate.ismime && sstate.mimestate == MS_EPILOGUE)
    {
        result->startpos = ftell (datei);   /* remember start of epilogue */
        prevpos          = ftell (datei);
        preheaders       = ftell (datei);
        preenc           = ftell (datei);
        hcount = lcount  = 0;
        ecount = bhflag  = 0;
        begflag = vflag  = 0;
        res = 0;

        /*
         * If we are in the outermost message and uu_fast_scanning, we
         * know (or assume) that no more messages will follow, so there's
         * no need to scan the rest.
         */
        if (uu_fast_scanning && mssdepth == 0)
        {
            /*
             * check if the epilogue is empty
             */
            while (!feof (datei) && !ferror (datei) && lcount<10 && res==0)
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                if (!IsLineEmpty (line))
                    res++;
                lcount++;
            }
            if (uu_usepreamble && res)
            {
                sprintf (line, "%04d.txt", ++mimseqno);
                result->subject  = _FP_strdup (sstate.envelope.subject);
                result->filename = _FP_strdup (line);
                result->origin   = _FP_strdup (sstate.envelope.from);
                result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
                result->mimetype = _FP_strdup ("text/plain");
                result->mode     = 0644;
                result->uudet    = PT_ENCODED;  /* plain text */
                result->sfname   = _FP_strdup (fname);
                result->flags    = FL_SINGLE | FL_PROPER | FL_TOEND;
                result->partno   = 1;
                /* result->startpos set from above */
                result->length   = progress.fsize - result->startpos;

                if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
                        result->filename == NULL || result->sfname == NULL)
                {
                    *errcode = UURET_NOMEM;
                }

                return result;
            }
            _FP_free (result);
            return NULL;
        }

        if (mssdepth > 0)
            blen = strlen (multistack[mssdepth-1].envelope.boundary);

        while (!feof (datei))
        {
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                line[0] = '\0';
                break;
            }
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            line[255] = '\0';
            /* check for parent boundary */
            if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
                    strncmp (line+2,
                             multistack[mssdepth-1].envelope.boundary, blen) == 0)
                break;

            /* check for next headers only at outermost level */
            if (mssdepth == 0 && IsKnownHeader (line))
            {
                (void) ScanHeaderLine (datei, line);
                if (hcount == 0)
                {
                    preheaders = prevpos;
                    lcount     = 0;
                }
                hcount++;
                lcount++;

                if (hcount >= hlcount.restart)
                {
                    /* okay, new headers */
                    break;
                }
            }
            else if (lcount > WAITHEADER)
            {
                hcount = 0;
                lcount = 0;
            }
            else if (hcount)
            {
                lcount++;
            }
            else
            {
                hcount = lcount = 0;
            }

            /* check for begin and encoded data only at outermost level */
            if (mssdepth == 0 && !uu_more_mime)
            {
                if (strncmp      (line, "begin ",       6) == 0 ||
                        _FP_strnicmp (line, "<pre>begin ", 11) == 0)
                {
                    preenc  = prevpos;
                    begflag = 1;
                }
                else if (strncmp (line, "end", 3) == 0 && begflag)
                {
                    ecount = ELC_COUNT;
                    break;
                }
                else if ((vflag = UUValidData (line, 0, &bhflag)) != 0)
                {
                    if (vflag == BH_ENCODED && bhflag == 0)
                    {
                        /* very short BinHex file follows */
                        preenc = prevpos;
                        break;
                    }
                    /* remember that XX can easily be mistaken as Base64 */
                    if ((vflag == UU_ENCODED || vflag == XX_ENCODED ||
                            vflag == B64ENCODED) && begflag)
                    {
                        if (++ecount >= ELC_COUNT)
                            break;
                    }
                    else
                    {
                        begflag = 0;
                        ecount  = 0;
                    }
                }
                else
                {
                    begflag = 0;
                    ecount  = 0;
                }
            }

            if (!IsLineEmpty (line))
                res++;

            prevpos = ftell (datei);
        }

        if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
                strncmp (line+2,
                         multistack[mssdepth-1].envelope.boundary, blen) == 0)
        {
            /* restore previous state */
            mssdepth--;
            UUkillheaders (&sstate.envelope);
            _FP_free  (sstate.source);
            memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));

            ptr1 = line + 2 + strlen (sstate.envelope.boundary);

            if (*ptr1 == '-' && *(ptr1+1) == '-')
            {
                sstate.mimestate = MS_EPILOGUE;
            }
            else
            {
                sstate.mimestate = MS_SUBPART;
            }
            result->length = prevpos - result->startpos;
            *errcode = UURET_CONT;
        }
        else if (mssdepth > 0)
        {
            UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                       uustring (S_MIME_B_NOT_FOUND));
            /*
             * restart and try again; don't restart if uu_fast_scanning
             */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
            sstate.mimestate = MS_BODY;

            while (mssdepth)
            {
                mssdepth--;
                UUkillheaders (&(multistack[mssdepth].envelope));
                _FP_free (multistack[mssdepth].source);
            }

            if (!uu_fast_scanning)
            {
                *errcode = UURET_CONT;
                fseek (datei, preheaders, SEEK_SET);
            }
            _FP_free (result);
            return NULL;
        }
        else if (IsKnownHeader (line))
        {
            /* new message follows */
            sstate.isfolder  = 1;
            sstate.ismime    = 0;
            sstate.mimestate = MS_HEADERS;
            result->length   = preheaders - result->startpos;
            fseek (datei, preheaders, SEEK_SET);
        }
        else if (ecount >= ELC_COUNT)
        {
            /* new plain encoding */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
            sstate.mimestate = MS_BODY;
            result->length   = preenc - result->startpos;
            fseek (datei, preenc, SEEK_SET);
        }

        /* produce result if uu_usepreamble is set */
        if (uu_usepreamble && res)
        {
            sprintf (line, "%04d.txt", ++mimseqno);
            result->subject  = _FP_strdup (sstate.envelope.subject);
            result->filename = _FP_strdup (line);
            result->origin   = _FP_strdup (sstate.envelope.from);
            result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
            result->mimetype = _FP_strdup ("text/plain");
            result->mode     = 0644;
            result->uudet    = PT_ENCODED;    /* plain text */
            result->sfname   = _FP_strdup (fname);
            result->flags    = FL_SINGLE | FL_PROPER;
            result->partno   = 1;
            /* result->startpos set from above */
            /* result->length set from above */

            if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
                    result->filename == NULL || result->sfname == NULL)
            {
                *errcode = UURET_NOMEM;
            }

            return result;
        }
        /* otherwise, just return NULL */
        _FP_free (result);
        return NULL;
    }

    /*
     * Scan a new part from a Multipart message. Check for a new local
     * envelope (which defaults to `Content-Type: text/plain') and
     * evaluate its Content-Type and Content-Transfer-Encoding. If this
     * is another Multipart/something, push the current state onto our
     * stack and dive into the new environment, starting with another
     * preamble.
     */

    if (sstate.ismime && sstate.mimestate == MS_SUBPART)
    {
        memset (&localenv, 0, sizeof (headers));
        result->startpos = ftell (datei);
        prevpos = ftell (datei);
        hcount  = 0;
        lcount  = 0;

        /*
         * Duplicate some data from outer envelope
         */

        localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
        localenv.from     = _FP_strdup (sstate.envelope.from);
        localenv.subject  = _FP_strdup (sstate.envelope.subject);
        localenv.rcpt     = _FP_strdup (sstate.envelope.rcpt);
        localenv.date     = _FP_strdup (sstate.envelope.date);

        if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
                (sstate.envelope.from     != NULL && localenv.from     == NULL) ||
                (sstate.envelope.subject  != NULL && localenv.subject  == NULL) ||
                (sstate.envelope.rcpt     != NULL && localenv.rcpt     == NULL) ||
                (sstate.envelope.date     != NULL && localenv.date     == NULL))
        {

            while (mssdepth)
            {
                mssdepth--;
                UUkillheaders (&(multistack[mssdepth].envelope));
                _FP_free (multistack[mssdepth].source);
            }
            sstate.isfolder = 0;
            sstate.ismime   = 0;

            UUkillheaders (&localenv);
            *errcode = UURET_NOMEM;
            _FP_free (result);
            return NULL;
        }

        /* Scan subheader. But what if there is no subheader? */
        hcount = 0;
        lcount = 0;
        preheaders = prevpos;

        if (_FP_fgets (line, 255, datei) == NULL)
        {
            sstate.isfolder = 0;
            sstate.ismime   = 0;
            while (mssdepth)
            {
                mssdepth--;
                UUkillheaders (&(multistack[mssdepth].envelope));
                _FP_free (multistack[mssdepth].source);
            }
            UUkillheaders (&localenv);
            _FP_free (result);
            return NULL;
        }
        line[255] = '\0';

        while (!feof (datei) && !IsLineEmpty (line))
        {
            if (IsKnownHeader (line))
                hcount++;
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            if (lcount > WAITHEADER && hcount == 0)
            {
                fseek (datei, preheaders, SEEK_SET);
                prevpos = preheaders;
                break;
            }
            ptr1 = ScanHeaderLine (datei, line);
            if (ParseHeader (&localenv, ptr1) == NULL)
                *errcode = UURET_NOMEM;

            if (line[0] == '-' && line[1] == '-')
                break;

            prevpos = ftell (datei);

            if (_FP_fgets (line, 255, datei) == NULL)
                break;
            line[255] = '\0';
            lcount++;
        }
        if (line[0] == '-' && line[1] == '-')
        {
            /*
             * this shouldn't happen, there must always be an empty line,
             * but let's accept it anyway. Just skip back to before the
             * boundary, so that it gets handled below
             */
            fseek (datei, prevpos, SEEK_SET);
        }

        if (_FP_stristr (localenv.ctype, "multipart") != NULL)
        {
            /* oh no, not again */
            if (mssdepth >= MSMAXDEPTH)
            {
                /* Argh, what an isane message. Treat as plain text */
                UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                           uustring (S_MIME_MULTI_DEPTH));
            }
            else if (localenv.boundary == NULL)
            {
                UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                           uustring (S_MIME_NO_BOUNDARY));
            }
            else
            {
                memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
                memcpy (&sstate.envelope,    &localenv, sizeof (headers));
                memset (&localenv, 0, sizeof (headers));
                sstate.mimestate = MS_PREAMBLE;
                if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
                    *errcode = UURET_NOMEM;

                if (*errcode == UURET_OK)
                    *errcode = UURET_CONT;

                mssdepth++;
                /* need a restart */
                _FP_free (result);
                return NULL;
            }
        }

        /*
         * So this subpart is either plain text or something else. Check
         * the Content-Type and Content-Transfer-Encoding. If the latter
         * is a defined value, we know what to do and just copy everything
         * up to the boundary.
         * If Content-Transfer-Encoding is unknown or missing, look at the
         * Content-Type. If it's "text/plain" or undefined, we subject the
         * message to our encoding detection. Otherwise, treat as plain
         * text.
         * This is done because users might `attach' a uuencoded file, which
         * would then be correctly typed as `text/plain'.
         */

        if (_FP_stristr (localenv.ctenc, "base64") != NULL)
            result->uudet = B64ENCODED;
        else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL)
        {
            result->uudet = UU_ENCODED;
            result->begin = result->end = 1;
        }
        else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL)
        {
            result->uudet = YENC_ENCODED;
            result->begin = result->end = 1;
        }
        else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
            result->uudet = QP_ENCODED;
        else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
                 _FP_stristr (localenv.ctenc, "8bit") != NULL)
            result->uudet = PT_ENCODED;
        else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
                 _FP_stristr (localenv.ctype, "message")   != NULL)
            result->uudet = PT_ENCODED;

        /*
         * If we're switched to MIME-only mode, handle as text
         */

        if (uu_more_mime >= 2 && !result->uudet)
        {
            result->uudet = PT_ENCODED;
        }

        if (result->uudet)
        {
            /*
             * Oh-kay, go ahead. Just read and wait for the boundary
             */
            result->startpos = ftell (datei);
            prevpos          = ftell (datei);
            blen = strlen (sstate.envelope.boundary);
            lcount = 0;

            while (!feof (datei))
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                {
                    line[0] = '\0';
                    break;
                }
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                line[255] = '\0';
                if (line[0] == '-' && line[1] == '-' &&
                        strncmp (line+2, sstate.envelope.boundary, blen) == 0)
                    break;
                /*
                 * I've had a report of someone who tried to decode a huge file
                 * that had an early truncated multipart message and later another
                 * multipart message with the *same* boundary. Consequently, all
                 * some hundred messages inbetween were ignored ...
                 * This check here doesn't cover folded header lines, but we don't
                 * want to slow down scanning too much. We just check for
                 * Content-Type: multipart/... boundary="same-boundary"
                 */
                if (line[0] == 'C' && line[1] == 'o' &&
                        _FP_strnicmp (line, "Content-Type:", 13) == 0)
                {
                    ptr1 = ScanHeaderLine (datei, line);
                    ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
                    ptr1 = (ptr2)?ParseValue(ptr2):NULL;
                    if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
                        break;
                    for (res=0; ptr1 && res<mssdepth; res++)
                        if (strcmp (ptr1, multistack[res].envelope.boundary) == 0)
                            break;
                    if (res<mssdepth)
                        break;
                }
                if (!IsLineEmpty (line))
                    lcount++;
                prevpos = ftell (datei);
            }
            if (line[0] == '-' && line[1] == '-' &&
                    strncmp (line+2, sstate.envelope.boundary, blen) == 0)
            {
                ptr1 = line + 2 + blen;
                if (*ptr1 == '-' && *(ptr1+1) == '-')
                    sstate.mimestate = MS_EPILOGUE;
                else
                    sstate.mimestate = MS_SUBPART;
            }
            else
            {
                UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                           uustring (S_MIME_B_NOT_FOUND));

                while (mssdepth)
                {
                    mssdepth--;
                    UUkillheaders (&(multistack[mssdepth].envelope));
                    _FP_free (multistack[mssdepth].source);
                }
                /*
                 * Don't retry if uu_fast_scanning
                 */

                if (uu_fast_scanning)
                {
                    UUkillheaders (&localenv);
                    sstate.isfolder  = 0;
                    sstate.ismime    = 0;
                    sstate.mimestate = MS_BODY;
                    _FP_free (result);
                    return NULL;
                }

                /*
                 * Retry, but listening to headers this time
                 */
                fseek (datei, result->startpos, SEEK_SET);

                UUkillfread (result);
                if ((result = (fileread *) malloc (sizeof (fileread))) == NULL)
                {
                    *errcode = UURET_NOMEM;
                    sstate.isfolder = 0;
                    sstate.ismime   = 0;
                    UUkillheaders (&localenv);
                    return NULL;
                }
                memset (result, 0, sizeof (fileread));

                if ((res = ScanData (datei, errcode, NULL, 1, 1, result))==-1)
                {
                    /* oops, something went wrong */
                    sstate.isfolder = 0;
                    sstate.ismime   = 0;
                    UUkillfread   (result);
                    UUkillheaders (&localenv);
                    return NULL;
                }
                if (res == 1)
                {
                    /*
                     * new headers found
                     */
                    sstate.isfolder  = 1;
                    sstate.ismime    = 0;
                    sstate.mimestate = MS_HEADERS;
                }
                else
                {
                    sstate.isfolder  = 0;
                    sstate.ismime    = 0;
                }
            }
            /* produce result if uu_handletext is set */
            /* or if the file is explicitely named */
            if (result->uudet == B64ENCODED || lcount)
            {
                if (localenv.fname)
                {
                    _FP_free (result->filename);
                    if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
                        *errcode = UURET_NOMEM;
                }
                else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
                         result->filename == NULL && uu_handletext)
                {
                    sprintf (line, "%04d.txt", ++mimseqno);
                    if ((result->filename = _FP_strdup (line)) == NULL)
                        *errcode = UURET_NOMEM;
                }
                result->subject  = _FP_strdup (localenv.subject);
                result->origin   = _FP_strdup (localenv.from);
                result->mimeid   = _FP_strdup (localenv.mimeid);
                result->mimetype = _FP_strdup (localenv.ctype);
                result->mode     = 0644;
                result->sfname   = _FP_strdup (fname);
                result->flags    = FL_SINGLE | FL_PROPER;
                result->partno   = 1;
                /* result->uudet determined above */
                /* result->startpos set from above */
                result->length   = prevpos - result->startpos;

                if ((localenv.subject != NULL && result->subject == NULL) ||
                        result->filename == NULL  || result->sfname == NULL)
                {
                    *errcode = UURET_NOMEM;
                }
            }
            else
            {
                /* don't produce a result */
                _FP_free (result);
                result = NULL;
            }
            if (*errcode == UURET_OK)
                *errcode = UURET_CONT;
            /*
             * destroy local envelope
             */
            UUkillheaders (&localenv);
            return result;
        }

        /*
         * we're in a subpart, but the local headers don't give us any
         * clue about what's to find here. So look for encoded data by
         * ourselves.
         */

        if ((res = ScanData (datei, errcode,
                             sstate.envelope.boundary,
                             1, 0, result)) == -1)
        {
            /* oops, something went wrong */
            sstate.isfolder = 0;
            sstate.ismime   = 0;
            UUkillfread   (result);
            UUkillheaders (&localenv);
            return NULL;
        }
        /*
         * we should really be at a boundary here, but check again
         */
        blen    = strlen (sstate.envelope.boundary);
        prevpos = ftell  (datei);

        while (!feof (datei))
        {
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                line[0] = '\0';
                break;
            }
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            line[255] = '\0';
            if (line[0] == '-' && line[1] == '-' &&
                    strncmp (line+2, sstate.envelope.boundary, blen) == 0)
                break;
            if (line[0] == 'C' && line[1] == 'o' &&
                    _FP_strnicmp (line, "Content-Type:", 13) == 0)
            {
                ptr1 = ScanHeaderLine (datei, line);
                ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
                ptr1 = (ptr2)?ParseValue(ptr2):NULL;
                if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
                    break;
            }
            prevpos = ftell (datei);
        }
        /*
         * check if this was the last subpart
         */
        if (line[0] == '-' && line[1] == '-' &&
                strncmp (line+2, sstate.envelope.boundary, blen) == 0)
        {
            ptr1 = line + 2 + blen;
            if (*ptr1 == '-' && *(ptr1+1) == '-')
                sstate.mimestate = MS_EPILOGUE;
            else
                sstate.mimestate = MS_SUBPART;
        }
        else
        {
            UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                       uustring (S_MIME_B_NOT_FOUND));

            while (mssdepth)
            {
                mssdepth--;
                UUkillheaders (&(multistack[mssdepth].envelope));
                _FP_free (multistack[mssdepth].source);
            }

            if (uu_fast_scanning)
            {
                UUkillheaders (&localenv);
                sstate.isfolder  = 0;
                sstate.ismime    = 0;
                sstate.mimestate = MS_BODY;
                _FP_free (result);
                return NULL;
            }

            /*
             * Retry, listening to headers this time
             */
            fseek (datei, result->startpos, SEEK_SET);

            UUkillfread (result);
            if ((result = (fileread *) malloc (sizeof (fileread))) == NULL)
            {
                *errcode = UURET_NOMEM;
                sstate.isfolder = 0;
                sstate.ismime   = 0;
                UUkillheaders (&localenv);
                return NULL;
            }
            memset (result, 0, sizeof (fileread));

            if ((res = ScanData (datei, errcode, NULL, 1, 1, result))==-1)
            {
                /* oops, something went wrong */
                sstate.isfolder = 0;
                sstate.ismime   = 0;
                UUkillfread   (result);
                UUkillheaders (&localenv);
                return NULL;
            }
            if (res == 1)
            {
                /*
                 * new headers found
                 */
                sstate.isfolder  = 1;
                sstate.ismime    = 0;
                sstate.mimestate = MS_HEADERS;
            }
            else
            {
                sstate.isfolder  = 0;
                sstate.ismime    = 0;
            }
        }

        /*
         * If this file has been nicely MIME so far, then be very suspicious
         * if ScanData reports anything else. So do a double check, and if
         * it doesn't hold up, handle as plain text instead.
         */

        if (strcmp (localenv.mimevers, "1.0") == 0 &&
                _FP_stristr (localenv.ctype, "text") != NULL &&
                sstate.ismime && sstate.mimestate == MS_SUBPART &&
                !uu_desperate)
        {
            if (result->uudet == UU_ENCODED && !(result->begin || result->end))
            {
                result->uudet = 0;
            }
        }

        /*
         * produce result
         */

        if (result->uudet == 0)
        {
            result->uudet = PT_ENCODED; /* plain text */
        }

        if (localenv.fname)
        {
            _FP_free (result->filename);
            if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
                 result->filename==NULL && uu_handletext)
        {
            sprintf (line, "%04d.txt", ++mimseqno);
            if ((result->filename = _FP_strdup (line)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else
        {
            /* assign a filename lateron */
        }
        if (result->mimetype) _FP_free (result->mimetype);
        if (result->uudet)
        {
            if (_FP_stristr (localenv.ctype, "text") != NULL &&
                    result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
                result->mimetype = NULL; /* better don't set it */
            else
                result->mimetype = _FP_strdup (localenv.ctype);
        }
        if (result->origin) _FP_free  (result->origin);
        result->origin  = _FP_strdup  (localenv.from);

        if (result->subject) _FP_free (result->subject);
        result->subject = _FP_strdup  (localenv.subject);

        if (result->sfname == NULL)
            if ((result->sfname = _FP_strdup (fname)) == NULL)
                *errcode = UURET_NOMEM;

        result->length = prevpos - result->startpos;
        result->flags  = FL_SINGLE | FL_PROPER;
        result->partno = 1;

        if (result->mode == 0)
            result->mode = 0644;

        /*
         * the other fields should already be set appropriately
         */

        if (*errcode == UURET_OK)
            *errcode = UURET_CONT;

        /*
         * kill local envelope
         */
        UUkillheaders (&localenv);

        return result;
    }

    /*
     * All right, so we're not in a Multipart message. Phew, took quite
     * long to figure this out. But this might still be a MIME message
     * body. And if it's a message/partial, we need more special handling
     */

    if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
            _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
            _FP_stristr (sstate.envelope.ctype, "partial") != NULL)
    {

        result->startpos = ftell (datei);

        if (sstate.envelope.partno == 1)
        {
            /* read local envelope */
            UUkillheaders (&localenv);
            memset (&localenv, 0, sizeof (headers));

            /* skip over blank lines first */
            prevpos = ftell (datei);
            while (!feof (datei))
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                line[255] = '\0';
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                if (!IsLineEmpty (line))
                    break;
                prevpos = ftell (datei);
            }
            /* Next, read header. But what if there is no subheader? */
            hcount = 0;
            lcount = 0;
            preheaders = prevpos;

            while (!feof (datei) && !IsLineEmpty (line))
            {
                if (IsKnownHeader (line))
                    hcount++;
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                if (lcount > WAITHEADER && hcount == 0)
                {
                    fseek (datei, preheaders, SEEK_SET);
                    break;
                }
                ptr1 = ScanHeaderLine (datei, line);
                if (ParseHeader (&localenv, ptr1) == NULL)
                    *errcode = UURET_NOMEM;

                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                line[255] = '\0';
                lcount++;
            }
            prevpos = ftell (datei);
            /*
             * Examine local header. We're mostly interested in the Content-Type
             * and the Content-Transfer-Encoding.
             */
            if (_FP_stristr (localenv.ctype, "multipart") != NULL)
            {
                UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
                           uustring (S_MIME_PART_MULTI));
            }
            if (localenv.subject)
                result->subject  = _FP_strdup (localenv.subject);
            else
                result->subject  = _FP_strdup (sstate.envelope.subject);

            if (localenv.from)
                result->origin   = _FP_strdup (localenv.from);
            else
                result->origin   = _FP_strdup (sstate.envelope.from);

            if (localenv.ctype)
                result->mimetype = _FP_strdup (localenv.ctype);
            else
                result->mimetype = _FP_strdup ("text/plain");

            if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
                result->uudet = QP_ENCODED;
            else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
                result->uudet = B64ENCODED;
            else if (_FP_stristr (localenv.ctenc, "x-uue") != NULL)
            {
                result->uudet = UU_ENCODED;
                result->begin = result->end = 1;
            }
            else if (_FP_stristr (localenv.ctenc, "x-yenc") != NULL)
            {
                result->uudet = YENC_ENCODED;
                result->begin = result->end = 1;
            }
            else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
                     _FP_stristr (localenv.ctenc, "8bit") != NULL)
                result->uudet = PT_ENCODED;
            else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
                     _FP_stristr (localenv.ctype, "message")   != NULL)
                result->uudet = PT_ENCODED;

            /*
             * If we're switched to MIME-only mode, handle as text
             */

            if (uu_more_mime >= 2 && !result->uudet)
            {
                result->uudet = PT_ENCODED;
            }
        }
        else
        {
            memset (&localenv, 0, sizeof (headers));
        }

        /*
         * If this is Quoted-Printable or Plain Text, just try looking
         * for the next message header. If uu_fast_scanning, and the
         * encoding is known, there's no need to look below. Otherwise,
         * we check the type of encoding first.
         * The encoding type is determined on the first part; in all
         * others, we also don't read on.
         * If we have a partial multipart message, scan for headers, but
         * do not react on standard MIME headers, as they are probably
         * from the subparts. However, we're stuck if there's an embedded
         * message/rfc822 :-(
         * If it is a "trivial" (non-embedded) message/rfc822, skip over
         * the message header and then start looking for the next header.
         */
        if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1))
        {
            /* do nothing */
            res = 0;
        }
        else if (result->uudet != 0)
        {
            hcount = lcount = 0;
            prevpos = ftell (datei);

            if (_FP_stristr (localenv.ctype, "message") != NULL &&
                    _FP_stristr (localenv.ctype, "rfc822")  != NULL)
            {
                /*
                 * skip over empty lines and local header
                 */
                preheaders = ftell (datei);
                while (!feof (datei))
                {
                    if (_FP_fgets (line, 255, datei) == NULL)
                        break;
                    line[255] = '\0';
                    if (!IsLineEmpty (line))
                    {
                        break;
                    }
                }

                while (!feof (datei) && !IsLineEmpty (line))
                {
                    if (IsKnownHeader (line))
                        hcount++;
                    lcount++;
                    if (lcount > WAITHEADER && hcount < hlcount.afternl)
                        break;

                    if (_FP_fgets (line, 255, datei) == NULL)
                        break;
                    line[255] = '\0';
                }
                if (hcount < hlcount.afternl)
                    fseek (datei, preheaders, SEEK_SET);
                hcount = lcount = 0;
            }

            /*
             * look for next header
             */

            while (!feof (datei))
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                if (ferror (datei))
                    break;
                line[255] = '\0';

                if ((vflag = IsKnownHeader (line)))
                {
                    (void) ScanHeaderLine (datei, line);

                    if (result->uudet != PT_ENCODED || vflag == 1)
                    {
                        if (hcount == 0)
                            preheaders = prevpos;
                        hcount++;
                        lcount++;
                        if (hcount >= hlcount.restart)
                        {
                            /*
                             * Hey, a new header starts here
                             */
                            fseek (datei, preheaders, SEEK_SET);
                            prevpos = preheaders;
                            break;
                        }
                    }
                }
                else if (lcount > WAITHEADER)
                {
                    hcount = 0;
                    lcount = 0;
                }
                else if (hcount)
                {
                    lcount++;
                }
                prevpos = ftell (datei);
            }
            res = 1;
        }
        else
        {
            /*
             * Otherwise, let's see what we can find ourself. No
             * boundary (NULL) but MIME, and respect new headers.
             */
            if ((res = ScanData (datei, errcode, NULL, 1, 1, result)) == -1)
            {
                /* oops, something went wrong */
                sstate.isfolder = 0;
                sstate.ismime   = 0;
                UUkillfread   (result);
                UUkillheaders (&localenv);
                return NULL;
            }
            if (result->uudet == 0 && uu_handletext)
                result->uudet = PT_ENCODED;

            prevpos = ftell (datei);
        }
        /*
         * produce result
         */
        if (localenv.fname)
        {
            _FP_free (result->filename);
            if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else if (sstate.envelope.fname)
        {
            _FP_free (result->filename);
            if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
                 result->filename == NULL)
        {
            sprintf (line, "%04d.txt", ++mimseqno);
            if ((result->filename = _FP_strdup (line)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else
        {
            /* assign a filename lateron */
        }
        if (result->subject == NULL)
        {
            if (sstate.envelope.subject)
                result->subject = _FP_strdup (sstate.envelope.subject);
        }
        result->partno = sstate.envelope.partno;
        result->maxpno = sstate.envelope.numparts;
        result->flags  = FL_PARTIAL |
                         ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
                         ((uu_fast_scanning) ? FL_TOEND : 0);
        result->mimeid = _FP_strdup (sstate.envelope.mimeid);
        if (result->partno == 1)
            result->begin = 1;

        if (uu_fast_scanning)
            result->length = progress.fsize - result->startpos;
        else
            result->length = prevpos - result->startpos;

        if (result->sfname == NULL)
            result->sfname = _FP_strdup (fname);

        if (result->mode == 0)
            result->mode = 0644;

        /*
         * the other fields should already be set appropriately
         */

        if (res == 1)
        {
            /*
             * new headers found
             */
            sstate.isfolder  = 1;
            sstate.ismime    = 0;
            sstate.mimestate = MS_HEADERS;

            UUkillheaders (&sstate.envelope);
            memset (&sstate.envelope, 0, sizeof (headers));
        }
        else
        {
            /*
             * otherwise, this can't be a mail folder
             */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
        }
        /*
         * kill local envelope
         */
        UUkillheaders (&localenv);
        return result;
    }

    /*
     * If this is a MIME body, honor a Content-Type different than
     * text/plain or a proper Content-Transfer-Encoding.
     * We also go in here if we have an assigned filename - this means
     * that we've had a Content-Disposition field, and we should probably
     * decode a plain-text segment with a filename.
     */

    if (sstate.isfolder && sstate.ismime &&
            sstate.mimestate == MS_BODY &&
            (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
             _FP_stristr (sstate.envelope.ctenc, "base64")           != NULL ||
             _FP_stristr (sstate.envelope.ctenc, "x-uue")            != NULL ||
             _FP_stristr (sstate.envelope.ctenc, "x-yenc")           != NULL ||
             _FP_stristr (sstate.envelope.ctype, "message")          != NULL ||
             sstate.envelope.fname != NULL))
    {

        if (sstate.envelope.subject)
            result->subject = _FP_strdup (sstate.envelope.subject);
        if (sstate.envelope.from)
            result->origin  = _FP_strdup (sstate.envelope.from);

        if (sstate.envelope.ctype)
            result->mimetype = _FP_strdup (sstate.envelope.ctype);
        else
            result->mimetype = _FP_strdup ("text/plain");

        if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
            result->uudet = QP_ENCODED;
        else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
            result->uudet = B64ENCODED;
        else if (_FP_stristr (sstate.envelope.ctenc, "x-uue") != NULL)
        {
            result->uudet = UU_ENCODED;
            result->begin = result->end = 1;
        }
        else if (_FP_stristr (sstate.envelope.ctenc, "x-yenc") != NULL)
        {
            result->uudet = YENC_ENCODED;
        }
        else if (_FP_stristr (sstate.envelope.ctenc, "7bit") != NULL ||
                 _FP_stristr (sstate.envelope.ctenc, "8bit") != NULL)
            result->uudet = PT_ENCODED;
        else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
                 _FP_stristr (sstate.envelope.ctype, "message")   != NULL ||
                 sstate.envelope.fname != NULL)
            result->uudet = PT_ENCODED;

        /*
         * If we're switched to MIME-only mode, handle as text
         */

        if (uu_more_mime >= 2 && !result->uudet)
        {
            result->uudet = PT_ENCODED;
        }

        result->startpos = prevpos = ftell (datei);

        /*
         * If this is Quoted-Printable or Plain Text, just try looking
         * for the next message header. If uu_fast_scanning, we know
         * there won't be more headers.
         * If it is a "trivial" (non-embedded) message/rfc822, skip over
         * the message header and then start looking for the next header.
         */
        if (result->uudet != 0 && uu_fast_scanning)
        {
            /* do nothing */
            res = 0;
        }
        else if (result->uudet != 0)
        {
            hcount = lcount = 0;
            prevpos = ftell (datei);

            if (_FP_stristr (sstate.envelope.ctype, "message") != NULL &&
                    _FP_stristr (sstate.envelope.ctype, "rfc822")  != NULL)
            {
                /*
                 * skip over empty lines and local header
                 */
                preheaders = ftell (datei);
                while (!feof (datei))
                {
                    if (_FP_fgets (line, 255, datei) == NULL)
                        break;
                    line[255] = '\0';
                    if (!IsLineEmpty (line))
                    {
                        break;
                    }
                }

                while (!feof (datei) && !IsLineEmpty (line))
                {
                    if (IsKnownHeader (line))
                        hcount++;
                    lcount++;
                    if (lcount > WAITHEADER && hcount < hlcount.afternl)
                        break;

                    if (_FP_fgets (line, 255, datei) == NULL)
                        break;
                    line[255] = '\0';
                }
                if (hcount < hlcount.afternl)
                    fseek (datei, preheaders, SEEK_SET);
                hcount = lcount = 0;
            }

            /*
             * look for next header
             */

            while (!feof (datei))
            {
                if (_FP_fgets (line, 255, datei) == NULL)
                    break;
                if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
                if (ferror (datei))
                    break;
                line[255] = '\0';

                if (IsKnownHeader (line))
                {
                    (void) ScanHeaderLine (datei, line);
                    if (hcount == 0)
                        preheaders = prevpos;
                    hcount++;
                    lcount++;
                    if (hcount >= hlcount.restart)
                    {
                        /*
                         * Hey, a new header starts here
                         */
                        fseek (datei, preheaders, SEEK_SET);
                        prevpos = preheaders;
                        break;
                    }
                }
                else if (lcount > WAITHEADER)
                {
                    hcount = 0;
                    lcount = 0;
                }
                else if (hcount)
                {
                    lcount++;
                }
                prevpos = ftell (datei);
            }
            res = 1;
        }
        else
        {
            /*
             * Otherwise, let's see what we can find ourself. No
             * boundary (NULL) but MIME, and respect new headers.
             */
            if ((res = ScanData (datei, errcode, NULL, 1, 1, result)) == -1)
            {
                /* oops, something went wrong */
                sstate.isfolder = 0;
                sstate.ismime   = 0;
                UUkillfread   (result);
                return NULL;
            }
            if (result->uudet == 0 && uu_handletext)
            {
                result->startpos = before;  /* display headers */
                result->uudet = PT_ENCODED;
            }

            prevpos = ftell (datei);
        }
        /*
         * produce result
         */
        if (sstate.envelope.fname)
        {
            _FP_free (result->filename);
            if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
                 result->filename == NULL)
        {
            sprintf (line, "%04d.txt", ++mimseqno);
            if ((result->filename = _FP_strdup (line)) == NULL)
                *errcode = UURET_NOMEM;
        }
        else
        {
            /* assign a filename lateron */
        }
        if (result->subject == NULL)
        {
            if (sstate.envelope.subject)
                result->subject = _FP_strdup (sstate.envelope.subject);
        }
        result->flags  = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
                         ((uu_fast_scanning) ? FL_TOEND : 0);
        result->mimeid = _FP_strdup (sstate.envelope.mimeid);

        if (uu_fast_scanning)
            result->length = progress.fsize - result->startpos;
        else
            result->length = prevpos - result->startpos;

        if (result->sfname == NULL)
            result->sfname = _FP_strdup (fname);

        if (result->mode == 0)
            result->mode = 0644;

        /*
         * the other fields should already be set appropriately
         */

        if (res == 1)
        {
            /*
             * new headers found
             */
            sstate.isfolder  = 1;
            sstate.ismime    = 0;
            sstate.mimestate = MS_HEADERS;

            UUkillheaders (&sstate.envelope);
            memset (&sstate.envelope, 0, sizeof (headers));
        }
        else
        {
            /*
             * otherwise, this can't be a mail folder
             */
            sstate.isfolder  = 0;
            sstate.ismime    = 0;
        }

        return result;
    }

    /*
     * Some files have reduced headers, and what should be a multipart
     * message is missing the proper Content-Type. If the first thing
     * we find after a couple of empty lines is a boundary, try it!
     * But make sure that this is indeed intended as being a boundary.
     *
     * Only accept it if there was indeed no Content-Type header line
     * and if the following line is a proper Content-Type header. BTW,
     * we know that sstate.envelope.boundary is NULL, or we wouldn't
     * be here!
     */

    if ((sstate.envelope.ctype == NULL ||
            _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) &&
            !uu_more_mime)
    {
        prevpos = ftell (datei);
        while (!feof (datei))
        {
            if (_FP_fgets (line, 255, datei) == NULL)
            {
                line[0] = '\0';
                break;
            }
            if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
            if (!IsLineEmpty (line))
                break;
        }
        if (line[0] == '-' && line[1] == '-' &&
                !IsLineEmpty (line+2) && !feof (datei))
        {
            ptr1 = _FP_strrstr (line+2, "--");
            ptr2 = ScanHeaderLine (datei, NULL);
            if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
                    ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0)
            {
                /*
                 * hmm, okay, let's do it!
                 */
                sstate.isfolder  = 1;
                sstate.ismime    = 1;
                sstate.mimestate = MS_PREAMBLE;
                /*
                 * get boundary
                 */
                ptr1 = line+2;
                while (*ptr1 && !isspace(*ptr1))
                    ptr1++;
                *ptr1 = '\0';

                sstate.envelope.mimevers = _FP_strdup ("1.0");
                sstate.envelope.boundary = _FP_strdup (line+2);

                /*
                 * need restart
                 */

                fseek (datei, prevpos, SEEK_SET);

                _FP_free (result);
                return NULL;
            }
        }
        fseek (datei, prevpos, SEEK_SET);
    }

    /*
     * Hmm, we're not in a ''special'' state, so it's more or less
     * Freestyle time. Anyway, if this seems to be a Mime message,
     * don't allow the minimal Base64 handling.
     */

    if (sstate.envelope.subject)
        result->subject = _FP_strdup (sstate.envelope.subject);
    if (sstate.envelope.from)
        result->origin  = _FP_strdup (sstate.envelope.from);

    if (sstate.envelope.ctype)
        result->mimetype = _FP_strdup (sstate.envelope.ctype);

    if ((res=ScanData (datei, errcode, NULL,
                       sstate.ismime, 1, result))==-1)
    {
        /* oops, something went wrong */
        sstate.isfolder = 0;
        sstate.ismime   = 0;
        UUkillfread   (result);
        return NULL;
    }

    /*
     * produce result
     */

    if (result->uudet == 0 && uu_handletext)
    {
        result->startpos = before;  /* display headers */
        result->uudet  = PT_ENCODED;
        result->partno = 1;
    }

    if (result->uudet == YENC_ENCODED && result->filename != NULL)
    {
        /*
         * prevent replacing the filename found on the =ybegin line
         */
    }
    else if (sstate.envelope.fname)
    {
        _FP_free (result->filename);
        if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
            *errcode = UURET_NOMEM;
    }
    else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
             result->filename == NULL)
    {
        sprintf (line, "%04d.txt", ++mimseqno);
        if ((result->filename = _FP_strdup (line)) == NULL)
            *errcode = UURET_NOMEM;
    }
    else
    {
        /* assign a filename lateron */
    }

    if (result->subject == NULL)
    {
        if (sstate.envelope.subject)
            result->subject = _FP_strdup (sstate.envelope.subject);
    }

    result->flags  = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
    result->mimeid = _FP_strdup (sstate.envelope.mimeid);
    result->length = ftell (datei) - result->startpos;

    if (result->mode == 0)
        result->mode = 0644;

    if (result->sfname == NULL)
        result->sfname = _FP_strdup (fname);

    if (res == 1)
    {
        /*
         * new headers found
         */
        sstate.isfolder  = 1;
        sstate.ismime    = 0;
        sstate.mimestate = MS_HEADERS;

        UUkillheaders (&sstate.envelope);
        memset (&sstate.envelope, 0, sizeof (headers));
    }
    else
    {
        /*
         * otherwise, this can't be a mail folder
         */
        sstate.isfolder  = 0;
        sstate.ismime    = 0;
    }

    return result;

    /*
     * Emergency handling. Set errcode before jumping here.
     */
ScanPartEmergency:
    UUkillfread   (result);
    UUkillheaders (&localenv);

    while (mssdepth)
    {
        mssdepth--;
        UUkillheaders (&(multistack[mssdepth].envelope));
        _FP_free (multistack[mssdepth].source);
    }

    return NULL;
}

