ftp.nice.ch/pub/next/connectivity/news/NewsBase.3.02.s.tar.gz#/NewsBase302.source/MMEdit/metamail.c

This is metamail.c in view mode; [Download] [Up]

/*
Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)

Permission to use, copy, modify, and distribute this material 
for any purpose and without fee is hereby granted, provided 
that the above copyright notice and this permission notice 
appear in all copies, and that the name of Bellcore not be 
used in advertising or publicity pertaining to this 
material without the specific, prior written permission 
of an authorized representative of Bellcore.  BELLCORE 
MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
*/
/****************************************************** 
    Metamail -- A tool to help diverse mail readers 
                cope with diverse multimedia mail formats.

    Author:  Nathaniel S. Borenstein, Bellcore

 ******************************************************* */
#import <stdio.h>
#import <ctype.h>
#import <libc.h>
#import "config.h"
#import <streams/streams.h>
#import "mem_file_desc.h"


#import <pwd.h>
#import <sys/time.h>
#import <signal.h>

#include <sgtty.h>
#define TMPFILE_NAME_SIZE   1000
#define MAX_FILE_NAME_SIZE 1000

#ifndef NO_RLIMITS
#include <sys/resource.h>
#endif

#define LoStr(key)      doLocalString(NULL,key,NULL)

#define LINE_BUF_SIZE       2000
char fileToDelete[MAX_FILE_NAME_SIZE];

char *FindParam();
extern int NXRunAlertPanel(), doLocalString();

static char *nomem = "Out of memory!";

NXStream *InputFP = NULL;

int EatLeadingNewlines = 0,
    PrintSomeHeaders = 1,
    DoInBackground = 0,
    Is822Format = 1,
    DoDebug = 0,
    CParamsAlloced = 0,
    CParamsUsed = 0,
    YankMode = 0,
    UsingStandardInput = 0;

int count=1;
int headpart=0;

char *ContentType = NULL,
    *ContentEncoding = NULL,
    *Mimeversion = NULL,
    *MailerName = "unknown",
    *MailSubject = "Mail message",
    *MailFrom = "unknown sender",
    *MailSummary = "non-text mail message",
    *mailheaders = NULL,
    **CParams = NULL,
    **CParamValues = NULL,
    *JunkParameter = NULL;

#define ENCODING_NONE 0
#define ENCODING_BASE64 1
#define ENCODING_QUOTEDPRINTABLE 2
#define ENCODING_8BIT 3
#define ENCODING_UUENCODE -1	/* non-standard */
int EncodingCode = ENCODING_NONE;

char *Cleanse(s) /* no leading or trailing space, all lower case */
char *s;
{
    char *tmp, *news;
    
    /* strip leading white space */
    while (*s && isspace((unsigned char) *s)) ++s;
    news = s;
    /* put in lower case */
    for (tmp=s; *tmp; ++tmp) {
        if (isupper((unsigned char) *tmp)) *tmp = tolower((unsigned char) *tmp);
    }
    /* strip trailing white space */
    while (*--tmp && isspace((unsigned char) *tmp)) *tmp = 0;
    return(news);
}

char *UnquoteString(s)
char *s;
{
    char *ans, *t;
    void ExitWithError();

    if (*s != '"') return(s);
    ans = malloc(1+strlen(s));
    if (!ans) ExitWithError(nomem);
    ++s;
    t = ans;
    while (*s) {
        if (*s == '\\') {
            *t++ = *++s;
        } else if (*s == '"') {
            break;
        } else {
            *t++ = *s;
        }
        ++s;
    }
    *t = 0;
    return(ans);
}


char **Boundaries = NULL;
int BoundaryCt = 0, BoundaryAlloc = 0;

#define getc(x) NXGetc(x)
#define ungetc(x,y) NXUngetc(y)
#define putc(x,stream) NXPutc(stream,x)

struct mem_file_desc *articles_desc = NULL;
struct mem_file_desc **adpp = &articles_desc;

struct mem_file_desc *get_Item(stream)
NXStream *stream;
{
    void ResetGlobals();
    int HandleMessage();
    int retcode=0;

    InputFP = stream;
    
    ResetGlobals();
    retcode |= HandleMessage(NULL, 0);

    *adpp = NULL;
    return(articles_desc) ;

}

void ResetGlobals() {

    int ExitWithError();

    CParamsAlloced = 0;
    CParamsUsed = 0;

    ContentType = NULL;
    Mimeversion = NULL;
    ContentEncoding = NULL;
    MailSubject = "Mail message";
    MailFrom = "unknown sender";
    MailSummary = "non-text mail message";
//    mailheaders = getenv("MM_HEADERS");
    mailheaders = NULL;
//    if (mailheaders) {
//        char *s;
//        s = malloc(15+strlen(mailheaders));
//        if (!s) ExitWithError(nomem);
//        sprintf(s, "MM_HEADERS=%s", mailheaders);
//        mailheaders = s;
//    }
    CParams = NULL;
    CParamValues = NULL;
    JunkParameter = NULL;

    count=1;
    headpart=0;
//    articles_desc = (struct mem_file_desc *)NULL;
//    articles_desc=(struct mem_file_desc *)malloc(sizeof(struct mem_file_desc));
    *adpp = (struct mem_file_desc *)&(articles_desc->fd_nextp);
}


