diff options
Diffstat (limited to 'src/messaging')
-rw-r--r-- | src/messaging/builtinServices.inl | 5 | ||||
-rw-r--r-- | src/messaging/imap/IMAPFolder.cpp | 6 | ||||
-rw-r--r-- | src/messaging/imap/IMAPMessage.cpp | 13 | ||||
-rw-r--r-- | src/messaging/maildir/maildirFolder.cpp | 9 | ||||
-rw-r--r-- | src/messaging/maildir/maildirMessage.cpp | 6 | ||||
-rw-r--r-- | src/messaging/pop3/POP3Folder.cpp | 6 | ||||
-rw-r--r-- | src/messaging/pop3/POP3Message.cpp | 7 | ||||
-rw-r--r-- | src/messaging/pop3/POP3Store.cpp | 6 | ||||
-rw-r--r-- | src/messaging/sendmail/sendmailTransport.cpp | 387 | ||||
-rw-r--r-- | src/messaging/smtp/SMTPTransport.cpp | 64 | ||||
-rw-r--r-- | src/messaging/transport.cpp | 2 |
11 files changed, 429 insertions, 82 deletions
diff --git a/src/messaging/builtinServices.inl b/src/messaging/builtinServices.inl index cea2f7a8..d1b63a30 100644 --- a/src/messaging/builtinServices.inl +++ b/src/messaging/builtinServices.inl @@ -47,5 +47,10 @@ REGISTER_SERVICE(maildir::maildirStore, maildir); #endif +#if VMIME_BUILTIN_MESSAGING_PROTO_SENDMAIL + #include "vmime/messaging/sendmail/sendmailTransport.hpp" + REGISTER_SERVICE(sendmail::sendmailTransport, sendmail); +#endif + #endif // VMIME_BUILDING_DOC diff --git a/src/messaging/imap/IMAPFolder.cpp b/src/messaging/imap/IMAPFolder.cpp index 5bbfa148..39404c82 100644 --- a/src/messaging/imap/IMAPFolder.cpp +++ b/src/messaging/imap/IMAPFolder.cpp @@ -596,7 +596,7 @@ std::vector <folder*> IMAPFolder::getFolders(const bool recursive) void IMAPFolder::fetchMessages(std::vector <message*>& msg, const int options, - progressionListener* progress) + utility::progressionListener* progress) { if (!m_store) throw exceptions::illegal_state("Store disconnected"); @@ -1045,7 +1045,7 @@ void IMAPFolder::setMessageFlags(const string& set, const int flags, const int m void IMAPFolder::addMessage(vmime::message* msg, const int flags, - vmime::datetime* date, progressionListener* progress) + vmime::datetime* date, utility::progressionListener* progress) { std::ostringstream oss; utility::outputStreamAdapter ossAdapter(oss); @@ -1060,7 +1060,7 @@ void IMAPFolder::addMessage(vmime::message* msg, const int flags, void IMAPFolder::addMessage(utility::inputStream& is, const int size, const int flags, - vmime::datetime* date, progressionListener* progress) + vmime::datetime* date, utility::progressionListener* progress) { if (!m_store) throw exceptions::illegal_state("Store disconnected"); diff --git a/src/messaging/imap/IMAPMessage.cpp b/src/messaging/imap/IMAPMessage.cpp index 629668c5..a2220c68 100644 --- a/src/messaging/imap/IMAPMessage.cpp +++ b/src/messaging/imap/IMAPMessage.cpp @@ -243,7 +243,7 @@ class IMAPMessage_literalHandler : public IMAPParser::literalHandler { public: - IMAPMessage_literalHandler(utility::outputStream& os, progressionListener* progress) + IMAPMessage_literalHandler(utility::outputStream& os, utility::progressionListener* progress) : m_os(os), m_progress(progress) { } @@ -268,7 +268,7 @@ public: private: utility::outputStream& m_os; - progressionListener* m_progress; + utility::progressionListener* m_progress; }; #endif // VMIME_BUILDING_DOC @@ -366,7 +366,7 @@ const header& IMAPMessage::getHeader() const } -void IMAPMessage::extract(utility::outputStream& os, progressionListener* progress, +void IMAPMessage::extract(utility::outputStream& os, utility::progressionListener* progress, const int start, const int length) const { if (!m_folder) @@ -377,7 +377,7 @@ void IMAPMessage::extract(utility::outputStream& os, progressionListener* progre void IMAPMessage::extractPart - (const part& p, utility::outputStream& os, progressionListener* progress, + (const part& p, utility::outputStream& os, utility::progressionListener* progress, const int start, const int length) const { if (!m_folder) @@ -401,8 +401,9 @@ void IMAPMessage::fetchPartHeader(part& p) } -void IMAPMessage::extract(const part* p, utility::outputStream& os, progressionListener* progress, - const int start, const int length, const bool headerOnly) const +void IMAPMessage::extract(const part* p, utility::outputStream& os, + utility::progressionListener* progress, const int start, + const int length, const bool headerOnly) const { IMAPMessage_literalHandler literalHandler(os, progress); diff --git a/src/messaging/maildir/maildirFolder.cpp b/src/messaging/maildir/maildirFolder.cpp index c3b7e71c..fa337d09 100644 --- a/src/messaging/maildir/maildirFolder.cpp +++ b/src/messaging/maildir/maildirFolder.cpp @@ -839,7 +839,7 @@ void maildirFolder::setMessageFlagsImpl void maildirFolder::addMessage(vmime::message* msg, const int flags, - vmime::datetime* date, progressionListener* progress) + vmime::datetime* date, utility::progressionListener* progress) { std::ostringstream oss; utility::outputStreamAdapter ossAdapter(oss); @@ -854,7 +854,7 @@ void maildirFolder::addMessage(vmime::message* msg, const int flags, void maildirFolder::addMessage(utility::inputStream& is, const int size, - const int flags, vmime::datetime* /* date */, progressionListener* progress) + const int flags, vmime::datetime* /* date */, utility::progressionListener* progress) { if (!m_store) throw exceptions::illegal_state("Store disconnected"); @@ -938,7 +938,8 @@ void maildirFolder::addMessage(utility::inputStream& is, const int size, void maildirFolder::copyMessageImpl(const utility::file::path& tmpDirPath, const utility::file::path& curDirPath, const utility::file::path::component& filename, - utility::inputStream& is, const utility::stream::size_type size, progressionListener* progress) + utility::inputStream& is, const utility::stream::size_type size, + utility::progressionListener* progress) { utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory(); @@ -1295,7 +1296,7 @@ store* maildirFolder::getStore() void maildirFolder::fetchMessages(std::vector <message*>& msg, - const int options, progressionListener* progress) + const int options, utility::progressionListener* progress) { if (!m_store) throw exceptions::illegal_state("Store disconnected"); diff --git a/src/messaging/maildir/maildirMessage.cpp b/src/messaging/maildir/maildirMessage.cpp index 9b728359..2815e980 100644 --- a/src/messaging/maildir/maildirMessage.cpp +++ b/src/messaging/maildir/maildirMessage.cpp @@ -309,14 +309,14 @@ void maildirMessage::setFlags(const int flags, const int mode) void maildirMessage::extract(utility::outputStream& os, - progressionListener* progress, const int start, const int length) const + utility::progressionListener* progress, const int start, const int length) const { extractImpl(os, progress, 0, m_size, start, length); } void maildirMessage::extractPart(const part& p, utility::outputStream& os, - progressionListener* progress, const int start, const int length) const + utility::progressionListener* progress, const int start, const int length) const { const maildirPart& mp = dynamic_cast <const maildirPart&>(p); @@ -324,7 +324,7 @@ void maildirMessage::extractPart(const part& p, utility::outputStream& os, } -void maildirMessage::extractImpl(utility::outputStream& os, progressionListener* progress, +void maildirMessage::extractImpl(utility::outputStream& os, utility::progressionListener* progress, const int start, const int length, const int partialStart, const int partialLength) const { utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory(); diff --git a/src/messaging/pop3/POP3Folder.cpp b/src/messaging/pop3/POP3Folder.cpp index c70e2b5b..6f4cb237 100644 --- a/src/messaging/pop3/POP3Folder.cpp +++ b/src/messaging/pop3/POP3Folder.cpp @@ -293,7 +293,7 @@ std::vector <folder*> POP3Folder::getFolders(const bool /* recursive */) void POP3Folder::fetchMessages(std::vector <message*>& msg, const int options, - progressionListener* progress) + utility::progressionListener* progress) { if (!m_store) throw exceptions::illegal_state("Store disconnected"); @@ -681,14 +681,14 @@ void POP3Folder::rename(const folder::path& /* newPath */) void POP3Folder::addMessage(vmime::message* /* msg */, const int /* flags */, - vmime::datetime* /* date */, progressionListener* /* progress */) + vmime::datetime* /* date */, utility::progressionListener* /* progress */) { throw exceptions::operation_not_supported(); } void POP3Folder::addMessage(utility::inputStream& /* is */, const int /* size */, const int /* flags */, - vmime::datetime* /* date */, progressionListener* /* progress */) + vmime::datetime* /* date */, utility::progressionListener* /* progress */) { throw exceptions::operation_not_supported(); } diff --git a/src/messaging/pop3/POP3Message.cpp b/src/messaging/pop3/POP3Message.cpp index 01680d34..46d57ba9 100644 --- a/src/messaging/pop3/POP3Message.cpp +++ b/src/messaging/pop3/POP3Message.cpp @@ -110,8 +110,8 @@ const header& POP3Message::getHeader() const } -void POP3Message::extract(utility::outputStream& os, progressionListener* progress, - const int start, const int length) const +void POP3Message::extract(utility::outputStream& os, + utility::progressionListener* progress, const int start, const int length) const { if (!m_folder) throw exceptions::illegal_state("Folder closed"); @@ -146,7 +146,8 @@ void POP3Message::extract(utility::outputStream& os, progressionListener* progre void POP3Message::extractPart - (const part& /* p */, utility::outputStream& /* os */, progressionListener* /* progress */, + (const part& /* p */, utility::outputStream& /* os */, + utility::progressionListener* /* progress */, const int /* start */, const int /* length */) const { throw exceptions::operation_not_supported(); diff --git a/src/messaging/pop3/POP3Store.cpp b/src/messaging/pop3/POP3Store.cpp index d6ece2a0..69e09bc6 100644 --- a/src/messaging/pop3/POP3Store.cpp +++ b/src/messaging/pop3/POP3Store.cpp @@ -311,7 +311,7 @@ void POP3Store::sendRequest(const string& buffer, const bool end) void POP3Store::readResponse(string& buffer, const bool multiLine, - progressionListener* progress) + utility::progressionListener* progress) { bool foundTerminator = false; int current = 0, total = 0; @@ -406,8 +406,8 @@ void POP3Store::readResponse(string& buffer, const bool multiLine, } -void POP3Store::readResponse(utility::outputStream& os, progressionListener* progress, - const int predictedSize) +void POP3Store::readResponse(utility::outputStream& os, + utility::progressionListener* progress, const int predictedSize) { bool foundTerminator = false; int current = 0, total = predictedSize; diff --git a/src/messaging/sendmail/sendmailTransport.cpp b/src/messaging/sendmail/sendmailTransport.cpp new file mode 100644 index 00000000..87d1637f --- /dev/null +++ b/src/messaging/sendmail/sendmailTransport.cpp @@ -0,0 +1,387 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2005 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include "vmime/messaging/sendmail/sendmailTransport.hpp" + +#include "vmime/exception.hpp" +#include "vmime/platformDependant.hpp" +#include "vmime/message.hpp" +#include "vmime/mailboxList.hpp" + +#include "vmime/messaging/authHelper.hpp" + +#include "vmime/utility/filteredStream.hpp" + + +#if VMIME_BUILTIN_PLATFORM_POSIX + + +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/wait.h> + + +namespace vmime { +namespace messaging { +namespace sendmail { + + +sendmailTransport::sendmailTransport(session* sess, authenticator* auth) + : transport(sess, getInfosInstance(), auth), m_connected(false) +{ +} + + +sendmailTransport::~sendmailTransport() +{ + if (isConnected()) + disconnect(); +} + + +const string sendmailTransport::getProtocolName() const +{ + return "sendmail"; +} + + +void sendmailTransport::connect() +{ + if (isConnected()) + throw exceptions::already_connected(); + + // Use the specified path for 'sendmail' or a default one if no path is specified + m_sendmailPath = getSession()->getProperties().getProperty + (sm_infos.getPropertyPrefix() + "binpath", string(VMIME_SENDMAIL_PATH)); + + m_connected = true; +} + + +const bool sendmailTransport::isConnected() const +{ + return (m_connected); +} + + +void sendmailTransport::disconnect() +{ + if (!isConnected()) + throw exceptions::not_connected(); + + internalDisconnect(); +} + + +void sendmailTransport::internalDisconnect() +{ + m_connected = false; +} + + +void sendmailTransport::noop() +{ + // Do nothing +} + + +void sendmailTransport::send + (const mailbox& expeditor, const mailboxList& recipients, + utility::inputStream& is, const utility::stream::size_type size, + utility::progressionListener* progress) +{ + // If no recipient/expeditor was found, throw an exception + if (recipients.isEmpty()) + throw exceptions::no_recipient(); + else if (expeditor.isEmpty()) + throw exceptions::no_expeditor(); + + // Construct the argument list + std::vector <string> args; + + args.push_back("-i"); + args.push_back("-f"); + args.push_back(expeditor.getEmail()); + args.push_back("--"); + + for (int i = 0 ; i < recipients.getMailboxCount() ; ++i) + args.push_back(recipients.getMailboxAt(i)->getEmail()); + + // Call sendmail + try + { + internalSend(args, is, size, progress); + } + catch (vmime::exception& e) + { + throw exceptions::command_error("SEND", "", "sendmail failed", e); + } +} + + +static const string getSignalMessage(const int num) +{ + switch (num) + { + case SIGHUP: return "SIGHUP"; + case SIGINT: return "SIGINT"; + case SIGQUIT: return "SIGQUIT"; + case SIGILL: return "SIGILL"; + case SIGABRT: return "SIGABRT"; + case SIGFPE: return "SIGFPE"; + case SIGKILL: return "SIGKILL"; + case SIGSEGV: return "SIGSEGV"; + case SIGPIPE: return "SIGPIPE"; + case SIGALRM: return "SIGALRM"; + case SIGTERM: return "SIGTERM"; + case SIGUSR1: return "SIGUSR1"; + case SIGUSR2: return "SIGUSR2"; + case SIGCHLD: return "SIGCHLD"; + case SIGCONT: return "SIGCONT"; + case SIGSTOP: return "SIGSTOP"; + case SIGTSTP: return "SIGTSTP"; + case SIGTTIN: return "SIGTTIN"; + case SIGTTOU: return "SIGTTOU"; + } + + return "(unknown)"; +} + + +static const string getErrorMessage(const int num) +{ +#ifdef strerror_r + char res[256]; + res[0] = '\0'; + + strerror_r(num, res, sizeof(res)); + + return string(res); +#else + return string(strerror(num)); +#endif +} + + + +#ifndef VMIME_BUILDING_DOC + +// Output stream adapter for UNIX pipe + +class outputStreamPipeAdapter : public utility::outputStream +{ +public: + + outputStreamPipeAdapter(const int desc) + : m_desc(desc) + { + } + + void write(const value_type* const data, const size_type count) + { + if (::write(m_desc, data, count) == -1) + { + const string errorMsg = getErrorMessage(errno); + throw exceptions::system_error(errorMsg); + } + } + +private: + + int m_desc; +}; + +#endif // VMIME_BUILDING_DOC + + + +// The following code is highly inspired and adapted from the 'sendmail' +// provider module in Evolution data server code. +// +// Original authors: Dan Winship <[email protected]> +// Copyright 2000 Ximian, Inc. (www.ximian.com) + +void sendmailTransport::internalSend + (const std::vector <string> args, utility::inputStream& is, + const utility::stream::size_type size, utility::progressionListener* progress) +{ + // Construct C-style argument array + const char** argv = new const char*[args.size() + 2]; + + argv[0] = "sendmail"; + argv[args.size()] = NULL; + + for (unsigned int i = 0 ; i < args.size() ; ++i) + argv[i + 1] = args[i].c_str(); + + // Create a pipe to communicate with sendmail + int fd[2]; + + if (pipe(fd) == -1) + { + throw exceptions::system_error(getErrorMessage(errno)); + } + + // Block SIGCHLD so the calling application doesn't notice + // sendmail exiting before we do + sigset_t mask, oldMask; + + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &oldMask); + + // Spawn 'sendmail' process + pid_t pid = fork(); + + if (pid == -1) // error + { + const string errorMsg = getErrorMessage(errno); + + sigprocmask(SIG_SETMASK, &oldMask, NULL); + + close(fd[0]); + close(fd[1]); + + throw exceptions::system_error(errorMsg); + } + else if (pid == 0) // child process + { + dup2(fd[0], STDIN_FILENO); + close(fd[1]); + + execv(m_sendmailPath.c_str(), const_cast <char**>(argv)); + _exit(255); + } + + close(fd[0]); + + // Copy message data from input stream to output pipe + try + { + outputStreamPipeAdapter pos(fd[1]); + + // Workaround for lame sendmail implementations that + // can't handle CRLF eoln sequences: we transform CRLF + // sequences into LF characters. + utility::CRLFToLFFilteredOutputStream fos(pos); + + // TODO: remove 'Bcc:' field from message header + + utility::bufferedStreamCopy(is, fos, size, progress); + } + catch (exception& e) + { + close(fd[1]); + + int wstat; + + while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR) + ; + + sigprocmask(SIG_SETMASK, &oldMask, NULL); + + throw; + } + + close(fd[1]); + + // Wait for sendmail to exit + int wstat; + + while (waitpid(pid, &wstat, 0) == -1 && errno == EINTR) + ; + + sigprocmask(SIG_SETMASK, &oldMask, NULL); + + if (!WIFEXITED(wstat)) + { + throw exceptions::system_error("sendmail exited with signal " + + getSignalMessage(WTERMSIG(wstat)) + ", mail not sent"); + } + else if (WEXITSTATUS(wstat) != 0) + { + if (WEXITSTATUS(wstat) == 255) + { + std::ostringstream oss; + oss << "Could not execute '" << m_sendmailPath; + oss << "', mail not sent"; + + throw exceptions::system_error(oss.str()); + } + else + { + std::ostringstream oss; + oss << "sendmail exited with status " << WEXITSTATUS(wstat); + oss << ", mail not sent"; + + throw exceptions::system_error(oss.str()); + } + } +} + + +// Service infos + +sendmailTransport::_infos sendmailTransport::sm_infos; + + +const serviceInfos& sendmailTransport::getInfosInstance() +{ + return (sm_infos); +} + + +const serviceInfos& sendmailTransport::getInfos() const +{ + return (sm_infos); +} + + +const port_t sendmailTransport::_infos::getDefaultPort() const +{ + return (0); +} + + +const string sendmailTransport::_infos::getPropertyPrefix() const +{ + return "transport.sendmail."; +} + + +const std::vector <string> sendmailTransport::_infos::getAvailableProperties() const +{ + std::vector <string> list; + + // Path to sendmail (override default) + list.push_back("binpath"); + + return (list); +} + + +} // sendmail +} // messaging +} // vmime + + +#endif // VMIME_BUILTIN_PLATFORM_POSIX diff --git a/src/messaging/smtp/SMTPTransport.cpp b/src/messaging/smtp/SMTPTransport.cpp index 16fc1454..4f7df174 100644 --- a/src/messaging/smtp/SMTPTransport.cpp +++ b/src/messaging/smtp/SMTPTransport.cpp @@ -26,6 +26,8 @@ #include "vmime/messaging/authHelper.hpp" +#include "vmime/utility/filteredStream.hpp" + namespace vmime { namespace messaging { @@ -259,7 +261,7 @@ void SMTPTransport::noop() void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, - progressionListener* progress) + utility::progressionListener* progress) { // If no recipient/expeditor was found, throw an exception if (recipients.isEmpty()) @@ -304,63 +306,13 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients throw exceptions::command_error("DATA", response); } - int current = 0, total = size; - - if (progress) - progress->start(total); - - char buffer[65536]; - char previousChar = '\0'; - - while (!is.eof()) - { - const int read = is.read(buffer, sizeof(buffer)); - - // Transform '.' into '..' at the beginning of a line - char* start = buffer; - char* end = buffer + read; - char* pos = buffer; - - while ((pos = std::find(pos, end, '.')) != end) - { - // '\n' in the previous buffer, '.' in the current one - if (pos == buffer && previousChar == '\n') - { - m_socket->sendRaw(".", 1); - } - // Both '\n' and '.' are in the current buffer - else if (pos > buffer && *(pos - 1) == '\n') - { - m_socket->sendRaw(start, pos - start); - m_socket->sendRaw(".", 1); - - start = pos; - } - - ++pos; - } - - if (read > 0) - previousChar = buffer[read - 1]; - else - previousChar = '\0'; - - // Send the remaining data - m_socket->sendRaw(start, end - start); - - current += read; - - // Notify progression - if (progress) - { - total = std::max(total, current); - progress->progress(current, total); - } - } + // Stream copy with "\n." to "\n.." transformation + utility::outputStreamSocketAdapter sos(*m_socket); + utility::dotFilteredOutputStream fos(sos); - if (progress) - progress->stop(total); + utility::bufferedStreamCopy(is, fos, size, progress); + // Send end-of-data delimiter m_socket->sendRaw("\r\n.\r\n", 5); readResponse(response); diff --git a/src/messaging/transport.cpp b/src/messaging/transport.cpp index 1caa7fae..0b52aa39 100644 --- a/src/messaging/transport.cpp +++ b/src/messaging/transport.cpp @@ -47,7 +47,7 @@ static void extractMailboxes } -void transport::send(vmime::message* msg, progressionListener* progress) +void transport::send(vmime::message* msg, utility::progressionListener* progress) { // Extract expeditor mailbox expeditor; |