|
|
|
//=============================================================================
|
|
|
|
// File: addrlist.cpp
|
|
|
|
// Contents: Definitions for DwAddressList
|
|
|
|
// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
|
|
|
|
// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
|
|
|
|
//
|
|
|
|
// Copyright (c) 1996, 1997 Douglas W. Sauder
|
|
|
|
// All rights reserved.
|
|
|
|
//
|
|
|
|
// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
|
|
|
|
// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
|
|
|
|
// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
|
|
|
|
// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
//
|
|
|
|
// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
|
|
|
|
// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
|
|
// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
|
|
|
|
// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
|
|
|
|
// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
|
|
|
//
|
|
|
|
//=============================================================================
|
|
|
|
|
|
|
|
#define DW_IMPLEMENTATION
|
|
|
|
|
|
|
|
#include <mimelib/config.h>
|
|
|
|
#include <mimelib/debug.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <mimelib/config.h>
|
|
|
|
#include <mimelib/address.h>
|
|
|
|
#include <mimelib/addrlist.h>
|
|
|
|
#include <mimelib/token.h>
|
|
|
|
#include <mimelib/group.h>
|
|
|
|
#include <mimelib/mailbox.h>
|
|
|
|
|
|
|
|
const char* const DwAddressList::sClassName = "DwAddressList";
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList* (*DwAddressList::sNewAddressList)(const DwString&,
|
|
|
|
DwMessageComponent*) = 0;
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList* DwAddressList::NewAddressList(const DwString& aStr,
|
|
|
|
DwMessageComponent* aParent)
|
|
|
|
{
|
|
|
|
if (sNewAddressList) {
|
|
|
|
return sNewAddressList(aStr, aParent);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return new DwAddressList(aStr, aParent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList::DwAddressList()
|
|
|
|
{
|
|
|
|
mFirstAddress = 0;
|
|
|
|
mClassId = kCidAddressList;
|
|
|
|
mClassName = sClassName;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList::DwAddressList(const DwAddressList& aList)
|
|
|
|
: DwFieldBody(aList)
|
|
|
|
{
|
|
|
|
mFirstAddress = 0;
|
|
|
|
const DwAddress* addr = aList.mFirstAddress;
|
|
|
|
if (addr) {
|
|
|
|
CopyList(addr);
|
|
|
|
}
|
|
|
|
mClassId = kCidAddressList;
|
|
|
|
mClassName = sClassName;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList::DwAddressList(const DwString& aStr, DwMessageComponent* aParent)
|
|
|
|
: DwFieldBody(aStr, aParent)
|
|
|
|
{
|
|
|
|
mFirstAddress = 0;
|
|
|
|
mClassId = kCidAddressList;
|
|
|
|
mClassName = sClassName;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressList::~DwAddressList()
|
|
|
|
{
|
|
|
|
if (mFirstAddress) {
|
|
|
|
DeleteAll();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const DwAddressList& DwAddressList::operator = (const DwAddressList& aList)
|
|
|
|
{
|
|
|
|
if (this == &aList) return *this;
|
|
|
|
DwFieldBody::operator = (aList);
|
|
|
|
if (mFirstAddress) {
|
|
|
|
DeleteAll();
|
|
|
|
}
|
|
|
|
const DwAddress* addr = aList.mFirstAddress;
|
|
|
|
if (addr) {
|
|
|
|
CopyList(addr);
|
|
|
|
}
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwMessageComponent* DwAddressList::Clone() const
|
|
|
|
{
|
|
|
|
return new DwAddressList(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddress* DwAddressList::FirstAddress() const
|
|
|
|
{
|
|
|
|
return mFirstAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::Add(DwAddress* aAddr)
|
|
|
|
{
|
|
|
|
aAddr->SetNext(0);
|
|
|
|
aAddr->SetParent(this);
|
|
|
|
if (!mFirstAddress) {
|
|
|
|
mFirstAddress = aAddr;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
while (addr->Next()) {
|
|
|
|
addr = (DwAddress*) addr->Next();
|
|
|
|
}
|
|
|
|
addr->SetNext(aAddr);
|
|
|
|
}
|
|
|
|
SetModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::Remove(DwAddress* aAddr)
|
|
|
|
{
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
if (addr == aAddr) {
|
|
|
|
mFirstAddress = (DwAddress*) addr->Next();
|
|
|
|
aAddr->SetNext(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
while (addr) {
|
|
|
|
if (addr->Next() == aAddr) {
|
|
|
|
addr->SetNext(aAddr->Next());
|
|
|
|
aAddr->SetNext(0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetModified();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::DeleteAll()
|
|
|
|
{
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
while (addr) {
|
|
|
|
DwAddress* nextAddr = (DwAddress*) addr->Next();
|
|
|
|
delete addr;
|
|
|
|
addr = nextAddr;
|
|
|
|
}
|
|
|
|
mFirstAddress = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::Parse()
|
|
|
|
{
|
|
|
|
mIsModified = 0;
|
|
|
|
if (mFirstAddress) {
|
|
|
|
DeleteAll();
|
|
|
|
}
|
|
|
|
DwAddressListParser parser(mString);
|
|
|
|
DwAddress* address;
|
|
|
|
while (1) {
|
|
|
|
switch (parser.AddrType()) {
|
|
|
|
case DwAddressListParser::eAddrError:
|
|
|
|
case DwAddressListParser::eAddrEnd:
|
|
|
|
goto LOOP_EXIT;
|
|
|
|
case DwAddressListParser::eAddrMailbox:
|
|
|
|
address = DwMailbox::NewMailbox(parser.AddrString(), this);
|
|
|
|
address->Parse();
|
|
|
|
if (address->IsValid()) {
|
|
|
|
Add(address);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete address;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DwAddressListParser::eAddrGroup:
|
|
|
|
address = DwGroup::NewGroup(parser.AddrString(), this);
|
|
|
|
address->Parse();
|
|
|
|
if (address->IsValid()) {
|
|
|
|
Add(address);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
delete address;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DwAddressListParser::eAddrNull:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++parser;
|
|
|
|
}
|
|
|
|
LOOP_EXIT:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::Assemble()
|
|
|
|
{
|
|
|
|
if (!mIsModified) return;
|
|
|
|
mString = "";
|
|
|
|
int count = 0;
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
while (addr) {
|
|
|
|
addr->Assemble();
|
|
|
|
if (addr->IsValid()) {
|
|
|
|
if (count > 0){
|
|
|
|
if (IsFolding()) {
|
|
|
|
mString += "," DW_EOL " ";
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mString += ", ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mString += addr->AsString();
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
addr = (DwAddress*) addr->Next();
|
|
|
|
}
|
|
|
|
mIsModified = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::CopyList(const DwAddress* aFirstAddr)
|
|
|
|
{
|
|
|
|
const DwAddress* addr = aFirstAddr;
|
|
|
|
while (addr) {
|
|
|
|
DwAddress* newAddr = (DwAddress*) addr->Clone();
|
|
|
|
Add(newAddr);
|
|
|
|
addr = (const DwAddress*) addr->Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#if defined (DW_DEBUG_VERSION)
|
|
|
|
void DwAddressList::PrintDebugInfo(std::ostream& aStrm, int aDepth/*=0*/) const
|
|
|
|
{
|
|
|
|
aStrm <<
|
|
|
|
"-------------- Debug info for DwAddressList class --------------\n";
|
|
|
|
_PrintDebugInfo(aStrm);
|
|
|
|
int depth = aDepth - 1;
|
|
|
|
depth = (depth >= 0) ? depth : 0;
|
|
|
|
if (aDepth == 0 || depth > 0) {
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
while (addr) {
|
|
|
|
addr->PrintDebugInfo(aStrm, depth);
|
|
|
|
addr = addr->Next();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void DwAddressList::PrintDebugInfo(std::ostream&, int) const {}
|
|
|
|
#endif // defined (DW_DEBUG_VERSION)
|
|
|
|
|
|
|
|
|
|
|
|
#if defined (DW_DEBUG_VERSION)
|
|
|
|
void DwAddressList::_PrintDebugInfo(std::ostream& aStrm) const
|
|
|
|
{
|
|
|
|
DwFieldBody::_PrintDebugInfo(aStrm);
|
|
|
|
aStrm << "Address objects: ";
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
if (addr) {
|
|
|
|
int count = 0;
|
|
|
|
while (addr) {
|
|
|
|
if (count > 0) aStrm << ' ';
|
|
|
|
aStrm << addr->ObjectId();
|
|
|
|
addr = addr->Next();
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
aStrm << '\n';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
aStrm << "(none)\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
void DwAddressList::_PrintDebugInfo(std::ostream&) const {}
|
|
|
|
#endif // defined (DW_DEBUG_VERSION)
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressList::CheckInvariants() const
|
|
|
|
{
|
|
|
|
#if defined (DW_DEBUG_VERSION)
|
|
|
|
DwAddress* addr = mFirstAddress;
|
|
|
|
while (addr) {
|
|
|
|
addr->CheckInvariants();
|
|
|
|
assert((DwMessageComponent*) this == addr->Parent());
|
|
|
|
addr = addr->Next();
|
|
|
|
}
|
|
|
|
#endif // defined (DW_DEBUG_VERSION)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressListParser::DwAddressListParser(const DwString& aStr)
|
|
|
|
: mTokenizer(aStr),
|
|
|
|
mAddrString(aStr)
|
|
|
|
{
|
|
|
|
mAddrType = eAddrError;
|
|
|
|
ParseNextAddress();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DwAddressListParser::~DwAddressListParser()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DwAddressListParser::Restart()
|
|
|
|
{
|
|
|
|
mTokenizer.Restart();
|
|
|
|
ParseNextAddress();
|
|
|
|
return mAddrType;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DwAddressListParser::operator ++ ()
|
|
|
|
{
|
|
|
|
ParseNextAddress();
|
|
|
|
return mAddrType;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DwAddressListParser::ParseNextAddress()
|
|
|
|
{
|
|
|
|
mAddrString.SetFirst(mTokenizer);
|
|
|
|
mAddrType = eAddrEnd;
|
|
|
|
int type = mTokenizer.Type();
|
|
|
|
if (type == eTkNull) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
enum {
|
|
|
|
eTopLevel,
|
|
|
|
eInGroup,
|
|
|
|
eInRouteAddr
|
|
|
|
} state;
|
|
|
|
state = eTopLevel;
|
|
|
|
// The type will be a mailbox, unless we discover otherwise
|
|
|
|
mAddrType = eAddrMailbox;
|
|
|
|
int done = 0;
|
|
|
|
while (!done) {
|
|
|
|
if (type == eTkNull) {
|
|
|
|
mAddrString.ExtendTo(mTokenizer);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (type == eTkSpecial) {
|
|
|
|
int ch = mTokenizer.Token()[0];
|
|
|
|
switch (state) {
|
|
|
|
case eTopLevel:
|
|
|
|
switch (ch) {
|
|
|
|
case ',':
|
|
|
|
mAddrString.ExtendTo(mTokenizer);
|
|
|
|
done = 1;
|
|
|
|
break;
|
|
|
|
case '<':
|
|
|
|
state = eInRouteAddr;
|
|
|
|
break;
|
|
|
|
case ':':
|
|
|
|
mAddrType = eAddrGroup;
|
|
|
|
state = eInGroup;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case eInRouteAddr:
|
|
|
|
switch (ch) {
|
|
|
|
case '>':
|
|
|
|
state = eTopLevel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case eInGroup:
|
|
|
|
switch (ch) {
|
|
|
|
case ';':
|
|
|
|
state = eTopLevel;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++mTokenizer;
|
|
|
|
type = mTokenizer.Type();
|
|
|
|
}
|
|
|
|
if (mAddrString.Tokens().length() == 0) {
|
|
|
|
mAddrType = eAddrNull;
|
|
|
|
}
|
|
|
|
}
|