Initial import of the CDE 2.1.30 sources from the Open Group.

This commit is contained in:
Peter Howkins
2012-03-10 18:21:40 +00:00
commit 83b6996daa
18978 changed files with 3945623 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
/*
*+SNOTICE
*
*
* $XConsortium: AliasExpand.C /main/4 1996/04/21 19:49:19 drk $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#include <assert.h>
#include "AliasExpand.hh"
#include "RFCImpl.hh"
AliasKey::AliasKey(const char * str)
: ObjectKey("AliasKey")
{
_str = strdup(str);
}
AliasKey::~AliasKey(void)
{
free(_str);
}
int
AliasKey::operator==(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) == 0);
}
int
AliasKey::operator!=(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) != 0);
}
int
AliasKey::operator<(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) < 0);
}
int
AliasKey::operator<=(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) <= 0);
}
int
AliasKey::operator>(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) > 0);
}
int
AliasKey::operator>=(ObjectKey & other)
{
AliasKey * ok = (AliasKey *)&other;
return(strcmp(_str, ok->_str) >= 0);
}
HashVal
AliasKey::hashValue(void)
{
return(genericHashValue(_str, strlen(_str)));
}
// deleteAllocatedKey: used to iterate through a hash table to remove
// all key values that are allocated during the duration of rfcAliasExpand
//
static int
deleteAllocatedKey(ObjectKey & object, AliasKey *, void *) {
assert(&object != NULL);
delete &object;
return(1);
}
void
rfcAliasExpand(DtMailEnv & error,
DtMail::MailRc & mailrc,
DtMailAddressSeq & addrs)
{
HashTable<DtMailBoolean> been_there(32);
error.clear();
// We will go through each item in the address table.
// For each address, we will look it up in the alias
// table. If it exists there, we will check to see if
// we have expanded before. If not, then we expand and
// note our visit.
//
DtMailEnv lerror;
for (int naddr = 0; naddr < addrs.length(); naddr++) {
DtMailValueAddress * caddr = addrs[naddr];
const char * alias = mailrc.getAlias(lerror, caddr->dtm_address);
if (alias) {
AliasKey * key = new AliasKey(caddr->dtm_address);
if (been_there.lookup(*key)) { // already visited address?
delete key; // yes: cleanup unneeded key
}
else { // no: expand the alias
DtMailAddressSeq exp_addrs(32);
RFCTransport::arpaPhrase(alias, exp_addrs);
for (int cp = 0; cp < exp_addrs.length(); cp++) {
DtMailValueAddress * new_addr = new DtMailValueAddress(*exp_addrs[cp]);
addrs.append(new_addr);
}
been_there.set(*key, DTM_TRUE);
}
addrs.remove(naddr); // no longer need this address
naddr -= 1; // ...
delete caddr; // or what it pointed to.
}
}
// Finally, as a courtesy to the recipients, we will throw away
// duplicates that have resulted from our expansion.
//
HashTable<DtMailBoolean> done_that(32);
for (int cur = 0; cur < addrs.length(); cur++) {
DtMailValueAddress * caddr = addrs[cur];
AliasKey * dup_key = new AliasKey(caddr->dtm_address);
if (done_that.lookup(*dup_key)) {
addrs.remove(cur);
delete caddr;
delete dup_key;
cur -= 1;
}
else {
done_that.set(*dup_key, DTM_TRUE);
}
}
}

View File

@@ -0,0 +1,50 @@
/*
*+SNOTICE
*
*
* $XConsortium: AliasExpand.hh /main/4 1996/04/21 19:49:22 drk $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef _ALIASEXPAND_HH
#define _ALIASEXPAND_HH
#include <DtMail/DtMail.hh>
#include <DtMail/HashTable.hh>
class AliasKey : public ObjectKey {
public:
AliasKey(const char * str);
~AliasKey(void);
int operator==(ObjectKey &);
int operator!=(ObjectKey &);
int operator<(ObjectKey &);
int operator>(ObjectKey &);
int operator<=(ObjectKey &);
int operator>=(ObjectKey &);
HashVal hashValue(void);
private:
char * _str;
};
void rfcAliasExpand(DtMailEnv &,
DtMail::MailRc & mailrc,
DtMailAddressSeq & addrs);
#endif

View File

@@ -0,0 +1,53 @@
XCOMM $TOG: Imakefile /main/8 1998/08/05 13:25:32 mgreess $
#define DoNormalLib YES
#define DoSharedLib NO
#define DoDebugLib NO
#define DoProfileLib NO
#define LibName DtMail
#define LibHeaders NO
#define LibCreate NO
#define CplusplusSource YES
DEPEND_DEFINES = $(CXXDEPENDINCLUDES)
#include <Threads.tmpl>
INCLUDES = -I. -I../Common -I../../include -I../../include/utils -I$(CDELIBSRC)
#if HasVFork
VFORK_DEFINES = -DHAS_VFORK
#else
VFORK_DEFINES =
#endif
#ifndef DtMailDefines
# define DtMailDefines
#endif
DEFINES = -DTTLOCK_OFF $(VFORK_DEFINES) DtMailDefines
SRCS = \
AliasExpand.C MIMEBodyPart.C \
MIMEPartial.C RFCBodyPart.C \
RFCEnvelope.C RFCFormat.C \
RFCMIME.C RFCMailBox.C \
RFCMailValues.C RFCMessage.C \
RFCTransport.C SunV3.C \
V3BodyPart.C
/*
* NOTE: All changes here must be mirrored in ../Imakefile's RFC_OBJS
*/
OBJS = \
AliasExpand.o MIMEBodyPart.o \
MIMEPartial.o RFCBodyPart.o \
RFCEnvelope.o RFCFormat.o \
RFCMailBox.o RFCMailValues.o \
RFCMessage.o RFCMIME.o \
RFCTransport.o SunV3.o \
V3BodyPart.o
#include <Library.tmpl>
SubdirLibraryRule($(OBJS))
DependTarget()

View File