int CheckTmp(SquirrelFile)
char *SquirrelFile;
{
	int SaveSquirrelFile(),MkTmpFileName(),WriteTmpFile();

        if (SquirrelFile) {
            return(SaveSquirrelFile(SquirrelFile));
       } else {
            char TmpFileName[TMPFILE_NAME_SIZE];
            MkTmpFileName(TmpFileName);
            return(WriteTmpFile(TmpFileName));
	}	
}

int HandleMessage(SquirrelFile, nestingdepth)
char *SquirrelFile;
/* SquirrelFile, if non-NULL, is a place to save a recognized body instead of executing it. */
int nestingdepth;
{
    int Read822Prefix(),PrepareMessage(),lc2strcmp(),WriteTmpFile();
    int SaveSquirrelFile(),lc2strncmp();
    int MkTmpFileName(),ConsumeRestOfPart(),CreateMMP();
    int TranslateInputToOutput(),ExitWithError() ;
    int c;
    int r822;
    int len,max;
    char *buff, *makelower();
    char *extfilename=NULL;
    char *accesstype=NULL;
    char *Extsite=NULL;
    char *Extname=NULL;
    char *UnquoteString();
    NXStream *textonly;
    NXStream *externalB;

    if (Is822Format) {
         r822=Read822Prefix(SquirrelFile?0:1, nestingdepth);
	 if ( r822 == -1) return(-1);
    } else Is822Format = 1; /* this property is not recursive for multipart or message */
    PrepareMessage();

    if (!lc2strcmp(Mimeversion,"1.0") && count == 1 ){

	textonly = NXOpenMemory(NULL,0,NX_READWRITE);

        NXGetMemoryBuffer(InputFP,&buff,&len,&max);
        NXWrite(textonly, (const void *)buff, len);
        CreateMMP(textonly,"textonly.plain");
	count++;
        return(-1);

    }

    if (!lc2strcmp(ContentType,"text")
         || !lc2strcmp(ContentType, "text/plain") 
         || !lc2strcmp(ContentType,"text/richtext")) {
	
    CheckTmp(SquirrelFile);
    return(0);
     }

    if (!lc2strcmp(ContentType,"image")
         || !lc2strcmp(ContentType, "image/tiff") 
         || !lc2strcmp(ContentType,"image/gif")
         || !lc2strcmp(ContentType,"image/jfif")
         || !lc2strcmp(ContentType,"image/jpeg")
         || !lc2strcmp(ContentType,"image/eps")) {
	
        Extname = FindParam("name");
	if ( Extname ){
                extfilename = (char *) calloc (200, sizeof(char));
                sprintf(extfilename,"/%s", Extname);
		WriteTmpFile(extfilename);
	} else{
		CheckTmp(SquirrelFile);
	}
//    CheckTmp(SquirrelFile);
    return(0);
     }

    if (!lc2strcmp(ContentType,"audio")
         || !lc2strcmp(ContentType, "audio/basic") 
         || !lc2strcmp(ContentType,"audio/next")) {
	
        Extname = FindParam("name");
	if ( Extname ){
                extfilename = (char *) calloc (200, sizeof(char));
                sprintf(extfilename,"/%s", Extname);
		WriteTmpFile(extfilename);
	} else{
		CheckTmp(SquirrelFile);
	}
//    CheckTmp(SquirrelFile);
    return(0);
     }

    if (!lc2strcmp(ContentType,"application")
         || !lc2strcmp(ContentType, "application/andrew-inset") 
         || !lc2strcmp(ContentType, "application/x-be2") 
         || !lc2strcmp(ContentType, "application/postscript") 
         || !lc2strcmp(ContentType,"application/ps")) {
	
    CheckTmp(SquirrelFile);
    return(0);
     }
    if (!lc2strcmp(ContentType,"application")
         || !lc2strcmp(ContentType, "application/octet-stream")) {
        Extname = FindParam("name");
	if ( Extname ){
	  Extname = makelower(Extname);

	WriteTmpFile(Extname);
	}
	 else{
        externalB = NXOpenMemory(NULL,0,NX_READWRITE);
        CreateMMP(externalB, "/octet.vox");
	}
        return(0);
     }
    if (!lc2strcmp(ContentType, "message")
         || !lc2strcmp(ContentType, "message/external-body")) {
//         || !lc2strcmp(ContentType, "message/rfc822")) {

        accesstype = FindParam("access-type");
	if ( accesstype ){
        accesstype = makelower(accesstype);

	if( !strcmp(accesstype, "local-file") ){
	        Extname = FindParam("name");
		extfilename = (char *) calloc (200, sizeof(char));
		sprintf(extfilename,"%s.local-file", Extname);
	}else if ( !strcmp(accesstype, "anon-ftp")){
	        Extname = FindParam("name");
       		Extsite = FindParam("site");
		extfilename = (char *) calloc (200, sizeof(char));
		sprintf(extfilename,"%s@%s.anon-ftp", Extname, Extsite);
	}else if ( !strcmp(accesstype, "x-news")){
	        Extname = FindParam("name");
		extfilename = (char *) calloc (200, sizeof(char));
		sprintf(extfilename,"%s.X-news", Extname);
	}else{
		fprintf(stderr,"%s is not support yet.", accesstype);
		return(0);
	}
	
        externalB = NXOpenMemory(NULL,0,NX_READWRITE);
        CreateMMP(externalB, extfilename);
	}else{
        externalB = NXOpenMemory(NULL,0,NX_READWRITE);
        CreateMMP(externalB, "/text.plain");
	}
//    CheckTmp(SquirrelFile);
        return(0);
//        if (SquirrelFile) return(SaveSquirrelFile(SquirrelFile));
//        ContentType = NULL; /* reset default */
//        ContentEncoding = NULL; /* reset default */
//        return(HandleMessage(NULL, nestingdepth+1)); /* simple recursion */
    }
    if (!lc2strncmp(ContentType, "multipart", 9)) {
        char *boundary, *LineBuf, NewSquirrelFile[TMPFILE_NAME_SIZE];
        char *subtype = NULL;
        int currct, result, IsAlternative, WroteSquirrelFile;

        if (SquirrelFile) return(SaveSquirrelFile(SquirrelFile));
        boundary = FindParam("boundary");
        if (!boundary) boundary =JunkParameter; /* backward compatibility hack */
        if (!boundary) {
            ExitWithError("Bad message format -- multipart message has no boundary parameter!");
        }
        if (boundary[0] == '"') {
            boundary=UnquoteString(boundary);
        }
        subtype = index(ContentType, '/');
        if (subtype) {
            ++subtype;
            subtype = Cleanse(subtype);
        } else subtype = "mixed";
#ifndef __MSDOS__
        DoInBackground = strcmp(subtype, "parallel") ? 0 : 1;
#endif

        IsAlternative = strcmp(subtype, "alternative") ? 0 : 1;
        IsAlternative = 0;
        if (IsAlternative) {
            MkTmpFileName(NewSquirrelFile);
            WroteSquirrelFile = 0;
        }
        LineBuf = malloc(LINE_BUF_SIZE);
        if (!LineBuf) ExitWithError(nomem);
        sprintf(LineBuf, "--%s", boundary);
        strcpy(boundary, LineBuf);
        if (BoundaryCt >= BoundaryAlloc) {
            BoundaryAlloc += 5;
            if (Boundaries) {
                Boundaries = (char **) realloc(Boundaries, BoundaryAlloc*sizeof(char *));
            } else {
                Boundaries = (char **) malloc(BoundaryAlloc*sizeof(char *));
            }
            if (!Boundaries) ExitWithError(nomem);
        }
        Boundaries[BoundaryCt++] = boundary;
        if (DoDebug) printf("Handling multipart as built-in here.  Boundary: %s\n", boundary);
	c = 1;
        while (c != -1 ) { /* find start */
//            c = readline(InputFP, LineBuf, LINE_BUF_SIZE);
          c = NXScanf(InputFP,"%1998[^\r\n]\r\n",LineBuf);
            if (!strncmp(LineBuf, boundary, strlen(boundary))) break;
        }
        free(LineBuf);
        currct = BoundaryCt;
        while(currct == BoundaryCt) {
            if (!strcmp(subtype, "digest")) {
                ContentType = "message/rfc822";
            } else {
                ContentType = NULL; /* reset default */
            }
            ContentEncoding = NULL; /* reset default */
            if (IsAlternative) {
                result = HandleMessage(NewSquirrelFile, nestingdepth+1);
            } else{
                result = HandleMessage(NULL, nestingdepth+1);
		if (result == -1 )return(-1);
            }
            if (result) {
                /* Need to consume the rest of the part */
                char TmpFileName[TMPFILE_NAME_SIZE];
		NXStream *newfp;
                MkTmpFileName(TmpFileName);
                newfp = NXOpenMemory(NULL,0,NX_READWRITE);
                if (!newfp) ExitWithError("Cannot open temporary file");
                ConsumeRestOfPart(newfp);
	        CreateMMP(newfp,TmpFileName);
	        //NXCloseMemory(newfp,NX_FREEBUFFER);
		
            } else {
                ++WroteSquirrelFile;
            }
        }
        /* Now we've seen the last encapsulation boundary, but if there is a "postfix"
            we must throw it away.*/
        if (BoundaryCt > 0) {
                char TmpFileName[TMPFILE_NAME_SIZE];
		NXStream *newfp;
                MkTmpFileName(TmpFileName);
                newfp = NXOpenMemory(NULL,0,NX_READWRITE);
                if (!newfp) ExitWithError("Cannot open temporary file");
                ConsumeRestOfPart(newfp);
	        CreateMMP(newfp,TmpFileName);
	        //NXCloseMemory(newfp,NX_FREEBUFFER);
        }
//        if (IsAlternative) {
//            if (WroteSquirrelFile) {
//                int retcode; 
//                char Cmd[TMPFILE_NAME_SIZE + 15];
//                sprintf(Cmd, "%s %s", METAMAIL, NewSquirrelFile);
//                fflush(stdout); fflush(stderr);
//                retcode = system(Cmd);
//                unlink(NewSquirrelFile);
//                return(retcode);
//            } else {
//                printf("Cannot handle any part of multipart/alternative message\n");
//            }
//        }
        return(0);
    }

    if (ContentType){
      if (strlen(ContentType) >= 1){
        	CheckTmp(SquirrelFile);
        	return(0);
       }
    }
    if (!SquirrelFile) { /* Very last resort -- unrecognized types */
        char Fname[MAX_FILE_NAME_SIZE];
        NXStream *fp;
        if (Fname[0] == 0 || Fname[0] == '\n') {
                char TmpFileName[TMPFILE_NAME_SIZE];
		NXStream *newfp;
                MkTmpFileName(TmpFileName);
                newfp = NXOpenMemory(NULL,0,NX_READWRITE);
                if (!newfp) ExitWithError("Cannot open temporary file");
                ConsumeRestOfPart(newfp);
	        CreateMMP(newfp,TmpFileName);
	        //NXCloseMemory(newfp,NX_FREEBUFFER);
            return(0);
        } else {
            fp = NXOpenMemory(NULL,0,NX_READWRITE);
            if (!fp) ExitWithError("Cannot open temporary file");
            TranslateInputToOutput(InputFP, fp, EncodingCode);
	    CreateMMP(fp,Fname);
	  //NXCloseMemory(fp,NX_FREEBUFFER);
            return(0);
        }
    }
    return(-1); /* Unrecognized, really */
}

