diff options
Diffstat (limited to 'libmail/smtp.C')
| -rw-r--r-- | libmail/smtp.C | 1420 |
1 files changed, 0 insertions, 1420 deletions
diff --git a/libmail/smtp.C b/libmail/smtp.C deleted file mode 100644 index cb515c2..0000000 --- a/libmail/smtp.C +++ /dev/null @@ -1,1420 +0,0 @@ -/* -** Copyright 2002-2011, Double Precision Inc. -** -** See COPYING for distribution information. -*/ -#include "libmail_config.h" -#include "misc.H" -#include "smtp.H" -#include "driver.H" -#include "search.H" -#include "imaphmac.H" -#include "base64.H" -#include "smtpfolder.H" -#include "tcpd/spipe.h" -#include "unicode/courier-unicode.h" -#include "libcouriertls.h" - -#include <errno.h> - -#include <sstream> -#include <iomanip> - -#include <sys/types.h> -#include <signal.h> -#if HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#ifndef WEXITSTATUS -#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) -#endif -#ifndef WIFEXITED -#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) -#endif - -using namespace std; - -#define SMTPTIMEOUT 60 - -#define INACTIVITY_TIMEOUT 30 - -#define DIGIT(c) (strchr("0123456789", (c))) - - -///////////////////////////////////////////////////////////////////////////// - -LIBMAIL_START - -static bool open_smtp(mail::account *&accountRet, - mail::account::openInfo &oi, - mail::callback &callback, - mail::callback::disconnect &disconnectCallback) -{ - mail::loginInfo nntpLoginInfo; - - if (!mail::loginUrlDecode(oi.url, nntpLoginInfo)) - return false; - - if (nntpLoginInfo.method != "smtp" && - nntpLoginInfo.method != "smtps" && - nntpLoginInfo.method != "sendmail") - return false; - - accountRet=new mail::smtp(oi.url, oi.pwd, oi.certificates, callback, - disconnectCallback, - oi.loginCallbackObj); - return true; -} - -static bool smtp_remote(string url, bool &flag) -{ - mail::loginInfo nntpLoginInfo; - - if (!mail::loginUrlDecode(url, nntpLoginInfo)) - return false; - - if (nntpLoginInfo.method != "smtp" && - nntpLoginInfo.method != "smtps") - return false; - - flag=true; - return true; -} - -driver smtp_driver= { &open_smtp, &smtp_remote }; - -LIBMAIL_END - -/////////////////////////////////////////////////////////////////////////// -// -// Helper class sends outbound message -// -/////////////////////////////////////////////////////////////////////////// - -mail::smtp::Blast::Blast(mail::smtp *smtpArg) - : eofSent(false), mySmtp(smtpArg), lastChar('\n'), - bytesTotal(0), bytesDone(0) -{ -} - -mail::smtp::Blast::~Blast() -{ - if (mySmtp) - mySmtp->myBlaster=NULL; -} - -bool mail::smtp::Blast::fillWriteBuffer() -{ - if (!mySmtp) - { - if (!eofSent) - { - eofSent=true; - writebuffer += "\r\n.\r\n"; - return true; - } - return false; - } - - mySmtp->installHandler(mySmtp->responseHandler); - // Reset the timeout every time the write buffer gets filled - - char buffer[BUFSIZ]; - - size_t i; - - FILE *fp=mySmtp->sendQueue.front().message; - - for (i=0; i<sizeof(buffer); i++) - { - int ch=getc(fp); - - if (ch == EOF) - { - writebuffer += string(buffer, buffer+i); - if (lastChar != '\n') - writebuffer += "\r\n"; - writebuffer += ".\r\n"; - - mail::callback *c=mySmtp->sendQueue.front().callback; - - if (c) - c->reportProgress(bytesTotal, bytesTotal, - 0, 1); - - mySmtp->myBlaster=NULL; - mySmtp=NULL; - eofSent=true; - return true; - } - - ++bytesDone; - - if (lastChar == '\n' && ch == '.') - { - ungetc(ch, fp); // Leading .s are doubled. - --bytesDone; - } - - if (ch == '\n' && lastChar != '\r') - { - ungetc(ch, fp); - --bytesDone; - ch='\r'; - } - - buffer[i]=lastChar=ch; - } - - mail::callback *c=mySmtp->sendQueue.front().callback; - - if (c) - c->reportProgress(bytesDone, bytesTotal, 0, 1); - - writebuffer += string(buffer, buffer+sizeof(buffer)); - return true; -} - -// Something arrived from the server. - -int mail::smtp::socketRead(const string &readbuffer) -{ - size_t n=readbuffer.find('\n'); - - if (n == std::string::npos) - return 0; - - string l=readbuffer.substr(0, n++); - - size_t cr; - - while ((cr=l.find('\r')) != std::string::npos) - l=l.substr(0, cr) + l.substr(cr+1); - - // Collect multiline SMTP replies. Keep only the last 30 lines - // received. - - smtpResponse.push_back(l); - - if (smtpResponse.size() > 30) - smtpResponse.erase(smtpResponse.begin()); - - string::iterator b=l.begin(), e=l.end(); - int numCode=0; - - while (b != e && isdigit((int)(unsigned char)*b)) - numCode=numCode * 10 + (*b++ - '0'); - - if (b == l.begin()+3) - { - if (b == e || unicode_isspace((unsigned char)*b)) - { - string s=""; - - list<string>::iterator b, e; - - b=smtpResponse.begin(); - e=smtpResponse.end(); - - while (b != e) - { - if (s.size() > 0) s += "\n"; - - s += *b++; - } - - smtpResponse.clear(); - - if (responseHandler != 0) - (this->*responseHandler)(numCode, s); - else - fatalError=true; - // SMTP msg when no handler installed, something's - // gone wrong. - - } - } - - return n; -} - -void mail::smtp::installHandler(void (mail::smtp::*handler)(int, - string)) -{ - responseHandler=handler; - responseTimeout=0; - - if (handler != 0) - { - time(&responseTimeout); - responseTimeout += SMTPTIMEOUT; - } -} - - -void mail::smtp::disconnect(const char *reason) -{ - while (!sendQueue.empty()) - { - struct messageQueueInfo &info=sendQueue.front(); - - info.callback->fail(reason); - fclose(info.message); - sendQueue.pop(); - } - pingTimeout=0; - - if (getfd() >= 0) - { - string errmsg=socketDisconnect(); - - if (errmsg.size() == 0) - errmsg=reason; - - if (orderlyShutdown) - success(errmsg); - else if (smtpLoginInfo.callbackPtr) - error(errmsg); - else - disconnect_callback.disconnected(errmsg.c_str()); - } -} - -void mail::smtp::resumed() -{ - if (responseHandler != 0) - { - time(&responseTimeout); - responseTimeout += SMTPTIMEOUT; - } -} - - -void mail::smtp::handler(vector<pollfd> &fds, int &ioTimeout) -{ - if (fatalError) - return; - - int fd_save=getfd(); - - time_t now; - - time(&now); - - if (responseHandler != 0) - { - if (now >= responseTimeout) - { - fatalError=true; - ioTimeout=0; - (this->*responseHandler)(500, "500 Server timed out."); - return; - } - - if (ioTimeout >= (responseTimeout - now) * 1000) - { - ioTimeout=(responseTimeout - now)*1000; - } - } - - if (pingTimeout) - { - if (pingTimeout < now) - { - mail::smtpInfo dummy; - - send(NULL, dummy, NULL, false); - } - else - { - if (ioTimeout >= (pingTimeout - now)*1000) - { - ioTimeout=(pingTimeout - now)*1000; - } - } - } - - - mail::fd::process(fds, ioTimeout); - - if (getfd() < 0) - { - size_t i; - - for (i=fds.size(); i; ) - { - --i; - - if (fds[i].fd == fd_save) - { - fds.erase(fds.begin()+i, fds.begin()+i+1); - break; - } - } - } -} - -mail::smtp::smtp(string url, string passwd, - std::vector<std::string> &certificates, - mail::callback &callback, - mail::callback::disconnect &disconnectCallback, - loginCallback *loginCallbackFunc) - : mail::fd(disconnectCallback, certificates), orderlyShutdown(false), - ready2send(false), fatalError(true), pingTimeout(0) -{ - responseHandler=NULL; - smtpLoginInfo.callbackPtr= &callback; - smtpLoginInfo.loginCallbackFunc=loginCallbackFunc; - - if (!loginUrlDecode(url, smtpLoginInfo)) - { - smtpLoginInfo.callbackPtr->fail("Invalid SMTP URL."); - return; - } - - if (smtpLoginInfo.method == "sendmail") // Local sendmail - { - smtpLoginInfo.use_ssl=false; - smtpLoginInfo.uid=""; - smtpLoginInfo.pwd=""; - - string errmsg; - - int pipefd[2]; - - if (libmail_streampipe(pipefd) < 0) - { - smtpLoginInfo.callbackPtr->fail(strerror(errno)); - return; - } - - pid_t pid1=fork(); - - if (pid1 < 0) - { - close(pipefd[0]); - close(pipefd[1]); - smtpLoginInfo.callbackPtr->fail(strerror(errno)); - return; - } - - if (pid1 == 0) - { - close(0); - close(1); - errno=EIO; - if (dup(pipefd[1]) != 0 || dup(pipefd[1]) != 1) - { - perror("500 dup"); - exit(1); - } - close(pipefd[0]); - close(pipefd[1]); - - pid1=fork(); - if (pid1 < 0) - { - printf("500 fork() failed.\r\n"); - exit(1); - } - - if (pid1) - exit(0); - execl(SENDMAIL, SENDMAIL, "-bs", (char *)NULL); - - printf("500 %s: %s\n", SENDMAIL, strerror(errno)); - exit(0); - } - - close(pipefd[1]); - int waitstat; - pid_t pid2; - - while ((pid2=wait(&waitstat)) != pid1) - { - if (kill(pid1, 0)) - break; - } - - - try { - errmsg=socketAttach(pipefd[0]); - } catch (...) { - close(pipefd[0]); - LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); - } - } - else - { - smtpLoginInfo.use_ssl= smtpLoginInfo.method == "smtps"; - - if (passwd.size() > 0) - smtpLoginInfo.pwd=passwd; - - string errmsg=socketConnect(smtpLoginInfo, "smtp", "smtps"); - - if (errmsg.size() > 0) - { - smtpLoginInfo.callbackPtr->fail(errmsg); - return; - } - } - - fatalError=false; - hmac_method_index=0; - installHandler(&mail::smtp::greetingResponse); -} - -// Login failed - -void mail::smtp::error(string errMsg) -{ - mail::callback *c=smtpLoginInfo.callbackPtr; - - smtpLoginInfo.callbackPtr=NULL; - - if (c) - c->fail(errMsg); - -} - -// Login succeeded - -void mail::smtp::success(string errMsg) -{ - mail::callback *c=smtpLoginInfo.callbackPtr; - - smtpLoginInfo.callbackPtr=NULL; - - if (c) - c->success(errMsg); -} - -// Send EHLO/HELO - -void mail::smtp::howdy(const char *hi) -{ - char buffer[512]; - - buffer[sizeof(buffer)-1]=0; - - if (gethostname(buffer, sizeof(buffer)-1) < 0) - strcpy(buffer, "localhost"); - - socketWrite(string(hi) + buffer + "\r\n"); -} - -void mail::smtp::greetingResponse(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - case 3: - break; - default: - error(s); - return; - } - - installHandler(&mail::smtp::ehloResponse); - howdy("EHLO "); -} - -void mail::smtp::ehloResponse(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - case 3: - break; - default: // Maybe HELO will work - installHandler(&mail::smtp::heloResponse); - howdy("HELO "); - return; - } - - // Parse EHLO capability list - - bool firstLine=true; - - while (s.size() > 0) - { - string line; - - size_t p=s.find('\n'); - - if (p == std::string::npos) - { - line=s; - s=""; - } - else - { - line=s.substr(0, p); - s=s.substr(p+1); - } - - if (firstLine) - { - firstLine=false; - continue; - } - - while ((p=s.find('\r')) != std::string::npos) - s=s.substr(0, p) + s.substr(p+1); - - for (p=0; p<line.size(); p++) - if (!DIGIT((int)(unsigned char)line[p])) - break; - - if (p < line.size()) - p++; - - // Put capability to uppercase - - line=mail::iconvert::convert_tocase(line.substr(p), - "iso-8859-1", - unicode_uc); - - for (p=0; p<line.size(); p++) - if (unicode_isspace((unsigned char)line[p]) || - line[p] == '=') - break; - - string capa=line.substr(0, p); - - // Save SASL authentication methods as capabilities - // AUTH=method - - if (capa == "AUTH" || capa == "XSECURITY") - { - if (p < line.size()) - p++; - - line=line.substr(p); - - while (line.size() > 0) - { - for (p=0; p<line.size(); p++) - if (unicode_isspace((unsigned char) - line[p]) || - line[p] == ',') - break; - - if (p > 0) - { - capabilities.insert(capa + "=" + - line.substr(0, p)); - } - if (p < line.size()) - p++; - line=line.substr(p); - } - } - else - capabilities.insert(capa); - } - starttls(); -} - -void mail::smtp::heloResponse(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - case 3: - starttls(); - return; - } - - error(s); -} - -void mail::smtp::starttls() -{ -#if HAVE_LIBCOURIERTLS - - if (smtpLoginInfo.use_ssl // Already SSL-encrypted - || smtpLoginInfo.options.count("notls") > 0 - || !hasCapability("STARTTLS") - || socketEncrypted()) - { - begin_auth(); - return; - } - - installHandler(&mail::smtp::starttlsResponse); - - socketWrite("STARTTLS\r\n"); -#else - begin_auth(); - return; -#endif -} - -void mail::smtp::starttlsResponse(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - if (!socketBeginEncryption(smtpLoginInfo)) - { - smtpLoginInfo.callbackPtr=NULL; - return; - } - capabilities.clear(); - greetingResponse(n, s); - return; - } - - error(s); -} - -void mail::smtp::begin_auth() -{ - if (!hasCapability("AUTH=EXTERNAL")) - { - begin_auth_nonexternal(); - return; - } - installHandler(&mail::smtp::auth_external_response); - socketWrite("AUTH EXTERNAL =\r\n"); -} - -void mail::smtp::auth_external_response(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - case 3: - authenticated(); - return; - } - begin_auth_nonexternal(); -} - -void mail::smtp::begin_auth_nonexternal() -{ - int i; - - if (smtpLoginInfo.uid.size() == 0) - { - authenticate_hmac(); - return; - } - - for (i=0; mail::imaphmac::hmac_methods[i]; ++i) - { - if (hasCapability(string("AUTH=CRAM-") + - mail::imaphmac - ::hmac_methods[hmac_method_index]->getName() - )) - break; - } - - if (mail::imaphmac::hmac_methods[i] || - hasCapability("AUTH=LOGIN")) - { - if (smtpLoginInfo.pwd.size() == 0) - { - currentCallback=smtpLoginInfo.loginCallbackFunc; - - if (currentCallback) - { - currentCallback->target=this; - currentCallback->getPassword(); - return; - } - } - } - authenticate_hmac(); -} - -void mail::smtp::loginInfoCallback(std::string str) -{ - currentCallback=NULL; - smtpLoginInfo.pwd=str; - authenticate_hmac(); -} - -void mail::smtp::loginInfoCallbackCancel() -{ - currentCallback=NULL; - error("Login cancelled"); -} - -void mail::smtp::authenticate_hmac() -{ - for (;;) - { - if (mail::imaphmac::hmac_methods[hmac_method_index] == NULL || - smtpLoginInfo.uid.size() == 0) - { - authenticate_login(); // Exhausted SASL, forget it. - return; - } - - if (hasCapability(string("AUTH=CRAM-") + - mail::imaphmac - ::hmac_methods[hmac_method_index]->getName() - )) - break; - hmac_method_index++; - } - - installHandler(&mail::smtp::hmacResponse); - - socketWrite(string("AUTH CRAM-") + - mail::imaphmac::hmac_methods[hmac_method_index]->getName() - + "\r\n"); -} - -void mail::smtp::hmacResponse(int n, string s) -{ - switch (n / 100) { - case 1: - case 2: - authenticated(); - return; - } - - if ((n / 100) != 3 || s.size() < 4) - { - ++hmac_method_index; - authenticate_hmac(); - return; - } - - s=mail::decodebase64str(s.substr(4)); - s=(*mail::imaphmac::hmac_methods[hmac_method_index])(smtpLoginInfo - .pwd, s); - - string sHex; - - { - ostringstream hexEncode; - - hexEncode << hex; - - string::iterator b=s.begin(); - string::iterator e=s.end(); - - while (b != e) - hexEncode << setw(2) << setfill('0') - << (int)(unsigned char)*b++; - - sHex=hexEncode.str(); - } - - s=mail::encodebase64str(smtpLoginInfo.uid + " " + sHex); - socketWrite(s + "\r\n"); -} - -void mail::smtp::authenticate_login() -{ - if (!hasCapability("AUTH=LOGIN") || smtpLoginInfo.uid.size() == 0 || - smtpLoginInfo.options.count("cram")) - { - authenticated(); - return; - } - - installHandler(&mail::smtp::loginUseridResponse); - - socketWrite("AUTH LOGIN\r\n"); -} - -void mail::smtp::loginUseridResponse(int n, string msg) -{ - if ((n / 100) != 3) - { - error(msg); - return; - } - - installHandler(&mail::smtp::loginPasswdResponse); - socketWrite(string(mail::encodebase64str(smtpLoginInfo.uid)) - + "\r\n"); -} - -void mail::smtp::loginPasswdResponse(int n, string msg) -{ - if ((n / 100) != 3) - { - error(msg); - return; - } - - installHandler(&mail::smtp::loginResponse); - socketWrite(string(mail::encodebase64str(smtpLoginInfo.pwd)) - + "\r\n"); -} - -void mail::smtp::loginResponse(int n, string msg) -{ - if ((n / 100) != 2) - { - error(msg); - return; - } - - authenticated(); -} - -void mail::smtp::authenticated() -{ - ready2send=true; - if (!sendQueue.empty()) - startNextMessage(); // Already something's queued up. - else - pingTimeout=time(NULL) + INACTIVITY_TIMEOUT; - success("Connected to " + smtpLoginInfo.server); -} - -mail::smtp::~smtp() -{ - disconnect("Connection forcibly aborted."); -} - -void mail::smtp::logout(mail::callback &callback) -{ - if (fatalError) - { - callback.success("Server timed out."); - return; - } - - smtpLoginInfo.callbackPtr= &callback; - orderlyShutdown=true; - installHandler(&mail::smtp::quitResponse); - - socketWrite("QUIT\r\n"); -} - -void mail::smtp::quitResponse(int n, string s) -{ - if (!socketEndEncryption()) - { - socketDisconnect(); - success(s); - } -} - -void mail::smtp::checkNewMail(mail::callback &callback) // STUB -{ - callback.success("OK"); -} - -bool mail::smtp::hasCapability(string capability) -{ - if (capability == LIBMAIL_SINGLEFOLDER) - return false; - - return capabilities.count(capability) > 0; -} - -string mail::smtp::getCapability(string name) -{ - upper(name); - - if (name == LIBMAIL_SERVERTYPE) - { - return "smtp"; - } - - if (name == LIBMAIL_SERVERDESCR) - { - return "ESMTP server"; - } - - if (name == LIBMAIL_SINGLEFOLDER) - return ""; - - return capabilities.count(name) > 0 ? "1":""; -} - - -// Not implemented - -mail::folder *mail::smtp::folderFromString(string) -{ - errno=EINVAL; - return NULL; -} - -// Not implemented - -void mail::smtp::readTopLevelFolders(mail::callback::folderList &callback1, - mail::callback &callback2) -{ - vector<const mail::folder *> dummy; - - callback1.success(dummy); - callback2.success("OK"); -} - -// Not implemented - -void mail::smtp::findFolder(string folder, - class mail::callback::folderList &callback1, - class mail::callback &callback2) -{ - callback2.fail("Folder not found."); -} - -// This is why we're here: - -mail::folder *mail::smtp::getSendFolder(const mail::smtpInfo &info, - const mail::folder *folderArg, - string &errmsg) -{ - if (folderArg) - { - return mail::account::getSendFolder(info, folderArg, errmsg); - } - - if (info.recipients.size() == 0) - { - errno=ENOENT; - errmsg="Empty recipient list."; - return NULL; - } - - mail::smtpFolder *folder=new mail::smtpFolder(this, info); - - if (!folder) - { - errmsg=strerror(errno); - return NULL; - } - return folder; -} - - -void mail::smtp::readMessageAttributes(const vector<size_t> &messages, - MessageAttributes attributes, - mail::callback::message &callback) -{ - callback.fail("Invalid message number."); -} - - -void mail::smtp::readMessageContent(const vector<size_t> &messages, - bool peek, - enum mail::readMode readType, - mail::callback::message &callback) -{ - callback.fail("Invalid message number."); -} - -void mail::smtp::readMessageContent(size_t messageNum, - bool peek, - const mail::mimestruct &msginfo, - enum mail::readMode readType, - mail::callback::message &callback) -{ - callback.fail("Invalid message number."); -} - -void mail::smtp::readMessageContentDecoded(size_t messageNum, - bool peek, - const mail::mimestruct &msginfo, - mail::callback::message &callback) -{ - callback.fail("Invalid message number."); -} - -size_t mail::smtp::getFolderIndexSize() -{ - return 0; -} - -mail::messageInfo mail::smtp::getFolderIndexInfo(size_t messageNum) -{ - return mail::messageInfo(); -} - -void mail::smtp::saveFolderIndexInfo(size_t messageNumber, - const mail::messageInfo &info, - mail::callback &callback) -{ - callback.fail("Invalid message number."); -} - -void mail::smtp::updateFolderIndexFlags(const vector<size_t> &messages, - bool doFlip, - bool enableDisable, - const mail::messageInfo &flags, - mail::callback &callback) -{ - callback.fail("Invalid message number."); -} - -void mail::smtp::updateFolderIndexInfo(mail::callback &callback) -{ - callback.success("OK"); -} - -void mail::smtp::removeMessages(const std::vector<size_t> &messages, - mail::callback &cb) -{ - updateFolderIndexInfo(cb); -} - -void mail::smtp::copyMessagesTo(const vector<size_t> &messages, - mail::folder *copyTo, - mail::callback &callback) -{ - callback.fail("Invalid message number."); -} - -void mail::smtp::searchMessages(const mail::searchParams &searchInfo, - mail::searchCallback &callback) -{ - vector<size_t> empty; - - callback.success(empty); -} - -////////////////////////////////////////////////////////////////////////////// -// -// Another message is ready to go out. Called by mail::smtpFolder::go, -// and one other place. - -void mail::smtp::send(FILE *tmpfile, mail::smtpInfo &info, - mail::callback *callback, bool flag8bit) -{ - pingTimeout=0; - - struct messageQueueInfo msgInfo; - - msgInfo.message=tmpfile; - msgInfo.messageInfo=info; - msgInfo.callback=callback; - msgInfo.flag8bit=flag8bit; - - bool wasEmpty=sendQueue.empty(); - - sendQueue.push(msgInfo); - - if (wasEmpty && ready2send) - startNextMessage(); -} - -void mail::smtp::startNextMessage() -{ - if (fatalError) - { - messageProcessed(500, "500 A fatal error occurred while connected to remote server."); - return; - } - - socketWrite("RSET\r\n"); - installHandler(&mail::smtp::rsetResponse); -} - -void mail::smtp::rsetResponse(int result, string message) -{ - struct messageQueueInfo &info=sendQueue.front(); - - if (info.message == NULL) // Just a NO-OP ping. - { - sendQueue.pop(); - - if (!sendQueue.empty()) - startNextMessage(); - else - pingTimeout=time(NULL) + INACTIVITY_TIMEOUT; - return; - } - - switch (result / 100) { - case 1: - case 2: - case 3: - break; - default: - messageProcessed(result, message); - return; - } - - if (!validString(info.messageInfo.sender)) - return; - - { - vector<string>::iterator b=info.messageInfo.recipients.begin(), - e=info.messageInfo.recipients.end(); - - while (b != e) - if (!validString(*b++)) - return; - } - - { - map<string, string>::iterator - b=info.messageInfo.options.begin(), - e=info.messageInfo.options.end(); - - while (b != e) - if (!validString((*b++).second)) - return; - } - - string mailfrom="MAIL FROM:<" + info.messageInfo.sender + ">"; - - if (hasCapability("8BITMIME")) - mailfrom += info.flag8bit ? " BODY=8BITMIME":" BODY=7BIT"; - - if (hasCapability("SIZE")) - { - long pos; - - if (fseek(info.message, 0L, SEEK_END) < 0 || - (pos=ftell(info.message)) < 0) - { - messageProcessed(500, strerror(errno)); - return; - } - - pos= pos < 1024 * 1024 ? pos * 70 / 68: pos/68 * 70; - - string buffer; - - { - ostringstream o; - - o << pos; - buffer=o.str(); - } - - mailfrom += " SIZE="; - mailfrom += buffer; - } - - if (info.messageInfo.options.count("DSN") > 0 || - info.messageInfo.options.count("RET") > 0) - { - if (!hasCapability("DSN")) - { - messageProcessed(500, "500 This mail server does not support delivery status notifications."); - return; - } - } - - if (hasCapability("DSN")) - { - if (info.messageInfo.options.count("RET") > 0) - mailfrom += " RET=" + info.messageInfo.options - .find("RET")->second; - } - - if (hasCapability("XVERP=COURIER")) - { - if (info.messageInfo.options.count("VERP") > 0) - mailfrom += " VERP"; - } - - if (info.messageInfo.options.count("SECURITY") > 0) - { - string sec=info.messageInfo.options.find("SECURITY")->second; - - if (info.messageInfo.options.count("XSECURITY=" + sec) == 0) - { - messageProcessed(500, "500 requested security not available."); - return; - } - - mailfrom += " SECURITY=" + sec; - } - - pipelineCmd=mailfrom; - - mailfrom += "\r\n"; - - pipelineCount=0; - installHandler(&mail::smtp::mailfromResponse); - socketWrite(mailfrom); -} - -// RCPT TO handler in pipeline mode. - -void mail::smtp::pipelinedResponse(int result, string message) -{ - switch (result / 100) { - case 1: - case 2: - case 3: - break; - default: - if (pipelineError.size() == 0) - pipelineError=sendQueue.front().messageInfo - .recipients[rcptCount] + ": " + message; - break; - } - - ++rcptCount; - if (--pipelineCount || fatalError) - return; // More on the way - - if (pipelineError.size() > 0) - messageProcessed(500, pipelineError); - else - { - installHandler(&mail::smtp::dataResponse); - socketWrite("DATA\r\n"); - } -} - -// MAIL FROM response. RCPT TO response in non-pipelined mode. - -void mail::smtp::mailfromResponse(int result, string message) -{ - switch (result / 100) { - case 1: - case 2: - case 3: - break; - default: - messageProcessed(result, pipelineCmd + ": " + message); - return; - } - - struct messageQueueInfo &info=sendQueue.front(); - - rcptCount=0; - if (pipelineCount == 0 && hasCapability("PIPELINING") && - smtpLoginInfo.options.count("nopipelining") == 0) - { - string rcptto=""; - - vector<string>::iterator b=info.messageInfo.recipients.begin(), - e=info.messageInfo.recipients.end(); - - pipelineError=""; - - while (b != e) - { - rcptto += "RCPT TO:<" + *b++ + ">"; - - if (info.messageInfo.options.count("DSN") > 0) - rcptto += " NOTIFY=" - + info.messageInfo.options.find("DSN") - ->second; - rcptto += "\r\n"; - ++pipelineCount; - } - - installHandler(&mail::smtp::pipelinedResponse); - socketWrite(rcptto); - return; - } - - if (pipelineCount < info.messageInfo.recipients.size()) - { - pipelineCmd=info.messageInfo.recipients[pipelineCount++]; - string rcptto= "RCPT TO:<" + pipelineCmd + ">"; - - if (info.messageInfo.options.count("DSN") > 0) - rcptto += " NOTIFY=" - + info.messageInfo.options.find("DSN") - ->second; - - rcptto += "\r\n"; - socketWrite(rcptto); - return; - } - - installHandler(&mail::smtp::dataResponse); - socketWrite("DATA\r\n"); -} - -// 1st DATA response - -void mail::smtp::dataResponse(int result, string message) -{ - switch (result / 100) { - case 1: - case 2: - case 3: - break; - default: - messageProcessed(result, message); - break; - } - - long fpos; - - if ( fseek(sendQueue.front().message, 0L, SEEK_END) < 0 || - (fpos=ftell(sendQueue.front().message)) < 0 || - fseek(sendQueue.front().message, 0L, SEEK_SET) < 0 || - (myBlaster=new Blast(this)) == NULL) - - { - fatalError=true; - messageProcessed(500, strerror(errno)); - return; - } - - myBlaster->bytesTotal=fpos; - installHandler(&mail::smtp::data2Response); - socketWrite(myBlaster); -} - -void mail::smtp::data2Response(int result, string message) -{ - if (myBlaster) - myBlaster->mySmtp=NULL; - installHandler(NULL); // Nothing more. - messageProcessed(result, message); -} - -bool mail::smtp::validString(string s) -{ - string::iterator b=s.begin(), e=s.end(); - - while (b != e) - { - if ((int)(unsigned char)*b <= ' ' || *b == '>' || *b == '<') - { - messageProcessed(500, "500 Invalid character in message sender, recipient, or options."); - return false; - } - b++; - } - return true; -} - -void mail::smtp::messageProcessed(int result, string message) -{ - struct messageQueueInfo &info=sendQueue.front(); - - mail::callback *callback=info.callback; - fclose(info.message); - - try { - sendQueue.pop(); - if (!sendQueue.empty()) - startNextMessage(); - else - pingTimeout=time(NULL) + INACTIVITY_TIMEOUT; - - switch (result / 100) { - case 1: - case 2: - case 3: - callback->success(message); - break; - default: - callback->fail(message); - break; - } - - } catch (...) { - callback->fail("An exception has occurred while processing message."); - } -} - -string mail::smtp::translatePath(string path) -{ - return "INBOX"; // NOOP -} |