@@ -0,0 +1,998 @@
/*
*+SNOTICE
*
*
* $TOG: MIMEBodyPart.C /main/11 1998/04/06 13:27:03 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#include <EUSCompat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <Dt/Dts.h>
#include <DtMail/DtMail.hh>
#include "RFCImpl.hh"
#include "RFCMIME.hh"
#include <DtMail/Threads.hh>
#include "md5.h"
// For CHARSET
#include <locale.h>
#include <DtHelp/LocaleXlate.h>
#include "str_utils.h"
MIMEBodyPart::MIMEBodyPart(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const int len,
RFCEnvelope * body_env)
: RFCBodyPart(error, parent, start, len, body_env)
{
// A single part message. We are done for now.
//
error.clear();
return;
}
MIMEBodyPart::MIMEBodyPart(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const char ** end,
const char * boundary)
: RFCBodyPart(error, parent, start, 0, NULL)
{
error.clear();
// We are sitting at the start of a boundary. We need to get
// past the boundary to do the real processing.
//
const char * body_end;
for (body_end = _body_text; body_end <= *end && *body_end != '\n'; body_end++) {
continue;
}
body_end += 1;
if (body_end > *end) {
// Don't know. Give up!
*end = body_end;
_body_len = *end - start + 1;
// Need a bogus envelope for other uses.
//
_body_env = new RFCEnvelope(error, parent, NULL, 0);
return;
}
const char * env_start = body_end;
_my_env = DTM_TRUE;
if (isTerm(env_start)) {
_body_env = new RFCEnvelope(error, parent, env_start, 0);
}
else {
// Find the blank line where the envelope ends.
//
for (; body_end <= *end; body_end++) {
if (*body_end == '\n') {
int blank_only = 1;
for (const char * blank = body_end + 1;
blank <= *end && *blank != '\n'; blank++) {
if (!isspace((unsigned char)*blank)) {
blank_only = 0;
break;
}
}
if (blank_only) {
break;
}
}
}
_body_env = new RFCEnvelope(error,
parent,
env_start,
body_end - env_start + 1);
body_end += 1;
}
// Chew everything up to the next new line, which should be only
// a CRLF.
//
for (;body_end <= *end && *body_end != '\n'; body_end++) {
continue;
}
body_end += 1;
_body_text = body_end; // This is where the body really starts.
// Now we need to find the end of the body. MIME doesn't have
// any predefined length fields so we have to use the boundaries.
//
int bndry_len = strlen(boundary);
for (;body_end <= *end; body_end++) {
if (*body_end == '\n' &&
*(body_end + 1) == '-' &&
*(body_end + 2) == '-' &&
strncmp(body_end + 3, boundary, bndry_len) == 0) {
break;
}
}
if (*(body_end - 1) == '\r') {
body_end -= 1;
}
_body_len = body_end - _body_text + 1;
// MIME says the CRLF preceding a boundary belongs to the boundary.
// We will pull it off here rather than do it on entry to this
// method for the next message.
for (;body_end <= *end && *body_end != '\n'; body_end++) {
continue;
}
body_end += 1;
// Computing the end here is a little different. If the boundary
// ends with a "--" as well, then we are at the real end of
// the message.
//
const char * bndry_end = body_end + 2 + strlen(boundary);
if (*bndry_end == '-' && *(bndry_end + 1) == '-') {
*end = *end + 1;
}
else {
*end = body_end;
}
return;
}
MIMEBodyPart::~MIMEBodyPart(void)
{
}
#ifdef DEAD_WOOD
DtMailChecksumState
MIMEBodyPart::checksum(DtMailEnv & error)
{
error.clear();
// Look for the Content-MD5 header. If it is not present, then
// the state is unknown and we can punt.
//
DtMailEnv my_error;
DtMailValueSeq value;
_body_env->getHeader(my_error, "Content-MD5", DTM_FALSE, value);
if (my_error.isSet()) {
return(DtMailCheckUnknown);
}
if (_body_type == NULL) {
getDtType(error);
if (error.isSet()) {
return(DtMailCheckUnknown);
}
}
char stored_digest[32];
int stored_size = 0;
RFCMIME::readBase64(stored_digest, stored_size,
*(value[0]), strlen(*(value[0])));
if (stored_size != 16) {
// The MD5 sum must be 16 bytes, or we have a bad checksum.
//
return(DtMailCheckBad);
}
// See if we call this text. We need to handle md5 checksums
// different for text. They must be computed with CRLF line
// termination.
//
char * text_type = DtDtsDataTypeToAttributeValue(_body_type,
DtDTS_DA_IS_TEXT,
NULL);
unsigned char digest[16];
if (text_type && strcasecmp(text_type, "true") == 0) {
RFCMIME::md5PlainText(_body, _body_decoded_len, digest);
}
else {
MD5_CTX context;
MD5Init(&context);
MD5Update(&context, (unsigned char *)_body, _body_decoded_len);
MD5Final(digest, &context);
}
free(text_type);
if (memcmp(digest, stored_digest, sizeof(digest)) == 0) {
return(DtMailCheckGood);
}
else {
return(DtMailCheckBad);
}
}
#endif /* DEAD_WOOD */
static int
countTypes(char ** types)
{
int count;
for (count = 0; *types; types++, count++) {
continue;
}
return(count);
}
void
MIMEBodyPart::getContentType(DtMailEnv &error, char **mime_type)
{
DtMailValueSeq value;
if (mime_type)
*mime_type = (char *)0;
if (_body_env)
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
if (_body_env && !error.isSet())
{
// Handle "Content-Type: text" problem with /usr/lib/mail.local
if (strcasecmp(*(value[0]), "text")==0)
*mime_type = strdup("text/plain");
else
*mime_type = strdup(*(value[0]));
}
else
{
error.clear();
*mime_type = strdup("text/plain");
}
}
void
MIMEBodyPart::getDtType(DtMailEnv & error)
{
MutexLock lock_scope(_obj_mutex);
MutexLock dt_lib_lock(_DtMutex);
// error.clear();
char * end;
char * mime_type;
DtMailValueSeq value;
if (_body_env) {
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
}
if (_body_env && !error.isSet()) {
// Handle "Content-Type: text" problem with /usr/lib/mail.local
//
if (strcasecmp(*(value[0]), "text")==0)
mime_type = strdup("text/plain");
else
mime_type = strdup(*(value[0]));
}
else {
error.clear();
mime_type = strdup("text/plain");
}
for (end = mime_type; *end; end++) {
if (*end == ';' || isspace((unsigned char)*end)) {
break;
}
if (isupper(*end)) {
*end = tolower(*end);
}
}
*end = 0;
char ** types = DtDtsFindAttribute(DtDTS_DA_MIME_TYPE, mime_type);
// We must have an exact 1:1 mapping between the mime type and the
// CDE type to use this inverse mapping. If we have no hits then we
// dont have any thing to use. If we have several hits, then we have
// no idea which type is the correct type.
//
if (NULL != types) {
if (countTypes(types) == 1) {
// We will use the first name. It may be wrong, but
// it is the best we can do at this point.
//
_body_type = strdup(types[0]);
DtDtsFreeDataTypeNames(types);
free(mime_type);
return;
}
DtDtsFreeDataTypeNames(types);
}
// We need the bits so we can type the buffer and get
// a type for the object. This is where things can get
// very slow for the user.
//
loadBody(error);
if (error.isSet()) {
return;
}
int istext = (strcasecmp(mime_type, "text/plain") == 0);
char * name = getNameHeaderVal(error);
char * type = DtDtsBufferToDataType(_body, _body_decoded_len, name);
// We have written a name pattern for text parts that will match
// the name "text" as a TEXT part. If the first attempt to get the
// data type fails and we have a MIMETYPE of text/plain, then we try
// again using the name "text".
//
if ( (0 == strcasecmp(mime_type, "text/plain")) &&
(NULL == type || 0 == strcasecmp(type, "DATA")) )
{
if (type)
DtDtsFreeDataType(type);
type = DtDtsBufferToDataType(_body, _body_decoded_len, "text");
}
if (NULL != type)
_body_type = strdup(type);
else
_body_type = strdup("UNKNOWN");
if (error.isSet())
error.clear();
if (type)
DtDtsFreeDataType(type);
if (mime_type)
free(mime_type);
if (name)
free(name);
}
void
MIMEBodyPart::loadBody(DtMailEnv & error)
{
// For CHARSET
char *cs = NULL, *to_cs = NULL, *from_cs = NULL;
// There is no reason to clear the error object because it is assumed
// that whoever instantiated it, cleared it.
// error.clear();
if (_body) {
return;
}
// If there is any encoding done to the body, reverse it
//
DtMailValueSeq value;
if (_body_env) {
_body_env->getHeader(error, "Content-Transfer-Encoding",
DTM_FALSE, value);
}
if (_body_env && !error.isSet()) {
const char * enc = *(value[0]);
if (strcasecmp(enc, "base64") == 0) {
// Decoded bodies will always be smaller than
// encoded bodies.
//_body = (char *)malloc(_body_len);
_body = (char *)malloc(_body_len+1);
int size = _body_decoded_len = 0;
_must_free_body = DTM_TRUE;
RFCMIME::readBase64(_body, size, _body_text, _body_len);
_body_decoded_len = size;
// Changed this temporarily until after release. We really should not
// be null terminating these buffers.
(_body)[_body_decoded_len] = 0;
}
else if (strcasecmp(enc, "quoted-printable") == 0) {
_body = (char *)malloc(_body_len + 20);
_must_free_body = DTM_TRUE;
int size = _body_decoded_len = 0;
RFCMIME::readQPrint(_body, size, _body_text, _body_len);
_body_decoded_len = size;
// Changed this temporarily until after release. We really should not
// be null terminating these buffers.
(_body)[_body_decoded_len] = 0;
}
else {
// Default case is no transfer encoding applies (7bit==8bit==binary)
_body = (char *)_body_text;
_must_free_body = DTM_FALSE;
_body_decoded_len = _body_len;
}
}
else {
// Default case is no transfer encoding applies.
error.clear();
_body = (char *)_body_text;
_must_free_body = DTM_FALSE;
_body_decoded_len = _body_len;
}
// For CHARSET
// Get charset from content-type field
char *ret = NULL;
value.clear();
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
if (error.isNotSet()) {
cs = csFromContentType(value);
if ( cs == NULL ) {
// Random allocation for cs
cs = (char *)calloc(128, sizeof(char));
DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
setlocale(LC_CTYPE, NULL),
NULL,
NULL,
&ret);
strcpy(cs, "DEFAULT");
strcat(cs, ".");
strcat(cs, ret);
}
} else { // No Content-Type
// We'll be flexible here. If Content-Type header is missing, we'll
// still try to convert from the locale specific default codeset.
error.clear();
// Random allocation for cs
cs = (char *)calloc(128, sizeof(char));
DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
setlocale(LC_CTYPE, NULL),
NULL,
NULL,
&ret);
strcpy(cs, "DEFAULT");
strcat(cs, ".");
strcat(cs, ret);
}
// Handle ISO-2022-INT, RFC approved, or private encoding names
if ( strcasecmp(cs, "ISO-2022-INT-1") == 0 ) {
// Need to obtain charset from encoding
} // RFC approved and private names are not treated differently.
// Get iconv name from charset - this is the "from" name.
from_cs = NULL;
from_cs = csToConvName(cs);
// Get current locale's iconv name - this is the "to" name.
to_cs = NULL;
to_cs = locToConvName();
if ( from_cs && to_cs ) {
if ( strcasecmp(from_cs, to_cs) != 0 ) {
unsigned long tmp_len = (unsigned long) _body_decoded_len;
if (csConvert(&_body, tmp_len, (int)_must_free_body, from_cs, to_cs)) {
_must_free_body = DTM_TRUE;
_body_decoded_len = (int) tmp_len;
}
}
}
if ( cs )
free ( cs );
if ( from_cs )
free( from_cs );
if ( to_cs )
free ( to_cs );
if ( ret )
free( ret );
// End of For CHARSET
// Clear the error condition before proceeding. This is done
// because functions that take a DtMailEnv object as a parameter
// expect it to be cleared. (Already cleared above)
// error.clear();
// If the body is text/enriched, convert it to text/plain
// At some point the front end should be able to handle this via
// data typing and do an 'intelligent' conversion, in which
// case this code can be removed
//
value.clear();
if (_body_env) {
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
}
if (_body_env && !error.isSet() &&
((strncasecmp(*(value[0]), "text/enriched", 13) == 0)
|| (strncasecmp(*(value[0]), "text/richtext", 13) == 0))) {
char *new_body = (char *)malloc((unsigned)(_body_len*2));
int size = 0;
RFCMIME::readTextEnriched(new_body, size, _body, _body_decoded_len);
new_body = (char *)realloc(new_body, size+2);
if (_must_free_body == DTM_TRUE)
free(_body);
_must_free_body = DTM_TRUE;
_body_decoded_len = size;
_body = new_body;
// Changed this temporarily until after release. We really should not
// be null terminating these buffers.
(_body)[_body_decoded_len] = 0;
}
error.clear();
return;
}
// NOTES ON HANDLING OF "FILE NAMES" FOR BODY PARTS IN MIME COMPLIANT ENTITIES:
// (see full description in evaluation for bug 1189035)
//
// The ability to provide a "file name" for a body part in a MIME compliant
// entity is partially addressed in RFC 1341 [MIME: Multipurpose Internet Mail
// Extentions] and RFC 1521 [which obsoleted RFC 1341].
//
// RFC 1341 proposed a solution to the file name problem (Content-Type:
// type; name=name); RFC 1521 subsequently depreciated this solution in
// favor of a to-be-defined future specification of "Content-Disposition".
//
// In essence there is an anticipation that "Content-Disposition" will
// be defined in a future RFC such that the notion of a "file name" may
// be given to a body part of a MIME compliant entity.
//
// OpenWindows mailtool currently recognizes "Content-Description" on MIME
// compliant entities and uses that information as the "file name" for
// an attachment (as per a loose interpretation of RFC 1521).
//
// CDE DtMail currently sends out and recognizes "X-Content-Name" on MIME
// compliant entities and uses that information as the "file name" for an
// attachment. This is essentially a non-standard header field as per RFC
// 1521:
//
// "X-" fields may be created for experimental or private purposes,
// with the recognition that the information they contain may be
// lost at some gateways.
//
// Since OpenWindows mailtool does not understand "X-Content-Name", any
// body part in e-mail originating from CDE DtMail does not appear to
// have a file name when read by mailtool.
//
// Given these facts:
//
// . OpenWindows mailtool cannot be changed until at least the Solaris
// 2.5 release (if at all).
//
// . OpenWindows mailtool is recognizing a valid MIME header field
// which is essentially "free form" in nature.
//
// . CDE DtMail is currently using an experimental or private field
// which is not part of the standard and is not guaranteed to survive
// transport across gateways.
//
// . There is no officially proscribed method for providing the "file
// name" of a body part in a MIME compliant entity in RFC 1521.
//
// The reasonable approach to take to solve this problem is:
//
// 1. Have DtMail use "Content-Description" to transmit the "file name"
// for a body part - this achieves compatibility with mailtool.
//
// 2. Have DtMail also continue to use "X-Content-Name" to transmit the
// "file name" - this maintains compatibility with previous versions
// of DtMail which only recognize this header.
//
// 3. Have Dtmail recognize both "Content-Description" and "X-Content-Name"
// as specifying the "file name" for a body part. In the case that both
// fields are present, "Content-Description" takes precedence over
// "X-Content-Name".
//
// 4. When "Content-Disposition" is properly defined and included as part
// of an updated MIME specification, revisit this issue.
//
//
// So, since dtmail currently *ignores* the "Content-Description" field,
// we overload the "getNameHeaderVal" function to use "Content-Description"
// first, then the older unofficial experimental "X-Content-Name". If
// and when Content-Disposition takes hold, it will have to override
// Content-Description when both are present.
//
//
// March 25, 1997
// The Content-Disposition field has been designated as the primary
// header field for transmitting file names. See RFC 1806. Therefore
// the algorithm has bee updated as follows.
//
// 1. DtMail checks the following headers for the "filename" for a body part:
// o The "filename" parameter of the "Content-Disposition" header field.
// o The contents of the "Content-Description" header field.
// o The "name" parameter of the "Content-Type" header field.
// o The contents of the "Content-Name" header field.
// o The contents of the "X-Content-Name" header field.
//
// 2. DtMail uses the following fields to specify the "filename" for a body
// part in outgoing mail:
// o The "filename" parameter of the "Content-Disposition" header field.
// o The contents of the "Content-Description" header field.
//
char *
MIMEBodyPart::getDescription(DtMailEnv &)
{
// Dont have this return anything without checking
// ramifications with getNameHeaderValue
// No need to clear error object here because we assume it has already
// been cleared by the caller and nothing has touched it in this method.
// error.clear();
return(NULL);
}
char *
MIMEBodyPart::getNameHeaderVal(DtMailEnv & error)
{
DtMailValueSeq value;
if (_body_env == NULL) {
// No need to clear the error object...it is unchanged from the
// state we received it in.
//error.clear();
return(NULL);
}
// The current standard seems to be to use the "Content-Disposition"
// header as the primary mechanism for transmitting file names.
//
_body_env->getHeader(error, "Content-Disposition", DTM_FALSE, value);
if (error.isNotSet()) {
char *param = parameterValue(value, "filename", DTM_FALSE);
if (NULL != param)
return strdup(param);
}
error.clear();
// In keeping with the current undefined nature of
// file names for body parts in RFC 1521, and to be
// compatible with OpenWindows mailtool, the first
// overriding "name" comes from "Content-Description"
//
_body_env->getHeader(error, "Content-Description", DTM_FALSE, value);
if (error.isNotSet()) {
return(strdup(*(value[0])));
}
error.clear();
// For backward compatibility with older mail agents, check the "Name"
// parameter in the "Content-Type" header.
//
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
if (error.isNotSet()) {
char *param = parameterValue(value, "name", DTM_FALSE);
if (NULL != param)
return strdup(param);
}
error.clear();
// Next we remain compatible with previous versions
// of DtMail that used "X-Content-Name" instead of
// "Content-Description" for the file name of a
// body part (1-27-95)
//
_body_env->getHeader(error, "X-Content-Name",
DTM_FALSE, value);
if (error.isNotSet()) {
return(strdup(*(value[0])));
}
error.clear();
// This code was in dtmail on 1-27-95 and even though
// that version of dtmail did not send out "Content-Name"
// (which is not part of RFC 1341 or 1521) it doesnt
// hurt to recognize it if its the only header there.
//
_body_env->getHeader(error, "Content-Name",
DTM_FALSE, value);
if (error.isNotSet()) {
return(strdup(*(value[0])));
}
error.clear(); // NULL is the real error here.
// No name for this body part
//
return(NULL);
}
char *
MIMEBodyPart::getName(DtMailEnv & error)
{
char * h_name = getNameHeaderVal(error);
// don't care about the error returned by getNameHeaderVal()
error.clear();
if (h_name) {
return(h_name);
}
if (!_body_type) {
getDtType(error);
if (error.isSet()) {
error.clear();
return(strdup("Attachment"));
}
}
char * pat = DtDtsDataTypeToAttributeValue(_body_type,
"NAME_TEMPLATE",
NULL);
if (pat) {
int max_len = strlen(pat) + 20;
char * name = (char*) malloc((size_t) max_len);
sprintf(name, pat, "Attachment");
DtDtsFreeAttributeValue(pat);
return(name);
}
return(strdup("Attachment"));
}
void
MIMEBodyPart::setName(DtMailEnv & error, const char * name)
{
if (_body_env) {
_body_env->setHeader(error, "X-Content-Name", DTM_TRUE, name);
}
}
unsigned long
MIMEBodyPart::getLength(DtMailEnv & error)
{
MutexLock lock_scope(_obj_mutex);
loadBody(error);
if (error.isSet()) {
// propogate the error back to the caller.
return (0);
}
// We have to treat external bodies differently. The headers on these
// parts contain useful information to the client.
//
const char * mime_type;
DtMailValueSeq value;
if (_body_env) {
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
}
if (_body_env && !error.isSet()) {
mime_type = *(value[0]);
}
else {
// only need to clear the error object if getHeader returned
// an error condition. We don't want to propogate the error
// back up the calling sequence.
error.clear();
mime_type = "text/plain";
}
unsigned long len;
if (strncasecmp(mime_type, "message/external-body", 21) == 0) {
const char * contents = _body_start;
for (;contents < (_body_text + _body_len); contents++) {
if (*contents == '\n') {
break;
}
}
contents += 1;
len = _body_len + (_body_text - contents);
}
else {
len = _body_decoded_len;
}
return(len);
}
int
MIMEBodyPart::rfcSize(const char *, DtMailBoolean &)
{
return(0);
}
char *
MIMEBodyPart::writeBodyParts(char * buf)
{
return(buf);
}
const void *
MIMEBodyPart::getBody(DtMailEnv & error)
{
// No need to clear the error here, should be cleared by the object
// that instantiated it.
// error.clear();
if (!_body) {
loadBody(error);
// loadBody currently (version 1.31) clears the error before
// returning, so the following check is not needed. We'll
// leave it alone on the chance that loadBody() will someday
// return an error condition.
if (error.isSet()) {
return(NULL);
}
}
// We have to treat external bodies differently. The headers on these
// parts contain useful information to the client.
//
const char * mime_type;
DtMailValueSeq value;
if (_body_env) {
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
}
if (_body_env && !error.isSet()) {
// Handle "Content-Type: text" problem with /usr/lib/mail.local
//
if (strcasecmp(*(value[0]), "text")==0)
mime_type = "text/plain";
else
mime_type = *(value[0]);
}
else {
error.clear();
mime_type = "text/plain";
}
const char * contents;
if (strncasecmp(mime_type, "message/external-body", 21) == 0) {
contents = _body_start;
for (;contents < (_body_text + _body_len); contents++) {
if (*contents == '\n') {
break;
}
}
contents += 1;
}
else {
contents = _body;
}
return(contents);
}
// For CHARSET
// Given the Content-Type field, extract the charset value.
// Returns one of the following:
// 1) charset value,
// Caller MUST FREE this return value.
// 2) NULL if charset is not specified but Content-Type specifies
// text/plain data. If this routine returns NULL, that means
// charset is not specified but the data is text/plain. Therefore,
// (as in the case of MIMEBodyPart::loadBody) caller
// will call csToConvName("DEFAULT.<locale>") and csToConvName will return
// a default iconv conversion name for the current locale.
// This is the case because some (old) mailers do not set the charset value
// but encodes the message in a "popular" codeset. The default conversion
// name for a particular locale assumes the "popular" codeset used.
// 3) non NULL but invalid charset value if Content-Type does not specify
// text/plain data. Caller MUST FREE this return value.
char *
MIMEBodyPart::csFromContentType(DtMailValueSeq &value)
{
char *cs_str = NULL;
char *val_ptr = NULL;
int quoted = 0;
// value[0] should be valid else error would have occurred before
// this routine ever gets called. And value index is 0 because
// previous value stored should have been removed.
const char *val = *(value[0]);
// Check to see if Content-Type field specifies text/plain data.
// If so, look for charset value
// else, returns value in Content-Type field
if ( strstr(val, "text") == NULL ) {
if ( strstr(val, "TEXT") == NULL ) {
cs_str = strdup(val);
return cs_str;
}
}
// Get charset value
val_ptr = strstr(val, "charset=");
if ( val_ptr == NULL ) {
val_ptr = strstr(val, "CHARSET=");
}
if ( val_ptr == NULL ) {
return NULL;
}
val_ptr = val_ptr+8;
// Check if charset value is quoted
if ( val_ptr[0] == '"' ) {
val_ptr++;
quoted = 1;
}
if ( quoted ) {
cs_str = strdup(strtok(val_ptr, "\""));
} else {
cs_str = (char *)calloc(strlen(val_ptr)+1, sizeof(char));
sscanf(val_ptr, "%s", cs_str);
}
return cs_str;
}
// End of For CHARSET
char *
MIMEBodyPart::parameterValue(
DtMailValueSeq &value,
const char * parameter,
DtMailBoolean isCaseSensitive)
{
char *lasts=NULL;
char *ptok, *vtok;
char *parm, *val;
int rtn = 0;
val = strdup(*(value[0]));
vtok = strrchr(val, ';');
while (NULL != vtok)
{
*vtok = '\0';
vtok++;
while(isspace(*vtok))
vtok++;
if (isCaseSensitive)
rtn = strncmp(vtok, parameter, sizeof(parameter));
else
rtn = strncasecmp(vtok, parameter, sizeof(parameter));
if (0 == rtn)
{
ptok = strrchr(vtok, '=');
if (NULL == ptok)
{
free(val);
return NULL;
}
ptok++;
if (*ptok == '"' )
{
ptok++;
parm = strdup(strtok(ptok, (const char *) "\""));
}
else
parm = strdup(ptok);
free(val);
return parm;
}
vtok = strrchr(val, ';');
}
free(val);
return NULL;
}