int writeline(stream,ptr,nbytes)
char *ptr;
NXStream *stream; 
int nbytes;
{
        int     nleft, nread;
	char     c, *Buf;

        nleft = nbytes;
        nread = 0;
	Buf = ptr;
        while( nleft > 0){
		c = *Buf++;
                if( c  !=  '\n' )
		{
                	NXPutc(stream,c);
			nread++;
		}
                else
		{
                	NXPutc(stream,c);
			return(0);
		}
                nleft--;
        }
        return( nread );

}

int readline(stream,ptr,nbytes)
NXStream     *stream;
char    *ptr;
int     nbytes;
{
        int     nleft, nread;
	char     c;

        nleft = nbytes;
        nread = 0;
        while( nleft > 0){
                c = NXGetc(stream);
                if( c  !=  '\n' && c != EOF)
		{
                        *ptr++ = c;
			nread++;
		}
                else
		{
			if ( c == EOF )
			{
				*ptr++=c;
        			return( -1 );
			}
			*ptr++='\n';
			*ptr++='\0';
        		return( nread+1 );
		}

                nleft--;
        }
	*ptr++='\0';
        return( nread );
}


void usage() {
int ExitWithError();
    ExitWithError(NULL);
}

void CleanBuf(buf, si)
char *buf;
int si;
{
	int i;

	for( i = 0; i < si ; i++)
		buf[i]='\0';
}
int SaveSquirrelFile(SquirrelFile)
char *SquirrelFile;
{
    int TranslateInputToOutput(),CreateMMP();
    NXStream *outfp;
    char ffff[1024];

    CleanBuf(ffff, sizeof(ffff));
    outfp = NXOpenMemory(NULL, 0, NX_READWRITE);
    if (!outfp) {
        fprintf(stderr, "Cannot open %s to squirrel away a portion of a multipart/alternative\n", SquirrelFile);
        return(-1);
    }
//    NXPrintf(outfp, "Content-type: %s", ContentType);
//    for (j=0; j<CParamsUsed; ++j) {
//        NXPrintf(outfp, " ; ");
//        NXPrintf(outfp, CParams[j]);
//        NXPrintf(outfp, " = ");
//        NXPrintf(outfp, CParamValues[j]);
//    }
//    NXPrintf(outfp, "\n\n"); 

    TranslateInputToOutput(InputFP, outfp, EncodingCode);
    strcat(ffff,SquirrelFile);
    CreateMMP(outfp,ffff);
//    NXCloseMemory(outfp, NX_FREEBUFFER);
    return(0);
}
int CreateMMP(NXStream *stream, char *filename)
{

    int lc2strcmp();
    NXStream *basic2next();
    long len;
    char *extention=NULL;
    char *key=NULL;

    extention = rindex(filename, '.');
    if (extention) {
        ++extention;
    } else {
	extention = (char *) calloc (15, sizeof(char));
	strcpy(extention,"NULL_Extension");
    }
    NXSeek(stream, (long)0, NX_FROMEND); 
    len = NXTell(stream);
    NXSeek(stream, (long)0, NX_FROMSTART); 
    if (!lc2strcmp(extention,"plain") ) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"richtext")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
