gecko-dev/lib/mailto/ap_encod.c
akkana%netscape.com 1a97e11ffd Mailto landing.
The mailto library is the mail compose code ripped out of the old
Messenger libmsg library, then cleaned up somewhat
(it could still use more cleaning).
This library should only be built ifdef MOZ_MAIL_COMPOSE.
1998-09-04 19:04:30 +00:00

734 lines
16 KiB
C

/* -*- 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 "msg.h"
#include "appledbl.h"
#include "ad_codes.h"
#ifdef XP_MAC
extern int MK_UNABLE_TO_OPEN_TMP_FILE;
extern int MK_MIME_ERROR_WRITING_FILE;
#include <Errors.h>
/*
** 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,
XP_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,
XP_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] = XP_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,
XP_Bool 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,
XP_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<num_magic; i++)
{
if (magic[i].len == 0)
magic[i].len = XP_STRLEN(magic[i].num);
}
for (i=0; i<num_magic; i++)
{
if (numread >= magic[i].len)
{
for (j=0; j<magic[i].len; j++)
{
if (inbuff[j] != magic[i].num[j]) break;
}
if (j == magic[i].len)
return magic[i].name;
}
}
return default_type;
}
/*
** ap_encode_data
**
** ---------------
**
** encode on the data fork.
**
*/
int ap_encode_data(
appledouble_encode_object* p_ap_encode_obj,
XP_Bool firstime)
{
Str255 name;
char rd_buff[256];
short fileId;
OSErr retval = noErr;
long in_count;
int status;
if (firstime)
{
char* magic_type;
/*
** preparing to encode the data fork.
*/
name[0] = XP_STRLEN(p_ap_encode_obj->fname);
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)
XP_FREE(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,
XP_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,
XP_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 */