View File

@@ -0,0 +1,538 @@
/*
*+SNOTICE
*
*
* $TOG: MIMEPartial.C /main/6 1998/04/06 13:27:21 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#include <EUSCompat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <DtMail/DtMail.hh>
#include "RFCImpl.hh"
#include "str_utils.h"
static const char * contentType = "content-type";
static const char * partial = "message/partial";
//
// Get the named header out of out of the message.
//
static char *
getNamedHeader(DtMailEnv & error,
const char * headerName,
RFCMessage * message)
{
DtMailValueSeq value;
char * results = NULL;
RFCEnvelope * env = (RFCEnvelope *)message->getEnvelope(error);
if (error.isNotSet()) {
env->getHeader(error, headerName, DTM_FALSE, value);
if (error.isNotSet()) {
results = strdup(*(value[0]));
}
}
return(results);
}
//
// Return the value to the right of the '=' in the named string.
// As an INT.
//
static unsigned int
getNamedValueInt(const char *string, const char *name)
{
int stringLen = strlen(string);
int nameLen = strlen(name);
int results = 0;
register unsigned int offset;
for (offset = 0; offset < stringLen - nameLen; offset++) {
if (strncasecmp(&string[offset], name, nameLen) == 0) {
if (string[offset + nameLen] == '=') {
results = atoi(&string[offset + nameLen + 1]);
break;
}
}
}
return(results);
}
//
// Return the value to the right of the '=' in the named string.
// As a const char *.
//
static const char *
getNamedValueString(const char *string, const char *name)
{
int stringLen = strlen(string);
int nameLen = strlen(name);
const char * results;
char * stringEnd;
register unsigned int offset;
for (offset = 0; offset < stringLen - nameLen; offset++) {
if (strncasecmp(&string[offset], name, nameLen) == 0) {
if (string[offset + nameLen] == '=') {
//
// We only want what is inside the '"' quotes.
//
results = strdup(&string[offset + nameLen + 1]);
if (*results == '"') {
results++;
stringEnd = strchr(results, '"');
if (stringEnd != NULL) {
*stringEnd = '\0';
}
}
break;
}
}
}
return(results);
}
DtMailBoolean
RFCMailBox::_isPartial(DtMailEnv & error,
RFCMessage * message)
{
DtMailBoolean results = DTM_FALSE;
RFCMessage * messageArray = NULL;
char * type;
if (message != NULL
&& (type = getNamedHeader(error, contentType, message)) != NULL) {
if (error.isNotSet()) {
if (strncasecmp(type, partial, 15) == 0) {
//
// Add ourselves to the array.
//
_partialData * newData = new _partialData;
newData->id = getNamedValueString(type, "id");
newData->number = getNamedValueInt(type, "number");
newData->total = getNamedValueInt(type, "total");
newData->msg = message;
//
// It has to have a number and an ID or it is not a valid
// message/partial and there would be no way to put it
// back together. Total is optional except for the last part
// where it is required.
//
if (newData->number > 0 && newData->id != NULL) {
_partialList = (_partialData **)realloc(_partialList,
sizeof(_partialData *)
*(_partialListCount+1));
if (_partialList != NULL) {
_partialList[_partialListCount] = newData;
_partialListCount++;
results = DTM_TRUE;
}
} else {
delete newData; // Not a valid message/partial.
}
}
free(type);
}
else {
error.clear();
}
}
return(results);
}
RFCMessage *
RFCMailBox::_assemblePartial(DtMailEnv & error,
RFCMessage * message)
{
register unsigned int offset;
unsigned int totalParts = 0;
RFCMessage * msg = message;
_partialData * data = NULL;
if (message != NULL) {
char * type = getNamedHeader(error, contentType, message);
//
// Find ourselfs in the list.
//
for (offset = 0 ; offset < _partialListCount ; offset++) {
if (_partialList[offset]->msg == message) {
data = _partialList[offset];
break;
}
}
//
// Now look for the total for this message-id.
//
if (data != NULL) {
for (offset = 0 ; offset < _partialListCount ; offset++) {
if (strcasecmp(_partialList[offset]->id, data->id) == 0) {
totalParts = _partialList[offset]->total;
if (totalParts > 0) {
break;
}
}
}
}
//
// If we know how many parts we are to process - start looking.
//
// If we do not know the total, then we know that not all of the
// parts have arrived. (the last partial message must have
// the total in it).
//
if (totalParts > 0) {
char * dummy = (char *) calloc(1, totalParts * sizeof(RFCMessage *));
RFCMessage ** messages = (RFCMessage **)dummy;
//
// Now we go thru the list again, this time looking for
// all of the parts. Place them in the correct order
// in the list.
//
for (offset = 0 ; offset < _partialListCount ; offset++) {
if (strcasecmp(_partialList[offset]->id, data->id) == 0) {
messages[_partialList[offset]->number - 1]
= _partialList[offset]->msg;
}
}
//
// If all of the parts are IN, then assemble them into
// a new message.
//
int totalSize = 0; // Total size of all of the parts.
char *messageLength;
for (offset = 0 ; offset < totalParts ; offset++) {
if (messages[offset] == NULL) {
break; // Found a missing part, do not assemble.
}
messageLength = getNamedHeader(error, "Content-Length",
messages[offset]);
if (messageLength == NULL || error.isSet()) {
break; // No way to assemble if we do not know the size.
}
totalSize += atoi(messageLength); // Bump the total size.
free(messageLength);
}
if (offset == totalParts) { // Did we find all of the parts ?
//
// From RFC 1521, section 7.3.2:
//
// When generating and reassembling the parts of a message/partial
// message, the headers of the encapsulated message must be merged with
// the headers of the enclosing entities. In this process the
// following rules must be observed:
//
// (1) All of the header fields from the initial enclosing entity
// (part one), except those that start with "Content-" and the
// specific header fields "Message-ID", "Encrypted", and
// "MIME-Version", must be copied, in order, to the new message.
//
// (2) Only those header fields in the enclosed message which start
// with "Content-" and "Message-ID", "Encrypted", and "MIME-Version"
// must be appended, in order, to the header fields of the new
// message. Any header fields in the enclosed message which do not
// start with "Content-" (except for "Message-ID", "Encrypted", and
// "MIME-Version") will be ignored.
//
// (3) All of the header fields from the second and any subsequent
// messages will be ignored.
//
// Pick 10% more space for the headers, or a random size for
// the new message.
//
totalSize = (totalSize > 10*1024) ? (int) (totalSize*1.1) : (20*1024);
char * newMessage = (char *)malloc(totalSize);
newMessage[0] = '\0';
//
// Copy over all of the headers from the outer 1st message
// except the ones that we are not suppost to copy.
//
RFCEnvelope * env
= (RFCEnvelope *)messages[0]->getEnvelope(error);
DtMailHeaderHandle headerHandle;
DtMailValueSeq headerValue;
char * headerName;
const char * unixFromLine = NULL;
unsigned int duplicateCount;
int fromLen;
int headerNumber = 0;
register unsigned int dupOffset;
if (error.isNotSet()) {
//
// Get the first header.
//
headerHandle = env->getFirstHeader(error, &headerName, headerValue);
unixFromLine = env->unixFrom(error, fromLen);
if (unixFromLine != NULL) {
strncat(newMessage, unixFromLine, fromLen);
newMessage[fromLen] = '\0';
}
if (error.isNotSet()) {
//
// Keep geting more (all) of the headers.
//
do {
if ((strncasecmp(headerName, "Content-", 8) != 0)
&& (strcasecmp(headerName, "Message-ID") != 0)
&& (strcasecmp(headerName, "Encrypted") != 0)
&& (strcasecmp(headerName, "MIME-Version") != 0)
&& (strcasecmp(headerName, "Status") != 0)) {
//
// If there is more than one value for each type,
// then get all of the values.
//
duplicateCount = headerValue.length();
for (dupOffset=0; dupOffset < duplicateCount; dupOffset++ ) {
//
// Skip if the first line is a from.
//
if (unixFromLine != NULL && headerNumber == 0) {
continue;
}
strcat(newMessage, headerName);
strcat(newMessage, ": ");
strcat(newMessage, *(headerValue[dupOffset]));
strcat(newMessage, "\n");
}
}
//
// Clear out the current one, so that getNextHeader
// does not append.
//
headerValue.clear();
headerHandle = env->getNextHeader(error,
headerHandle,
&headerName,
headerValue);
headerNumber++;
//
// getNextHeader returns NULL where there are no more.
//
} while(error.isNotSet() && headerHandle != NULL);
//
headerValue.clear();
//
// Now add in the headers from the imbeded message in part 1.
// To do this we need to convert the message to an envelope
// and then get the headers from that.
//
// We then delete the envelope as it is not longer needed.
//
RFCBodyPart * bp
= (RFCBodyPart *)messages[0]->getFirstBodyPart(error);
unsigned long length;
int embHeader1StLen;
const void * contents;
const char * embHeader1St;
char * endHeader;
//
// Get the body part of the first message. It contains
// the headers that we need to merge with.
//
if (error.isNotSet()) {
bp->getContents(error, &contents, &length,
NULL, NULL, NULL, NULL);
if (error.isNotSet()) {
//
// Turn the 1st messages body into an envelope.
//
// Headers end with two new lines.
//
embHeader1StLen = (int) length;
embHeader1St = (const char *)contents;
endHeader = strstr((const char *)contents, "\n\n");
if (endHeader != NULL) {
RFCEnvelope embEnv(error,
(DtMail::Message *)NULL,
(const char *)contents,
(int)((unsigned long)endHeader
- (unsigned long)contents));
if (error.isNotSet()) {
//
// Get the first header from the embeded message.
//
headerHandle = embEnv.getFirstHeader(error,
&headerName,
headerValue);
if (error.isNotSet()) {
//
// Keep geting more (all) of the headers.
//
do {
if ((strncasecmp(headerName, "Content-", 8) == 0)
|| (strcasecmp(headerName, "Message-ID") == 0)
|| (strcasecmp(headerName, "Encrypted") == 0)
|| (strcasecmp(headerName, "MIME-Version") == 0)) {
//
// If there is more than one value for each type,
// then get all of the values.
//
duplicateCount = headerValue.length();
for (dupOffset=0
; dupOffset < duplicateCount
; dupOffset++ ) {
strcat(newMessage, headerName);
strcat(newMessage, ": ");
strcat(newMessage, *(headerValue[dupOffset]));
strcat(newMessage, "\n");
}
}
//
// Clear out the current one, so that getNextHeader
// does not append.
//
headerValue.clear();
headerHandle = embEnv.getNextHeader(error,
headerHandle,
&headerName,
headerValue);
//
// getNextHeader returns NULL where there are no more.
//
} while(error.isNotSet() && headerHandle != NULL);
//
headerValue.clear();
strcat(newMessage, "\n"); // End of headers.
}
}
}
}
if (error.isNotSet()) {
//
// Now add the data parts into the one part.
//
size_t messageSize = strlen(newMessage);
length = embHeader1StLen - (&endHeader[2] - embHeader1St);
strncat(newMessage,
(const char *)&endHeader[2], // After \n\n.
(size_t) length);
messageSize += (size_t) length;
newMessage[messageSize] = '\0';
//
// Add in the 2nd -> Nth body parts.
//
for (offset = 1; offset < totalParts ; offset++) {
bp =(RFCBodyPart *)messages[offset]->getFirstBodyPart(error);
if (error.isSet()) {
break;
}
bp->getContents(error, &contents, &length,
NULL, NULL, NULL, NULL);
if (error.isSet()) {
break;
}
strncat(newMessage, (const char *)contents, (size_t) length);
messageSize += (size_t) length;
newMessage[messageSize] = '\0';
}
//
// Make the new Message, we strdup() so we only use
// as much space as needed (and free() old).
//
const char *msgResults = strdup(newMessage);
free(newMessage);
newMessage = (char *)msgResults;
msg = new RFCMessage(error, this,
(const char **)&msgResults,
(const char *)newMessage + messageSize);
for (offset = 0; offset < totalParts ; offset++) {
//
// Delete the old parts.
//
messages[offset]->setFlag(error, DtMailMessageDeletePending);
//
// TODO - CALL EXPUNGE to get rid of the message that
// we just marked for delete !!!!!
//
messages[offset] = NULL;
}
}
}
}
}
}
if (messages != NULL) {
free(messages);
}
}
free(type);
}
return(msg); // This could be the new or the original message.
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
/*
*+SNOTICE
*
*
* $TOG: RFCFormat.C /main/11 1998/07/23 18:03:02 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#include <ctype.h>
#include <EUSCompat.h>
#include <DtMail/IO.hh>
#include "RFCFormat.hh"
#include "str_utils.h"
#include <time.h>
RFCFormat::RFCFormat(DtMail::Session * session)
{
_session = session;
_is_write_bcc = DTM_FALSE;
}
RFCFormat::~RFCFormat(void)
{
}
void
RFCFormat::msgToBuffer(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_content_length,
DtMailBoolean include_unix_from,
DtMailBoolean,
Buffer & headers,
Buffer & body)
{
error.clear();
_use_cr = DTM_TRUE;
if (include_content_length || include_unix_from) {
_use_cr = DTM_FALSE;
}
// We will format the bodies first, then the headers. The
// reason we do this is that the result of formatting the body
// is required for the headers. The content-type, content-length,
// and other content based headers need to be computed before
// being written.
//
char * extra_headers = NULL;
formatBodies(error, msg, include_content_length, &extra_headers, body);
if (error.isSet()) {
return;
}
formatHeaders(error, msg, include_unix_from, extra_headers, headers);
free(extra_headers);
return;
}
void
RFCFormat::writeHeaders(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_unix_from,
const char * extra_headers,
const char ** suppress_headers,
Buffer & buf)
{
error.clear();
// First we copy each header from the message to the
// buffer. The headers may need encoding to put them away, so
// we will apply RFC1522 if necessary.
//
DtMailHeaderHandle hnd;
DtMail::Envelope * env = msg.getEnvelope(error);
if (error.isSet()) {
return;
}
char * name = NULL;
DtMailValueSeq value;
hnd = env->getFirstHeader(error, &name, value);
if (!hnd || error.isSet()) {
return;
}
if (include_unix_from &&
(error.isSet() || strcmp(name, "From") != 0)) {
// We require a Unix from line, and we don't have one.
// we will make one up using the sender, and the current
// date.
//
char *unix_from = new char[100];
strcpy(unix_from, "From ");
DtMailValueSeq sender;
env->getHeader(error, DtMailMessageSender, DTM_TRUE, sender);
if (error.isSet()) {
// We no longer know who this is really from.
//
strcat(unix_from, "nobody@nowhere");
}
else {
DtMailAddressSeq * addrSeq = sender[0]->toAddress();
strcat(unix_from, (*addrSeq)[0]->dtm_address);
delete addrSeq;
}
error.clear();
time_t now = time(NULL);
char time_format[30];
SafeCtime(&now, time_format, sizeof(time_format));
strcat(unix_from, " ");
strcat(unix_from, time_format);
buf.appendData(unix_from, strlen(unix_from));
delete [] unix_from;
}
else {
// Put out any header, except Unix From line
//
if (strcmp(name, "From") == 0) {
value.clear();
free(name);
hnd = env->getNextHeader(error, hnd, &name, value);
}
}
for (; // First time is determined above.
hnd && !error.isSet();
value.clear(), hnd = env->getNextHeader(error, hnd, &name, value)) {
for (const char ** hdr = suppress_headers; *hdr; hdr++) {
if (strcasecmp(name, *hdr) == 0)
break;
}
//add _is_write_bcc for fixing aix defect 177096
if (*hdr || strcasecmp(name, "bcc") == 0 && !_is_write_bcc ) {
free(name);
continue; // We will generate these headers.
}
int name_len = strlen(name);
for (int val = 0; val < value.length(); val++) {
//
// If the value is null or empty do not emit this field
for (const char *valPtr = *(value[val]);
*valPtr && (isspace((unsigned char)*valPtr));
valPtr++)
{}
if (!*valPtr)
continue;
buf.appendData(name, name_len);
buf.appendData(": ", 2);
rfc1522cpy(buf, *(value[val]));
}
free(name);
}
error.clear();
buf.appendData(extra_headers, strlen(extra_headers));
// Add new line that terminates the headers.
//
crlf(buf);
}
void
RFCFormat::rfc1522cpy(Buffer & buf, const char * value)
{
buf.appendData(value, strlen(value));
crlf(buf);
}
void
RFCFormat::getCharSet(char * charset)
{
char *mimeCS = NULL;
mimeCS = _session->targetTagName();
if (mimeCS) {
strcpy(charset, mimeCS);
free(mimeCS);
} else {
strcpy(charset, "us-ascii"); /* default MIME codeset */
}
}
void
RFCFormat::getCharSet(char * charset, char *special)
{
char *mimeCS = NULL;
mimeCS = _session->targetTagName(special);
if (mimeCS) {
strcpy(charset, mimeCS);
free(mimeCS);
} else {
strcpy(charset, "us-ascii"); /* default MIME codeset */
}
}