//	(*adpp)->fd_stream = richtext2rtf(stream);
	(*adpp)->fd_stream = (NXStream *)stream;
        NXSeek((*adpp)->fd_stream, (long)0, NX_FROMEND); 
//        len = NXTell((*adpp)->fd_stream);
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"andrew-inset") ||
	     !lc2strcmp(extention,"x-be2")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
        (void)strcpy(extention,"ez");
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
        NXSeek((*adpp)->fd_stream, (long)0, NX_FROMEND); 
//        len = NXTell((*adpp)->fd_stream);
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"tiff")
 	     || !lc2strcmp(extention,"next")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"vox")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
//        (void)strcpy(extention,"snd");
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"gif")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"jfif")
 	     || !strcmp(extention,"jpeg")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
        (void)strcpy(extention,"jpeg");
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!strcmp(extention,"external-body") 
 	     || !strcmp(extention,"x-news")
 	     || !strcmp(extention,"anon-ftp")
 	     || !strcmp(extention,"local-file")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
        NXSeek((*adpp)->fd_stream, (long)0, NX_FROMEND); 
//        len = NXTell((*adpp)->fd_stream);
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"ps") 
 	     || !lc2strcmp(extention,"postscript")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
        //(void)strcpy(extention,"eps");
	if (key)
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else 
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream = (NXStream *)stream;
        NXSeek((*adpp)->fd_stream, (long)0, NX_FROMEND); 
