diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 |
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 |
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /libmail/smapfetchattr.C | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'libmail/smapfetchattr.C')
| -rw-r--r-- | libmail/smapfetchattr.C | 621 |
1 files changed, 621 insertions, 0 deletions
diff --git a/libmail/smapfetchattr.C b/libmail/smapfetchattr.C new file mode 100644 index 0000000..5124094 --- /dev/null +++ b/libmail/smapfetchattr.C @@ -0,0 +1,621 @@ +/* +** Copyright 2003-2004, Double Precision Inc. +** +** See COPYING for distribution information. +*/ + +#include "smap.H" +#include "misc.H" +#include "smapfetchattr.H" +#include "imapfolder.H" + +#include "rfcaddr.H" +#include "envelope.H" + +#include "rfc822/rfc822.h" + +#include <iostream> +#include <sstream> +#include <stdio.h> + +using namespace std; + +const char *mail::smapFETCHATTR::getName() +{ + return "FETCHATTR"; +} + +mail::smapFETCHATTR::smapFETCHATTR(const vector<size_t> &messages, + mail::account::MessageAttributes attributesArg, + mail::callback::message &callbackArg, + mail::imap &imapAccount) + : uidSet(imapAccount, messages), + attributes(attributesArg), msgcallback(callbackArg), + nextPtr(0) +{ + defaultCB= &msgcallback; +} + +mail::smapFETCHATTR::~smapFETCHATTR() +{ +} + +void mail::smapFETCHATTR::installed(imap &imapAccount) +{ + fetchList.init(imapAccount, uidSet); + uidSet.clear(); + if (go()) + { + return; + } + ok("OK"); + imapAccount.uninstallHandler(this); +} + + +bool mail::smapFETCHATTR::ok(string msg) +{ + if (doFetchingStructure) + { + checkMimeVersion(); + msgcallback.messageStructureCallback(fetchingMessageNum-1, + fetchingStructure); + } + + if (go()) + { + doDestroy=false; + return true; + } + + return smapHandler::ok(msg); +} + +bool mail::smapFETCHATTR::go() +{ + ostringstream msgList; + + doFetchingStructure=NULL; + fetchingMessageNum=0; + fetchingStructCount=0; + seenMimeVersion=false; + + if (!myimap->currentFolder || + myimap->currentFolder->closeInProgress || + !(fetchList >> msgList)) + { + return false; + } + + bool hasAttr=false; + + if (attributes & mail::account::ARRIVALDATE) + { + msgList << " INTERNALDATE"; + hasAttr=true; + } + + if (attributes & mail::account::MESSAGESIZE) + { + msgList << " SIZE"; + hasAttr=true; + } + + if (attributes & mail::account::MIMESTRUCTURE) + { + msgList << " CONTENTS.PEEK=MIME(:MIME)"; + hasAttr=true; + fetchingStructure=mail::mimestruct(); + fetchingStructure.type="TEXT"; + fetchingStructure.subtype="PLAIN"; + } + else /* MIMESTRUCTURE can also be used to build an envelope */ + + if (attributes & mail::account::ENVELOPE) + { + msgList << " CONTENTS.PEEK=HEADERS(:ENVELOPE)"; + hasAttr=true; + } + + if (!hasAttr) + return false; + + doFetchingEnvelope=false; + myimap->imapcmd("", "FETCH" + msgList.str() + "\n"); + return true; +} + +void mail::smapFETCHATTR::fetchedMessageSize(size_t msgNum, + unsigned long bytes) +{ + msgcallback.messageSizeCallback(msgNum, bytes); +} + +void mail::smapFETCHATTR::fetchedInternalDate(size_t msgNum, + time_t internalDate) +{ + msgcallback.messageArrivalDateCallback(msgNum, internalDate); +} + +// New FETCH data coming back. + +void mail::smapFETCHATTR::beginProcessData(imap &imapAccount, + vector<const char *> &words, + unsigned long estimatedSize) +{ + doFetchingEnvelope=false; + + if (words.size() >= 2 && strcasecmp(words[0], "FETCH") == 0 && + (attributes & (mail::account::ENVELOPE + |mail::account::MIMESTRUCTURE))) + { + size_t oldFetchingMessageNum=fetchingMessageNum; + + // Requested a FETCH for an envelope + + string n=words[1]; + istringstream i(n); + + fetchingMessageNum=0; + + i >> fetchingMessageNum; + + if (fetchingMessageNum > 0 && + fetchingMessageNum <= + (imapAccount.currentFolder && + !imapAccount.currentFolder->closeInProgress ? + imapAccount.currentFolder->exists:0)) + { + if (attributes & mail::account::MIMESTRUCTURE) + { + if (doFetchingStructure && + oldFetchingMessageNum + != fetchingMessageNum) + { + checkMimeVersion(); + msgcallback + .messageStructureCallback(oldFetchingMessageNum-1, + fetchingStructure); + fetchingStructure= mail::mimestruct(); + fetchingStructure.type="TEXT"; + fetchingStructure.subtype="PLAIN"; + } + + unsigned long mimeSize=0; + string mimeid=""; + string mimeparent=""; + + vector<const char *>::iterator + b=words.begin()+2, e=words.end(); + + while (b != e) + { + const char *c= *b++; + + if (strncasecmp(c, "SIZE=", 5) == 0) + { + string n=c+5; + + istringstream i(n); + + i >> mimeSize; + } + + if (strncasecmp(c, "MIME.ID=", 8) == 0) + mimeid=c+8; + + if (strncasecmp(c, "MIME.PARENT=", 12) + == 0) + { + mimeparent=c+12; + } + } + +#if 0 + cerr << "new MIME struct: id=" + << mimeid << ", parent=" << mimeparent + << endl; +#endif + + seenMimeVersion=false; + if (fetchingStructCount > 1000) + { + doFetchingStructure=NULL; + // Limit to 1000 MIME sections + } + else if (mimeid == "") + { + doFetchingStructure= + &fetchingStructure; + } + else + { + mail::mimestruct *p= + findMimeId(&fetchingStructure, + mimeparent, 0); + + doFetchingStructure=NULL; + if (p) + { + doFetchingStructure= + p->addChild(); + doFetchingStructure->type + ="TEXT"; + doFetchingStructure->subtype + ="PLAIN"; + } + } + + if (doFetchingStructure) + { + ++fetchingStructCount; + +#if 0 + cerr << "added " << mimeid + << ", parent's numChildren=" + << (doFetchingStructure + ->getParent() + ? doFetchingStructure + ->getParent()->getNumChildren() + : 0) << endl; +#endif + + doFetchingStructure->mime_id=mimeid; + doFetchingStructure->content_size= + mimeSize; + } + } + + doFetchingEnvelope=true; + fetchingEnvelope= mail::envelope(); + fetchingHeader=""; + } + } +} + +mail::mimestruct *mail::smapFETCHATTR::findMimeId(mail::mimestruct *p, + string mimeid, + size_t recursionLevel) +{ + if (!p || recursionLevel > 20) + return NULL; +#if 0 + cerr << "findMimeId(" << mimeid << "), current=" + << p->mime_id << endl; +#endif + if (p->mime_id == mimeid) + return p; + + size_t n=p->getNumChildren(); + size_t i; + + for (i=0; i<n; i++) + { + mail::mimestruct *q= findMimeId(p->getChild(i), mimeid, + recursionLevel+1); + + if (q) + return q; + } + + return NULL; +} + +void mail::smapFETCHATTR::checkMimeVersion() +{ + if (seenMimeVersion) + return; + + mail::mimestruct *p=doFetchingStructure->getParent(); + + if (p && !p->messagerfc822()) + return; // Assumed + + mail::mimestruct dummy; + + dummy.type="TEXT"; + dummy.subtype="PLAIN"; + + dummy.content_size= doFetchingStructure->content_size; + dummy.content_lines= doFetchingStructure->content_lines; + dummy.mime_id=doFetchingStructure->mime_id; + + *doFetchingStructure=dummy; +} + +// As header data comes back, split it at newlines, and parse each individual +// header line. + +void mail::smapFETCHATTR::processData(imap &imapAccount, + string data) +{ + if (!doFetchingEnvelope) + return; + + fetchingHeader += data; + + size_t n; + + while ((n=fetchingHeader.find('\n')) != std::string::npos) + { + string h=fetchingHeader.substr(0, n); + + fetchingHeader.erase(fetchingHeader.begin(), + fetchingHeader.begin()+n+1); + + processFetchedHeader(h); + } +} + +void mail::smapFETCHATTR::endData(imap &imapAccount) +{ + if (doFetchingEnvelope) + { + processFetchedHeader(fetchingHeader); // Anything that's left + + if (doFetchingStructure) + { + mail::mimestruct *p=doFetchingStructure->getParent(); + + if (p && p->messagerfc822()) + p->getEnvelope() = fetchingEnvelope; + } + + if ( (!doFetchingStructure || + doFetchingStructure->mime_id == "") && + attributes & mail::account::ENVELOPE) + msgcallback + .messageEnvelopeCallback(fetchingMessageNum-1, + fetchingEnvelope); + + } +} + +// Process a FETCHed header line. + +void mail::smapFETCHATTR::processFetchedHeader(string hdr) +{ + size_t n=hdr.find(':'); + + if (n == std::string::npos) + return; + + string h=hdr.substr(0, n); + + string::iterator b=hdr.begin()+n+1; + + while (b != hdr.end() && unicode_isspace((unsigned char)*b)) + b++; + + string v=string(b, hdr.end()); + + mail::upper(h); + if (doFetchingEnvelope) + { + if (h == "DATE") + { + fetchingEnvelope.date=rfc822_parsedt(v.c_str()); + } + + if (h == "SUBJECT") + { + fetchingEnvelope.subject=v; + } + + if (h == "IN-REPLY-TO") + { + fetchingEnvelope.inreplyto=v; + } + + if (h == "MESSAGE-ID") + { + fetchingEnvelope.messageid=v; + } + + if (h == "REFERENCES") + { + vector<address> address_list; + size_t err_index; + + address::fromString(v, address_list, err_index); + + fetchingEnvelope.references.clear(); + + vector<address>::iterator + b=address_list.begin(), + e=address_list.end(); + + while (b != e) + { + string s=b->getAddr(); + + if (s.size() > 0) + fetchingEnvelope.references + .push_back("<" + s + ">"); + ++b; + } + } + + if (h == "FROM") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.from, + dummy); + } + + if (h == "TO") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.to, + dummy); + } + + if (h == "CC") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.cc, + dummy); + } + + if (h == "BCC") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.bcc, + dummy); + } + + if (h == "SENDER") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.sender, + dummy); + } + + if (h == "REPLY-TO") + { + size_t dummy; + + mail::address::fromString(v, fetchingEnvelope.replyto, + dummy); + } + + } + + if (doFetchingStructure) + { + if (h == "MIME-VERSION") + seenMimeVersion=1; + + if (h == "CONTENT-TYPE") + { + string t; + + parseMimeHeader(v, t, + doFetchingStructure->type_parameters); + + size_t n=t.find('/'); + + if (n == std::string::npos) + { + doFetchingStructure->type=t; + doFetchingStructure->subtype=""; + } + else + { + doFetchingStructure->type=t.substr(0, n); + doFetchingStructure->subtype=t.substr(n+1); + } + } + + if (h == "CONTENT-ID") + doFetchingStructure->content_id=v; + + if (h == "CONTENT-DESCRIPTION") + doFetchingStructure->content_description=v; + if (h == "CONTENT-TRANSFER-ENCODING") + doFetchingStructure->content_transfer_encoding=v; + if (h == "CONTENT-MD5") + doFetchingStructure->content_md5=v; + if (h == "CONTENT-LANGUAGE") + doFetchingStructure->content_language=v; + if (h == "CONTENT-DISPOSITION") + { + parseMimeHeader(v, doFetchingStructure-> + content_disposition, + doFetchingStructure-> + content_disposition_parameters); + } + } +} + +void mail::smapFETCHATTR::parseMimeHeader(std::string hdr, + std::string &name, + mail::mimestruct::parameterList &p) +{ + p=mail::mimestruct::parameterList(); + + string::iterator b=hdr.begin(), e=hdr.end(); + + name.clear(); + + while (b != e && *b != ';') + { + if (!unicode_isspace((unsigned char)*b)) + name += *b; + ++b; + } + + mail::upper(name); + + while (b != e) + { + if (unicode_isspace((unsigned char)*b) || *b == ';') + { + b++; + continue; + } + + string::iterator s=b; + + while (b != e) + { + if (*b == ';' || + unicode_isspace((unsigned char)*b) || *b == '=') + break; + ++b; + } + + string name(s, b), value; + + while (b != e && unicode_isspace((unsigned char)*b)) + ++b; + + if (b != e && *b == '=') + { + ++b; + + while (b != e && unicode_isspace((unsigned char)*b)) + ++b; + + bool inQuote=false; + + while (b != e) + { + if (!inQuote && (*b == ';' || + unicode_isspace(*b))) + { + b++; + break; + } + + if (*b == '"') + { + ++b; + inQuote= !inQuote; + continue; + } + + if (*b == '\\') + { + ++b; + if (b == e) + break; + } + + value += *b; + b++; + } + } + else + value="1"; + + mail::upper(name); + + p.set_simple(name, value); + } +} |