View File

@@ -0,0 +1,98 @@
/*
*+SNOTICE
*
*
* $XConsortium: RFCFormat.hh /main/4 1996/04/02 16:20:29 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef I_HAVE_NO_IDENT
#endif
#ifndef _RFCFORMAT_HH
#define _RFCFORMAT_HH
#include <DtMail/DtMail.hh>
#include <DtMail/Buffer.hh>
class RFCFormat : public DtCPlusPlusAllocator {
public:
RFCFormat(DtMail::Session * session);
~RFCFormat(void);
virtual void msgToBuffer(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_content_length,
DtMailBoolean include_unix_from,
DtMailBoolean process_ignores,
Buffer & headers,
Buffer & body);
//call setIsWriteBcc when log message to files so that the BCC
// field will log to those files.
void setIsWriteBcc() { _is_write_bcc = DTM_TRUE;}
void unsetIsWriteBcc() { _is_write_bcc = DTM_FALSE;}
DtMailBoolean getIsWriteBcc() { return _is_write_bcc;}
protected:
DtMail::Session *_session;
DtMailBoolean _use_cr;
DtMailBoolean _is_write_bcc; // if log to file: Yes
// send out: No (RFC 822)
virtual void formatBodies(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_content_length,
char ** extra_headers,
Buffer & buf) = 0;
virtual void formatHeaders(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_unix_from,
const char * extra_headers,
Buffer & buf) = 0;
void writeHeaders(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_unix_from,
const char * extra_headers,
const char ** suppress_headers,
Buffer & buf);
virtual void rfc1522cpy(Buffer & buf, const char * value);
void getCharSet(char * charset);
void getCharSet(char * charset, char *special);
int OpenLcxDb(void);
void DtXlateStdToOpLocale(char *op, char *std, char *dflt, char **ret);
void DtXlateOpToStdLocale(char *op, char *opLoc, char **retLoc, char **ret_retLang, char **retSet);
char *targetTagName();
void crlf(Buffer & buf)
{
const char * term = (_use_cr ? "\r\n" : "\n");
int len = (_use_cr ? 2 : 1);
buf.appendData(term, len);
}
};
inline void
appendString(Buffer & buf, const char * str)
{
buf.appendData(str, strlen(str));
}
#endif

View File

@@ -0,0 +1,895 @@
/*
*+SNOTICE
*
*
* $TOG: RFCImpl.hh /main/22 1998/10/01 17:28:08 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef I_HAVE_NO_IDENT
#endif
#ifndef _RFCIMPL_HH
#define _RFCIMPL_HH
#include <DtMail/Buffer.hh>
#include <DtMail/DtMail.hh>
#include <DtMail/DtMailServer.hh>
#include <DtMail/FileShare.hh>
#include <DtMail/Threads.hh>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#if defined(NEED_MMAP_WRAPPER)
extern "C" {
#endif
#include <sys/mman.h>
#if defined(NEED_MMAP_WRAPPER)
}
#endif
// Structs needed to exec sendmail
typedef struct waitentry {
struct waitentry * next;
int pid;
void * data;
SubProcessFinishedProc * proc;
} waitentry_t;
typedef struct pipedata {
int pid;
int status;
} pipedata_t;
typedef enum {
DTMBX_LONGLOCK_FAILED_CANCEL, // failed to obtain lock, cancel operation
DTMBX_LONGLOCK_FAILED_READONLY, // failed to obtain lock, open read only
DTMBX_LONGLOCK_FAILED_READWRITE, // failed to obtain lock,
// open read write [user locking override]
DTMBX_LONGLOCK_SUCCESSFUL // obtained the lock
} DTMBX_LONGLOCK;
class RFCMailBox;
class RFCBodyPart;
class RFCMessage : public DtMail::Message {
public:
RFCMessage(DtMailEnv & error,
DtMail::MailBox * parent,
const char ** start, // Also returns the end of the message.
const char * end_of_file);
RFCMessage(DtMailEnv & error,
const char * alt_start,
const char * alt_end);
RFCMessage(DtMailEnv & error,
DtMail::Session * session,
DtMailObjectSpace space,
void * arg,
DtMailCallback cb,
void * client_data);
virtual ~RFCMessage(void);
virtual DtMail::Envelope * getEnvelope(DtMailEnv &);
// This should only be used when you REALLY need to know
// how many body parts are present before actually traversing
// the body parts (i.e. like when writing a MIME format message).
virtual int getBodyCount(DtMailEnv &);
virtual DtMail::BodyPart * getFirstBodyPart(DtMailEnv &);
virtual DtMail::BodyPart * getNextBodyPart(DtMailEnv &,
DtMail::BodyPart *);
virtual DtMail::BodyPart * newBodyPart(DtMailEnv &,
DtMail::BodyPart *);
#ifdef DEAD_WOOD
virtual void newBodyPartOrder(DtMailEnv &,
DtMail::BodyPart *,
const int) { };
#endif /* DEAD_WOOD */
virtual void setFlag(DtMailEnv &,
const DtMailMessageState);
virtual void resetFlag(DtMailEnv &,
const DtMailMessageState);
virtual DtMailBoolean flagIsSet(DtMailEnv &,
const DtMailMessageState);
virtual time_t getDeleteTime(DtMailEnv &);
virtual void toBuffer(DtMailEnv & error, DtMailBuffer &);
virtual const char * impl(DtMailEnv &);
// Methods following this point are specific to RFCMessage.
//
void markDirty(const int delta);
void fixMessageLocation(char ** msgHeaderStart, long & msgHeaderLen,
char ** msgBodyStart, long &msgBodyLen,
int & msgTemporary, long & msgBodyOffset);
void unfixMessageLocation(char *msgStart, int msgTemporary);
void adjustMessageLocation(
char * oldStart,
char * newStart,
long newLength,
int msgTemporary,
long newBodyOffset);
void pinMessageDown(char ** msgHeaderStart, long & msgHeaderLen,
char ** msgBodyStart, long &msgBodyLen);
RFCMailBox * parent(void) { return (RFCMailBox *)_parent; }
protected:
unsigned long _object_signature;
const char * _msg_start;
const char * _msg_end;
const char * _body_start;
SafeScalar<int> _dirty;
DtMailBuffer *_msg_buf;
struct BodyPartCache : public DtCPlusPlusAllocator {
RFCBodyPart *body;
const char * body_start;
};
DtVirtArray<BodyPartCache *> _bp_cache;
// _alternativeMultipart -- does message contain alternative messages?
// If DTM_FALSE: this message does not contain alternative messages.
// .. can ignore: _alt_msg_cache, _alternativeValid
// If DTM_TRUE: this message does contain alternative messages.
// The body part cache is allocated; however, the pointers within
// the cache are copied from the latest valid alternative message
// within the alternative message cache, and so should not be
// deleted when a message is destroyed and this is true.
// The alternative message cache (_alt_msg_cache) contains one or
// more messages that map 1 to 1 with the corresponding alternative
// messages contained within the entire message.
//
DtMailBoolean _alternativeMultipart;
// _alternativeMessage -- is this message an alternative message?
// If DTM_FALSE: this is not an alternative message but rather a real
// message -- _msg_start, _msg_end, _body_start, etc. are valid.
// If DTM_TRUE: this message is an alternative message; _msg_start,
// _msg_end, _body_start, etc. demark the alternative message within
// the entire real message. The body part cache is fully allocated and
// represents all body parts contained within this alternative message.
//
DtMailBoolean _alternativeMessage;
// _alternativeValid -- is this alternative message part valid?
// If DTM_FALSE: this alternative cannot be displayed or otherwise
// acted upon on this system
// If DTM_TRUE: this alternative can be displayed or otherwise
// acted upon on this system
//
DtMailBoolean _alternativeValid;
// _alt_msg_cache is the "alternative message cache", an array of
// MIMEBodyParts an RFCMessages, which have _alternativeMessage
// set, and contain only those body parts that are associated with a
// single alternative message. There is one entry in the array for
// each alternative message within the entire message. Each alternative
// message will have _alternativeMessage == DTM_TRUE.
// This cache is present only if _alternativeMultipart == DTM_TRUE.
//
struct AlternativeMessageCache : public DtCPlusPlusAllocator {
RFCMessage * amc_msg; // -> RFCMessage for alternative
RFCBodyPart * amc_body; // -> MIMEBodyPart for alternative
const char * amc_body_start; // -> first byte of body
const char * amc_body_end; // -> last byte of body
};
DtVirtArray<AlternativeMessageCache *> _alt_msg_cache;
DtMail::BodyPart * bodyPart(DtMailEnv & error, const int slot);
int lookupByBody(DtMail::BodyPart *);
const char * parseMsg(DtMailEnv &, const char * end_of_file);
const char * findMsgEnd(DtMailEnv &, const char * end_of_file);
void parseBodies(DtMailEnv &);
void parseMIMEBodies(DtMailEnv &);
void parseMIMETextPlain(DtMailEnv &);
void parseMIMEMultipartSubtype(DtMailEnv &, const char * subtype);
void parseMIMEMessageSubtype(DtMailEnv &, const char * subtype);
void parseMIMEMessageExternalBody(DtMailEnv &);
void parseMIMEMultipartMixed(DtMailEnv &, const char * boundary);
void parseMIMEMultipartAlternative(DtMailEnv &, const char * boundary);
void parseV3Bodies(DtMailEnv &);
void writeMsg(char * buffer);
int sizeMIMEBodies(DtMailEnv &);
int sizeV3Bodies(DtMailEnv &);
char * extractBoundary(const char * content_type);
DtMailBoolean hasHeaders(const char * buf, const unsigned long size);
// This friend declaration is used temporarily by copyMsg to copy
// messages from RFC->RFC. A more general solution is needed for
// FCS.
friend class RFCMailBox;
};
class RFCEnvelope : public DtMail::Envelope {
public:
RFCEnvelope(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const int len);
virtual ~RFCEnvelope(void);
virtual DtMailHeaderHandle getFirstHeader(DtMailEnv &,
char ** name,
DtMailValueSeq & value);
virtual DtMailHeaderHandle getNextHeader(DtMailEnv &,
DtMailHeaderHandle last,
char ** name,
DtMailValueSeq & value);
virtual void getHeader(DtMailEnv &,
const char * name,
const DtMailBoolean abstract,
DtMailValueSeq & value);
virtual void setHeaderSeq(DtMailEnv &,
const char *,
const DtMailValueSeq &) {} ;
// The last parameter is left to the client to provide
// because it can not be done in a type safe manner.
//
virtual void setHeader(DtMailEnv &,
const char *,
const DtMailBoolean,
const char *);
virtual void removeHeader(DtMailEnv &,
const char *);
// Methods below this point are specific to RFCEnvelope.
//
int dirty(void) { return _dirty; }
void adjustHeaderLocation(char * headerStart, int headerLength);
char *writeHeaders(char *buf);
const char * headerLocation(void) { return _header_text; }
long headerLength(void) { return _header_len; }
const char * unixFrom(DtMailEnv &, int & length);
//
// fix for the defect 177527
// when a reply-to field is in a message headers, the reply-to is
// going to be displayed as the send in RMW's msg list scrolled window
// instead of the real sender. The following three public methods are
// going to access _use_reply_to.
//
void setUseReplyTo(void) { _use_reply_to = DTM_TRUE; }
void unsetUseReplyTo(void) { _use_reply_to = DTM_FALSE; }
DtMailBoolean getUseReplyTo(void) { return _use_reply_to; }
protected:
DtMailBoolean _use_reply_to;
unsigned long _object_signature;
SafeScalar<int> _dirty;
struct ParsedHeader : public DtCPlusPlusAllocator {
ParsedHeader(void);
~ParsedHeader(void);
const char *name_start;
int name_len;
const char *value_start;
int value_len;
int alloc_mask; // Tracks updates to value.
void * mutex;
};
const char * _header_text;
int _header_len;
DtVirtArray<ParsedHeader *> _parsed_headers;
void * _header_lock;
void getTransportHeader(DtMailEnv & error,
const char * name,
DtMailValueSeq & value);
DtMailBoolean matchName(const ParsedHeader &, const char *);
void parseUnixFrom(DtMailEnv &,
const ParsedHeader &,
DtMailValueSeq & value);
void parseUnixDate(DtMailEnv &,
const ParsedHeader &,
DtMailValueSeq & value);
void makeValue(DtMailEnv &,
const ParsedHeader &,
DtMailValueSeq & value);
void makeReply(DtMailEnv &,
const char * name,
DtMailValueSeq & value);
DtMailBoolean metooAddr(DtMailValueAddress & addr,
DtMailAddressSeq & alts,
DtMailBoolean allnet);
void parseHeaders(void);
int lookupHeader(const char * name, DtMailBoolean real_only = DTM_FALSE);
const char * mapName(const char * name);
};
class RFCBodyPart : public DtMail::BodyPart {
public:
RFCBodyPart(DtMailEnv &,
DtMail::Message * parent,
const char * start,
const int len,
RFCEnvelope * body_env);
virtual void lockContents(DtMailEnv &, const DtMailLock);
virtual void unlockContents(DtMailEnv &);
virtual void getContents(DtMailEnv &,
const void ** contents,
unsigned long * length,
char ** type,
char ** name,
int * mode,
char ** description);
virtual void setContents(DtMailEnv &,
const void * contents,
const unsigned long length,
const char * type,
const char * name,
const int mode,
const char * description);
virtual void setFlag(DtMailEnv &,
DtMailBodyPartState);
virtual void resetFlag(DtMailEnv &,
DtMailBodyPartState);
virtual DtMailBoolean flagIsSet(DtMailEnv &,
DtMailBodyPartState);
virtual time_t getDeleteTime(DtMailEnv &);
virtual void getHeader(DtMailEnv &,
const char * name,
const DtMailBoolean abstract,
DtMailValueSeq & value);
// For CHARSET
//---------------------------------------------------
// These methods are duplicated in class BodyPart (also being implemented
// in class Session) because RFCFormat and RFCBodyPart need to access
// them. Duplicating routines like what is being done here is a workaround
// for an implementation bug/hole because there is no class where global
// routines can be defined (and be accessed by any class).
// class Session is not a proper place to put (global) methods because
// not every class can get at Session.
// RFCFormat accesses these routines through its private Session handle.
// RFCBodyPart does not have a Session handle. Hence the need to duplicate
// the following routines.
virtual int OpenLcxDb(void);
virtual void DtXlateStdToOpLocale(char *op, char *std, char *dflt,
char **ret);
virtual void DtXlateOpToStdLocale(char *op, char *opLoc, char **retLoc,
char **ret_retLang, char **retSet);
virtual void DtXlateStdToOpCodeset(char *op, char *std, char *dflt,
char **ret);
virtual void DtXlateMimeToIconv(const char *, const char *, const char *,
char **, char **);
virtual void DtXlateLocaleToMime(const char *, const char *,
const char *, char **);
virtual char *csToConvName(char *);
virtual char *locToConvName();
virtual char *targetConvName();
virtual char *targetTagName();
virtual int csConvert(char **, unsigned long &, int, char *, char *);
//---------------------------------------------------
// Implement in both MIMEBodyPart and V3BodyPart
virtual char *csFromContentType(DtMailValueSeq & value) = 0;
// End of For CHARSET
#ifdef DEAD_WOOD
virtual DtMailChecksumState checksum(DtMailEnv &) = 0;
#endif /* DEAD_WOOD */
// Methods below this point are specific to RFCBodyPart.
//
virtual char *writeBodyParts(char * buf) = 0;
void adjustBodyPartsLocation(char * start);
virtual int rfcSize(const char * boundary, DtMailBoolean &) = 0;
protected:
~RFCBodyPart(void);
DtMailBoolean isTerm(const char *); // Determines if we have an eol.
void * _body_lock;
// _body_start includes any boundaries.
const char * _body_start;
// _body_text is where the text of the body begins, after
// boundaries, headers, and other uninteresting stuff.
//
const char * _body_text;
int _body_len;
RFCEnvelope * _body_env;
DtMailBoolean _my_env; // True if we made the envelope.
SafeScalar<int> _dirty;
friend class RFCMessage;
// The following entries are a computed cache. They
// are built in a lazy fashion, based on the caller's
// requests. These entries can be very expensive to
// compute so lazy is important.
//
char * _body;
DtMailBoolean _must_free_body;
int _body_decoded_len;
char * _body_type;
// The sub classes implement these because they are the major difference
// in the get/set contents methods.
//
virtual void getContentType(DtMailEnv &, char**) = 0;
virtual void getDtType(DtMailEnv &) = 0;
virtual void loadBody(DtMailEnv &) = 0;
virtual char * getDescription(DtMailEnv &) = 0;
virtual char * getName(DtMailEnv &) = 0;
virtual void setName(DtMailEnv &, const char *) = 0;
virtual unsigned long getLength(DtMailEnv &) = 0;
virtual const void * getBody(DtMailEnv &);
};
class MIMEBodyPart : public RFCBodyPart {
public:
MIMEBodyPart(DtMailEnv &,
DtMail::Message * parent,
const char * start,
const int len,
RFCEnvelope * body_env);
MIMEBodyPart(DtMailEnv &,
DtMail::Message * parent,
const char * start,
const char ** end,
const char * boundary);
#ifdef DEAD_WOOD
virtual DtMailChecksumState checksum(DtMailEnv &);
#endif /* DEAD_WOOD */
char *writeBodyParts(char * buf);
int rfcSize(const char * boundary, DtMailBoolean &);
// For CHARSET
virtual char *csFromContentType(DtMailValueSeq & value);
char * parameterValue(
DtMailValueSeq & value,
const char* parameter,
DtMailBoolean isCaseSensitive);
protected:
friend RFCMessage::~RFCMessage(void);
~MIMEBodyPart(void);
void getContentType(DtMailEnv &, char **);
void getDtType(DtMailEnv &);
void loadBody(DtMailEnv &);
char * getDescription(DtMailEnv &);
char * getName(DtMailEnv &);
void setName(DtMailEnv &, const char *);
char * getNameHeaderVal(DtMailEnv &);
unsigned long getLength(DtMailEnv &);
const void * getBody(DtMailEnv &);
};
class V3BodyPart : public RFCBodyPart {
public:
V3BodyPart(DtMailEnv &,
DtMail::Message * parent,
const char * start,
const int len,
RFCEnvelope * body_env);
V3BodyPart(DtMailEnv &,
DtMail::Message * parent,
const char * start,
const char ** end);
#ifdef DEAD_WOOD
virtual DtMailChecksumState checksum(DtMailEnv &);
#endif /* DEAD_WOOD */
char *writeBodyParts(char * buf);
int rfcSize(const char * boundary, DtMailBoolean &);
// For CHARSET
virtual char *csFromContentType(DtMailValueSeq & value);
protected:
friend RFCMessage::~RFCMessage(void);
~V3BodyPart(void);
void getContentType(DtMailEnv &, char **);
void getDtType(DtMailEnv &);
void loadBody(DtMailEnv &);
char * getDescription(DtMailEnv &);
char * getName(DtMailEnv &);
void setName(DtMailEnv &, const char *);
unsigned long getLength(DtMailEnv &);
};
class RFCMailBox : public DtMail::MailBox
{
public:
RFCMailBox(DtMailEnv &,
DtMail::Session * session,
DtMailObjectSpace space,
void * arg,
DtMailCallback cb,
void * clientData,
const char * impl_name);
virtual ~RFCMailBox(void);
static void appendCB(DtMailEnv&, char *buf, int len, void *clientData);
virtual void append(DtMailEnv &error, char *buf, int len);
virtual void create(DtMailEnv & error, mode_t = DTMAIL_DEFAULT_CREATE_MODE);
virtual void open(DtMailEnv &,
DtMailBoolean auto_create = DTM_TRUE,
int open_mode = DTMAIL_DEFAULT_OPEN_MODE,
mode_t create_mode = DTMAIL_DEFAULT_CREATE_MODE,
DtMailBoolean lock_flag = DTM_TRUE,
DtMailBoolean auto_parse = DTM_TRUE);
virtual void lock();
virtual void unlock();
virtual void save();
virtual void callCallback(DtMailCallbackOp, void *);
virtual void disableMailRetrieval()
{ _mr_allowed = DTM_FALSE; }
virtual void enableMailRetrieval()
{ _mr_allowed = DTM_TRUE; }
virtual void checkForMail(
DtMailEnv &,
const DtMailBoolean
already_locked = DTM_FALSE);
virtual void clearMessageSummary(DtMailHeaderLine &);
virtual void copyMessage(DtMailEnv &, DtMail::Message *);
virtual void copyMailBox(DtMailEnv &, DtMail::MailBox *);
virtual void createMailRetrievalAgent(char *passwd=NULL);
virtual void deleteMailRetrievalAgent();
virtual void expunge(DtMailEnv &);
virtual DtMail::Message *getFirstMessage(DtMailEnv &);
virtual DtMailMessageHandle getFirstMessageSummary(
DtMailEnv &,
const DtMailHeaderRequest &,
DtMailHeaderLine &);
virtual DtMail::Message *getNextMessage(DtMailEnv &, DtMail::Message *);
virtual DtMailMessageHandle getNextMessageSummary(
DtMailEnv &,
DtMailMessageHandle,
const DtMailHeaderRequest &,
DtMailHeaderLine &);
virtual DtMail::Message *getMessage(DtMailEnv &, DtMailMessageHandle);
virtual void getMessageSummary(
DtMailEnv &,
DtMailMessageHandle,
const DtMailHeaderRequest &,
DtMailHeaderLine &);
virtual const char *impl(DtMailEnv & error);
#ifdef DEAD_WOOD
virtual int messageCount(DtMailEnv &);
#endif /* DEAD_WOOD */
virtual DtMail::Message *newMessage(DtMailEnv &);
virtual DtMailCallbackOp retrieveNewMail(DtMailEnv&);
virtual void updateMailRetrievalPassword(char *passwd=NULL);
// This is not used by any clients!
struct MapRegion : public DtCPlusPlusAllocator
{
char * map_region;
unsigned long map_size;
char * file_region; // Where the parsing begins.
unsigned long file_size;
long offset;
};
struct MessageCache : public DtCPlusPlusAllocator {
RFCMessage *message;
DtMailBoolean delete_pending;
};
// Methods below this point are specific to RFCMailBox.
void markDirty(const int delta);
void startAutoSave(DtMailEnv & error, DtMailBoolean start=DTM_TRUE);
protected:
struct NewMailData : public DtCPlusPlusAllocator
{
RFCMailBox * self;
Condition * object_valid;
};
// Content-Type: message/partial support.
struct _partialData
{
const char * id;
unsigned int number;
unsigned int total; // 0 == I do not know.
RFCMessage * msg;
};
// Keep track of how many messages, and whether we've hit the
// EOF. The number of messages is a condition variable because
// we might have multiple threads trying to read the state
// while the parsing thread is reading the state.
//
Condition _at_eof;
char *_buffer;
SafeScalar<int> _dirty; // Write access/dirty state.
DtMailBoolean _dot_lock_active;
DtMailBoolean _errorLogging; // Extra logging done??
int _fd;
SafeScalar<unsigned long> _file_size;
const char *_impl_name; // Might be V3 or MIME.
int _last_check; // For polling only.
time_t _last_poll; // For polling only.
int _links;
DtMailBoolean _lock_flag;
FileShare *_lock_obj;
DtMailBoolean _lockf_active; // lockf() is being held
char * _lockFileName; // lock file name for mailbox
DtMailBoolean _long_lock_active;
Thread _mbox_daemon;
void * _map_lock;
DtVirtArray<MapRegion *> _mappings;
unsigned long _object_signature;
Condition *_object_valid;
DtMailBoolean _parsed;
char *_real_path;
DtMailBoolean _mr_allowed;
char *_mra_command;
DtMailServer *_mra_server;
char *_mra_serverpw;
DtVirtArray<MessageCache *> _msg_list;
_partialData **_partialList;
unsigned int _partialListCount;
struct stat _stinfo;
NewMailData *_thread_info;
DtMailBoolean _tt_lock;
char * _uniqueLockId; // unique id for .lock files
int _uniqueLockIdLength;
DtMailBoolean _use_dot_lock;
// void CheckPointEvent(DtMailEnv & error);
void CheckPointEvent();
void ExpungeEvent(DtMailBoolean closing = DTM_FALSE);
void NewMailEvent(const DtMailBoolean already_locked = DTM_FALSE);
static DtMailBoolean
PollEntry(void *);
static void *ThreadNewMailEntry(void *);
static void *ThreadParseEntry(void *);
RFCMessage *_assemblePartial(DtMailEnv &error,RFCMessage *Message);
DtMailBoolean
_isPartial(DtMailEnv &error, RFCMessage *message);
DtMailBoolean
addressIsMapped(void *addressToCheck);
#if defined(linux)
void alterPageMappingAdvice(MapRegion *map, int advice = 0);
#else
void alterPageMappingAdvice(
MapRegion *map,
int advice = MADV_SEQUENTIAL);
#endif
int createTemporaryMailboxFile(DtMailEnv &, char *tmp_name);
void checkLockFileOwnership(DtMailEnv &);
void dotDtmailLockFile(char *, int);
void dotDtmailLock(DtMailEnv &);
void dotDtmailUnlock(DtMailEnv &);
void dumpMaps(const char *);
char *generateLockFileName(void);
char *generateUniqueLockId(void);
void incorporate(
DtMailEnv &,
const DtMailBoolean already_locked = DTM_FALSE);
time_t linkLockFile(DtMailEnv &, char *tempLockFileName);
void lockFile(DtMailEnv &);
void lockNewMailboxFile(int new_fd);
DTMBX_LONGLOCK
longLock(DtMailEnv &);
void longUnlock(DtMailEnv &);
int lookupByMsg(RFCMessage * msg);
void mailboxAccessHide(char *prefix);
void mailboxAccessShow(time_t mtime, char *prefix);
void makeHeaderLine(DtMailEnv & error,
int slot,
const DtMailHeaderRequest & request,
DtMailHeaderLine &);
int mapFile(DtMailEnv & error,
const DtMailBoolean already_locked = DTM_FALSE,
mode_t create_mode = DTMAIL_DEFAULT_CREATE_MODE);
MapRegion *mapNewRegion(DtMailEnv &, int fd, unsigned long bytesWritten);
int nextNotDel(const int cur);
void openRealFile(DtMailEnv &error, int mode, mode_t create_mode);
int prevNotDel(const int cur);
void parseFile(DtMailEnv & error, int slot);
off_t realFileSize(DtMailEnv &error, struct stat *stat_buffer = NULL);
void transferLock(int old_fd, int new_fd);
void unlockOldMailboxFile(int old_fd);
void unlockFile(DtMailEnv &, int fd);
void waitForMsgs(int needed);
void writeMailBox(DtMailEnv&, DtMailBoolean);
void writeToDumpFile(const char* format, ...);
};
class RFCTransport : public DtMail::Transport {
public:
RFCTransport(DtMailEnv &, DtMail::Session *, DtMailStatusCallback, void *,
const char * impl);
virtual ~RFCTransport(void);
virtual DtMailOperationId submit(DtMailEnv &,
DtMail::Message *,
DtMailBoolean log_msg);
static void arpaPhrase(const char * list, DtMailAddressSeq & tokens);
// SendMsgDialog initiates a send. It needs to set information
// needed to exec sendmail by calling these initialization functions.
// getSendmailReturnProc returns a handler so that SendMsgDialog
// can use it in XtAppAddInput.
virtual void initTransportData(int fds[2],
SubProcessFinishedProc proc, void *ptr);
virtual void *getSendmailReturnProc(void);
protected:
Condition * _object_valid;
char * _impl;
struct ThreadSimpleData : public DtCPlusPlusAllocator {
RFCTransport * self;
const char * to;
const char * cc;
const char * bcc;
const char * subject;
const char * text;
};
static void * ThreadSimpleEntry(void * arg);
void format(DtMailEnv &, DtMail::Message * msg, DtMailBoolean log_msg);
void formatSimple(DtMailEnv &,
const char * to,
const char * cc,
const char * bcc,
const char * subject,
const char * text);
void deliver(DtMailEnv &,
DtMailAddressSeq &,
Buffer & headers,
Buffer & bodies,
DtMailBoolean log_msg,
int **log_files,
int & log_count);
void launchSendmail(DtMailEnv & error,
Buffer & headers,
Buffer & boides,
char ** argv);
char * concatValue(DtMailValueSeq &);
void appendAddrs(DtMailAddressSeq & to, DtMailAddressSeq & from);
void skinFiles(DtMailAddressSeq &);
char * addrToString(DtMailAddressSeq &);
int openLogFile(const char * path);
void closeLogFiles(int * files, int file_cnt);
// These functions are needed to exec sendmail
static void childHandler(void);
void signalRegister(void);
int startSubprocess(DtMailEnv &error, char * cmd,
Buffer & headers, Buffer & bodies, char **argv);
static void sendmailReturnProc(void);
// Store info from SendMsgDialog
// ptr to SendMsgDialog::SendmaliErrorProc
SubProcessFinishedProc *_error_proc;
// a pointer to SendMsgDialog
void *_smd;
// get the status from the low and hi bytes returned from wait()
inline static int lowByte (int status) { return (status & 0377); }
inline static int highByte (int status) { return (lowByte(status >> 8)); }
};
extern const char * RFCDeleteHeader;
class RFCValue : public DtMailValue {
public:
RFCValue(const char * str, int size, DtMail::Session *s);
RFCValue(const char * str, int size);
~RFCValue(void);
virtual operator const char *(void);
virtual const char * operator= (const char *);
virtual DtMailValueDate toDate(void);
#ifdef DEAD_WOOD
virtual void fromDate(const DtMailValueDate &) { }
#endif /* DEAD_WOOD */
virtual DtMailAddressSeq * toAddress(void);
#ifdef DEAD_WOOD
virtual void fromAddress(const DtMailAddressSeq &) { }
#endif /* DEAD_WOOD */
virtual const char * raw(void);
protected:
DtMail::Session *_session;
char * _decoded;
void decodeValue(void);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
/*
*+SNOTICE
*
*
* $TOG: RFCMIME.hh /main/6 1997/03/28 12:10:13 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef I_HAVE_NO_IDENT
#endif
#ifndef _RFCMIME_HH
#define _RFCMIME_HH
#include "RFCFormat.hh"
class RFCMIME : public RFCFormat {
public:
RFCMIME(DtMail::Session *);
~RFCMIME(void);
static void readBase64(char * dest, int & size, const char * text,
const unsigned long text_len);
static void readQPrint(char * dest, int & size, const char * text,
const unsigned long text_len);
static void readTextEnriched(char * dest, int & size, const char * text,
const unsigned long text_len);
void writeBase64(Buffer & buf, const char * bp,
const unsigned long len);
void writeQPrint(Buffer & buf, const char * bp,
const unsigned long len);
// digest is:
// unsigned char digest[16];
//
static void md5PlainText(const char * bp,
const unsigned long len,
unsigned char * digest);
enum Encoding {
MIME_7BIT,
MIME_8BIT,
MIME_QPRINT,
MIME_BASE64
};
protected:
virtual void formatBodies(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_content_length,
char ** extra_headers,
Buffer & buf);
virtual void formatHeaders(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_unix_from,
const char * extra_headers,
Buffer & buf);
virtual void rfc1522cpy(Buffer & buf, const char * value);
private:
void getMIMEType(
DtMail::BodyPart * bp,
char * mime_type,
DtMailBoolean & is_text);
Encoding getHdrEncodingType(
const char *,
const unsigned int,
DtMailBoolean,
const char *);
Encoding getEncodingType(
const char *,
const unsigned int,
DtMailBoolean,
int *);
Encoding getClearEncoding(
const char *,
const unsigned int,
int *);
void writeContentHeaders(
Buffer & buf,
const char * type,
const char * name,
const Encoding,
const char * digest,
DtMailBoolean show_as_attachment,
int is2022ASCII );
void writePlainText(
Buffer & buf,
const char * bp,
const unsigned long len);
void owCompat(
Buffer & buf, char * type, char * name,
char *contents, unsigned long len);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,823 @@
/*
*+SNOTICE
*
*
* $TOG: RFCMailValues.C /main/10 1998/09/03 07:01:06 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef I_HAVE_NO_IDENT
#endif
#include <EUSCompat.h>
#include <stdlib.h>
#include <string.h>
#if !defined(USL) && !defined(__uxp__)
#include <strings.h>
#endif
#include <ctype.h>
#include <DtMail/IO.hh>
#include "RFCImpl.hh"
#include "RFCMIME.hh"
#include "str_utils.h"
// String values. These assume an RFC format for now. They will
// apply RFC1522 coding rules to the strings for dealing with
// non-ASCII text in RFC headers.
//
RFCValue::RFCValue(const char * str, int size) : DtMailValue(NULL)
{
_value = (char *)malloc(size + 1);
memcpy(_value, str, size);
_value[size] = 0;
_decoded = NULL;
}
RFCValue::RFCValue(const char * str, int size, DtMail::Session *s) : DtMailValue(NULL)
{
_value = (char *)malloc(size + 1);
memcpy(_value, str, size);
_value[size] = 0;
_decoded = NULL;
_session = s;
}
RFCValue::~RFCValue(void)
{
if (_decoded) {
free(_decoded);
}
}
static const char *
decode1522(const char * enc_start, const char * max_end, char **output, DtMail::Session *s)
{
// Find the end of the encoded region.
//
int qs = 0;
const char *enc_end;
for (enc_end = enc_start;
*enc_end && enc_end < max_end;
enc_end++) {
if (*enc_end == '?') {
qs += 1;
if (qs > 3 && *(enc_end + 1) == '=') {
break;
}
}
}
if (*enc_end != '?') {
return(enc_start);
}
enc_end += 1;
// Pull off the char set name.
//
const char *cs_end;
for (cs_end = enc_start + 2; *cs_end != '?'; cs_end++) {
continue;
}
int cs_name_length = cs_end - enc_start - 2;
char *cs_name = (char*) malloc(cs_name_length + 1);
strncpy(cs_name, enc_start + 2, cs_name_length);
cs_name[cs_name_length] = 0;
// Set the encoding method and start of buffer.
//
char encoding = *(cs_end + 1);
const char * buf_start = cs_end + 3;
switch (toupper(encoding)) {
case 'Q':
{
int len = 0;
RFCMIME::readQPrint(*output, len, buf_start, enc_end - buf_start - 1);
(*output)[len] = 0;
break;
}
case 'B':
{
int len = 0;
RFCMIME::readBase64(*output, len, buf_start, enc_end - buf_start - 1);
(*output)[len] = 0;
break;
}
default:
// Invalid encoding. Assume a false match.
if (cs_name != NULL) free(cs_name);
return (enc_start);
}
// Do codeset conversion if charset is present
char *from_cs = s->csToConvName(cs_name);
char *to_cs = s->locToConvName();
if ( from_cs && to_cs ) {
if ( strcasecmp(from_cs, to_cs) != 0 ) {
unsigned long tmplen = (unsigned long) strlen(*output);
(void) s->csConvert(&(*output), tmplen, 1, from_cs, to_cs);
}
}
if (NULL != from_cs)
free( from_cs );
if (NULL != to_cs)
free ( to_cs );
if (NULL != cs_name)
free(cs_name);
return(enc_end);
}
RFCValue::operator const char *(void)
{
if (_decoded) {
return(_decoded);
}
decodeValue();
return(_decoded);
}
const char *
RFCValue::operator= (const char * str)
{
if (_decoded) {
free(_decoded);
_decoded = NULL;
}
if (_value) {
free(_value);
}
_value = strdup(str);
return(_value);
}
static const char * DaysOfTheWeek[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char * MonthsOfTheYear[] = {
"Jan", "Feb", "Mar",
"Apr", "May", "Jun",
"Jul", "Aug", "Sep",
"Oct", "Nov", "Dec"
};
static int
matchDay(const char * start, const char * end)
{
int len = end - start + 1;
for (int i = 0; i < 7; i++) {
if (strncmp(DaysOfTheWeek[i], start, len) == 0) {
return(i);
}
}
return(-1);
}
static int
matchMonth(const char * start, const char * end)
{
int len = end - start + 1;
for (int i = 0; i < 12; i++) {
if (strncmp(MonthsOfTheYear[i], start, len) == 0) {
return(i);
}
}
return(-1);
}
static void
parseTime(const char * start, const char * end, tm & val)
{
int size = end - start + 1;
// Time will be in the form hh:mm:ss where seconds are optional.
char num_buf[10];
strncpy(num_buf, start, 2);
num_buf[2] = 0;
val.tm_hour = (int) strtol(num_buf, NULL, 10);
strncpy(num_buf, &start[3], 2);
num_buf[2] = 0;
val.tm_min = (int) strtol(num_buf, NULL, 10);
if (size > 6) {
strncpy(num_buf, &start[6], 2);
num_buf[2] = 0;
val.tm_sec = (int) strtol(num_buf, NULL, 10);
}
else {
val.tm_sec = 0;
}
return;
}
static const char * TZNames[] = {
"EST", "CST", "MST", "PST"
};
static const char * TZNamesDST[] = {
"EDT", "CDT", "MDT", "PDT"
};
static time_t
parseTZ(const char * start, const char * end)
{
int size = end - start + 1;
// There are at 3 possibilities that we understand. There
// is the single letter military time zone. In that case
// Z is 0 UTC. A-M is -1 to -12, skipping J. N-Y is +1 to +12
// from UTC.
//
// Lets start with that one because it is the easiest.
if (size == 1) {
int hours_from = 0;
if (*start >= 'A' && *start <= 'I') {
hours_from = *start - 'A' + 1;
}
else if (*start >= 'L' && *start <= 'M') {
hours_from = *start - 'K' + 10;
}
else if (*start >= 'N' && *start <= 'Y') {
hours_from = ('N' - *start) - 1;
}
return(hours_from * 3600);
}
// The next option is one of the ANSI standard time zones. These
// are three letter abbrievations that tell us where DST in in effect.
// So, if we have a length of three, lets see if it is in the table.
if (size == 3) {
// First normal zones.
int i;
for (i = 0; i < 4; i++) {
if (strncmp(start, TZNames[i], 3) == 0) {
return((5 + i) * -3600);
}
}
// Now DST zones
for (i = 0; i < 4; i++) {
if (strncmp(start, TZNames[i], 3) == 0) {
return((4 + i) * -3600);
}
}
}
// Finally we understand +/- HHMM from UTC.
if (size == 5) {
int sign = (*start == '+') ? 1 : -1;
char num_buf[10];
strncpy(num_buf, &start[1], 2);
num_buf[2] = 0;
int hours = (int) strtol(num_buf, NULL, 10);
strncpy(num_buf, &start[3], 2);
num_buf[2] = 0;
int minutes = (int) strtol(num_buf, NULL, 10);
return(sign * ((hours * 3600) + (minutes * 60)));
}
// We have no idea at this point, and it is very unlikely that the
// text is meaningful to the reader either. Set the zone to UTC and
// punt. It is also possible that the text is "UT" or "GMT" in which
// case offset 0 is the right answer.
return(0);
}
DtMailValueDate
RFCValue::toDate(void)
{
DtMailValueDate date;
const char * pos = _value;
tm new_time;
memset(&date, 0, sizeof(date));
memset(&new_time, 0, sizeof(new_time));
date.dtm_date = 0;
date.dtm_tz_offset_secs = 0;
// Before doing anything, check to see if _value is valid.
// Some messages have no Date string. Return date with zeroed fields
// in those cases.
if (!_value || (strlen(_value) == 0)) return (date);
// Find the first non-blank
for (; *pos && isspace((unsigned char)*pos); pos++) {
continue;
}
// There are usually no more than 6 tokens in an RFC date. We will
// have a few extras just in case we are given a wierd string.
const char *token_begin[12];
const char *token_end[12];
int n_tokens = 0;
// Look for the end of each token. Date tokens are white space
// separated.
while (*pos) {
token_begin[n_tokens] = pos;
for (; *pos && !isspace((unsigned char)*pos); pos++) {
continue;
}
if (*pos) {
token_end[n_tokens++] = pos - 1;
}
else {
token_end[n_tokens++] = pos;
}
for (; *pos && isspace((unsigned char)*pos); pos++) {
continue;
}
// This means the message is most likely corrupted so just bail out
if (n_tokens == 12)
break;
}
// Some dates will have a comma after the day of the week. We
// want to remove that. It will always be the first token if
// we have the day of the week.
if (*token_end[0] == ',') {
token_end[0]--;
}
if (n_tokens < 2) {
return(date);
}
// There are two possible formats, and many variations, that we
// will see in an RFC message. They are:
//
// Tue Oct 12 10:36:10 1993
// Tue, 12 Oct 1993 10:35:05 PDT
//
// The first is the 821 format put on by sendmail. The second is
// one of the many variants of the 822 format. The big difference
// we must detect is "mon dd time year" vs "dd mon year time tz"
//
// The first qualifier is usually the day of the week. For our purposes,
// we will simply throw it away. This information will be recomputed
// based on the date and time.
int this_token = 0;
int day = matchDay(token_begin[this_token], token_end[this_token]);
if (day >= 0) {
// Ignore the day.
this_token += 1;
}
// This token should either be a numeric day, or an alpha month.
// Lets see if it is a month. If so, we know what the rest of
// the date will look like.
int month = matchMonth(token_begin[this_token], token_end[this_token]);
if (month >= 0) {
new_time.tm_mon = month;
// Now should be the day of the month.
char num_buf[20];
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
strncpy(num_buf, token_begin[this_token], 2);
num_buf[2] = 0;
new_time.tm_mday = (int) strtol(num_buf, NULL, 10);
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
parseTime(token_begin[this_token], token_end[this_token], new_time);
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
// Sometimes the Unix date will include the time zone.
//
if (isalpha(*token_begin[this_token])) {
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
}
strncpy(num_buf, token_begin[this_token], 4);
// Don't remove last digit from year and get bad dates in header.
num_buf[token_end[this_token] - token_begin[this_token] + 1] = 0;
new_time.tm_year = (int) strtol(num_buf, NULL, 10);
if (new_time.tm_year > 1900) {
new_time.tm_year -= 1900;
}
new_time.tm_isdst = -1;
date.dtm_date = SafeMktime(&new_time);
date.dtm_tz_offset_secs = (int) timezone;
}
else {
// In this format, we should have a day of the month.
char num_buf[20];
strncpy(num_buf, token_begin[this_token], 2);
num_buf[2] = 0;
new_time.tm_mday = (int) strtol(num_buf, NULL, 10);
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
// Now the month name.
new_time.tm_mon = matchMonth(token_begin[this_token], token_end[this_token]);
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
// The year, which is either 2 or 4 digits.
int t_size = token_end[this_token] - token_begin[this_token] + 1;
strncpy(num_buf, token_begin[this_token], t_size);
num_buf[t_size] = 0;
new_time.tm_year = (int) strtol(num_buf, NULL, 10);
if (new_time.tm_year > 1900) {
new_time.tm_year -= 1900;
}
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
// The time, in the specified time zone.
parseTime(token_begin[this_token], token_end[this_token], new_time);
this_token += 1;
if (this_token == n_tokens) {
return(date);
}
time_t offset = parseTZ(token_begin[this_token], token_end[this_token]);
time_t orig_zone = (time_t) timezone;
timezone = offset;
// Tell "mktime" to figure "dst" on or not.
new_time.tm_isdst = -1;
date.dtm_date = SafeMktime(&new_time);
date.dtm_tz_offset_secs = offset;
timezone = orig_zone;
}
return(date);
}
static char *
findParenComment(const char * value)
{
int in_quote = 0;
const char *sparen;
for (sparen = value; *sparen; sparen++) {
// We must ignore stuff in quotes.
//
if (*sparen == '"') {
if (in_quote) {
in_quote = 0;
}
else {
in_quote = 1;
}
continue;
}
if (in_quote) {
continue;
}
if (*sparen == '(') {
break;
}
}
if (*sparen != '(') {
return(NULL);
}
in_quote = 0;
const char *lparen;
for (lparen = (sparen + 1); *lparen; lparen++) {
// We will support nested comments of the form (Joe (Hi) Blow)
//
if (*lparen == '(') {
in_quote += 1;
continue;
}
if (*lparen == ')') {
in_quote -= 1;
}
if (in_quote < 0) {
break;
}
}
if (*lparen != ')') {
return(NULL);
}
char * comment = (char *)malloc(lparen - sparen + 1);
memcpy(comment, (sparen + 1), lparen - sparen - 1);
comment[lparen - sparen - 1] = 0;
return(comment);
}
static char *
stripAngleAddr(const char * value)
{
int in_quote = 0;
const char *lt;
for (lt = value; *lt; lt++)
{
if (*lt == '"')
{
if (in_quote) in_quote = 0;
else in_quote = 1;
continue;
}
if (in_quote) continue;
if (*lt == '<') break;
}
if (*lt != '<') return(NULL);
in_quote = 0;
const char *gt;
for (gt = (lt + 1); *gt; gt++)
{
if (*gt == '"')
{
if (in_quote) in_quote = 0;
else in_quote = 1;
continue;
}
if (in_quote) continue;
if (*gt == '>') break;
}
if (*gt != '>') return(NULL);
// Copy everything not in the angle brackets.
//
char * name = (char *)malloc(strlen(value) + 1);
char * out = name;
for (const char * cp = value; *cp; cp++)
{
if (cp >= lt && cp <= gt) continue;
*out++ = *cp;
}
*out = 0;
if (strlen(name) == 0)
{
free(name);
return(NULL);
}
return(name);
}
static char *
stripQuotesWhiteSpace(const char * value)
{
int found_alphanum = 0;
char *name = NULL;
char *out = NULL;
//
// Skip past leading white space.
//
const char *cp = value;
while (isspace(*cp)) cp++;
//
// If there are no quotes, copy and return.
//
if (*cp != '"')
{
name = strdup(cp);
return name;
}
//
// Strip out the quotes.
//
cp++;
out = name = (char*) malloc(strlen(value)+1);
if (NULL == out) return NULL;
while (*cp != '"')
{
*out = *cp;
out++;
cp++;
}
*out = 0;
return name;
}
DtMailAddressSeq *
RFCValue::toAddress(void)
{
// Count the commas, to figure out how big to make the
// sequence.
//
int commas = 3;
for (const char * comma = _value; *comma; comma++)
if (*comma == ',') commas += 1;
DtMailAddressSeq * seq = new DtMailAddressSeq(commas);
if (!_decoded) decodeValue();
RFCTransport::arpaPhrase(_decoded, *seq);
// If we have only one address, then let's try to find a comment
// so the person can be set. This is trivial to do for one address
// and can have a win for displaying the headers in the message
// scrolling list.
//
if (seq->length() == 1)
{
// This is less than perfect, but we will look for (Name) and
// use it first. If we can't find that, then see if we can
// find something outside <addr>. If not that, then simply
// give up.
//
DtMailValueAddress * addr = (*seq)[0];
addr->dtm_person = findParenComment(_decoded);
if (!addr->dtm_person)
{
char *name = stripAngleAddr(_decoded);
if (name)
{
addr->dtm_person = stripQuotesWhiteSpace(name);
free(name);
}
}
}
return(seq);
}
const char *
RFCValue::raw(void)
{
return(_value);
}
void
RFCValue::decodeValue(void)
{
// Create the output buffer. We will assume that it is
// the header will only shrink by applying RFC1522.
//
int outleft = strlen(_value);
char * output = (char *)malloc(outleft + 2);
*output = 0;
char * cur_c = output;
char *buf = NULL;
// Scan the value, looking for =? which indicates the start
// of a encoded string.
//
for (const char * in_c = _value; *in_c; in_c++) {
if (*in_c == '=' && *(in_c + 1) == '?') {
//
// Decode the encoding. Return the last character so the loop
// continues to work. Also reset cur_c because the output buffer
// has been updated.
//
// Allocate space for buf to contain rest of output because it
// is enough space for the decoded quoted-printable or base64.
// If codeset conversion is done, then csConvert will re-allocate
// enough space.
//
size_t _valueLen = strlen(_value);
const char *in_c_sav = in_c;
buf = (char *)malloc(outleft + 2);
strcpy(buf, in_c);
in_c = decode1522(in_c, _value + _valueLen - 1, &buf, _session);
if (in_c > in_c_sav) {
size_t bufLen = strlen(buf);
if (bufLen > outleft) {
output =
(char*) realloc((char*)output, _valueLen + bufLen + 2);
outleft += bufLen;
}
strncat(output, buf, bufLen);
cur_c = output + strlen(output);
outleft -= bufLen;
free(buf);
continue;
}
free(buf);
}
// Just copy the byte and reset the null pointer, unless
// we are dealing with carriage return.
//
if (*in_c != '\r') {
if (outleft == 0) {
output = (char*) realloc((char*) output, strlen(output) * 2);
outleft = strlen(output);
}
*cur_c = *in_c;
cur_c++;
*cur_c = 0;
outleft--;
}
}
// Kill any trailing white space.
//
*cur_c = 0;
for (cur_c -= 1;
cur_c >= output && isspace((unsigned char)*cur_c);
cur_c--)
{
*cur_c = 0;
}
_decoded = output;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
/*
*+SNOTICE
*
*
* $XConsortium: SunV3.hh /main/4 1996/04/21 19:50:07 drk $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef _SUNV3_HH
#define _SUNV3_HH
#include "RFCFormat.hh"
class SunV3 : public RFCFormat {
public:
SunV3(DtMail::Session *);
~SunV3(void);
static void decode(const char * enc_info,
char ** outputBp,
int & outputLen,
const char * inputBp,
const unsigned long inputLen);
static void encode(Buffer & buf,
const char * path,
const char * bp,
const unsigned long len);
protected:
virtual void formatBodies(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_content_length,
char ** extra_headers,
Buffer & buf);
virtual void formatHeaders(DtMailEnv & error,
DtMail::Message & msg,
DtMailBoolean include_unix_from,
const char * extra_headers,
Buffer & buf);
private:
static int uudecode(char ** outputBp,
int & outputLen,
const char * inputBp,
const unsigned long inputLen);
static int uncompress(char ** outputBp,
int & outputLen,
const char * inputBp,
const unsigned long inputLen);
void encode_uue_line(Buffer & buf,
const unsigned char * unencodedBp,
const unsigned long unencodedLen);
void uuencode(Buffer & buf,
const char * path,
const char * bp,
const unsigned long len);
void getV3Type(DtMail::BodyPart *, char *);
};
#endif

View File

@@ -0,0 +1,680 @@
/*
*+SNOTICE
*
* $TOG: V3BodyPart.C /main/8 1998/07/23 18:04:38 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement bertween
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel wihtout
* Sun's specific written approval. This documment and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#include <EUSCompat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <Dt/Dts.h>
#include <DtMail/DtMail.hh>
#include "RFCImpl.hh"
#include "SunV3.hh"
#include <DtMail/Threads.hh>
#include "str_utils.h"
#include <assert.h>
// For CHARSET
#include <locale.h>
#include <DtHelp/LocaleXlate.h>
V3BodyPart::V3BodyPart(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const int len,
RFCEnvelope * body_env)
: RFCBodyPart(error, parent, start, len, body_env)
{
// This constructor is used for single body parts. This
// includes generic RFC822 messages, i.e. no Mime-Version
// field.
//
// There really isn't anything we can do. We may have to
// apply a content encoding, but let's wait until the user
// expresses an interest.
//
error.clear();
return;
}
// V3BodyPart:V3BodyPart -- retrieve next V3 message body part
// Arguments:
// DtMailEnv & error --
// DtMail::Message * parent --
// const char * start -- -> beginning of boundary separator
// const char ** end -- -> end of message
// Outputs:
// *end -- is set to the first byte past the end of the retrieved
// part. This either points to the next body part (if any) or
// is 1 byte past the end of the message if no further parts.
// _body_env -- RFCEnvelope defining entire body part
// _body_len -- true length of contained body part (minus headers)
// _body_text -- first byte of contained body part (minus headers)
// Description:
// This constructor is used for multi-part body parts. Given a
// pointer to the beginning of the boundary separator and a
// pointer to the end of the message, reduce pointers to actual
// body part data (minus headers) and update class variables
// as appropriate.
//
V3BodyPart::V3BodyPart(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const char ** end)
: RFCBodyPart(error, parent, start, 0, NULL)
{
// Get past the boundary separator.
//
const char * body_end;
for (body_end = start; body_end <= *end && *body_end != '\n'; body_end++) {
continue;
}
if (body_end > *end) {
// no data after separator?? Bogus body part!
_body_len = 0;
*end = body_end;
return;
}
// The body part headers begin here. We will look from here until
// the first blank line for the end of the headers.
//
body_end += 1; // Chew the newline.
const char * env_start = body_end;
for (; body_end <= *end; body_end++) {
if (*body_end == '\n') {
int blank_only = 1;
for (const char * blank = body_end + 1;
blank <= *end && *blank != '\n'; blank++) {
if (!isspace((unsigned char)*blank)) {
blank_only = 0;
break;
}
}
if (blank_only) {
break;
}
}
}
_my_env = DTM_TRUE; // indicate that we created this envelope
_body_env = new RFCEnvelope(error, parent, env_start, body_end - env_start + 1);
// Now we need to find the start of the body (the real start, not
// where the boundary begins. This is immediately after the newline
// that is placed after the end of the headers.
//
_body_text = body_end + 1;
for (; _body_text <= *end && *_body_text != '\n'; _body_text++) {
continue;
}
_body_text += 1;
// We now need to figure out where the end of the attachment is.
// We have 2 choices. Content lines, or content length.
//
DtMailValueSeq value;
_body_env->getHeader(error, "x-sun-content-length",
DTM_FALSE, value);
if (error.isNotSet()) {
// Great! content-length is much easier.
// We do this by computing a -> where the end of the attachment
// is supposed to be as indicated by the specified content length.
// If we come to the end of the message altogether, or to the start
// of another header body, then we know we have bounded this body part.
//
int content_length = (int) strtol(*(value[0]), NULL, 10);
body_end = _body_text + content_length; // "supposed" end of body part
for (int i = 0; i < 2; i++) {
if (body_end == *end) { // at end of message??
// Yes, this is the last header body in this message
// We are at the end -- force this body part to end at the
// end of the message and use length as computed.
// Mark end of this body for caller as 1 byte past end of last body header
// to prevent from being called again.
//
_body_len = content_length;
*end += 1;
return;
}
if (body_end > *end) { // past end of message??
// Yes, this is the last header body in this message
// We are past the end -- force this body part to end at the
// end of the message and compute length based upon that assumption.
// Mark end of this body for caller as 1 byte past end of last body header
// to prevent from being called again.
//
*end += 1;
_body_len = *end - _body_text;
return;
}
// V3BodyParts have a "----------" (10 dashes) at the beginning of a
// line with no white space before them and a new line at the end to
// signal the beginning of an attachment.
if ((*(body_end-1) == '\n') &&
strncmp(body_end, "----------", 10) == 0 &&
isTerm(body_end + 10)) { // start of another body header?
// Yes, this is one of many header bodies in this message
// Mark end of this body for caller as first byte of next body header
//
assert(body_end < *end); // cant be last
_body_len = body_end - _body_text;
*end = body_end+1; // current end
return;
}
// Chew through white space and test again.
//
while (isspace((unsigned char)*body_end)) {
body_end += 1;
}
}
}
else {
error.clear();
}
// We didn't have content-length, or it was wrong or bogus.
// Try for content lines.
//
value.clear(); // clear out any previous header(s) retrieved
_body_env->getHeader(error, "x-sun-content-lines",
DTM_FALSE, value);
if (error.isNotSet()) {
// content-lines requires a bit o' muching first.
// We do this by marching through the body counting new lines
// until the specified number of lines have been passed. This
// is the determined end of the body part.
//
int content_lines = (int) strtol(*(value[0]), NULL, 10);
int lines = 0;
for (body_end = _body_text;
body_end <= *end && lines < content_lines; body_end++) {
if (*body_end == '\n') {
lines += 1;
}
}
if (body_end >= *end) { // at end of message??
// Yes, this is the last header body in this message
// We are at or past the end -- force this body part to end at the
// end of the message and compute length based upon that assumption.
// Mark end of this body for caller as 1 byte past end of last body header
// to prevent from being called again.
//
*end += 1;
_body_len = *end - _body_text;
return;
}
// V3BodyParts have a "----------" (10 dashes) at the beginning of a
// line with no white space before them and a new line at the end to
// signal the beginning of an attachment.
if ((*(body_end-1) == '\n') &&
strncmp(body_end, "----------", 10) == 0 &&
isTerm(body_end + 10) == DTM_TRUE) { // start of another body header?
// Yes, this is one of many header bodies in this message
// Mark end of this body for caller as first byte of next body header
//
assert(body_end < *end); // cant be last
_body_len = body_end - _body_text;
*end = body_end+1; // current end
return;
}
}
else {
error.clear();
}
// We either didn't have a length, or number of lines, or they
// didn't work. We will now apply a dangerous but last resort
// effort to find the end of the body by looking for the 10 dash
// separator.
// V3BodyParts have a "----------" (10 dashes) at the beginning of a
// line with no white space before them and a new line at the end to
// signal the beginning of an attachment.
//
for (body_end = _body_text; body_end <= (*end - 12); body_end++) {
if (*body_end == '\n' &&
strncmp(body_end + 1, "----------", 10) == 0 &&
isTerm(body_end + 11) == DTM_TRUE) {
// Dangerously by successfully located what appears to be the end
// of this attachment.
//
*end = body_end;
_body_len = body_end - _body_text;
return;
}
}
// At this point we are at the end of the message and are without
// the benefit of content lines or content length or the discovery
// of what appears to be a message separator. Assume this body part
// consumes the remainder of the message. Mark end of this body for
// caller as 1 byte past end to prevent from being called again.
//
*end += 1;
_body_len = *end - _body_text;
return;
}
V3BodyPart::~V3BodyPart(void)
{
}
#ifdef DEAD_WOOD
DtMailChecksumState
V3BodyPart::checksum(DtMailEnv & error)
{
error.clear();
return(DtMailCheckUnknown);
}
#endif /* DEAD_WOOD */
static int
countTypes(char ** types)
{
if (NULL == types) return 0;
for (int count = 0; *types; types++, count++) {
continue;
}
return(count);
}
void
V3BodyPart::getContentType(DtMailEnv &error, char **v3_type)
{
MutexLock lock_scope(_obj_mutex);
MutexLock dt_lib_lock(_DtMutex);
DtMailValueSeq value;
if (v3_type)
*v3_type = (char *)0;
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
if (error.isNotSet())
*v3_type = strdup(*(value[0]));
else
{
error.clear();
value.clear();
_body_env->getHeader(error, "X-Sun-Data-Type", DTM_FALSE, value);
if (error.isNotSet())
*v3_type = strdup(*(value[0]));
else
{
error.clear();
*v3_type = strdup("text");
}
}
}
void
V3BodyPart::getDtType(DtMailEnv & error)
{
MutexLock lock_scope(_obj_mutex);
MutexLock dt_lib_lock(_DtMutex);
// No need to clear the error object here because it should have
// been cleared by the object that instantiated it.
// error.clear();
char * v3_type;
DtMailValueSeq value;
_body_env->getHeader(error, "Content-Type", DTM_FALSE, value);
if (error.isNotSet()) {
v3_type = strdup(*(value[0]));
}
else {
error.clear();
value.clear();
_body_env->getHeader(error, "X-Sun-Data-Type", DTM_FALSE,
value);
if (error.isNotSet()) {
v3_type = strdup(*(value[0]));
}
else {
error.clear();
v3_type = strdup("text");
}
}
char ** types = DtDtsFindAttribute("SUNV3_TYPE", v3_type);
if (NULL != types)
{
if (countTypes(types) == 1) {
// We will use the first name. It may be wrong, but
// it is the best we can do at this point.
//
_body_type = strdup(types[0]);
DtDtsFreeDataTypeNames(types);
free(v3_type);
return;
}
DtDtsFreeDataTypeNames(types);
}
// We need the bits so we can type the buffer and get
// a type for the object. This is where things can get
// very slow for the user.
//
loadBody(error);
if (error.isSet()) {
return;
}
char * name = getName(error);
if (error.isSet()) {
// don't care about error conditions returned by getName().
error.clear();
}
// If the name is "Attachment" and the type is "text", then
// use the type as the name to avoid the buffer being called
// generic data.
//
if (name && strcasecmp(name, "attachment") == 0 &&
strcasecmp(v3_type, "text") == 0) {
free(name);
name = strdup(v3_type);
}
char * type = DtDtsBufferToDataType(_body, _body_decoded_len, name);
_body_type = strdup(type);
DtDtsFreeDataType(type);
free(name);
free(v3_type);
// error.clear();
}
void
V3BodyPart::loadBody(DtMailEnv &)
{
// For CHARSET
char *to_cs = NULL, *from_cs = NULL;
char *cs = new char[64];
// End of For CHARSET
int do_decode = 1;
if (_body) {
delete [] cs;
return;
}
// See if we are using an encoding.
DtMailValueSeq value;
DtMailEnv lerror;
_body_env->getHeader(lerror, "X-Sun-Encoding-Info",
DTM_FALSE, value);
if (lerror.isSet() || (_body_len == 0)) {
// No Encodings.
lerror.clear();
_body = (char *)_body_text;
_must_free_body = DTM_FALSE;
_body_decoded_len = _body_len;
// Before the codeset conversion code was put in, return here.
do_decode = 0;
}
if (do_decode) {
_body_decoded_len = 0;
_must_free_body = DTM_TRUE;
SunV3::decode(*(value[0]), &_body, _body_decoded_len,
_body_text, _body_len);
}
// For CHARSET
// If Content-Type is text, then get charset and do conversion.
// If Content-Type is X-sun-attachment, then if X-Sun-Data-Type is text,
// then get charset and do conversion.
// If Content-Type is missing, check if X-Sun-Data-Type exists, and
// if X-Sun-Data-Type exists and is text, then get charset and do conversion.
// If Content-Type and X-Sun-Data-Type are missing, then assume text so get
// charset and do conversion.
// Else don't need codeset conversion.
const char *cstmp = NULL;
const char *ct = NULL;
value.clear();
_body_env->getHeader(lerror, "Content-Type", DTM_FALSE, value);
if (lerror.isNotSet()) {
// Sun's V.3 Mail File Format requires a Content-Type header field to be
// "X-sun-attachment" for attachment message. X-Sun-Data-Type header
// field is also required for attachment message.
ct = *(value[0]);
if ( strcasecmp(ct, "X-sun-attachment") == 0 ) {
value.clear();
_body_env->getHeader(lerror, "X-Sun-Data-Type", DTM_FALSE, value);
if (lerror.isNotSet()) {
ct = *(value[0]);
if ( strcasecmp(ct, "text") == 0 ) {
// Get charset from X-Sun-Text-Type which contains the name of
// the codeset for the text-based body part. It is a mandatory
// header iff X-Sun-Data-Type is of type text.
value.clear();
_body_env->getHeader(lerror, "X-Sun-Text-Type", DTM_FALSE, value);
if (lerror.isNotSet()) {
cstmp = *(value[0]);
strcpy(cs, cstmp);
} else {
// We are not returning yet. We'll be flexible here.
// Some mailers may not set this field. We'll try to obtain charset
// from X-Sun-Charset or use the locale default. See below.
lerror.clear();
}
} else { // Attachment not text type
delete [] cs;
return;
}
} else {
// Required field for attachment message not set -- return!
delete [] cs;
return;
}
} else if ( strcasecmp(ct, "text") != 0 ) {
delete [] cs;
return;
}
} else { // Content-Type does not exist!
lerror.clear();
value.clear();
_body_env->getHeader(lerror, "X-Sun-Data-Type", DTM_FALSE, value);
if (lerror.isNotSet()) {
ct = *(value[0]);
if ( strcasecmp(ct, "text") == 0 ) {
// Get charset from X-Sun-Text-Type which contains the name of
// the codeset for the text-based body part. It is a mandatory
// header iff X-Sun-Data-Type is of type text.
value.clear();
_body_env->getHeader(lerror, "X-Sun-Text-Type", DTM_FALSE, value);
if (lerror.isNotSet()) {
cstmp = *(value[0]);
strcpy(cs, cstmp);
} else {
// We are not returning yet. We'll be flexible here.
// Some mailers may not set this field. We'll try to obtain charset
// from X-Sun-Charset or use the locale default. See below.
lerror.clear();
}
} else { // Attachment not text type
delete [] cs;
return;
}
} else {
// Base on Sun's V.3 Mail File Format version 1.9: If no Content-Type,
// and X-Sun-Data-Type is not set (means no/not attachment,
// then assume text. Proceed with getting charset.
lerror.clear();
}
}
if (cstmp == NULL) {
value.clear();
// Get charset from charset field
_body_env->getHeader(lerror, "X-Sun-Charset", DTM_FALSE, value);
if (lerror.isNotSet()) {
cstmp = *(value[0]);
strcpy(cs, cstmp);
} else { // No Charset
// We'll be flexible here. If Content-Type is missing or if Content-Type
// is text, then we get charset but if charset is missing, we'll try to
// convert from the locale specific default codeset.
lerror.clear();
char *ret = NULL;
strcpy(cs, "DEFAULT");
DtXlateOpToStdLocale(DtLCX_OPER_SETLOCALE,
setlocale(LC_CTYPE, NULL),
NULL,
NULL,
&ret);
strcpy(cs, "DEFAULT");
strcat(cs, ".");
strcat(cs, ret);
if ( ret )
free( ret );
}
} // If cstmp is NULL
// Handle ISO-2022-INT, RFC approved, or private encoding names
if ( strcasecmp(cs, "ISO-2022-INT-1") == 0 ) {
// Need to obtain charset from encoding
} // RFC approved and private names are not treated differently.
// Get iconv name from charset - this is the "from" name.
from_cs = NULL;
from_cs = csToConvName(cs);
// Get current locale's iconv name - this is the "to" name.
to_cs = NULL;
to_cs = locToConvName();
if ( from_cs && to_cs ) {
if ( strcasecmp(from_cs, to_cs) != 0 ) {
unsigned long tmp_len = (unsigned long) _body_decoded_len;
if (csConvert(&_body, tmp_len, (int)_must_free_body, from_cs, to_cs)) {
_must_free_body = DTM_TRUE;
_body_decoded_len = (int) tmp_len;
}
}
}
if ( from_cs )
free( from_cs );
if ( to_cs )
free ( to_cs );
// End of For CHARSET
delete [] cs;
}
char *
V3BodyPart::getDescription(DtMailEnv & error)
{
// No need to clear the error object here, whoever created it, cleared it.
// error.clear();
DtMailValueSeq value;
_body_env->getHeader(error, "X-Sun-Data-Description",
DTM_FALSE, value);
if (error.isNotSet()) {
return(strdup(*(value[0])));
}
error.clear(); // clear error so it doesn't propogate back up.
return(NULL);
}
char *
V3BodyPart::getName(DtMailEnv & error)
{
// No need to clear the error object here, it should be passed in already
// cleared.
// error.clear();
DtMailValueSeq value;
_body_env->getHeader(error, "X-Sun-Data-Name",
DTM_FALSE, value);
if (error.isNotSet()) {
return(strdup(*(value[0])));
}
// Since we are returning a valid name in spite of the call to
// getHeader returning an error, we should clear the error.
//
error.clear();
return(strdup("Attachment"));
}
void
V3BodyPart::setName(DtMailEnv & error, const char * name)
{
_body_env->setHeader(error, "X-Sun-Data-Name", DTM_TRUE, name);
}
unsigned long
V3BodyPart::getLength(DtMailEnv & error)
{
MutexLock lock_scope(_obj_mutex);
loadBody(error);
if (error.isSet()) {
// propogate the error back to the caller
return (0);
}
return(_body_decoded_len);
}
int
V3BodyPart::rfcSize(const char *, DtMailBoolean &)
{
return(0);
}
char *
V3BodyPart::writeBodyParts(char *buf)
{
return(buf);
}
// Do not need to implement this method because getHeader already
// returns the X-Sun-Charset value.
char *
V3BodyPart::csFromContentType(DtMailValueSeq&)
{
return NULL;
}