//        len = NXTell((*adpp)->fd_stream);
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"basic")
		|| !lc2strcmp(extention,"snd")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');

        (void)strcpy(extention,"snd");
	(void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	(*adpp)->fd_stream =(NXStream *) basic2next(stream);
        NXSeek((*adpp)->fd_stream, (long)0, NX_FROMEND); 
//        len = NXTell((*adpp)->fd_stream);
//	(*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    else if (!lc2strcmp(extention,"tbl")) {
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc))) == NULL){
            exit(-1);
        }
	(*adpp)->fd_type = FD_STREAM;
	(void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
	(*adpp)->fd_stream =(NXStream *) stream;
//	(*adpp)->fd_stream->buf_size = len;
	articles_desc=(*adpp);
        adpp = &(*adpp)->fd_nextp;
    }
    else{ 
        if (( *adpp = (struct mem_file_desc *)malloc(sizeof(struct mem_file_desc
))) == NULL){
            exit(-1);
        }
        (*adpp)->fd_type = FD_STREAM;
	key = rindex(filename, '/');
	if (key)
        (void)strncpy((*adpp)->fd_name , ++key , NAMSIZ);
	else
        (void)strncpy((*adpp)->fd_name , filename , NAMSIZ);
        (*adpp)->fd_stream = stream;
//      (*adpp)->fd_stream->buf_size = len;
        adpp = &(*adpp)->fd_nextp;
    }
    if ( !strcmp(extention, "NULL_Extension"))
    	free(extention);
    return(0);
}



int ExitWithError(txt)
char *txt;
{
    if (txt) fprintf(stderr, "metamail: %s\n", txt);
    NXRunAlertPanel(LoStr("MMEdit"),
	LoStr(txt),LoStr("OK"),NULL,NULL);
    exit(-1);
}

char *
FreshHeaderCopy(s)
char *s;
{
    char *t, *newcopy;
    int len;

    while (s && *s && isspace((unsigned char) *s) && *s != '\n') ++s;
    t = index(s, '\n');
    while (t && (*(t+1) == ' ' || *(t+1) == '\t')) {
        t = index(t+1, '\n');
    }
    len = t ? (t-s+1) : (strlen(s)+1);
    newcopy = malloc(len+1);
    if (!newcopy) ExitWithError(nomem);
    strncpy(newcopy, s, len);
    newcopy[len] = 0;
    return(newcopy);
}

