cdesktopenv/cde/programs/dtmail/libDtMail/RFC/RFCEnvelope.C

1100 lines
27 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
*+SNOTICE
*
*
* $TOG: RFCEnvelope.C /main/7 1998/04/06 13:27:59 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 <unistd.h>
#include <string.h>
#include <ctype.h>
#include <sys/utsname.h>
#include <DtMail/DtMail.hh>
#include "RFCImpl.hh"
#include <DtMail/Threads.hh>
#include <DtMail/IO.hh>
#include "str_utils.h"
unsigned long RFCEnvelopeSignature = 0x55fd23ef;
// This constant defines how big the parsed header structure starts.
// it will grow dynamically over time if need be. The guess here is
// that most messages will have about 32 headers so we won't have
// to grow very often, but we also aren't wasting a lot of space.
//
static const int INITIAL_HEADER_COUNT = 32;
static const int NAME_MASK = 0x1;
static const int VALUE_MASK = 0x2;
RFCEnvelope::RFCEnvelope(DtMailEnv & error,
DtMail::Message * parent,
const char * start,
const int len)
: DtMail::Envelope(error, parent), _parsed_headers(INITIAL_HEADER_COUNT)
{
error.clear();
_header_text = start;
_header_len = len;
_dirty = 0;
_header_lock = MutexInit();
if (_header_text) {
parseHeaders();
}
_object_signature = RFCEnvelopeSignature;
//fix for the defect 177527
_use_reply_to=DTM_TRUE;
}
RFCEnvelope::~RFCEnvelope(void)
{
if (_object_signature == RFCEnvelopeSignature) {
MutexLock lock_scope(_obj_mutex);
if (_object_signature == RFCEnvelopeSignature) {
for (int hdr = 0; hdr < _parsed_headers.length(); hdr++) {
ParsedHeader * hdrp = _parsed_headers[hdr];
delete _parsed_headers[hdr];
}
_object_signature = 0;
}
}
}
DtMailHeaderHandle
RFCEnvelope::getFirstHeader(DtMailEnv & error,
char ** name,
DtMailValueSeq & value)
{
MutexLock lock_header(_header_lock);
error.clear();
if (_parsed_headers.length() == 0) {
return(NULL); // No headers.
}
DtMailHeaderHandle handle = _parsed_headers[0];
*name = (char *)malloc(_parsed_headers[0]->name_len + 1);
strncpy(*name, _parsed_headers[0]->name_start, _parsed_headers[0]->name_len);
(*name)[_parsed_headers[0]->name_len] = 0;
makeValue(error, *_parsed_headers[0], value);
return(handle);
}
DtMailHeaderHandle
RFCEnvelope::getNextHeader(DtMailEnv & error,
DtMailHeaderHandle last,
char ** name,
DtMailValueSeq & value)
{
MutexLock lock_header(_header_lock);
error.clear();
if (!last) {
error.setError(DTME_BadArg);
return(NULL);
}
int slot = _parsed_headers.indexof((ParsedHeader *)last);
if (slot < 0) {
return(NULL);
}
slot += 1;
if (slot >= _parsed_headers.length()) {
return(NULL);
}
ParsedHeader * hdr = _parsed_headers[slot];
*name = (char *)malloc(hdr->name_len + 1);
strncpy(*name, hdr->name_start, hdr->name_len);
(*name)[hdr->name_len] = 0;
makeValue(error, *hdr, value);
return(hdr);
}
struct AbstractMap {
const char * abstract;
const char ** transports;
};
static const char * DtMailMessageToMap[] = {
"To", "Apparently-To", "Resent-To", NULL
};
static const char * DtMailMessageSenderMap[] = {
"Reply-To", "From", "Return-Path", "Resent-From", NULL
};
static const char * DtMailMessageCcMap[] = {
"Cc", NULL
};
static const char * DtMailMessageBccMap[] = {
"Bcc", NULL
};
static const char * DtMailMessageReceivedTimeMap[] = {
NULL
};
static const char * DtMailMessageSentTimeMap[] = {
"Date", NULL
};
static const char * DtMailMessageIdMap[] = {
"Message-Id", NULL
};
static const char * DtMailMessageSubjectMap[] = {
"Subject", NULL
};
static const char * DtMailMessageContentLengthMap[] = {
"Content-Length", NULL
};
static const char * DtMailMessageStatusMap[] = {
"Status", "X-Status", NULL
};
static const char * DtMailMessageV3charsetMap[] = {
"X-Sun-Charset", NULL
};
static const char * DtMailMessageContentTypeMap[] = {
"Content-Type", NULL
};
static const AbstractMap abstract_map[] = {
{ DtMailMessageTo, DtMailMessageToMap },
{ DtMailMessageSender, DtMailMessageSenderMap },
{ DtMailMessageCc, DtMailMessageCcMap },
{ DtMailMessageBcc, DtMailMessageBccMap },
{ DtMailMessageReceivedTime, DtMailMessageReceivedTimeMap },
{ DtMailMessageSentTime, DtMailMessageSentTimeMap },
{ DtMailMessageMessageId, DtMailMessageIdMap },
{ DtMailMessageSubject, DtMailMessageSubjectMap },
{ DtMailMessageContentLength, DtMailMessageContentLengthMap },
{ DtMailMessageStatus, DtMailMessageStatusMap },
{ DtMailMessageV3charset, DtMailMessageV3charsetMap },
{ DtMailMessageContentType, DtMailMessageContentTypeMap },
{ NULL, NULL }
};
void
RFCEnvelope::getHeader(DtMailEnv & error,
const char * name,
const DtMailBoolean abstract,
DtMailValueSeq & value)
{
MutexLock lock_header(_header_lock);
error.clear();
// If we are not in the abstract space, then simply get the
// transport header and return.
//
if (abstract == DTM_FALSE) {
getTransportHeader(error, name, value);
}
else {
// We need to handle reply to's with special care. We may
// need to strip the sender from the list.
//
if (strcmp(name, DtMailMessageToReply) == 0) {
makeReply(error, DtMailMessageTo, value);
return;
}
if (strcmp(name, DtMailMessageCcReply) == 0) {
makeReply(error, DtMailMessageCc, value);
return;
}
// Okay, we need to work out what the transport name
// might be. We do this by first finding the abstract
// name in the abstract->transport mapping table.
//
int abs = 0;
for (abs = 0; abstract_map[abs].abstract; abs++) {
if (strcmp(abstract_map[abs].abstract, name) == 0) {
break;
}
}
// If we didn't find the abstract name, then feed it through
// as a transport name. This is useful behavior so intermediates
// like the RFCMailBox::getMessageSummary method can always
// assume abstract names, but allow its client to specify transport
// names.
//
if (!abstract_map[abs].abstract) {
getTransportHeader(error, name, value);
return;
}
// Now we need to go through the list of transport names until
// we find a match. The first match is taken because the map
// should be ordered based on preference.
//
for (int trans = 0; abstract_map[abs].transports[trans]; trans++) {
getTransportHeader(error,
abstract_map[abs].transports[trans],
value);
// If the abstract is DtMailMessageSender we need do something
// special. If the request is for displaying the sender's
// name or e-mail address in the msg list scrolled window in the
// RMW, we should return the "From" value instead of the
// "Reply-To" value. Otherwise, we should return the Reply-To
// value (such as "Reply to sender")
//
if (error.isNotSet()) { // Found one!
if(!getUseReplyTo() &&
strcmp(abstract_map[abs].transports[trans],"Reply-To") == 0)
{
value.clear();
continue;
}
else
return;
}
error.clear();
}
// If this isn't a request for the sender ("From"), then
// we don't have a known value for the header. Bail!
//
if (strcmp(DtMailMessageSender, name) &&
strcmp(DtMailMessageReceivedTime, name)) {
error.setError(DTME_NoObjectValue);
return;
}
if (strncmp(_parsed_headers[0]->name_start, "From", 4) == 0) {
if (strcmp(DtMailMessageSender, name) == 0) {
parseUnixFrom(error, *_parsed_headers[0], value);
}
else if (strcmp(DtMailMessageReceivedTime, name) == 0) {
parseUnixDate(error, *_parsed_headers[0], value);
}
}
else {
error.setError(DTME_NoObjectValue);
return;
}
return;
}
return;
}
void
RFCEnvelope::setHeader(DtMailEnv & error,
const char * name,
const DtMailBoolean replace,
const char * val)
{
MutexLock lock_header(_header_lock);
RFCMessage * msg = (RFCMessage *)_parent;
error.clear();
// First we need to see if we have this header. We are
// only interested in the first occurrence.
//
ParsedHeader * hdr;
const char * real_name;
// Find the header if it currently exists
//
int slot = lookupHeader(name);
// Determine if the value is really empty (just blanks)
//
DtMailBoolean valueIsEmpty = DTM_TRUE;
for (const char *cv = val; *cv; cv++) {
if (!isspace((unsigned char)*cv)) {
valueIsEmpty = DTM_FALSE;
break;
}
}
// If the value to be set is empty (only spaces), then treat this
// set header request specially - either toss it if requesting to
// append an empty header, or remove an existing header if requesting
// to set an empty header
//
if (valueIsEmpty == DTM_TRUE) {
if (slot < 0) {
// The header was not found and the value is empty -
// Just return as there was no header to set anyway
return;
}
if (replace == DTM_TRUE) {
// The header was found and replacement was requested
// but the value is empty - request to replace existing
// header with empty header - treat as a remove header request
//
removeHeader(error, name);
return;
}
// The header was found, replacement is not requested, and the
// value is empty - request to append empty header - toss
//
return;
}
if (slot < 0 || replace == DTM_FALSE) {
// Need to create a new header entry for this one.
//
hdr = new ParsedHeader;
slot = _parsed_headers.append(hdr);
real_name = mapName(name);
_dirty = 1; // new entry: header dirty
}
else {
hdr = _parsed_headers[slot];
real_name = name;
}
// First, see if we need to do something about the name.
//
if (!hdr->name_start) {
hdr->alloc_mask |= NAME_MASK;
hdr->name_start = strdup(real_name);
hdr->name_len = strlen(real_name);
_header_len += hdr->name_len;
_dirty = 1; // new name: header dirty
}
// Clean up the existing value if need be.
//
if (hdr->value_start) {
if ( (strlen(val) != hdr->value_len)
|| (strncmp(hdr->value_start, val, hdr->value_len)!=0) ) // has value changed??
_dirty = 1; // yes: header dirty
if (hdr->alloc_mask & VALUE_MASK) {
free((char *)hdr->value_start);
}
hdr->value_start = NULL;
_header_len -= hdr->value_len;
hdr->value_len = 0;
}
else
_dirty = 1; // new value: header dirty
hdr->value_start = strdup(val);
hdr->value_len = strlen(hdr->value_start);
_header_len += hdr->value_len + 1;
hdr->alloc_mask |= VALUE_MASK;
if (msg) {
msg->markDirty(_dirty);
}
}
void
RFCEnvelope::removeHeader(DtMailEnv & error, const char * name)
{
MutexLock lock_header(_header_lock);
error.clear();
// Remove all versions of this header.
//
int slot = lookupHeader(name);
while (slot >= 0) {
_parsed_headers.remove(slot);
slot = lookupHeader(name);
}
RFCMessage * msg = (RFCMessage *)_parent;
if (msg) {
msg->markDirty(1);
}
if (!_dirty) {
_dirty += 1;
}
return;
}
void
RFCEnvelope::adjustHeaderLocation(char * headerStart, int headerLength)
{
MutexLock lock_header(_header_lock);
if (_dirty) {
// reparse headers in their new location
// destroy current headers
//
for (int hdr = 0; hdr < _parsed_headers.length(); hdr++) {
ParsedHeader * hdrp = _parsed_headers[hdr];
delete _parsed_headers[hdr];
_parsed_headers.remove(hdr);
hdr -=1;
}
// parse headers from scratch
_header_text = headerStart;
_header_len = headerLength;
parseHeaders();
}
else {
// We must adjust the offset of every header in the parsed header
// structure. For those headers values that have been malloc()ed
// (e.g. NAME_MASK or VALUE_MASK are set), don't have to do anything
// as they are deallocated only when the header is destroyed.
//
for (int hdr = 0; hdr < _parsed_headers.length(); hdr++) {
ParsedHeader * h = _parsed_headers[hdr];
if (!(h->alloc_mask & NAME_MASK)) {
h->name_start = (h->name_start - _header_text) + headerStart;
}
if (!(h->alloc_mask & VALUE_MASK)) {
h->value_start = (h->value_start - _header_text) + headerStart;
}
}
_header_text = headerStart;
}
_dirty = 0;
return;
}
char *
RFCEnvelope::writeHeaders(char * new_loc)
{
MutexLock lock_header(_header_lock);
// Copy the headers to the new region
//
char * cur_loc = new_loc;
int first = 1;
for (int hdr = 0; hdr < _parsed_headers.length(); hdr++) {
ParsedHeader * h = _parsed_headers[hdr];
const char * new_name = cur_loc;
memcpy(cur_loc, h->name_start, h->name_len);
cur_loc += h->name_len;
if (!first || strncmp(h->name_start, "From", h->name_len) != 0) {
*cur_loc++ = ':';
}
*cur_loc++ = ' ';
first = 0;
// Copy the value
//
const char * new_value = cur_loc;
memcpy(cur_loc, h->value_start, h->value_len);
cur_loc += h->value_len;
// Insert a trailing crlf if necessary. We need this so that when
// we write into the file, the header lines are as in RFC822 format.
if (*(cur_loc - 1) != '\n') {
*cur_loc++ = '\n';
}
}
return(cur_loc - 1);
}
const char *
RFCEnvelope::unixFrom(DtMailEnv & error, int & length)
{
ParsedHeader * hdr = _parsed_headers[0];
const char * ufrom = NULL;
length = 0;
error.clear();
if (strncmp(hdr->name_start, "From ", 5) == 0) {
ufrom = hdr->name_start;
length = (hdr->value_start + hdr->value_len) - hdr->name_start + 1;
}
else {
error.setError(DTME_NoObjectValue);
}
return(ufrom);
}
void
RFCEnvelope::parseHeaders(void)
{
// Now we actually parse the headers. Each header either ends with
// a new line, or is continued if the next line begins with white
// space.
//
ParsedHeader * hdr = new ParsedHeader;
for (const char * scan = _header_text; scan < (_header_text + _header_len);) {
if ((scan == _header_text) && (strncmp(scan, "From ", 5) == 0)) {
// Unix "From" line. This header has a different structure.
// It is "From user@host <date>". It does not have a colon
// like all other RFC headers so we have to parse it specially.
//
hdr->name_start = scan;
hdr->name_len = 4;
// Look for the first non-blank after the "From ".
//
for (scan += 4; *scan && isspace((unsigned char)*scan); scan++) {
continue;
}
hdr->value_start = scan;
// Find the new line.
for (; *scan && *scan != '\n'; scan++) {
continue;
}
hdr->value_len = scan - hdr->value_start;
if (*(scan - 1) == '\r') {
hdr->value_len -= 1;
}
scan += 1;
_parsed_headers.append(hdr);
hdr = new ParsedHeader;
continue;
}
// We should be at the start of a header. Let's look for a ":". If
// we find any white space first, then we have a problem.
//
hdr->name_start = scan;
for (;*scan && *scan != ':'; scan++) {
if (isspace((unsigned char)*scan)) {
break;
}
}
if (*scan != ':') {
// Find the next new line, and try again.
//
for (;*scan && *scan != '\n'; scan++) {
continue;
}
scan += 1;
continue;
}
hdr->name_len = scan - hdr->name_start;
// Look for the first non-blank after the colon.
//
for (scan += 1; scan < (_header_text + _header_len)
&& *scan != '\n' && isspace((unsigned char)*scan); scan++) {
continue;
}
if (*scan == '\n') {
// Null value!
hdr->value_start = scan;
hdr->value_len = 0;
_parsed_headers.append(hdr);
hdr = new ParsedHeader;
scan += 1;
continue;
}
// Okay, now we want scan looking for a new line that is
// not followed immediately by white space. That will give
// us the end of the header.
//
hdr->value_start = scan;
for (;scan < (_header_text + _header_len); scan++) {
if (*scan == '\n' && !isspace((unsigned char)*(scan + 1))) {
break;
}
}
hdr->value_len = scan - hdr->value_start;
if (*(scan - 1) == '\r') {
hdr->value_len -= 1;
}
scan += 1;
_parsed_headers.append(hdr);
hdr = new ParsedHeader;
}
// Made one to many.
//
delete hdr;
}
void
RFCEnvelope::getTransportHeader(DtMailEnv & error,
const char * name,
DtMailValueSeq & value)
{
error.clear();
// First, let's try to find out how many times the header
// appears. It may appear 1, many, or not at all.
//
int appears = 0;
for (int hdr = 0; hdr < _parsed_headers.length(); hdr++) {
// We need to lock the object until we are done.
//
MutexLock lock_header(_parsed_headers[hdr]->mutex);
// Make sure we have a header!
//
if (!_parsed_headers[hdr]->name_start ||
!_parsed_headers[hdr]->value_start) {
continue;
}
// Unix From doesn't count. We only use it as a fall back.
// It will always appear as the first header, if it appears
// at all.
//
if (hdr == 0 &&
strncmp(_parsed_headers[hdr]->name_start, "From ", 5) == 0) {
continue;
}
if (matchName(*_parsed_headers[hdr], name) == DTM_TRUE) {
// If the header exists, make sure it has a value.
if (_parsed_headers[hdr]->value_len > 0)
appears += 1;
}
}
if (appears == 0) { // Not here!
error.setError(DTME_NoObjectValue);
return;
}
// Second pass, find the headers and convert the values to the
// appropriate type.
//
int ent = 0;
for (int val = 0; val < _parsed_headers.length(); val++) {
if (val == 0 &&
strncmp(_parsed_headers[val]->name_start, "From ", 5) == 0) {
continue;
}
if (matchName(*_parsed_headers[val], name) == DTM_TRUE) {
RFCValue * new_value = new RFCValue(_parsed_headers[val]->value_start,
_parsed_headers[val]->value_len, _parent->session());
value.append(new_value);
}
}
return;
}
void
RFCEnvelope::parseUnixFrom(DtMailEnv & error,
const ParsedHeader & hdr,
DtMailValueSeq & value)
{
error.clear();
// The value_start will point to the beginning of the address.
// The Unix From header doesn't maintain all of the strange
// quoting behavior so spaces don't appear.
//
const char *end;
for (end = hdr.value_start; *end && !isspace((unsigned char)*end); end++) {
continue;
}
int size = end - hdr.value_start;
RFCValue * new_value = new RFCValue(hdr.value_start, size, _parent->session());
value.append(new_value);
return;
}
void
RFCEnvelope::parseUnixDate(DtMailEnv & error,
const ParsedHeader & hdr,
DtMailValueSeq & value)
{
error.clear();
// The value_start will point to the beginning of the address.
// The Unix From header doesn't maintain all of the strange
// quoting behavior so spaces don't appear.
//
const char * end;
for (end = hdr.value_start; end < (hdr.value_start + hdr.value_len)
&& !isspace((unsigned char)*end); end++) {
continue;
}
// Now end points at the white space between the sender and
// the date it arrived.
//
for (; end < (hdr.value_start + hdr.value_len) &&
isspace((unsigned char)*end); end++) {
continue;
}
// Now we are at the start of the date.
//
int size = (hdr.value_start + hdr.value_len) - end;
RFCValue * new_value = new RFCValue(end, size, _parent->session());
value.append(new_value);
return;
}
void
RFCEnvelope::makeValue(DtMailEnv & error,
const ParsedHeader & hdr,
DtMailValueSeq & value)
{
error.clear();
RFCValue * new_value = new RFCValue(hdr.value_start, hdr.value_len, _parent->session());
value.append(new_value);
}
DtMailBoolean
RFCEnvelope::matchName(const ParsedHeader & hdr, const char * name)
{
if (hdr.name_len != strlen(name)) {
return(DTM_FALSE);
}
if (strncasecmp(hdr.name_start, name, hdr.name_len) == 0) {
return(DTM_TRUE);
}
return(DTM_FALSE);
}
int
RFCEnvelope::lookupHeader(const char * name, DtMailBoolean real_only)
{
// Look for the name in real space.
//
int hdr;
int len = strlen(name);
for (hdr = 0; hdr < _parsed_headers.length(); hdr++) {
if (_parsed_headers[hdr]->name_start &&
strncasecmp(_parsed_headers[hdr]->name_start, name, len) == 0) {
return(hdr);
}
}
if (real_only == DTM_TRUE) {
return(-1);
}
for (const AbstractMap * abs = abstract_map; abs->abstract; abs++) {
if (strcmp(abs->abstract, name) == 0) {
for (int trans = 0; abs->transports[trans]; trans++) {
int slot = lookupHeader(abs->transports[trans], DTM_TRUE);
if (slot >= 0) {
return(slot);
}
}
}
}
return(-1);
}
void
RFCEnvelope::makeReply(DtMailEnv & error,
const char * name,
DtMailValueSeq & value)
{
error.clear();
// We have an abstract name. We need to loop through the
// transport headers, gathering up the values.
//
int abs = 0;
for (abs = 0; abstract_map[abs].abstract; abs++) {
if (strcmp(abstract_map[abs].abstract, name) == 0) {
break;
}
}
if (!abstract_map[abs].abstract) {
error.setError(DTME_NoObjectValue);
}
// Now we need to go through the list of transport names until
// we find a match. The first match is taken because the map
// should be ordered based on preference.
//
DtMailBoolean found = DTM_FALSE;
DtMailValueSeq lvalue;
for (int trans = 0; abstract_map[abs].transports[trans]; trans++) {
getTransportHeader(error,
abstract_map[abs].transports[trans],
lvalue);
if (error.isNotSet()) { // Found one!
found = DTM_TRUE;
break;
}
error.clear();
}
if (found == DTM_FALSE) {
error.setError(DTME_NoObjectValue);
return;
}
if (_parent == NULL) {
// We're done. Copy the values from one to the other.
//
for (int nc = 0; nc < lvalue.length(); nc++) {
RFCValue * new_value = new RFCValue(*(lvalue[nc]), strlen(*(lvalue[nc])), _parent->session());
value.append(new_value);
}
return;
}
DtMail::MailRc * mailrc = _parent->session()->mailRc(error);
// If metoo is set, then we are also done.
//
const char * mval;
DtMailEnv lerror;
mailrc->getValue(lerror, "metoo", &mval);
if (lerror.isNotSet()) {
for (int nc = 0; nc < lvalue.length(); nc++) {
RFCValue * new_value = new RFCValue(*(lvalue[nc]), strlen(*(lvalue[nc])), _parent->session());
value.append(new_value);
}
return;
}
// Finally, the point of being here! We need to build a new
// value that has the user stripped from the reply list. This
// includes any alternates the user has specified.
//
passwd pw;
GetPasswordEntry(pw);
struct utsname uname_val;
uname(&uname_val);
char * my_addr = new char[strlen(pw.pw_name) + strlen(uname_val.nodename) + 5];
strcpy(my_addr, pw.pw_name);
strcat(my_addr, "@");
strcat(my_addr, uname_val.nodename);
DtMailAddressSeq alts;
DtMailValueAddress * me = new DtMailValueAddress(my_addr,
pw.pw_gecos,
DtMailAddressDefault);
alts.append(me);
// Fetch the alternates, if any and add them to the list to strip.
//
const char * others = mailrc->getAlternates(lerror);
if (others) {
RFCTransport::arpaPhrase(others, alts);
}
// Finally, we need to see if the user wants us to ignore the host
// component of the address when stripping.
//
DtMailBoolean allnet = DTM_FALSE;
mailrc->getValue(lerror, "allnet", &mval);
if (lerror.isNotSet()) {
allnet = DTM_TRUE;
}
DtMailAddressSeq keepers;
for (int nc = 0; nc < lvalue.length(); nc++) {
DtMailAddressSeq * cur_val = lvalue[nc]->toAddress();
for (int naddr = 0; naddr < cur_val->length(); naddr++) {
if (metooAddr(*(*cur_val)[naddr], alts, allnet) == DTM_FALSE) {
DtMailValueAddress * kaddr = new DtMailValueAddress(*(*cur_val)[naddr]);
keepers.append(kaddr);
}
}
}
// Finally, let's build a single string from the remaining list and
// set the value to that string.
//
int max_len = 0;
for (int cstr = 0; cstr < keepers.length(); cstr++) {
DtMailValueAddress * addr = keepers[cstr];
max_len += strlen(addr->dtm_address) + 3;
}
if (max_len > 0) {
char * str_addr = new char[max_len];
str_addr[0] = 0;
for (int copy = 0; copy < keepers.length(); copy++) {
DtMailValueAddress * addr = keepers[copy];
strcat(str_addr, addr->dtm_address);
if (copy != (keepers.length() - 1)) {
strcat(str_addr, ", ");
}
}
RFCValue * new_val = new RFCValue(str_addr, strlen(str_addr), _parent->session());
value.append(new_val);
delete str_addr;
}
}
char *
striphosts(char * addr)
{
char *cp, *cp2;
if ((cp = strrchr(addr,'!')) != NULL)
cp++;
else
cp = addr;
/*
* Now strip off all Internet-type
* hosts.
*/
if ((cp2 = strchr(cp, '%')) == NULL)
cp2 = strchr(cp, '@');
if (cp2 != NULL)
*cp2 = '\0';
return(cp);
}
DtMailBoolean
RFCEnvelope::metooAddr(DtMailValueAddress & addr,
DtMailAddressSeq & alts,
DtMailBoolean allnet)
{
char * str_addr_buf = strdup(addr.dtm_address);
char * str_addr = str_addr_buf;
if (allnet) {
str_addr = striphosts(str_addr_buf);
}
for (int nalt = 0; nalt < alts.length(); nalt++) {
char * cmp_addr_buf = strdup(alts[nalt]->dtm_address);
char * cmp_addr = cmp_addr_buf;
if (allnet) {
cmp_addr = striphosts(cmp_addr_buf);
}
if (strcasecmp(str_addr, cmp_addr) == 0) {
free(str_addr_buf);
free(cmp_addr_buf);
return(DTM_TRUE);
}
free(cmp_addr_buf);
}
free(str_addr_buf);
return(DTM_FALSE);
}
// This method attempts to map an abstract name to a transport name.
// When multiple transport names exist, the first is always used.
//
const char *
RFCEnvelope::mapName(const char * name)
{
for (const AbstractMap * abs = abstract_map; abs->abstract; abs++) {
if (strcmp(name, abs->abstract) == 0) {
return(abs->transports[0]);
}
}
// Must be a real name.
//
return(name);
}
RFCEnvelope::ParsedHeader::ParsedHeader(void)
{
mutex = MutexInit();
alloc_mask = 0;
name_start = NULL;
name_len = 0;
value_start = NULL;
value_len = 0;
}
RFCEnvelope::ParsedHeader::~ParsedHeader(void)
{
MutexLock lock_scope(mutex);
if (alloc_mask & NAME_MASK) {
free((char *)name_start);
}
if (alloc_mask & VALUE_MASK) {
free((char *)value_start);
}
lock_scope.unlock_and_destroy();
}