From c7cf30de2999c1cac0a1ddc0b7141630c84d070f Mon Sep 17 00:00:00 2001 From: "rhp%netscape.com" Date: Thu, 27 Jan 2000 00:02:23 +0000 Subject: [PATCH] Adding new files for AppleDouble support ... NOT PART OF THE BUILD git-svn-id: svn://10.0.0.236/trunk@58849 18797224-902f-48f8-a5cc-f745e15eee43 --- .../mailnews/compose/src/nsMsgAppleDecode.cpp | 1778 +++++++++++++++++ .../compose/src/nsMsgAppleDecodeStream.cpp | 725 +++++++ .../mailnews/compose/src/nsMsgAppleDouble.cpp | 616 ++++++ .../mailnews/compose/src/nsMsgAppleEncode.cpp | 735 +++++++ 4 files changed, 3854 insertions(+) create mode 100755 mozilla/mailnews/compose/src/nsMsgAppleDecode.cpp create mode 100755 mozilla/mailnews/compose/src/nsMsgAppleDecodeStream.cpp create mode 100755 mozilla/mailnews/compose/src/nsMsgAppleDouble.cpp create mode 100755 mozilla/mailnews/compose/src/nsMsgAppleEncode.cpp diff --git a/mozilla/mailnews/compose/src/nsMsgAppleDecode.cpp b/mozilla/mailnews/compose/src/nsMsgAppleDecode.cpp new file mode 100755 index 00000000000..32ca5c94509 --- /dev/null +++ b/mozilla/mailnews/compose/src/nsMsgAppleDecode.cpp @@ -0,0 +1,1778 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * + * apple_double_decode.c + * + * --------------------- + * + * Codes for decoding Apple Single/Double object parts. + * + * 05aug95 mym Created. + * 25sep95 mym Add support to write to binhex encoding on non-mac system. + */ + +#include "nscore.h" +#include "msgCore.h" + +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleCodes.h" +#include "m_binhex.h" +#ifdef XP_MAC +#include +#endif + +extern int MK_UNABLE_TO_OPEN_TMP_FILE; +extern int MK_MIME_ERROR_WRITING_FILE; + +/* +** Static functions. +*/ +PRIVATE int from_decoder(appledouble_decode_object* p_ap_decode_obj, + char *buff, + int buff_size, + PRInt32 *in_count); +PRIVATE int from_64(appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRInt32 *real_size); +PRIVATE int from_qp(appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRInt32 *real_size); +PRIVATE int from_uu(appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRInt32 *real_size); +PRIVATE int from_none(appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRInt32 *real_size); + +PRIVATE int decoder_seek(appledouble_decode_object* p_ap_decode_obj, + int seek_pos, + int start_pos); + +/* +** fetch_a_line +** ------------- +** +** get a line from the in stream.. +*/ +int fetch_a_line( + appledouble_decode_object* p_ap_decode_obj, + char *buff) +{ + int i, left; + char *p, c = 0; + + if (p_ap_decode_obj->s_leftover == 0 && + p_ap_decode_obj->s_inbuff <= p_ap_decode_obj->pos_inbuff) + { + *buff = '\0'; + return errEOB; + } + + if (p_ap_decode_obj->s_leftover) + { + for (p = p_ap_decode_obj->b_leftover, i = p_ap_decode_obj->s_leftover; i>0; i--) + *buff++ = *p++; + + p_ap_decode_obj->s_leftover = 0; + } + + p = p_ap_decode_obj->inbuff + p_ap_decode_obj->pos_inbuff; + left = p_ap_decode_obj->s_inbuff - p_ap_decode_obj->pos_inbuff; + + for (i = 0; i < left; ) + { + c = *p++; i++; + + if (c == CR && *p == LF) + { + p++; i++; /* make sure skip both LF & CR */ + } + + if (c == LF || c == CR) + break; + + *buff++ = c; + } + p_ap_decode_obj->pos_inbuff += i; + + if (i == left && c != LF && c != CR) + { + /* + ** we meet the buff end before we can terminate the string, + ** save the string to the left_over buff. + */ + p_ap_decode_obj->s_leftover = i; + + for (p = p_ap_decode_obj->b_leftover; i>0; i--) + *p++ = *(buff-i); + + return errEOB; + } + *buff = '\0'; + return NOERR; +} + +void parse_param( + char *p, + char **param, /* the param */ + char **define, /* the defination. */ + char **np) /* next position. */ +{ + while (*p == ' ' || *p == '\"' || *p == ';') p++; + *param = p; + + while (*p != ' ' && *p != '=' ) p++; + if (*p == ' ') + *define = p+1; + else + *define = p+2; + + while (*p && *p != ';') p++; + + if (*p == ';') + *np = p + 1; + else + *np = p; +} + +int ap_seek_part_start( + appledouble_decode_object* p_ap_decode_obj) +{ + int status; + char newline[256]; + + while (1) + { + status = fetch_a_line(p_ap_decode_obj, newline); + if(status != NOERR) + break; + + if (newline[0] == '\0' && p_ap_decode_obj->boundary0 != NULL) + return errDone; + + if (!XP_STRNCASECMP(newline, "--", 2)) + { + /* we meet the start seperator, copy it and it will be our boundary */ + p_ap_decode_obj->boundary0 = XP_STRDUP(newline+2); + return errDone; + } + } + return status; +} + +int ParseFileHeader( + appledouble_decode_object *p_ap_decode_obj) +{ + int status; + int i; + char newline[256], *p; + char *param, *define; + + while (1) + { + status = fetch_a_line(p_ap_decode_obj, newline); + if (newline[0] == '\0') + break; /* we get the end of a defination section. */ + + p = newline; + while (1) + { + parse_param(p, ¶m, &define, &p); + /* + ** we only care about these params. + */ + if (!XP_STRNCASECMP(param, "Content-Type:", 13)) + { + if (!XP_STRNCASECMP(define, MULTIPART_APPLEDOUBLE, + nsCRT::strlen(MULTIPART_APPLEDOUBLE)) || + !XP_STRNCASECMP(define, MULTIPART_HEADER_SET, + nsCRT::strlen(MULTIPART_HEADER_SET))) + p_ap_decode_obj->messagetype = kAppleDouble; + else + p_ap_decode_obj->messagetype = kGeneralMine; + } + else if (!XP_STRNCASECMP(param, "boundary=", 9)) + { + for (i = 0; *define && *define != '\"'; ) + p_ap_decode_obj->boundary0[i++] = *define++; + + p_ap_decode_obj->boundary0[i] = '\0'; + } + else if (!XP_STRNCASECMP(param, "Content-Disposition:", 20)) + { + if (!XP_STRNCASECMP(define, "inline", 5)) + p_ap_decode_obj->deposition = kInline; + else + p_ap_decode_obj->deposition = kDontCare; + } + else if (!XP_STRNCASECMP(param, "filename=", 9)) + { + for (i = 0, p=define; *p && *p != '\"'; ) + p_ap_decode_obj->fname[i++] = *p++; + + p_ap_decode_obj->fname[i] = '\0'; + } + + if (*p == '\0') + break; + } + } + + return NOERR; +} + +int ap_seek_to_boundary( + appledouble_decode_object *p_ap_decode_obj, + PRBool firstime) +{ + int status = NOERR; + char buff[256]; + + while (status == NOERR) + { + status = fetch_a_line(p_ap_decode_obj, buff); + if (status != NOERR) + break; + + if ((!XP_STRNCASECMP(buff, "--", 2) && + !XP_STRNCASECMP( buff+2, + p_ap_decode_obj->boundary0, + nsCRT::strlen(p_ap_decode_obj->boundary0))) + ||!XP_STRNCASECMP( buff, + p_ap_decode_obj->boundary0, + nsCRT::strlen(p_ap_decode_obj->boundary0))) + { + TRACEMSG(("Found boundary: %s", p_ap_decode_obj->boundary0)); + status = errDone; + break; + } + } + + if (firstime && status == errEOB) + status = NOERR; /* so we can do it again. */ + + return status; +} + +int ap_parse_header( + appledouble_decode_object *p_ap_decode_obj, + PRBool firstime) +{ + int status, i; + char newline[256], *p; + char *param, *define; + + if (firstime) + { + /* do the clean ups. */ + p_ap_decode_obj->encoding = kEncodeNone; + p_ap_decode_obj->which_part = kFinishing; + } + + while (1) + { + status = fetch_a_line(p_ap_decode_obj, newline); + if (status != NOERR) + return status; /* a possible end of buff happened. */ + + if (newline[0] == '\0') + break; /* we get the end of a defination section. */ + + p = newline; + while (1) + { + parse_param(p, ¶m, &define, &p); + /* + ** we only care about these params. + */ + if (!XP_STRNCASECMP(param, "Content-Type:", 13)) + { + if (!XP_STRNCASECMP(define, "application/applefile", 21)) + p_ap_decode_obj->which_part = kHeaderPortion; + else + { + p_ap_decode_obj->which_part = kDataPortion; + if (!XP_STRNCASECMP(define, "text/plain", 10)) + p_ap_decode_obj->is_binary = FALSE; + else + p_ap_decode_obj->is_binary = TRUE; + } + + /* Broken QuickMail messages */ + if (!XP_STRNCASECMP(define, "x-uuencode-apple-single", 23)) + p_ap_decode_obj->encoding = kEncodeUU; + } + else if (!XP_STRNCASECMP(param, "Content-Transfer-Encoding:",26)) + { + if (!XP_STRNCASECMP(define, "base64", 6)) + p_ap_decode_obj->encoding = kEncodeBase64; + else if (!XP_STRNCASECMP(define, "quoted-printable", 16)) + p_ap_decode_obj->encoding = kEncodeQP; + else + p_ap_decode_obj->encoding = kEncodeNone; + } + else if (!XP_STRNCASECMP(param, "Content-Disposition:", 20)) + { + if (!XP_STRNCASECMP(define, "inline", 5)) + p_ap_decode_obj->deposition = kInline; + else + p_ap_decode_obj->deposition = kDontCare; + } + else if (!XP_STRNCASECMP(param, "filename=", 9)) + { + if (p_ap_decode_obj->fname[0] == '\0') + { + for (i = 0; *define && *define != '\"'; ) + p_ap_decode_obj->fname[i++] = *define++; + + p_ap_decode_obj->fname[i] = '\0'; + } + } + + if (*p == '\0') + break; + } + } + return errDone; +} + + +/* +** decode the head portion. +*/ + + +int ap_decode_file_infor(appledouble_decode_object *p_ap_decode_obj) +{ + ap_header head; + ap_entry entries[NUM_ENTRIES + 1]; + int i, j; + int st_pt; + PRInt32 in_count; + int status; + char name[256]; + PRBool positionedAtRFork = FALSE; + + st_pt = p_ap_decode_obj->pos_inbuff; + + /* + ** Read & verify header + */ + status = from_decoder( + p_ap_decode_obj, + (char *) &head, + 26, /* sizeof (head), */ + &in_count); + if (status != NOERR) + return status; + + if (p_ap_decode_obj->is_apple_single) + { + if (ntohl(head.magic) != APPLESINGLE_MAGIC) + return errVersion; + } + else + { + if(ntohl(head.magic) != APPLEDOUBLE_MAGIC) + return errVersion; + } + + if (ntohl(head.version) != VERSION) + { + return errVersion; + } + + /* read entries */ + head.entries = ntohs(head.entries); + for (i = j = 0; i < head.entries; ++i) + { + status = from_decoder( + p_ap_decode_obj, + (char *) (entries + j), + sizeof (ap_entry), + &in_count); + if (status != NOERR) + return errDecoding; + + /* + ** correct the byte order now. + */ + entries[j].id = ntohl(entries[j].id); + entries[j].offset = ntohl(entries[j].offset); + entries[j].length = ntohl(entries[j].length); + /* + ** only care about these entries... + */ + if (j < NUM_ENTRIES) + switch (entries[j].id) + { + case ENT_NAME: + case ENT_FINFO: + case ENT_DATES: + case ENT_COMMENT: + case ENT_RFORK: + case ENT_DFORK: + ++j; + break; + } + } + + in_count = nsCRT::strlen(p_ap_decode_obj->fname); + + /* if the user has not provided the output file name, read it + * from the ENT_NAME entry + */ + + if (in_count == 0) + { + /* read name */ + for (i = 0; i < j && entries[i].id != ENT_NAME; ++i) + ; + if (i == j) + return errDecoding; + + status = decoder_seek( + p_ap_decode_obj, + entries[i].offset, + st_pt); + if (status != NOERR) + return status; + + if (entries[i].length > 63) + entries[i].length = 63; + + status = from_decoder( + p_ap_decode_obj, + p_ap_decode_obj->fname, + entries[i].length, + &in_count); + if (status != NOERR) + return status; + + p_ap_decode_obj->fname[in_count] = '\0'; + } + + /* P_String version of the file name. */ + XP_STRCPY((char *)name+1, p_ap_decode_obj->fname); + name[0] = (char) in_count; + + if (p_ap_decode_obj->write_as_binhex) + { + /* + ** fill out the simple the binhex head. + */ + binhex_header head; + myFInfo myFInfo; + + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + name, + name[0] + 2); + if (status != NOERR) + return status; + + /* get finder info */ + for (i = 0; i < j && entries[i].id != ENT_FINFO; ++i) + ; + if (i < j) + { + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + if (status != NOERR) + return status; + + status = from_decoder(p_ap_decode_obj, + (char *) &myFInfo, + sizeof (myFInfo), + &in_count); + if (status != NOERR) + return status; + } + + head.type = myFInfo.fdType; + head.creator = myFInfo.fdCreator; + head.flags = myFInfo.fdFlags; + + for (i = 0; i < j && entries[i].id != ENT_DFORK; ++i) + ; + if (i < j && entries[i].length != 0) + { + head.dlen = entries[i].length; /* set the data fork length */ + } + else + { + head.dlen = 0; + } + + for (i = 0; i < j && entries[i].id != ENT_RFORK; ++i) + ; + if (i < j && entries[i].length != 0) + { + head.rlen = entries[i].length; /* set the resource fork length */ + } + else + { + head.rlen = 0; + } + + /* + ** and the dlen, rlen is in the host byte order, correct it if needed ... + */ + head.dlen = htonl(head.dlen); + head.rlen = htonl(head.rlen); + /* + ** then encode them in binhex. + */ + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + (char*)&head, + sizeof(binhex_header)); + if (status != NOERR) + return status; + + /* + ** after we have done with the header, end the binhex header part. + */ + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + NULL, + 0); + } + else + { + +#ifdef XP_MAC + + ap_dates dates; + HFileInfo *fpb; + CInfoPBRec cipbr; + IOParam vinfo; + GetVolParmsInfoBuffer vp; + DTPBRec dtp; + char comment[256]; + + unsigned char filename[256]; /* this is a pascal string - should be unsigned char. */ + StandardFileReply reply; + + /* convert char* p_ap_decode_obj->fname to a pascal string */ + XP_STRCPY((char*)filename + 1, p_ap_decode_obj->fname); + filename[0] = nsCRT::strlen(p_ap_decode_obj->fname); + + if( !p_ap_decode_obj->mSpec ) + { + StandardPutFile("\pSave decoded file as:", + (const unsigned char*)filename, + &reply); + + if (!reply.sfGood) + { + return errUsrCancel; + } + } + else + { + reply.sfFile.vRefNum = p_ap_decode_obj->mSpec->vRefNum; + reply.sfFile.parID = p_ap_decode_obj->mSpec->parID; + XP_MEMCPY(&reply.sfFile.name, p_ap_decode_obj->mSpec->name , 63 ); + } + + XP_MEMCPY(p_ap_decode_obj->fname, + reply.sfFile.name+1, + *(reply.sfFile.name)+1); + p_ap_decode_obj->fname[*(reply.sfFile.name)] = '\0'; + + p_ap_decode_obj->vRefNum = reply.sfFile.vRefNum; + p_ap_decode_obj->dirId = reply.sfFile.parID; + + /* create & get info for file */ + HDelete(reply.sfFile.vRefNum, + reply.sfFile.parID, + reply.sfFile.name); + +#define DONT_CARE_TYPE 0x3f3f3f3f + + if (HCreate(reply.sfFile.vRefNum, + reply.sfFile.parID, + reply.sfFile.name, + DONT_CARE_TYPE, + DONT_CARE_TYPE) != NOERR) + { + return errFileOpen; + } + + fpb = (HFileInfo *) &cipbr; + fpb->ioVRefNum = reply.sfFile.vRefNum; + fpb->ioDirID = reply.sfFile.parID; + fpb->ioNamePtr = reply.sfFile.name; + fpb->ioFDirIndex = 0; + PBGetCatInfoSync(&cipbr); + + /* get finder info */ + for (i = 0; i < j && entries[i].id != ENT_FINFO; ++i) + ; + if (i < j) + { + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + if (status != NOERR) + return status; + + status = from_decoder(p_ap_decode_obj, + (char *) &fpb->ioFlFndrInfo, + sizeof (FInfo), + &in_count); + if (status != NOERR) + return status; + + status = from_decoder(p_ap_decode_obj, + (char *) &fpb->ioFlXFndrInfo, + sizeof (FXInfo), + &in_count); + + if (status != NOERR && status != errEOP ) + return status; + + fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */ + } + + /* + ** get file date info + */ + for (i = 0; i < j && entries[i].id != ENT_DATES; ++i) + ; + if (i < j) + { + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + if (status != NOERR && status != errEOP ) + return status; + + status = from_decoder(p_ap_decode_obj, + (char *) &dates, + sizeof (dates), + &in_count); + if (status != NOERR) + return status; + + fpb->ioFlCrDat = dates.create - CONVERT_TIME; + fpb->ioFlMdDat = dates.modify - CONVERT_TIME; + fpb->ioFlBkDat = dates.backup - CONVERT_TIME; + } + + /* + ** update info + */ + fpb->ioDirID = fpb->ioFlParID; + PBSetCatInfoSync(&cipbr); + + /* + ** get comment & save it + */ + for (i = 0; i < j && entries[i].id != ENT_COMMENT; ++i) + ; + if (i < j && entries[i].length != 0) + { + memset((void *) &vinfo, '\0', sizeof (vinfo)); + vinfo.ioVRefNum = fpb->ioVRefNum; + vinfo.ioBuffer = (Ptr) &vp; + vinfo.ioReqCount = sizeof (vp); + if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == NOERR && + ((vp.vMAttrib >> bHasDesktopMgr) & 1)) + { + memset((void *) &dtp, '\0', sizeof (dtp)); + dtp.ioVRefNum = fpb->ioVRefNum; + if (PBDTGetPath(&dtp) == NOERR) + { + if (entries[i].length > 255) + entries[i].length = 255; + + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + if (status != NOERR) + return status; + + status = from_decoder(p_ap_decode_obj, + comment, + entries[i].length, + &in_count); + if (status != NOERR) + return status; + + dtp.ioDTBuffer = (Ptr) comment; + dtp.ioNamePtr = fpb->ioNamePtr; + dtp.ioDirID = fpb->ioDirID; + dtp.ioDTReqCount = entries[i].length; + if (PBDTSetCommentSync(&dtp) == NOERR) + { + PBDTFlushSync(&dtp); + } + } + } + } + +#else + /* + ** in non-mac system, creating a data fork file will be it. + */ +#endif + } + + /* + ** Get the size of the resource fork, and (maybe) position to the beginning of it. + */ + for (i = 0; i < j && entries[i].id != ENT_RFORK; ++i) + ; + if (i < j && entries[i].length != 0) + { +#ifdef XP_MAC + /* Seek to the start of the resource fork only if we're on a Mac */ + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + positionedAtRFork = TRUE; +#endif + p_ap_decode_obj->rksize = entries[i].length; + } + else + p_ap_decode_obj->rksize = 0; + + /* + ** Get the size of the data fork, and (maybe) position to the beginning of it. + */ + for (i = 0; i < j && entries[i].id != ENT_DFORK; ++i) + ; + if (i < j && entries[i].length != 0) + { + if (p_ap_decode_obj->is_apple_single && !positionedAtRFork) + status = decoder_seek(p_ap_decode_obj, + entries[i].offset, + st_pt); + p_ap_decode_obj->dksize = entries[i].length; + } + else + p_ap_decode_obj->dksize = 0; + + /* + ** Prepare a tempfile to hold the resource fork decoded by the decoder, + ** because in binhex, resource fork appears after the data fork!!! + */ + if (p_ap_decode_obj->write_as_binhex) + { + if (p_ap_decode_obj->rksize != 0) + { + /* we need a temp file to hold all the resource data, because the */ + p_ap_decode_obj->tmpfname + = WH_TempName(xpTemporary, "apmail"); + + p_ap_decode_obj->tmpfd + = XP_FileOpen(p_ap_decode_obj->tmpfname, + xpTemporary, + XP_FILE_TRUNCATE_BIN); + + if (p_ap_decode_obj->tmpfd == NULL) + return errFileOpen; + } + } + return NOERR; +} + +/* +** ap_decode_process_header +** +** +*/ +int ap_decode_process_header( + appledouble_decode_object* p_ap_decode_obj, + PRBool firstime) +{ + PRInt32 in_count; + int status = NOERR; + char wr_buff[1024]; + + if (firstime) + { + status = ap_decode_file_infor(p_ap_decode_obj); + if (status != NOERR) + return status; + + if (p_ap_decode_obj->rksize > 0) + { +#ifdef XP_MAC + if(!p_ap_decode_obj->write_as_binhex) + { + Str63 fname; + short refNum; + + fname[0] = nsCRT::strlen(p_ap_decode_obj->fname); + XP_STRCPY((char*)fname+1, p_ap_decode_obj->fname); + + if (HOpenRF(p_ap_decode_obj->vRefNum, + p_ap_decode_obj->dirId, + fname, + fsWrPerm, + &refNum) != NOERR) + { + return (errFileOpen); + } + p_ap_decode_obj->fileId = refNum; + } +#endif + } + else + { + status = errDone; + } + } + + /* + ** Time to continue decoding all the resource data. + */ + while (status == NOERR && p_ap_decode_obj->rksize > 0) + { + in_count = PR_MIN(1024, p_ap_decode_obj->rksize); + + status = from_decoder(p_ap_decode_obj, + wr_buff, + in_count, + &in_count); + + if (p_ap_decode_obj->write_as_binhex) + { + /* + ** Write to the temp file first, because the resource fork appears after + ** the data fork in the binhex encoding. + */ + if (XP_FileWrite(wr_buff, + in_count, + p_ap_decode_obj->tmpfd) != in_count) + { + status = errFileWrite; + break; + } + p_ap_decode_obj->data_size += in_count; + } + else + { +#ifdef XP_MAC + long howMuch = in_count; + + if (FSWrite(p_ap_decode_obj->fileId, + &howMuch, + wr_buff) != NOERR) + { + status = errFileWrite; + break; + } +#else + /* ====== Write nothing in a non mac file system ============ */ +#endif + } + + p_ap_decode_obj->rksize -= in_count; + } + + if (p_ap_decode_obj->rksize <= 0 || status == errEOP) + { + if (p_ap_decode_obj->write_as_binhex) + { + /* + ** No more resource data, but we are not done + ** with tempfile yet, just seek back to the start point, + ** -- ready for a readback later + */ + if (p_ap_decode_obj->tmpfd) + XP_FileSeek(p_ap_decode_obj->tmpfd, 0L, 1); + } + +#ifdef XP_MAC + else if (p_ap_decode_obj->fileId) /* close the resource fork of the macfile */ + { + FSClose(p_ap_decode_obj->fileId); + p_ap_decode_obj->fileId = 0; + } +#endif + if (!p_ap_decode_obj->is_apple_single) + { + p_ap_decode_obj->left = 0; + p_ap_decode_obj->state64 = 0; + } + status = errDone; + } + return status; +} + +int ap_decode_process_data( + appledouble_decode_object* p_ap_decode_obj, + PRBool firstime) +{ + char wr_buff[1024]; + PRInt32 in_count; + int status = NOERR; + int retval = NOERR; + + if (firstime) + { + if (!p_ap_decode_obj->write_as_binhex) + { +#ifdef XP_MAC + char *filename; + FSSpec fspec; + + fspec.vRefNum = p_ap_decode_obj->vRefNum; + fspec.parID = p_ap_decode_obj->dirId; + fspec.name[0] = nsCRT::strlen(p_ap_decode_obj->fname); + XP_STRCPY((char*)fspec.name+1, p_ap_decode_obj->fname); + + filename = my_PathnameFromFSSpec(&fspec); + if (p_ap_decode_obj->is_binary) + p_ap_decode_obj->fd = + XP_FileOpen(filename+7, xpURL, XP_FILE_TRUNCATE_BIN); + else + p_ap_decode_obj->fd = + XP_FileOpen(filename+7, xpURL, XP_FILE_TRUNCATE); + PR_FREEIF(filename); +#else + if (p_ap_decode_obj->is_binary) + p_ap_decode_obj->fd = + XP_FileOpen(p_ap_decode_obj->fname, xpURL, XP_FILE_TRUNCATE_BIN); + else + p_ap_decode_obj->fd = + XP_FileOpen(p_ap_decode_obj->fname, xpURL, XP_FILE_TRUNCATE); +#endif + } + else + { + ; /* == don't need do anything to binhex stream, it is ready already == */ + } + } + + if (p_ap_decode_obj->is_apple_single && + p_ap_decode_obj->dksize == 0) + { + /* if no data in apple single, we already done then. */ + status = errDone; + } + + while (status == NOERR && retval == NOERR) + { + retval = from_decoder(p_ap_decode_obj, + wr_buff, + 1024, + &in_count); + + if (p_ap_decode_obj->is_apple_single) /* we know the data fork size in */ + p_ap_decode_obj->dksize -= in_count; /* apple single, use it to decide the end */ + + if (p_ap_decode_obj->write_as_binhex) + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + wr_buff, + in_count); + else + status = XP_FileWrite(wr_buff, + in_count, + p_ap_decode_obj->fd) == in_count ? NOERR : errFileWrite; + + if (retval == errEOP || /* for apple double, we meet the boundary */ + ( p_ap_decode_obj->is_apple_single && + p_ap_decode_obj->dksize <= 0)) /* for apple single, we know it is ending */ + { + status = errDone; + break; + } + } + + if (status == errDone) + { + if (p_ap_decode_obj->write_as_binhex) + { + /* CALL with data == NULL && size == 0 to end a part object in binhex encoding */ + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + NULL, + 0); + if (status != NOERR) + return status; + } + else if (p_ap_decode_obj->fd) + { + XP_FileClose(p_ap_decode_obj->fd); + p_ap_decode_obj->fd = 0; + } + + status = errDone; + } + return status; +} + +/* +** Fill the data from the decoder stream. +*/ +PRIVATE int from_decoder( + appledouble_decode_object* p_ap_decode_obj, + char *buff, + int buff_size, + PRUPRInt32 *in_count) +{ + int status; + + switch (p_ap_decode_obj->encoding) + { + case kEncodeQP: + status = from_qp(p_ap_decode_obj, + buff, + buff_size, + in_count); + break; + case kEncodeBase64: + status = from_64(p_ap_decode_obj, + buff, + buff_size, + in_count); + break; + case kEncodeUU: + status = from_uu(p_ap_decode_obj, + buff, + buff_size, + in_count); + break; + case kEncodeNone: + default: + status = from_none(p_ap_decode_obj, + buff, + buff_size, + in_count); + break; + } + return status; +} + +/* +** decoder_seek +** +** simulate a stream seeking on the encoded stream. +*/ +PRIVATE int decoder_seek( + appledouble_decode_object* p_ap_decode_obj, + int seek_pos, + int start_pos) +{ + char tmp[1024]; + int status = NOERR; + PRUPRInt32 in_count; + + /* + ** force a reset on the in buffer. + */ + p_ap_decode_obj->state64 = 0; + p_ap_decode_obj->left = 0; + p_ap_decode_obj->pos_inbuff = start_pos; + p_ap_decode_obj->uu_starts_line = TRUE; + p_ap_decode_obj->uu_bytes_written = p_ap_decode_obj->uu_line_bytes = 0; + p_ap_decode_obj->uu_state = kWaitingForBegin; + + while (seek_pos > 0) + { + status = from_decoder(p_ap_decode_obj, + tmp, + PR_MIN(1024, seek_pos), + &in_count); + if (status != NOERR) + break; + + seek_pos -= in_count; + } + return status; +} + +#define XX 127 +/* + * Table for decoding base64 + */ +static char index_64[256] = { + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,62, XX,XX,XX,63, + 52,53,54,55, 56,57,58,59, 60,61,XX,XX, XX,XX,XX,XX, + XX, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,XX, XX,XX,XX,XX, + XX,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, +}; + +#ifdef XP_OS2_HACK +/*DSR102196 - the OS/2 Visual Age compiler croaks when it tries*/ +/*to optomize this macro (/O+ on CSD4) */ +char CHAR64(int c) +{ + unsigned char index; + char rc; + + index = (unsigned char) c; + rc = index_64[index]; + return rc; +} +#else /*normal code...*/ +#define CHAR64(c) (index_64[(unsigned char)(c)]) +#endif +#define EndOfBuff(p) ((p)->pos_inbuff >= (p)->s_inbuff) + +PRIVATE int fetch_next_char_64( + appledouble_decode_object* p_ap_decode_obj) +{ + char c; + + c = p_ap_decode_obj->inbuff[p_ap_decode_obj->pos_inbuff++]; + if (c == '-') + --p_ap_decode_obj->pos_inbuff; /* put back */ + + while (c == LF || c == CR) /* skip the CR character. */ + { + if (EndOfBuff(p_ap_decode_obj)) + { + c = 0; + break; + } + + c = p_ap_decode_obj->inbuff[p_ap_decode_obj->pos_inbuff++]; + if (c == '-') + { + --p_ap_decode_obj->pos_inbuff; /* put back */ + } + } + return (int)c; +} + + +PRIVATE int from_64( + appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRUPRInt32 *real_size) +{ + int i, j, buf[4]; + int c1, c2, c3, c4; + + (*real_size) = 0; + + /* + ** decode 4 by 4s characters + */ + for (i = p_ap_decode_obj->state64; i<4; i++) + { + if (EndOfBuff(p_ap_decode_obj)) + { + p_ap_decode_obj->state64 = i; + break; + } + if ((p_ap_decode_obj->c[i] = fetch_next_char_64(p_ap_decode_obj)) == 0) + break; + } + + if (i != 4) + { + /* + ** not enough data to fill the decode buff. + */ + return errEOB; /* end of buff */ + } + + while (size > 0) + { + c1 = p_ap_decode_obj->c[0]; + c2 = p_ap_decode_obj->c[1]; + c3 = p_ap_decode_obj->c[2]; + c4 = p_ap_decode_obj->c[3]; + + if (c1 == '-' || c2 == '-' || c3 == '-' || c4 == '-') + { + return errEOP; /* we meet the part boundary. */ + } + + if (c1 == '=' || c2 == '=') + { + return errDecoding; + } + + c1 = CHAR64(c1); + c2 = CHAR64(c2); + buf[0] = ((c1<<2) | ((c2&0x30)>>4)); + + if (c3 != '=') + { + c3 = CHAR64(c3); + buf[1] = (((c2&0x0F) << 4) | ((c3&0x3C) >> 2)); + + if (c4 != '=') + { + c4 = CHAR64(c4); + buf[2] = (((c3&0x03) << 6) | c4); + } + else + { + if (p_ap_decode_obj->left == 0) + { + *buff++ = buf[0]; (*real_size)++; + } + *buff++ = buf[1]; (*real_size)++; + /* return errEOP; */ /* bug 87784 */ + return EndOfBuff(p_ap_decode_obj) ? errEOP : NOERR; + } + } + else + { + *buff++ = *buf; + (*real_size)++; + /* return errEOP; *bug 87784*/ /* we meet the the end */ + return EndOfBuff(p_ap_decode_obj) ? errEOP : NOERR; + } + /* + ** copy the content + */ + for (j = p_ap_decode_obj->left; j<3; ) + { + *buff++ = buf[j++]; + (*real_size)++; + if (--size <= 0) + break; + } + p_ap_decode_obj->left = j % 3; + + if (size <=0) + { + if (j == 3) + p_ap_decode_obj->state64 = 0; /* See if we used up all data, */ + /* ifnot, keep the data, */ + /* we need it for next time. */ + else + p_ap_decode_obj->state64 = 4; + + break; + } + + /* + ** fetch the next 4 character group. + */ + for (i = 0; i < 4; i++) + { + if (EndOfBuff(p_ap_decode_obj)) + break; + + if ((p_ap_decode_obj->c[i] = fetch_next_char_64(p_ap_decode_obj)) == 0) + break; + } + + p_ap_decode_obj->state64 = i % 4; + + if (i != 4) + break; /* some kind of end of buff met.*/ + } + + /* + ** decide the size and status. + */ + return EndOfBuff(p_ap_decode_obj) ? errEOB : NOERR; +} + +/* + * Table for decoding hexadecimal in quoted-printable + */ +static char index_hex[256] = { + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,10,11,12, 13,14,15,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, + XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, XX,XX,XX,XX, +}; + +#define HEXCHAR(c) (index_hex[(unsigned char)(c)]) +#define NEXT_CHAR(p) ((int)((p)->inbuff[(p)->pos_inbuff++])) +#define CURRENT_CHAR(p) ((int)((p)->inbuff[(p)->pos_inbuff])) +/* +** quoted printable decode, as defined in RFC 1521, page18 - 20 +*/ +PRIVATE int from_qp( + appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRUPRInt32 *real_size) +{ + char c; + int c1, c2; + + *real_size = 0; + + if (p_ap_decode_obj->c[0] == '=') + { + /* + ** continue with the last time's left over. + */ + p_ap_decode_obj->c[0] = 0; + + c1 = p_ap_decode_obj->c[1]; p_ap_decode_obj->c[1] = 0; + + if ( c1 == 0) + { + c1 = NEXT_CHAR(p_ap_decode_obj); + c2 = NEXT_CHAR(p_ap_decode_obj); + } + else + { + c2 = NEXT_CHAR(p_ap_decode_obj); + } + c = HEXCHAR(c1) << 4 | HEXCHAR(c2); + + size --; + *buff ++ = c; + (*real_size) ++; + } + + /* + ** Then start to work on the new data + */ + while (size > 0) + { + if (EndOfBuff(p_ap_decode_obj)) + break; + + c1 = NEXT_CHAR(p_ap_decode_obj); + + if (c1 == '=') + { + if (EndOfBuff(p_ap_decode_obj)) + { + p_ap_decode_obj->c[0] = c1; + break; + } + + c1 = NEXT_CHAR(p_ap_decode_obj); + if (c1 != '\n') + { + /* + ** Rule #2 + */ + c1 = HEXCHAR(c1); + if (EndOfBuff(p_ap_decode_obj)) + { + p_ap_decode_obj->c[0] = '='; + p_ap_decode_obj->c[1] = c1; + break; + } + + c2 = NEXT_CHAR(p_ap_decode_obj); + c2 = HEXCHAR(c2); + c = c1 << 4 | c2; + if (c != '\r') + { + size --; + *buff++ = c; + (*real_size)++; + } + } + else + { + /* ignore the line break -- soft line break, rule #5 */ + } + } + else + { + if (c1 == CR || c1 == LF) + { + if (p_ap_decode_obj->pos_inbuff < p_ap_decode_obj->s_inbuff) + { + if (p_ap_decode_obj->boundary0 && + (!XP_STRNCASECMP(p_ap_decode_obj->pos_inbuff+p_ap_decode_obj->inbuff, + "--", + 2) + && + !XP_STRNCASECMP(p_ap_decode_obj->pos_inbuff+p_ap_decode_obj->inbuff+2, + p_ap_decode_obj->boundary0, + nsCRT::strlen(p_ap_decode_obj->boundary0)))) + { + return errEOP; + } + } + } + + /* + ** general 8bits case, Rule #1 + */ + size -- ; + *buff++ = c1; + (*real_size) ++; + } + } + return EndOfBuff(p_ap_decode_obj) ? errEOB : NOERR; +} + +#define UUEOL(c) (((c) == CR) || ((c) == LF)) +# undef UUDEC +# define UUDEC(c) (((c) - ' ') & 077) + +/* Check for and skip past the "begin" line of a uuencode body. */ +PRIVATE void ensure_uu_body_state(appledouble_decode_object* p) +{ + char *end = &(p->inbuff[p->s_inbuff]); + char *current = &(p->inbuff[p->pos_inbuff]); + + if (p->uu_state == kMainBody && p->uu_starts_line + && !XP_STRNCASECMP(current, "end", PR_MIN(3, end - current))) + p->uu_state = kEnd; + + while (p->uu_state != kMainBody && (current < end)) + { + switch(p->uu_state) + { + case kWaitingForBegin: + case kBegin: + /* If we're not at the beginning of a line, move to the next line. */ + if (! p->uu_starts_line) + { + while(current < end && !UUEOL(*current)) + current++; + while(current < end && UUEOL(*current)) + current++; + + p->uu_starts_line = TRUE; /* we reached the start of a line */ + if (p->uu_state == kBegin) + p->uu_state = kMainBody; + + continue; + } + else + { + /* + At the start of a line. Test for "begin". + + ### mwelch: + + There is a potential danger here. If a buffer ends with a line + starting with some substring of "begin", this code will be fooled + into thinking that the uuencode body starts with the following line. + If the message itself contains lines that begin with a substring of + "begin", such as "be", "because", or "bezoar", and if those lines happen + to end a 1024-byte chunk, this becomes Really Bad. However, there is + no good, safe way to overcome this problem. So, for now, I hope and + pray that the 1024 character limit will always incorporate the entire + first line of a uuencode body. + + It should be noted that broken messages that have the body text in + the same MIME part as the uuencode attachment also risk this same + pitfall if any line in the message starts with "begin". + */ + + if ((p->uu_state == kWaitingForBegin) + && !XP_STRNCASECMP(current, "begin", PR_MIN(5, end - current))) + p->uu_state = kBegin; + p->uu_starts_line = FALSE; /* make us advance to next line */ + } + break; + case kEnd: + /* Run out the buffer. */ + current = end; + } + } + + /* Record where we stopped scanning. */ + p->pos_inbuff = p->s_inbuff - (end - current); +} + +#define UU_VOID_CHAR 0 + +PRIVATE int fetch_next_char_uu(appledouble_decode_object* p, PRBool newBunch) +{ + char c=0; + PRBool gotChar = FALSE; + + if (EndOfBuff(p)) + return 0; + + while(!gotChar) + { + if (EndOfBuff(p)) + { + c = 0; + gotChar = TRUE; + } + else if (p->uu_starts_line) + { + char *end = &(p->inbuff[p->s_inbuff]); + char *current = &(p->inbuff[p->pos_inbuff]); + + /* Look here for 'end' line signifying end of uuencode body. */ + if (!XP_STRNCASECMP(current, "end", PR_MIN(3, end - current))) + { + p->uu_state = kEnd; /* set the uuencode state to end */ + p->pos_inbuff = p->s_inbuff; /* run out the current buffer */ + + c = 0; /* return a 0 to uudecoder */ + gotChar = TRUE; + } + } + if (gotChar) + continue; + + c = NEXT_CHAR(p); + + if ((c == CR) || (c == LF)) + { + if (newBunch) + { + /* A new line could immediately follow either a CR or an LF. + If we reach the end of a buffer, simply assume the next buffer + will start a line (as it should in the current libmime implementation). + If it starts with CR or LF, that line will be skipped as well. */ + if (EndOfBuff(p) || ((CURRENT_CHAR(p) != CR) && (CURRENT_CHAR(p) != LF))) + p->uu_starts_line = TRUE; + + continue; + } + + /* End of line, but we have to finish a 4-tuple. Stop here. */ + -- p->pos_inbuff; /* give back the end-of-line character */ + c = UU_VOID_CHAR; /* flag as truncated */ + gotChar = TRUE; + } + + /* At this point, we have a valid char. */ + + else if (p->uu_starts_line) + { + /* read length char at start of each line */ + p->uu_line_bytes = UUDEC(c); + p->uu_starts_line = FALSE; + continue; + } + + else if (p->uu_line_bytes <= 0) + /* We ran out of bytes to decode on this line. Skip spare chars until + we reach the end of (line or buffer). */ + continue; + + else + gotChar = TRUE; /* valid returnable char */ + } + + return (int) c; +} + +/* +** uudecode +*/ + +PRIVATE int from_uu( + appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRUPRInt32 *real_size) +{ + char c; + int i; + int returnVal = NOERR; + int c1, c2, c3, c4; + + *real_size = 0; + + /* Make sure that we're in the uuencode body, or run out the buffer if + we don't have any body text in this buffer. */ + ensure_uu_body_state(p_ap_decode_obj); + + if (p_ap_decode_obj->uu_state == kEnd) + return errEOP; + + /* Continue with what was left over last time. */ + for (i = p_ap_decode_obj->state64; i<4; i++) + { + if (EndOfBuff(p_ap_decode_obj)) + { + p_ap_decode_obj->state64 = i; + break; + } + if ((p_ap_decode_obj->c[i] = fetch_next_char_uu(p_ap_decode_obj, (i==0))) == 0) + break; + } + + if ( (i < p_ap_decode_obj->uu_line_bytes+1) + && (EndOfBuff(p_ap_decode_obj))) + /* not enough data to decode, return here. */ + return errEOB; + + while((size > 0) && (!EndOfBuff(p_ap_decode_obj))) + { + c1 = p_ap_decode_obj->c[0]; + c2 = p_ap_decode_obj->c[1]; + c3 = p_ap_decode_obj->c[2]; + c4 = p_ap_decode_obj->c[3]; + + /* + At this point we have characters ready to decode. + Convert them to binary bytes. + */ + if ((i > 1) + && (p_ap_decode_obj->uu_bytes_written < 1) + && (p_ap_decode_obj->uu_line_bytes > 0)) + { + c = UUDEC(c1) << 2 | UUDEC(c2) >> 4; + size --; + *buff ++ = c; + (*real_size) ++; + p_ap_decode_obj->uu_line_bytes--; + p_ap_decode_obj->uu_bytes_written++; + } + + if ((i > 2) && (size > 0) + && (p_ap_decode_obj->uu_bytes_written < 2) + && (p_ap_decode_obj->uu_line_bytes > 0)) + { + c = UUDEC(c2) << 4 | UUDEC(c3) >> 2; + size --; + *buff ++ = c; + (*real_size) ++; + p_ap_decode_obj->uu_line_bytes--; + p_ap_decode_obj->uu_bytes_written++; + } + + if ((i > 3) && (size > 0) + && (p_ap_decode_obj->uu_line_bytes > 0)) + { + c = UUDEC(c3) << 6 | UUDEC(c4); + size --; + *buff ++ = c; + (*real_size) ++; + p_ap_decode_obj->uu_line_bytes--; + p_ap_decode_obj->uu_bytes_written = 0; + } + + if (p_ap_decode_obj->uu_state == kEnd) + continue; + + /* If this line is finished, this tuple is also finished. */ + if (p_ap_decode_obj->uu_line_bytes <= 0) + p_ap_decode_obj->uu_bytes_written = 0; + + if (p_ap_decode_obj->uu_bytes_written > 0) + { + /* size == 0, but we have bytes left in current tuple */ + p_ap_decode_obj->state64 = i; + continue; + } + + /* + ** fetch the next 4 character group. + */ + + for (i = 0; i < 4; i++) + { + if (EndOfBuff(p_ap_decode_obj)) + break; + + if ((p_ap_decode_obj->c[i] = fetch_next_char_uu(p_ap_decode_obj, (i == 0))) == 0) + break; + } + + p_ap_decode_obj->state64 = i; + + if ( (i < p_ap_decode_obj->uu_line_bytes+1) + && (EndOfBuff(p_ap_decode_obj))) + /* not enough data to decode, return here. */ + continue; + } + + if (p_ap_decode_obj->uu_state == kEnd) + returnVal = errEOP; + else if (EndOfBuff(p_ap_decode_obj)) + returnVal = errEOB; + + return returnVal; +} + +/* +** from_none +** +** plain text transfer. +*/ +PRIVATE int from_none( + appledouble_decode_object* p_ap_decode_obj, + char *buff, + int size, + PRUPRInt32 *real_size) +{ + char c; + int i, status = NOERR; + int left = p_ap_decode_obj->s_inbuff - p_ap_decode_obj->pos_inbuff; + int total = PR_MIN(size, left); + + for (i = 0; i < total; i++) + { + *buff ++ = c = NEXT_CHAR(p_ap_decode_obj); + if (c == CR || c == LF) + { + /* make sure the next thing is not a boundary string */ + if (p_ap_decode_obj->pos_inbuff < p_ap_decode_obj->s_inbuff) + { + if (p_ap_decode_obj->boundary0 && + (!XP_STRNCASECMP(p_ap_decode_obj->pos_inbuff+p_ap_decode_obj->inbuff, + "--", + 2) + && + !XP_STRNCASECMP(p_ap_decode_obj->pos_inbuff+p_ap_decode_obj->inbuff+2, + p_ap_decode_obj->boundary0, + nsCRT::strlen(p_ap_decode_obj->boundary0)))) + { + status = errEOP; + break; + } + } + } + } + + *real_size = i; + if (status == NOERR) + status = (left == i) ? errEOB : status; + return status; +} + diff --git a/mozilla/mailnews/compose/src/nsMsgAppleDecodeStream.cpp b/mozilla/mailnews/compose/src/nsMsgAppleDecodeStream.cpp new file mode 100755 index 00000000000..c81d983d9a9 --- /dev/null +++ b/mozilla/mailnews/compose/src/nsMsgAppleDecodeStream.cpp @@ -0,0 +1,725 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/** +* Apple Double encode/decode stream +* ---------------------------------- +* +* 11sep95 mym created. +*/ + +#include "nscore.h" +#include "msgCore.h" + +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleDoubleCodes.h" + +#include "m_binhex.h" +#include "m_cvstrm.h" +#include "ad_codes.h" + +extern int MK_MSG_SAVE_ATTACH_AS; + +#ifdef XP_MAC +#pragma warn_unusedarg off + +extern int MK_UNABLE_TO_OPEN_TMP_FILE; +extern int MK_MIME_ERROR_WRITING_FILE; + +/* --------------------------------------------------------------------------------- +** +** The codes for Apple-double encoding stream. --- it's only useful on Mac OS +** +** --------------------------------------------------------------------------------- +*/ + +#define WORKING_BUFF_SIZE 8192 + +typedef struct _AppledoubleEncodeObject +{ + appledouble_encode_object ap_encode_obj; + + char* buff; /* the working buff. */ + PRInt32 s_buff; /* the working buff size. */ + + XP_File fp; /* file to hold the encoding */ + char *fname; /* and the file name. */ + +} AppleDoubleEncodeObject; + +/* + Let's go "l" characters forward of the encoding for this write. + Note: + "s" is just a dummy paramter. + */ +PRIVATE int +net_AppleDouble_Encode_Write ( + void *stream, const char* s, PRInt32 l) +{ + int status = 0; + AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream; + PRInt32 count, size; + + while (l > 0) + { + size = obj->s_buff * 11 / 16; + size = PR_MIN(l, size); + status = ap_encode_next(&(obj->ap_encode_obj), + obj->buff, + size, + &count); + if (status == noErr || status == errDone) + { + /* + * we get the encode data, so call the next stream to write it to the disk. + */ + if (XP_FileWrite(obj->buff, count, obj->fp) != count) + return errFileWrite; + } + + if (status != noErr ) /* abort when error / done? */ + break; + + l -= size; + } + return status; +} + +/* +** is the stream ready for writing? + */ +PRIVATE unsigned int net_AppleDouble_Encode_Ready (void *stream) +{ + return(PR_MAX_WRITE_READY); /* always ready for writing */ +} + + +PRIVATE void net_AppleDouble_Encode_Complete (void *stream) +{ + AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream; + + ap_encode_end(&(obj->ap_encode_obj), false); /* this is a normal ending */ + + if (obj->fp) + { + XP_FileClose(obj->fp); /* done with the target file */ + + FREEIF(obj->fname); /* and the file name too */ + } + + FREEIF(obj->buff); /* free the working buff. */ + PR_FREE(obj); +} + +PRIVATE void net_AppleDouble_Encode_Abort (void *stream, int status) +{ + AppleDoubleEncodeObject * obj = (AppleDoubleEncodeObject*)stream; + + ap_encode_end(&(obj->ap_encode_obj), true); /* it is an aborting exist... */ + + if (obj->fp) + { + XP_FileClose(obj->fp); + + XP_FileRemove (obj->fname, xpURL); /* remove the partial file. */ + + FREEIF(obj->fname); + } + FREEIF(obj->buff); /* free the working buff. */ + PR_FREE(obj); +} + +/* +** fe_MakeAppleDoubleEncodeStream +** ------------------------------ +** +** Will create a apple double encode stream: +** +** -> take the filename as the input source (it needs to be a mac file.) +** -> take a file name for the temp file we are generating. +*/ + +PUBLIC NET_StreamClass * +fe_MakeAppleDoubleEncodeStream (int format_out, + void *data_obj, + URL_Struct *URL_s, + MWContext *window_id, + char* src_filename, + char* dst_filename, + char* separator) +{ + AppleDoubleEncodeObject* obj; + NET_StreamClass* stream; + char* working_buff = NULL; + int bSize = WORKING_BUFF_SIZE; + + TRACEMSG(("Setting up apple encode stream. Have URL: %s\n", URL_s->address)); + + stream = XP_NEW(NET_StreamClass); + if(stream == NULL) + return(NULL); + + obj = XP_NEW(AppleDoubleEncodeObject); + if (obj == NULL) + { + PR_FREE (stream); + return(NULL); + } + + while (!working_buff && (bSize >= 512)) + { + working_buff = (char *)PR_CALLOC(bSize); + if (!working_buff) + bSize /= 2; + } + if (working_buff == NULL) + { + PR_FREE (obj); + PR_FREE (stream); + return (NULL); + } + + stream->name = "Apple Double Encode"; + stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Encode_Complete; + stream->abort = (MKStreamAbortFunc) net_AppleDouble_Encode_Abort; + stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Encode_Write; + stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Encode_Ready; + stream->data_object = obj; + stream->window_id = window_id; + + obj->fp = XP_FileOpen(dst_filename, xpFileToPost, XP_FILE_WRITE_BIN); + if (obj->fp == NULL) + { + PR_FREE (working_buff); + PR_FREE (obj); + PR_FREE (stream); + return (NULL); + } + + obj->fname = XP_STRDUP(dst_filename); + + obj->buff = working_buff; + obj->s_buff = bSize; + + /* + ** setup all the need information on the apple double encoder. + */ + ap_encode_init(&(obj->ap_encode_obj), + src_filename, /* pass the file name of the source. */ + separator); + + TRACEMSG(("Returning stream from NET_AppleDoubleEncoder\n")); + + return stream; +} +#endif + +/* +** --------------------------------------------------------------------------------- +** +** The codes for the Apple sigle/double decoding. +** +** --------------------------------------------------------------------------------- +*/ +typedef struct AppleDoubleDecodeObject +{ + appledouble_decode_object ap_decode_obj; + + char* in_buff; /* the temporary buff to accumulate */ + /* the input, make sure the call to */ + /* the dedcoder engine big enough buff */ + PRInt32 bytes_in_buff; /* the count for the temporary buff. */ + + NET_StreamClass* binhex_stream; /* a binhex encode stream to convert */ + /* the decoded mac file to binhex. */ + +} AppleDoubleDecodeObject; + +PRIVATE int +net_AppleDouble_Decode_Write ( + void *stream, const char* s, PRInt32 l) +{ + int status = NOERR; + AppleDoubleDecodeObject * obj = (AppleDoubleDecodeObject*) stream; + PRInt32 size; + + /* + ** To force an effecient decoding, we should + ** make sure that the buff pass to the decode next is great than 1024 bytes. + */ + if (obj->bytes_in_buff + l > 1024) + { + size = 1024 - obj->bytes_in_buff; + XP_MEMCPY(obj->in_buff+obj->bytes_in_buff, + s, + size); + s += size; + l -= size; + + status = ap_decode_next(&(obj->ap_decode_obj), + obj->in_buff, + 1024); + obj->bytes_in_buff = 0; + } + + if (l > 1024) + { + /* we are sure that obj->bytes_in_buff == 0 at this point. */ + status = ap_decode_next(&(obj->ap_decode_obj), + (char *)s, + l); + } + else + { + /* and we are sure we will not get overflow with the buff. */ + XP_MEMCPY(obj->in_buff+obj->bytes_in_buff, + s, + l); + obj->bytes_in_buff += l; + } + return status; +} + +PRIVATE unsigned int +net_AppleDouble_Decode_Ready (NET_StreamClass *stream) +{ + return(PR_MAX_WRITE_READY); /* always ready for writing */ +} + + +PRIVATE void +net_AppleDouble_Decode_Complete (void *stream) +{ + AppleDoubleDecodeObject *obj = (AppleDoubleDecodeObject *)stream; + + if (obj->bytes_in_buff) + { + + ap_decode_next(&(obj->ap_decode_obj), /* do the last calls. */ + (char *)obj->in_buff, + obj->bytes_in_buff); + obj->bytes_in_buff = 0; + } + + ap_decode_end(&(obj->ap_decode_obj), FALSE); /* it is a normal clean up cases.*/ + + if (obj->binhex_stream) + PR_FREE(obj->binhex_stream); + + if (obj->in_buff) + PR_FREE(obj->in_buff); + + PR_FREE(obj); +} + +PRIVATE void +net_AppleDouble_Decode_Abort ( + void *stream, int status) +{ + AppleDoubleDecodeObject *obj = (AppleDoubleDecodeObject *)stream; + + ap_decode_end(&(obj->ap_decode_obj), TRUE); /* it is an abort. */ + + if (obj->binhex_stream) + PR_FREE(obj->binhex_stream); + + if (obj->in_buff) + PR_FREE(obj->in_buff); + + PR_FREE(obj); +} + + +/* +** fe_MakeAppleDoubleDecodeStream_1 +** --------------------------------- +** +** Create the apple double decode stream. +** +** In the Mac OS, it will create a stream to decode to an apple file; +** +** In other OS, the stream will decode apple double object, +** then encode it in binhex format, and save to the file. +*/ +#ifndef XP_MAC +static void +simple_copy(MWContext* context, char* saveName, void* closure) +{ + /* just copy the filename to the closure, so the caller can get it. */ + XP_STRCPY(closure, saveName); +} +#endif + +PUBLIC NET_StreamClass * +fe_MakeAppleDoubleDecodeStream_1 (int format_out, + void *data_obj, + URL_Struct *URL_s, + MWContext *window_id) +{ +#ifdef XP_MAC + return fe_MakeAppleDoubleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + false, + NULL); +#else + +#if 0 /* just a test in the mac OS */ + NET_StreamClass *p; + char* url; + StandardFileReply reply; + + StandardPutFile("\pSave binhex encoded file as:", "\pUntitled", &reply); + if (!reply.sfGood) + { + return NULL; + } + url = my_PathnameFromFSSpec(&(reply.sfFile)); + + p = fe_MakeAppleDoubleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + true, + url+7); + PR_FREE(url); + return (p); + +#else /* for the none mac-os to get a file name */ + + NET_StreamClass *p; + char* filename; + + filename = PR_CALLOC(1024); + if (filename == NULL) + return NULL; + +/***** RICHIE - CONVERT THIS + if (FE_PromptForFileName(window_id, + XP_GetString(MK_MSG_SAVE_ATTACH_AS), + 0, + FALSE, + FALSE, + simple_copy, + filename) == -1) + { + return NULL; + } +***/ + + p = fe_MakeAppleDoubleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + TRUE, + filename); + PR_FREE(filename); + return (p); + +#endif + +#endif +} + + +PUBLIC NET_StreamClass * +fe_MakeAppleDoubleDecodeStream (int format_out, + void *data_obj, + URL_Struct *URL_s, + MWContext *window_id, + PRBool write_as_binhex, + char *dst_filename) +{ + AppleDoubleDecodeObject* obj; + NET_StreamClass* stream; + + TRACEMSG(("Setting up apple double decode stream. Have URL: %s\n", URL_s->address)); + + stream = XP_NEW(NET_StreamClass); + if(stream == NULL) + return(NULL); + + obj = XP_NEW(AppleDoubleDecodeObject); + if (obj == NULL) + { + PR_FREE(stream); + return(NULL); + } + + stream->name = "AppleDouble Decode"; + stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Decode_Complete; + stream->abort = (MKStreamAbortFunc) net_AppleDouble_Decode_Abort; + stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Decode_Write; + stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Decode_Ready; + stream->data_object = obj; + stream->window_id = window_id; + + /* + ** setup all the need information on the apple double encoder. + */ + obj->in_buff = (char *)PR_CALLOC(1024); + if (obj->in_buff == NULL) + { + PR_FREE(obj); + PR_FREE(stream); + return (NULL); + } + + obj->bytes_in_buff = 0; + + if (write_as_binhex) + { + obj->binhex_stream = + fe_MakeBinHexEncodeStream(format_out, + data_obj, + URL_s, + window_id, + dst_filename); + if (obj->binhex_stream == NULL) + { + PR_FREE(obj); + PR_FREE(stream); + PR_FREE(obj->in_buff); + return NULL; + } + + ap_decode_init(&(obj->ap_decode_obj), + FALSE, + TRUE, + obj->binhex_stream); + } + else + { + obj->binhex_stream = NULL; + ap_decode_init(&(obj->ap_decode_obj), + FALSE, + FALSE, + window_id); + /* + * jt 8/8/97 -- I think this should be set to true. But' + * let's not touch it for now. + * + * obj->ap_decode_obj.is_binary = TRUE; + */ + } + + if (dst_filename) + { + XP_STRNCPY_SAFE(obj->ap_decode_obj.fname, dst_filename, + sizeof(obj->ap_decode_obj.fname)); + } + #ifdef XP_MAC + obj->ap_decode_obj.mSpec = (FSSpec*)( URL_s->fe_data ); + #endif + TRACEMSG(("Returning stream from NET_AppleDoubleDecode\n")); + + return stream; +} + +/* +** fe_MakeAppleSingleDecodeStream_1 +** -------------------------------- +** +** Create the apple single decode stream. +** +** In the Mac OS, it will create a stream to decode object to an apple file; +** +** In other OS, the stream will decode apple single object, +** then encode context in binhex format, and save to the file. +*/ + +PUBLIC NET_StreamClass * +fe_MakeAppleSingleDecodeStream_1 (int format_out, + void *data_obj, + URL_Struct *URL_s, + MWContext *window_id) +{ +#ifdef XP_MAC + return fe_MakeAppleSingleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + FALSE, + NULL); +#else + +#if 0 /* just a test in the mac OS */ + NET_StreamClass *p; + char* url; + StandardFileReply reply; + + StandardPutFile("\pSave binhex encoded file as:", "\pUntitled", &reply); + if (!reply.sfGood) + { + return NULL; + } + url = my_PathnameFromFSSpec(&(reply.sfFile)); + + p = fe_MakeAppleSingleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + true, + url+7); + PR_FREE(url); + return (p); + +#else /* for the none mac-os to get a file name */ + + NET_StreamClass *p; + char* filename; + char* defaultPath = 0; + + defaultPath = URL_s->content_name; + +#ifdef XP_WIN16 + if (XP_FileNameContainsBadChars(defaultPath)) + defaultPath = 0; +#endif + + filename = PR_CALLOC(1024); + if (filename == NULL) + return NULL; + +/***** RICHIE - CONVERT THIS + if (FE_PromptForFileName(window_id, + XP_GetString(MK_MSG_SAVE_ATTACH_AS), + defaultPath, + FALSE, + FALSE, + simple_copy, + filename) == -1) + { + return NULL; + } +*********/ + + p = fe_MakeAppleSingleDecodeStream(format_out, + data_obj, + URL_s, + window_id, + FALSE, + filename); + PR_FREE(filename); + return (p); + +#endif + +#endif +} + +/* +** Create the Apple Doube Decode stream. +** +*/ +PUBLIC NET_StreamClass * +fe_MakeAppleSingleDecodeStream (int format_out, + void *data_obj, + URL_Struct *URL_s, + MWContext *window_id, + PRBool write_as_binhex, + char *dst_filename) +{ + AppleDoubleDecodeObject* obj; + NET_StreamClass* stream; + int encoding = kEncodeNone; /* default is that we don't know the encoding */ + + TRACEMSG(("Setting up apple single decode stream. Have URL: %s\n", URL_s->address)); + + stream = XP_NEW(NET_StreamClass); + if(stream == NULL) + return(NULL); + + obj = XP_NEW(AppleDoubleDecodeObject); + if (obj == NULL) + { + PR_FREE(stream); + return(NULL); + } + + stream->name = "AppleSingle Decode"; + stream->complete = (MKStreamCompleteFunc) net_AppleDouble_Decode_Complete; + stream->abort = (MKStreamAbortFunc) net_AppleDouble_Decode_Abort; + stream->put_block = (MKStreamWriteFunc) net_AppleDouble_Decode_Write; + stream->is_write_ready = (MKStreamWriteReadyFunc) net_AppleDouble_Decode_Ready; + stream->data_object = obj; + stream->window_id = window_id; + + /* + ** setup all the need information on the apple double encoder. + */ + obj->in_buff = (char *)PR_CALLOC(1024); + if (obj->in_buff == NULL) + { + PR_FREE(obj); + PR_FREE(stream); + return (NULL); + } + + obj->bytes_in_buff = 0; + + if (write_as_binhex) + { + obj->binhex_stream = + fe_MakeBinHexEncodeStream(format_out, + data_obj, + URL_s, + window_id, + dst_filename); + if (obj->binhex_stream == NULL) + { + PR_FREE(obj); + PR_FREE(stream); + PR_FREE(obj->in_buff); + return NULL; + } + + ap_decode_init(&(obj->ap_decode_obj), + TRUE, + TRUE, + obj->binhex_stream); + } + else + { + obj->binhex_stream = NULL; + ap_decode_init(&(obj->ap_decode_obj), + TRUE, + FALSE, + window_id); +#ifndef XP_MAC + obj->ap_decode_obj.is_binary = TRUE; +#endif + } + + if (dst_filename) + { + XP_STRNCPY_SAFE(obj->ap_decode_obj.fname, dst_filename, + sizeof(obj->ap_decode_obj.fname)); + } + /* If we are of a broken content-type, impose its encoding. */ + if (URL_s->content_type + && !XP_STRNCASECMP(URL_s->content_type, "x-uuencode-apple-single", 23)) + obj->ap_decode_obj.encoding = kEncodeUU; + else + obj->ap_decode_obj.encoding = kEncodeNone; + + TRACEMSG(("Returning stream from NET_AppleSingleDecode\n")); + + return stream; +} diff --git a/mozilla/mailnews/compose/src/nsMsgAppleDouble.cpp b/mozilla/mailnews/compose/src/nsMsgAppleDouble.cpp new file mode 100755 index 00000000000..38e0879677d --- /dev/null +++ b/mozilla/mailnews/compose/src/nsMsgAppleDouble.cpp @@ -0,0 +1,616 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* +* +* apple-double.c +* -------------- +* +* The codes to do apple double encoding/decoding. +* +* 02aug95 mym created. +* 27sep95 mym Add the XP_Mac to ensure the cross-platform. +* +*/ +#include "nsID.h" +#include "nscore.h" +#include "msgCore.h" +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleCodes.h" + +#ifdef XP_MAC + +#pragma warn_unusedarg off +#include "m_cvstrm.h" + +#pragma cplusplus on +#include "InternetConfig.h" +#include "ufilemgr.h" +#include "BufferStream.h" +#include "Umimemap.h" +#include "uprefd.h" +#include "ulaunch.h" +void DecodingDone( appledouble_decode_object* p_ap_decode_obj ); + +OSErr my_FSSpecFromPathname(char* src_filename, FSSpec* fspec) +{ + /* don't resolve aliases... */ + return CFileMgr::FSSpecFromLocalUnixPath(src_filename, fspec, false); +} + +char* my_PathnameFromFSSpec(FSSpec* fspec) +{ + return CFileMgr::GetURLFromFileSpec(*fspec); +} + +/* returns true if the resource fork should be sent */ +PRBool isMacFile(char* filename) +{ + Boolean returnValue = FALSE; + + FSSpec fspec; + my_FSSpecFromPathname(filename, &fspec); + + returnValue = CFileMgr::FileHasResourceFork(fspec); + /* always use IC even if the pref isn't checked since we have no + other way to determine if the resource is significant */ + if ( returnValue ) + { + + CMimeMapper * mapper = CPrefs::sMimeTypes.FindMimeType(fspec); + if ( mapper ) + { + returnValue = mapper->GetFileFlags()& ICmap_resource_fork_mask; + return returnValue; + } + + // Get the Internet Config file mapping for this type + // and see if the existing resources are significant. + + // First, get the type/creator of the file. + FInfo fileInfo; + OSErr err = ::FSpGetFInfo(&fspec, &fileInfo); + if (err == noErr) + { + if ( fileInfo.fdType == 'APPL' ) + return TRUE; + ICMapEntry ent; + err = CInternetConfigInterface::GetInternetConfigFileMapping(fileInfo.fdType, + fileInfo.fdCreator, + fspec.name, &ent); + if (err == noErr) + { + // resource fork is significant if the resource fork mask bit is set + returnValue = (ent.flags & ICmap_resource_fork_mask) != 0; + } + } + } + + return (PRBool) returnValue; +} + +void DecodingDone( appledouble_decode_object* p_ap_decode_obj ) +{ + FSSpec fspec; + + fspec.vRefNum = p_ap_decode_obj->vRefNum; + fspec.parID = p_ap_decode_obj->dirId; + fspec.name[0] = nsCRT::strlen(p_ap_decode_obj->fname); + XP_STRCPY((char*)fspec.name+1, p_ap_decode_obj->fname); + CMimeMapper * mapper = CPrefs::sMimeTypes.FindMimeType(fspec); + if( mapper && (mapper->GetLoadAction() == CMimeMapper::Launch ) ) + { + LFileBufferStream file( fspec ); + LaunchFile( &file ); + } +} + +#pragma cplusplus reset + +/* +* ap_encode_init +* -------------- +* +* Setup the encode envirment +*/ + +int ap_encode_init( + appledouble_encode_object *p_ap_encode_obj, + char* fname, + char* separator) +{ + FSSpec fspec; + + if (my_FSSpecFromPathname(fname, &fspec) != noErr ) + return -1; + + XP_MEMSET(p_ap_encode_obj, 0, sizeof(appledouble_encode_object)); + + /* + ** Fill out the source file inforamtion. + */ + XP_MEMCPY(p_ap_encode_obj->fname, fspec.name+1, *fspec.name); + p_ap_encode_obj->fname[*fspec.name] = '\0'; + p_ap_encode_obj->vRefNum = fspec.vRefNum; + p_ap_encode_obj->dirId = fspec.parID; + + p_ap_encode_obj->boundary = XP_STRDUP(separator); + return noErr; +} +/* +** ap_encode_next +** -------------- +** +** return : +** noErr : everything is ok +** errDone : when encoding is done. +** errors : otherwise. +*/ +int ap_encode_next( + appledouble_encode_object* p_ap_encode_obj, + char *to_buff, + PRInt32 buff_size, + PRInt32* real_size) +{ + int status; + + /* + ** install the out buff now. + */ + p_ap_encode_obj->outbuff = to_buff; + p_ap_encode_obj->s_outbuff = buff_size; + p_ap_encode_obj->pos_outbuff = 0; + + /* + ** first copy the outstandind data in the overflow buff to the out buffer. + */ + if (p_ap_encode_obj->s_overflow) + { + status = write_stream(p_ap_encode_obj, + p_ap_encode_obj->b_overflow, + p_ap_encode_obj->s_overflow); + if (status != noErr) + return status; + + p_ap_encode_obj->s_overflow = 0; + } + + /* + ** go the next processing stage based on the current state. + */ + switch (p_ap_encode_obj->state) + { + case kInit: + /* + ** We are in the starting position, fill out the header. + */ + status = fill_apple_mime_header(p_ap_encode_obj); + if (status != noErr) + break; /* some error happens */ + + p_ap_encode_obj->state = kDoingHeaderPortion; + status = ap_encode_header(p_ap_encode_obj, true); + /* it is the first time to calling */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneHeaderPortion; + } + else + { + break; /* we need more work on header portion. */ + } + + /* + ** we are done with the header, so let's go to the data port. + */ + p_ap_encode_obj->state = kDoingDataPortion; + status = ap_encode_data(p_ap_encode_obj, true); + /* it is first time call do data portion */ + + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoingHeaderPortion: + + status = ap_encode_header(p_ap_encode_obj, false); + /* continue with the header portion. */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneHeaderPortion; + } + else + { + break; /* we need more work on header portion. */ + } + + /* + ** start the data portion. + */ + p_ap_encode_obj->state = kDoingDataPortion; + status = ap_encode_data(p_ap_encode_obj, true); + /* it is the first time calling */ + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoingDataPortion: + + status = ap_encode_data(p_ap_encode_obj, false); + /* it is not the first time */ + + if (status == errDone) + { + p_ap_encode_obj->state = kDoneDataPortion; + status = noErr; + } + break; + + case kDoneDataPortion: +#if 0 + status = write_stream(p_ap_encode_obj, + "\n-----\n\n", + 8); + if (status == noErr) +#endif + status = errDone; /* we are really done. */ + + break; + } + + *real_size = p_ap_encode_obj->pos_outbuff; + return status; +} + +/* +** ap_encode_end +** ------------- +** +** clear the apple encoding. +*/ + +int ap_encode_end( + appledouble_encode_object *p_ap_encode_obj, + PRBool is_aborting) +{ + /* + ** clear up the apple doubler. + */ + if (p_ap_encode_obj == NULL) + return noErr; + + if (p_ap_encode_obj->fileId) /* close the file if it is open. */ + FSClose(p_ap_encode_obj->fileId); + + PR_FREEIF(p_ap_encode_obj->boundary); /* the boundary string. */ + + return noErr; +} + +#endif /* the ifdef of XP_MAC */ + + +/* +** The initial of the apple double decoder. +** +** Set up the next output stream based on the input. +*/ +int ap_decode_init( + appledouble_decode_object* p_ap_decode_obj, + PRBool is_apple_single, + PRBool write_as_binhex, + void *closure) +{ + XP_MEMSET(p_ap_decode_obj, 0, sizeof(appledouble_decode_object)); + + /* presume first buff starts a line */ + p_ap_decode_obj->uu_starts_line = TRUE; + + if (write_as_binhex) + { + p_ap_decode_obj->write_as_binhex = TRUE; + p_ap_decode_obj->binhex_stream = (NET_StreamClass*)closure; + p_ap_decode_obj->data_size = 0; + } + else + { + p_ap_decode_obj->write_as_binhex = FALSE; + p_ap_decode_obj->binhex_stream = NULL; + + p_ap_decode_obj->context = (MWContext*)closure; + } + + p_ap_decode_obj->is_apple_single = is_apple_single; + + if (is_apple_single) + { + p_ap_decode_obj->encoding = kEncodeNone; + } + + return NOERR; +} + +static int ap_decode_state_machine(appledouble_decode_object* p_ap_decode_obj); +/* +* process the buffer +*/ +int ap_decode_next( + appledouble_decode_object* p_ap_decode_obj, + char *in_buff, + PRInt32 buff_size) +{ + /* + ** install the buff to the decoder. + */ + p_ap_decode_obj->inbuff = in_buff; + p_ap_decode_obj->s_inbuff = buff_size; + p_ap_decode_obj->pos_inbuff = 0; + + /* + ** run off the decode state machine + */ + return ap_decode_state_machine(p_ap_decode_obj); +} + +PRIVATE int ap_decode_state_machine( + appledouble_decode_object* p_ap_decode_obj) +{ + int status = NOERR; + PRInt32 size; + + switch (p_ap_decode_obj->state) + { + case kInit: + /* + ** Make sure that there are stuff in the buff + ** before we can parse the file head . + */ + if (p_ap_decode_obj->s_inbuff <=1 ) + return NOERR; + + if (p_ap_decode_obj->is_apple_single) + { + p_ap_decode_obj->state = kBeginHeaderPortion; + } + else + { + status = ap_seek_part_start(p_ap_decode_obj); + if (status != errDone) + return status; + + p_ap_decode_obj->state = kBeginParseHeader; + } + status = ap_decode_state_machine(p_ap_decode_obj); + break; + + case kBeginSeekBoundary: + p_ap_decode_obj->state = kSeekingBoundary; + status = ap_seek_to_boundary(p_ap_decode_obj, TRUE); + if (status == errDone) + { + p_ap_decode_obj->state = kBeginParseHeader; + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kSeekingBoundary: + status = ap_seek_to_boundary(p_ap_decode_obj, FALSE); + if (status == errDone) + { + p_ap_decode_obj->state = kBeginParseHeader; + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kBeginParseHeader: + p_ap_decode_obj->state = kParsingHeader; + status = ap_parse_header(p_ap_decode_obj, TRUE); + if (status == errDone) + { + if (p_ap_decode_obj->which_part == kDataPortion) + p_ap_decode_obj->state = kBeginDataPortion; + else if (p_ap_decode_obj->which_part == kHeaderPortion) + p_ap_decode_obj->state = kBeginHeaderPortion; + else + p_ap_decode_obj->state = kFinishing; + + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kParsingHeader: + status = ap_parse_header(p_ap_decode_obj, FALSE); + if (status == errDone) + { + if (p_ap_decode_obj->which_part == kDataPortion) + p_ap_decode_obj->state = kBeginDataPortion; + else if (p_ap_decode_obj->which_part == kHeaderPortion) + p_ap_decode_obj->state = kBeginHeaderPortion; + else + p_ap_decode_obj->state = kFinishing; + + status = ap_decode_state_machine(p_ap_decode_obj); + + } + break; + + case kBeginHeaderPortion: + p_ap_decode_obj->state = kProcessingHeaderPortion; + status = ap_decode_process_header(p_ap_decode_obj, TRUE); + if (status == errDone) + { + if (p_ap_decode_obj->is_apple_single) + p_ap_decode_obj->state = kBeginDataPortion; + else + p_ap_decode_obj->state = kBeginSeekBoundary; + + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + case kProcessingHeaderPortion: + status = ap_decode_process_header(p_ap_decode_obj, FALSE); + if (status == errDone) + { + if (p_ap_decode_obj->is_apple_single) + p_ap_decode_obj->state = kBeginDataPortion; + else + p_ap_decode_obj->state = kBeginSeekBoundary; + + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kBeginDataPortion: + p_ap_decode_obj->state = kProcessingDataPortion; + status = ap_decode_process_data(p_ap_decode_obj, TRUE); + if (status == errDone) + { + if (p_ap_decode_obj->is_apple_single) + p_ap_decode_obj->state = kFinishing; + else + p_ap_decode_obj->state = kBeginSeekBoundary; + + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kProcessingDataPortion: + status = ap_decode_process_data(p_ap_decode_obj, FALSE); + if (status == errDone) + { + if (p_ap_decode_obj->is_apple_single) + p_ap_decode_obj->state = kFinishing; + else + p_ap_decode_obj->state = kBeginSeekBoundary; + + status = ap_decode_state_machine(p_ap_decode_obj); + } + break; + + case kFinishing: + if (p_ap_decode_obj->write_as_binhex) + { + if (p_ap_decode_obj->tmpfd) + { + /* + ** It is time to append the data fork to bin hex encoder. + ** + ** The reason behind this dirt work is resource fork is the last + ** piece in the binhex, while it is the first piece in apple double. + */ + XP_FileSeek(p_ap_decode_obj->tmpfd, 0L, SEEK_SET); + + while (p_ap_decode_obj->data_size > 0) + { + char buff[1024]; + + size = PR_MIN(1024, p_ap_decode_obj->data_size); + XP_FileRead(buff, size, p_ap_decode_obj->tmpfd); + + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + buff, + size); + + p_ap_decode_obj->data_size -= size; + } + } + + if (p_ap_decode_obj->data_size <= 0) + { + /* CALL put_block with size == 0 to close a part. */ + status = (*p_ap_decode_obj->binhex_stream->put_block) + (p_ap_decode_obj->binhex_stream->data_object, + NULL, + 0); + if (status != NOERR) + break; + + /* and now we are really done. */ + status = errDone; + } + else + status = NOERR; + } + break; + } + return (status == errEOB) ? NOERR : status; +} + +int ap_decode_end( + appledouble_decode_object* p_ap_decode_obj, + PRBool is_aborting) +{ + /* + ** clear up the apple doubler object. + */ + if (p_ap_decode_obj == NULL) + return NOERR; + + PR_FREEIF(p_ap_decode_obj->boundary0); + +#ifdef XP_MAC + if (p_ap_decode_obj->fileId) + FSClose(p_ap_decode_obj->fileId); + if( p_ap_decode_obj->vRefNum ) + FlushVol(nil, p_ap_decode_obj->vRefNum ); +#endif + + if (p_ap_decode_obj->write_as_binhex) + { + /* + ** make sure close the binhex stream too. + */ + if (is_aborting) + { + (*p_ap_decode_obj->binhex_stream->abort) + (p_ap_decode_obj->binhex_stream->data_object, 0); + } + else + { + (*p_ap_decode_obj->binhex_stream->complete) + (p_ap_decode_obj->binhex_stream->data_object); + } + + if (p_ap_decode_obj->tmpfd) + XP_FileClose(p_ap_decode_obj->tmpfd); + + if (p_ap_decode_obj->tmpfname) + { + XP_FileRemove(p_ap_decode_obj->tmpfname, xpTemporary); + /* remove tmp file if we used it */ + PR_FREEIF(p_ap_decode_obj->tmpfname); /* and release the file name too. */ + } + } + else if (p_ap_decode_obj->fd) + { + XP_FileClose(p_ap_decode_obj->fd); + } +#ifdef XP_MAC + if( !is_aborting ) + DecodingDone( p_ap_decode_obj); +#endif + return NOERR; + +} diff --git a/mozilla/mailnews/compose/src/nsMsgAppleEncode.cpp b/mozilla/mailnews/compose/src/nsMsgAppleEncode.cpp new file mode 100755 index 00000000000..ee66a7df167 --- /dev/null +++ b/mozilla/mailnews/compose/src/nsMsgAppleEncode.cpp @@ -0,0 +1,735 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ + +/* + * + * apple_double_encode.c + * --------------------- + * + * The routines doing the Apple Double Encoding. + * + * 2aug95 mym Created. + * + */ + +#include "nscore.h" +#include "msgCore.h" + +#include "nsMsgAppleDouble.h" +#include "nsMsgAppleCodes.h" + +#ifdef XP_MAC + +extern int MK_UNABLE_TO_OPEN_TMP_FILE; +extern int MK_MIME_ERROR_WRITING_FILE; + +#include + +/* +** Local Functions prototypes. +*/ +PRIVATE int output64chunk( appledouble_encode_object* p_ap_encode_obj, + int c1, int c2, int c3, int pads); + +PRIVATE int to64(appledouble_encode_object* p_ap_encode_obj, + char *p, + int in_size); + +PRIVATE int finish64(appledouble_encode_object* p_ap_encode_obj); + + +#define BUFF_LEFT(p) ((p)->s_outbuff - (p)->pos_outbuff) + +/* +** write_stream. +*/ +int write_stream( + appledouble_encode_object *p_ap_encode_obj, + char *out_string, + int len) +{ + if (p_ap_encode_obj->pos_outbuff + len < p_ap_encode_obj->s_outbuff) + { + XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff, + out_string, + len); + p_ap_encode_obj->pos_outbuff += len; + return noErr; + } + else + { + /* + ** If the buff doesn't have enough space, use the overflow buffer then. + */ + int s_len = p_ap_encode_obj->s_outbuff - p_ap_encode_obj->pos_outbuff; + + XP_MEMCPY(p_ap_encode_obj->outbuff + p_ap_encode_obj->pos_outbuff, + out_string, + s_len); + XP_MEMCPY(p_ap_encode_obj->b_overflow + p_ap_encode_obj->s_overflow, + out_string + s_len, + p_ap_encode_obj->s_overflow += (len - s_len)); + p_ap_encode_obj->pos_outbuff += s_len; + return errEOB; + } +} + +int fill_apple_mime_header( + appledouble_encode_object *p_ap_encode_obj) +{ + int status; + + char tmpstr[266]; + +#if 0 +// strcpy(tmpstr, "Content-Type: multipart/mixed; boundary=\"-\"\n\n---\n"); +// status = write_stream(p_ap_encode_env, +// tmpstr, +// strlen(tmpstr)); +// if (status != noErr) +// return status; + + sprintf(tmpstr, + "Content-Type: multipart/appledouble; boundary=\"=\"; name=\""); + status = write_stream(p_ap_encode_obj, + tmpstr, + strlen(tmpstr)); + if (status != noErr) + return status; + + status = write_stream(p_ap_encode_obj, + p_ap_encode_obj->fname, + nsCRT::strlen(p_ap_encode_obj->fname)); + if (status != noErr) + return status; + + XP_SPRINTF(tmpstr, + "\"\nContent-Disposition: inline; filename=\"%s\"\n\n\n--=\n", + p_ap_encode_obj->fname); +#endif + XP_SPRINTF(tmpstr, "--%s"CRLF, p_ap_encode_obj->boundary); + status = write_stream(p_ap_encode_obj, + tmpstr, + nsCRT::strlen(tmpstr)); + return status; +} + +int ap_encode_file_infor( + appledouble_encode_object *p_ap_encode_obj) +{ + CInfoPBRec cipbr; + HFileInfo *fpb = (HFileInfo *)&cipbr; + ap_header head; + ap_entry entries[NUM_ENTRIES]; + ap_dates dates; + short i; + long comlen, procID; + DateTimeRec cur_time; + unsigned long cur_secs; + IOParam vinfo; + GetVolParmsInfoBuffer vp; + DTPBRec dtp; + char comment[256]; + Str63 fname; + int status; + + strcpy((char *)fname+1,p_ap_encode_obj->fname); + fname[0] = nsCRT::strlen(p_ap_encode_obj->fname); + + fpb->ioNamePtr = fname; + fpb->ioDirID = p_ap_encode_obj->dirId; + fpb->ioVRefNum = p_ap_encode_obj->vRefNum; + fpb->ioFDirIndex = 0; + if (PBGetCatInfoSync(&cipbr) != noErr) + { + return errFileOpen; + } + + /* get a file comment, if possible */ + procID = 0; + GetWDInfo(p_ap_encode_obj->vRefNum, &fpb->ioVRefNum, &fpb->ioDirID, &procID); + memset((void *) &vinfo, '\0', sizeof (vinfo)); + vinfo.ioCompletion = nil; + vinfo.ioVRefNum = fpb->ioVRefNum; + vinfo.ioBuffer = (Ptr) &vp; + vinfo.ioReqCount = sizeof (vp); + comlen = 0; + if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && + ((vp.vMAttrib >> bHasDesktopMgr) & 1)) + { + memset((void *) &dtp, '\0', sizeof (dtp)); + dtp.ioVRefNum = fpb->ioVRefNum; + if (PBDTGetPath(&dtp) == noErr) + { + dtp.ioCompletion = nil; + dtp.ioDTBuffer = (Ptr) comment; + dtp.ioNamePtr = fpb->ioNamePtr; + dtp.ioDirID = fpb->ioFlParID; + if (PBDTGetCommentSync(&dtp) == noErr) + comlen = dtp.ioDTActCount; + } + } + + /* write header */ +// head.magic = dfork ? APPLESINGLE_MAGIC : APPLEDOUBLE_MAGIC; + head.magic = APPLEDOUBLE_MAGIC; /* always do apple double */ + head.version = VERSION; + memset(head.fill, '\0', sizeof (head.fill)); + head.entries = NUM_ENTRIES - 1; + status = to64(p_ap_encode_obj, + (char *) &head, + sizeof (head)); + if (status != noErr) + return status; + + /* write entry descriptors */ + entries[0].offset = sizeof (head) + sizeof (ap_entry) * head.entries; + entries[0].id = ENT_NAME; + entries[0].length = *fpb->ioNamePtr; + entries[1].id = ENT_FINFO; + entries[1].length = sizeof (FInfo) + sizeof (FXInfo); + entries[2].id = ENT_DATES; + entries[2].length = sizeof (ap_dates); + entries[3].id = ENT_COMMENT; + entries[3].length = comlen; + entries[4].id = ENT_RFORK; + entries[4].length = fpb->ioFlRLgLen; + entries[5].id = ENT_DFORK; + entries[5].length = fpb->ioFlLgLen; + + /* correct the link in the entries. */ + for (i = 1; i < NUM_ENTRIES; ++i) + { + entries[i].offset = entries[i-1].offset + entries[i-1].length; + } + status = to64(p_ap_encode_obj, + (char *) entries, + sizeof (ap_entry) * head.entries); + if (status != noErr) + return status; + + /* write name */ + status = to64(p_ap_encode_obj, + (char *) fpb->ioNamePtr + 1, + *fpb->ioNamePtr); + if (status != noErr) + return status; + + /* write finder info */ + status = to64(p_ap_encode_obj, + (char *) &fpb->ioFlFndrInfo, + sizeof (FInfo)); + if (status != noErr) + return status; + + status = to64(p_ap_encode_obj, + (char *) &fpb->ioFlXFndrInfo, + sizeof (FXInfo)); + if (status != noErr) + return status; + + /* write dates */ + GetTime(&cur_time); + DateToSeconds(&cur_time, &cur_secs); + dates.create = fpb->ioFlCrDat + CONVERT_TIME; + dates.modify = fpb->ioFlMdDat + CONVERT_TIME; + dates.backup = fpb->ioFlBkDat + CONVERT_TIME; + dates.access = cur_secs + CONVERT_TIME; + status = to64(p_ap_encode_obj, + (char *) &dates, + sizeof (ap_dates)); + if (status != noErr) + return status; + + /* write comment */ + if (comlen) + { + status = to64(p_ap_encode_obj, + comment, + comlen * sizeof(char)); + } + /* + ** Get some help information on deciding the file type. + */ + if (fpb->ioFlFndrInfo.fdType == 'TEXT' || fpb->ioFlFndrInfo.fdType == 'text') + { + p_ap_encode_obj->text_file_type = true; + } + + return status; +} +/* +** ap_encode_header +** +** encode the file header and the resource fork. +** +*/ +int ap_encode_header( + appledouble_encode_object* p_ap_encode_obj, + PRBool firstime) +{ + Str255 name; + char rd_buff[256]; + short fileId; + OSErr retval = noErr; + int status; + long inCount; + + if (firstime) + { + XP_STRCPY(rd_buff, + "Content-Type: application/applefile\nContent-Transfer-Encoding: base64\n\n"); + status = write_stream(p_ap_encode_obj, + rd_buff, + strlen(rd_buff)); + if (status != noErr) + return status; + + status = ap_encode_file_infor(p_ap_encode_obj); + if (status != noErr) + return status; + + /* + ** preparing to encode the resource fork. + */ + name[0] = strlen(p_ap_encode_obj->fname); + strcpy((char *)name+1, p_ap_encode_obj->fname); + if (HOpenRF(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId, + name, fsRdPerm, + &p_ap_encode_obj->fileId) != noErr) + { + return errFileOpen; + } + } + + fileId = p_ap_encode_obj->fileId; + while (retval == noErr) + { + if (BUFF_LEFT(p_ap_encode_obj) < 400) + break; + + inCount = 256; + retval = FSRead(fileId, &inCount, rd_buff); + if (inCount) + { + status = to64(p_ap_encode_obj, + rd_buff, + inCount); + if (status != noErr) + return status; + } + } + + if (retval == eofErr) + { + FSClose(fileId); + + status = finish64(p_ap_encode_obj); + if (status != noErr) + return status; + + /* + ** write out the boundary + */ + XP_SPRINTF(rd_buff, + CRLF"--%s"CRLF, + p_ap_encode_obj->boundary); + + status = write_stream(p_ap_encode_obj, + rd_buff, + nsCRT::strlen(rd_buff)); + if (status == noErr) + status = errDone; + } + return status; +} + +static void replace(char *p, int len, char frm, char to) +{ + for (; len > 0; len--, p++) + if (*p == frm) *p = to; +} + +/* Description of the various file formats and their magic numbers */ +struct magic +{ + char *name; /* Name of the file format */ + char *num; /* The magic number */ + int len; /* Length (0 means strlen(magicnum)) */ +}; + +/* The magic numbers of the file formats we know about */ +static struct magic magic[] = +{ + { "image/gif", "GIF", 0 }, + { "image/jpeg", "\377\330\377", 0 }, + { "video/mpeg", "\0\0\001\263", 4 }, + { "application/postscript", "%!", 0 }, +}; +static int num_magic = (sizeof(magic)/sizeof(magic[0])); + +static char *text_type = TEXT_PLAIN; /* the text file type. */ +static char *default_type = APPLICATION_OCTET_STREAM; + + +/* + * Determins the format of the file "inputf". The name + * of the file format (or NULL on error) is returned. + */ +PRIVATE char *magic_look(char *inbuff, int numread) +{ + int i, j; + + for (i=0; i= magic[i].len) + { + for (j=0; jfname); + XP_STRCPY((char*)name+1, p_ap_encode_obj->fname); + if (HOpen( p_ap_encode_obj->vRefNum, + p_ap_encode_obj->dirId, + name, + fsRdPerm, + &fileId) != noErr) + { + return errFileOpen; + } + p_ap_encode_obj->fileId = fileId; + + + if (!p_ap_encode_obj->text_file_type) + { + OSErr err; + FSSpec file_spec; + char* path; + Bool do_magic = true; + + /* First attempt to get the file's mime type via FE_FileType. + If that fails, we'll do a "magic_look" + */ + + err = FSMakeFSSpec(p_ap_encode_obj->vRefNum, p_ap_encode_obj->dirId, name, &file_spec); + if (err == noErr) + { + path = my_PathnameFromFSSpec(&file_spec); + if (path != NULL) + { + char* ignore; + FE_FileType(path, &do_magic, &magic_type, &ignore); + + /* + if we ended up with the default type, dispose of it + so we can do a magic_look + */ + + if (do_magic && magic_type) + PR_FREEIF(magic_type); + } + } + + if (do_magic) + { + /* + ** do a smart check for the file type. + */ + in_count = 256; + retval = FSRead(fileId, &in_count, rd_buff); + magic_type = magic_look(rd_buff, in_count); + + /* don't forget to rewind the index to start point. */ + SetFPos(fileId, fsFromStart, 0L); + } + } + else + { + magic_type = text_type; /* we already know it is a text type. */ + } + + /* + ** the data portion header information. + */ + XP_SPRINTF(rd_buff, + "Content-Type: %s; name=\"%s\"" CRLF "Content-Transfer-Encoding: base64" CRLF "Content-Disposition: inline; filename=\"%s\""CRLF CRLF, + magic_type, + p_ap_encode_obj->fname, + p_ap_encode_obj->fname); + + status = write_stream(p_ap_encode_obj, + rd_buff, + nsCRT::strlen(rd_buff)); + if (status != noErr) + return status; + } + + while (retval == noErr) + { + if (BUFF_LEFT(p_ap_encode_obj) < 400) + break; + + in_count = 256; + retval = FSRead(p_ap_encode_obj->fileId, + &in_count, + rd_buff); + if (in_count) + { +/* replace(rd_buff, in_count, '\r', '\n'); */ +/* ** may be need to do character set conversion here for localization. ** */ + status = to64(p_ap_encode_obj, + rd_buff, + in_count); + if (status != noErr) + return status; + } + } + + if (retval == eofErr) + { + FSClose(p_ap_encode_obj->fileId); + + status = finish64(p_ap_encode_obj); + if (status != noErr) + return status; + + /* write out the boundary */ + + XP_SPRINTF(rd_buff, + CRLF"--%s--"CRLF CRLF, + p_ap_encode_obj->boundary); + + status = write_stream(p_ap_encode_obj, + rd_buff, + nsCRT::strlen(rd_buff)); + + if (status == noErr) + status = errDone; + } + return status; +} + +static char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* +** convert the stream in the inbuff to 64 format and put it in the out buff. +** To make the life easier, the caller will responcable of the cheking of the outbuff's bundary. +*/ +PRIVATE int +to64(appledouble_encode_object* p_ap_encode_obj, + char *p, + int in_size) +{ + int status; + int c1, c2, c3, ct; + unsigned char *inbuff = (unsigned char*)p; + + ct = p_ap_encode_obj->ct; /* the char count left last time. */ + + /* + ** resume the left state of the last conversion. + */ + switch (p_ap_encode_obj->state64) + { + case 0: + p_ap_encode_obj->c1 = c1 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 1; + return noErr; + } + p_ap_encode_obj->c2 = c2 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 2; + return noErr; + } + c3 = *inbuff ++; --in_size; + break; + case 1: + c1 = p_ap_encode_obj->c1; + p_ap_encode_obj->c2 = c2 = *inbuff ++; + if (--in_size <= 0) + { + p_ap_encode_obj->state64 = 2; + return noErr; + } + c3 = *inbuff ++; --in_size; + break; + case 2: + c1 = p_ap_encode_obj->c1; + c2 = p_ap_encode_obj->c2; + c3 = *inbuff ++; --in_size; + break; + } + + while (in_size >= 0) + { + status = output64chunk(p_ap_encode_obj, + c1, + c2, + c3, + 0); + if (status != noErr) + return status; + + ct += 4; + if (ct > 71) + { + status = write_stream(p_ap_encode_obj, + CRLF, + 2); + if (status != noErr) + return status; + + ct = 0; + } + + if (in_size <= 0) + { + p_ap_encode_obj->state64 = 0; + break; + } + + c1 = (int)*inbuff++; + if (--in_size <= 0) + { + p_ap_encode_obj->c1 = c1; + p_ap_encode_obj->state64 = 1; + break; + } + c2 = *inbuff++; + if (--in_size <= 0) + { + p_ap_encode_obj->c1 = c1; + p_ap_encode_obj->c2 = c2; + p_ap_encode_obj->state64 = 2; + break; + } + c3 = *inbuff++; + in_size--; + } + p_ap_encode_obj->ct = ct; + return status; +} + +/* +** clear the left base64 encodes. +*/ +PRIVATE int +finish64(appledouble_encode_object* p_ap_encode_obj) +{ + int status; + + switch (p_ap_encode_obj->state64) + { + case 0: + break; + case 1: + status = output64chunk(p_ap_encode_obj, + p_ap_encode_obj->c1, + 0, + 0, + 2); + break; + case 2: + status = output64chunk(p_ap_encode_obj, + p_ap_encode_obj->c1, + p_ap_encode_obj->c2, + 0, + 1); + break; + } + status = write_stream(p_ap_encode_obj, CRLF, 2); + p_ap_encode_obj->state64 = 0; + p_ap_encode_obj->ct = 0; + return status; +} + +PRIVATE int output64chunk( + appledouble_encode_object* p_ap_encode_obj, + int c1, int c2, int c3, int pads) +{ + char tmpstr[32]; + char *p = tmpstr; + + *p++ = basis_64[c1>>2]; + *p++ = basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)]; + if (pads == 2) + { + *p++ = '='; + *p++ = '='; + } + else if (pads) + { + *p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; + *p++ = '='; + } + else + { + *p++ = basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)]; + *p++ = basis_64[c3 & 0x3F]; + } + return write_stream(p_ap_encode_obj, + tmpstr, + p-tmpstr); +} + +#endif /* if define XP_MAC */