int Read822Prefix(PrintHeads, nestingdepth)
int PrintHeads, nestingdepth;
{
    int lc2strncmp(),StripTrailingSpace(),ParseContentParameters();
    int maybephead(),phead();
    int SawNewline = 0, bytes = 0, alloced = 1000, HasEncodedChars=0;
    int  nc=0,flag=0, oldbytes;
    char c, c1;
    NXStream *fhead;
    char *s, *t, *tmp, *topmailhead;

    if (!PrintSomeHeaders) PrintHeads = 0;
    mailheaders = malloc(alloced+1);
    if (!mailheaders) ExitWithError(nomem);
//    strcpy(mailheaders, "MM_HEADERS=\n");
//    bytes = 12;
    bytes = 0;
yankagain:
    t = mailheaders + bytes;
//    oldbytes = bytes-1; /* a hack for YankMode */
    oldbytes = bytes; /* a hack for YankMode */
    while ((c = getc(InputFP)) != EOF) {
        if (++bytes >= alloced) {
            alloced += 1000;
            mailheaders = realloc(mailheaders, alloced);
            if (!mailheaders) ExitWithError(nomem);
            t = mailheaders + bytes - 1;
        }
        if ( c =='-' ){
            c1 = getc(InputFP);
            if ( c1 == '-' ){
                if (SawNewline){
            	ungetc(c1,InputFP);
            	ungetc(c,InputFP);
		break;
		}else
            	ungetc(c,InputFP);
	    }else
            ungetc(c1,InputFP);
	}else if (c == '\r') {
		if ( nc == 0 ){
			*t++=c;
			break;
		}
		nc++;
            c1 = getc(InputFP);
            if ( c1 == '\n' ){
                flag=1;
                if (SawNewline){
                     *t++=c;
                     *t++=c1;
		     break;
           	}
                SawNewline = 1;
            }
            ungetc(c1,InputFP);
        } else {
	    if (c == '\n' && flag == 1)
               	SawNewline = 1;
            else{
               	SawNewline = 0;
                flag=0;
            }
        }
        *t++ = c;
	nc=1;
    }
    *t = 0;
    --bytes;
    if (c == EOF) {
        if (nestingdepth) {
    		NXRunAlertPanel(LoStr("MMEdit"),
		LoStr("Could not extract a MIME message from the body"),LoStr("OK"),NULL,NULL);
	 	strcpy(mailheaders,"Subject: NO MESSAGE\n");	
		return(-1);
        } else {
            if (YankMode) {
    		NXRunAlertPanel(LoStr("MMEdit"),
		LoStr("Could not extract a MIME message from this body"),LoStr("OK"),NULL,NULL);
	 	strcpy(mailheaders,"Subject: NO MESSAGE\n");	
            } else {
    		NXRunAlertPanel(LoStr("MMEdit"),
		LoStr("Could not find end of message headers"),LoStr("OK"),NULL,NULL);
	 	strcpy(mailheaders,"Subject: NO MESSAGE\n");	
            }
        }
    }
//printf("<<Headers>>%s",mailheaders);
    if ( headpart == 0 ){
        fhead = NXOpenMemory(NULL,0,NX_READWRITE);
        NXPrintf(fhead,"%s",mailheaders);
        CreateMMP(fhead, "header.tbl");
    //    NXCloseMemory(fhead,NX_FREEBUFFER);
        headpart++;
    } 
    topmailhead = malloc(2*alloced);

    strcpy(topmailhead,"\n");
    strcat(topmailhead,mailheaders);
//    for (s=mailheaders; *s; ++s) {
    for (s=topmailhead; *s; ++s) {
        if (*s == '\n' && (*(s+1) != ' ') && (*(s+1) != '\t')) {
            if (!ContentType && !lc2strncmp(s, "\ncontent-type:", 14)) {
                ContentType = FreshHeaderCopy(s+14);
                StripTrailingSpace(ContentType);
                ParseContentParameters(ContentType);
                if (PrintHeads) maybephead(s+1);
            } else if (!ContentEncoding && !lc2strncmp(s, "\ncontent-transfer-encoding:", 27)) {
                ContentEncoding = FreshHeaderCopy(s+27);
                if (PrintHeads) maybephead(s+1);
            } else if (!lc2strncmp(s, "\nmime-version:", 14)) {
                if (PrintHeads) maybephead(s+1);
                Mimeversion = FreshHeaderCopy(s+9);
            } else if (!lc2strncmp(s, "\nsubject:", 9)) {
                if (PrintHeads) maybephead(s+1);
                MailSubject = FreshHeaderCopy(s+9);
            } else if (!lc2strncmp(s, "\nfrom:", 6)) {
                if (PrintHeads) maybephead(s+1);
                MailFrom = FreshHeaderCopy(s+6);
            } else if (!lc2strncmp(s, "\ncontent-description:", 4)) {
                if(PrintHeads) maybephead(s+1);
                MailSubject = FreshHeaderCopy(s+21);
            } else {
                /* Print any with encoded variables */
                char *dum = s;
                while (dum) {
                    dum = index(dum, '?');
                    if (dum && *++dum == '=') break;
                }
                if (dum) {
                    char *nl = s+1;
                    while (nl) {
                        nl = index(nl, '\n');
                        if (nl && !isspace((unsigned char) *++nl)) break;
                    }
                    if (nl && nl > dum) ++HasEncodedChars;
                }
                if (HasEncodedChars) {
                    phead(s+1);
                } else if (PrintHeads) {
                    maybephead(s+1);
                }
            }
        }
    }
    /* Ugly, but effective */
    if (YankMode && !ContentType) {
        goto yankagain;
    }
    if (PrintHeads) printf("\n");
    if (!ContentType) ContentType = "text/plain";
    for (tmp=ContentType; *tmp; ++tmp) {
        if (isupper((unsigned char) *tmp)) *tmp = tolower((unsigned char) *tmp);
    }
    return(0);
}

int PrepareMessage() {
    int c;
    int StripTrailingSpace();
    int lc2strcmp(), lc2strncmp();

    EncodingCode = ENCODING_NONE;
    if (ContentEncoding) {
        /* strip leading white space */
        while (*ContentEncoding && isspace((unsigned char) *ContentEncoding)) ++ContentEncoding;
        StripTrailingSpace(ContentEncoding);
        if (!lc2strcmp(ContentEncoding, "base64")) {
            EncodingCode = ENCODING_BASE64;
        } else if (!lc2strcmp(ContentEncoding, "quoted-printable")) {
            EncodingCode = ENCODING_QUOTEDPRINTABLE;
        } else if (!lc2strncmp (ContentEncoding, "x-uue", 5)) {
            fprintf (stderr, "WARNING:  Using nonstandard %s encoding, trying uuencode algorithm.\n", ContentEncoding);
 	    EncodingCode = ENCODING_UUENCODE;
        } else {
            if (lc2strcmp(ContentEncoding, "none")
                 && !lc2strcmp(ContentEncoding, "8bit")
                 && !lc2strcmp(ContentEncoding, "7bit")) {
                fprintf(stderr, "Ignoring unrecognized Content-Transfer-Encoding value: %s\n", ContentEncoding);
            }
        }
    }
    if (EatLeadingNewlines) {
        while ((c = getc(InputFP)) != EOF) {
            if (c != '\n') {
                NXUngetc(InputFP);
                break;
            }
        }
    }
   return(0);
}





int lc2strncmp(s1, s2, len)
char *s1, *s2;
int len;
{
    if (!s1 || !s2) return (-1);
    while (*s1 && *s2 && len > 0) {
	if (*s1 != *s2 && (tolower(*s1) != *s2)) return(-1);
	++s1; ++s2; --len;
    }
    if (len <= 0) return(0);
    return((*s1 == *s2) ? 0 : -1);
}

int lc2strcmp(s1, s2)
char *s1, *s2;
{
    if (!s1 || !s2) return (-1);
    while (*s1 && *s2) {
	if (*s1 != *s2 && (tolower(*s1) != *s2)) return(-1);
	++s1; ++s2;
    }
    return((*s1 == *s2) ? 0 : -1);
}



int StripTrailingSpace(s)
char *s;
{
    char *t = s+strlen(s) -1;
    while (isspace((unsigned char) *t)) *t-- = 0;
    return(0);
}

int maybephead(hdr)
char *hdr;
{
    static char *KeyHeads=NULL;
    static char **KeyHeadList;
    char *s;
    int phead();
    int numkeys=0, len;

    if (!KeyHeads) {
        KeyHeads = getenv("KEYHEADS");
        if (KeyHeads) {
            for (s=KeyHeads;*s;++s) if (isupper((unsigned char) *s)) *s=tolower((unsigned char) *s);
        } else {
            char *khtmp; /* to avoid writing into a string constant later */
            khtmp = "to:cc:subject:from:content-description:date";
            KeyHeads = malloc(1+strlen(khtmp));
            if (!KeyHeads) ExitWithError(nomem);
            strcpy(KeyHeads, khtmp);
        }
        for (s=KeyHeads; *s; ++s) if (*s == ':') ++numkeys;
        numkeys += 2;
        KeyHeadList = (char **) malloc((numkeys) * sizeof(char *));
        if (!KeyHeadList) ExitWithError(nomem);
        numkeys = 0;
        KeyHeadList[0] = KeyHeads;
        for(s=KeyHeads; *s; ++s) {
            if (*s == ':') {
                *s = '\0';
                KeyHeadList[++numkeys] = s+1;
            }
        }
        KeyHeadList[++numkeys] = NULL;
    }
    s = index(hdr, ':');
    if (s) {
        len = s - hdr;
        for (numkeys=0; KeyHeadList[numkeys]; ++numkeys) {
            if (!strcmp(KeyHeadList[numkeys], "*")
                 || !lc2strncmp(hdr, KeyHeadList[numkeys], len)) {
                phead(hdr);
                break;
            }
        }
    }
    return(0);
}

/* This next routine prints out a mail header, and needs to deal with the new extended charset headers. */
int phead(s)
char *s;
{
  return(0);
}


/* This is the part that actually handles the charset issues */


int WriteTmpFile(fname)
char *fname;
{
    NXStream *fpout;
    int retval = 0;
    int TranslateInputToOutput();

    fpout = NXOpenMemory(NULL,0,NX_READWRITE);
    if (!fpout) ExitWithError("Can't create temporary file");
    TranslateInputToOutput(InputFP, fpout, EncodingCode);
    if (NXTell(fpout) == 0) retval = 1;
    CreateMMP(fpout, fname);
//    NXCloseMemory(fpout,NX_FREEBUFFER);
    return(retval);
}

int TranslateInputToOutput(InputFP, OutputFP, Ecode)
NXStream *InputFP, *OutputFP;
int Ecode;
{
    int from64(),fromqp(),fromuue();
    int ConsumeRestOfPart();
    int InMultipart = BoundaryCt > 0 ? 1 : 0;

    switch(Ecode) {
        case ENCODING_BASE64:
            from64(InputFP, OutputFP, InMultipart ? Boundaries : NULL, &BoundaryCt);
            break;
        case ENCODING_QUOTEDPRINTABLE:
            fromqp(InputFP, OutputFP, InMultipart ? Boundaries : NULL, &BoundaryCt);
            break;
 	case ENCODING_UUENCODE:
 	    fromuue(InputFP, OutputFP, InMultipart ? Boundaries: NULL, &BoundaryCt);
 	    break;
        default:
            ConsumeRestOfPart(OutputFP);
    }
    return(0);
}


int MkTmpFileName(name)
char *name;
{
	static int ctr = 0;
#ifdef AMIGA
    strcpy(name, "T:mmXXXXXX");
    mktemp(name);
#else
#ifndef __MSDOS__
    char *subtype=NULL;
	if (ContentType){
        subtype = index(ContentType, '/');
	}
            if (subtype) {
                ++subtype;
                subtype = Cleanse(subtype);
            } else subtype = "mixed";

    sprintf(name, "/tmp/mm_%d_%d_%d.%s", getuid(), getpid(), ctr++,subtype);
#else
     strcpy(name, "TXXXXXX");
     if (!mktemp(name))
         name[0] = 0;
     else
         printf("temp name = \"%s\"\n", name);
#endif
#endif
   return(0);
}


int ConsumeRestOfPart(outfp)
NXStream *outfp;
{
    char *Buf;
    int PendingBoundary();
    int c;

    if (BoundaryCt <= 0) {
        while ((c=getc(InputFP)) != EOF) {
            if (outfp) putc(c, outfp);
        }
        return(0);
    }
    Buf = malloc(LINE_BUF_SIZE);
    if (!Buf) ExitWithError(nomem);
//    while (fgets(Buf, LINE_BUF_SIZE, InputFP)) {
    c = 0;
    while ( c != -1 ) {
        c = readline(InputFP,Buf, LINE_BUF_SIZE);
//          c = NXScanf(InputFP,"%1999[^\n]\n",LineBuf);
        if ((BoundaryCt > 0)
             && (Buf[0] == '-')
             && (Buf[1] == '-')
             && PendingBoundary(Buf, Boundaries, &BoundaryCt)) {
            break;
        }
//        if (outfp) writeline(outfp,Buf,strlen(Buf));
        if (outfp) NXPrintf(outfp,Buf);
    }
    free(Buf);
    return(0);
}

char *paramend(s)
char *s;
{
    int inquotes=0;
    while (*s) {
        if (inquotes) {
            if (*s == '"') {
                inquotes = 0;
            } else if (*s == '\\') {
                ++s; /* skip a char */
            }
        } else if (*s == ';') {
            return(s);
        } else if (*s == '"') {
            inquotes = 1;
        }
        ++s;
    }
    return(NULL);
}        

int ParseContentParameters(ct)
char *ct;
{
    char *s, *t, *eq;

    CParamsUsed = 0;
    s = index(ct, ';');
    if (!s) return(0);
    *s++ = 0;
    do {
        t = paramend(s);
        if (t) *t++ = 0;
        eq = index(s, '=');
        if (!eq) {
            fprintf(stderr, "Ignoring unparsable content-type parameter: '%s'\n", s);
            JunkParameter=Cleanse(s);
        } else {
            if (CParamsUsed >= CParamsAlloced) {
                CParamsAlloced += 10;
                if (CParams) {
                    CParams = (char **) realloc(CParams, (1+CParamsAlloced) * sizeof (char *));
                    CParamValues = (char **) realloc(CParamValues, (1+CParamsAlloced) * sizeof (char *));
                } else {
                    CParams = (char **) malloc((1+CParamsAlloced) * sizeof (char *));
                    CParamValues = (char **) malloc((1+CParamsAlloced) * sizeof (char *));
                }
                if (!CParams || !CParamValues) ExitWithError(nomem);
            }
            *eq++ = 0;
            s = Cleanse(s);
            CParams[CParamsUsed] = s;
            /* strip leading white space */
            while (*eq && isspace((unsigned char) *eq)) ++eq;
            /* strip trailing white space */
            StripTrailingSpace(eq);
            CParamValues[CParamsUsed++] = eq; 
            if (DoDebug) printf("NEW PARAMETER: %s VALUE: %s\n", s, eq);
        }
        s = t;
    } while (t);
    return(0);
}

char *FindParam(s)
char *s;
{
    int i;
    for (i=0; i<CParamsUsed; ++i) {
        if (!strcmp(s, CParams[i])) {
            return(CParamValues[i]);
        }
    }
    return(NULL);
}


void strcatquoting(s1, s2)
char *s1;
char *s2;
{
    strcat(s1, s2);
#ifdef NOTDEF
    while (*s1) ++s1;
    while (*s2) {
        if (*s2 == '\"' || *s2 == '\\') *s1++ = '\\';
        *s1++ = *s2++;
    }
    *s1 = '\0';
#endif
}

void concatstream(plaintexts,addtext)
NXStream *plaintexts;
NXStream *addtext;
{
    int t,len,max,size;
    char *buff;

    NXSeek(plaintexts, (long)0,NX_FROMSTART);
    NXSeek(plaintexts, (long)0,NX_FROMEND);
    (long)t = NXTell(plaintexts);
    NXSeek(addtext, (long)0,NX_FROMEND);
    (long)size = NXTell(addtext);
    NXSeek(addtext, (long)0,NX_FROMSTART);
    NXGetMemoryBuffer(addtext,&buff,&len,&max);
    NXWrite(plaintexts, (const void *)buff, size);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.