aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/imap/IMAPUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/imap/IMAPUtils.cpp')
-rw-r--r--src/net/imap/IMAPUtils.cpp758
1 files changed, 0 insertions, 758 deletions
diff --git a/src/net/imap/IMAPUtils.cpp b/src/net/imap/IMAPUtils.cpp
deleted file mode 100644
index ff81ce71..00000000
--- a/src/net/imap/IMAPUtils.cpp
+++ /dev/null
@@ -1,758 +0,0 @@
-//
-// VMime library (http://www.vmime.org)
-// Copyright (C) 2002-2013 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 3 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.,
-// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-//
-// Linking this library statically or dynamically with other modules is making
-// a combined work based on this library. Thus, the terms and conditions of
-// the GNU General Public License cover the whole combination.
-//
-
-#include "vmime/config.hpp"
-
-
-#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
-
-
-#include "vmime/net/imap/IMAPUtils.hpp"
-#include "vmime/net/imap/IMAPStore.hpp"
-
-#include "vmime/net/message.hpp"
-#include "vmime/net/folder.hpp"
-
-#include <sstream>
-#include <iterator>
-#include <algorithm>
-
-
-namespace vmime {
-namespace net {
-namespace imap {
-
-
-// static
-const string IMAPUtils::quoteString(const string& text)
-{
- //
- // ATOM_CHAR ::= <any CHAR except atom_specials>
- //
- // atom_specials ::= "(" / ")" / "{" / SPACE / CTL /
- // list_wildcards / quoted_specials
- //
- // list_wildcards ::= "%" / "*"
- //
- // quoted_specials ::= <"> / "\"
- //
- // CHAR ::= <any 7-bit US-ASCII character except NUL,
- // 0x01 - 0x7f>
- //
- // CTL ::= <any ASCII control character and DEL,
- // 0x00 - 0x1f, 0x7f>
- //
-
- bool needQuoting = text.empty();
-
- for (string::const_iterator it = text.begin() ;
- !needQuoting && it != text.end() ; ++it)
- {
- const unsigned char c = *it;
-
- switch (c)
- {
- case '(':
- case ')':
- case '{':
- case 0x20: // SPACE
- case '%':
- case '*':
- case '"':
- case '\\':
-
- needQuoting = true;
- break;
-
- default:
-
- if (c <= 0x1f || c >= 0x7f)
- needQuoting = true;
- }
- }
-
- if (needQuoting)
- {
- string quoted;
- quoted.reserve((text.length() * 3) / 2 + 2);
-
- quoted += '"';
-
- for (string::const_iterator it = text.begin() ; it != text.end() ; ++it)
- {
- const unsigned char c = *it;
-
- if (c == '\\' || c == '"')
- quoted += '\\';
-
- quoted += c;
- }
-
- quoted += '"';
-
- return (quoted);
- }
- else
- {
- return (text);
- }
-}
-
-
-const string IMAPUtils::pathToString
- (const char hierarchySeparator, const folder::path& path)
-{
- string result;
-
- for (size_t i = 0 ; i < path.getSize() ; ++i)
- {
- if (i > 0) result += hierarchySeparator;
- result += toModifiedUTF7(hierarchySeparator, path[i]);
- }
-
- return (result);
-}
-
-
-const folder::path IMAPUtils::stringToPath
- (const char hierarchySeparator, const string& str)
-{
- folder::path result;
- string::const_iterator begin = str.begin();
-
- for (string::const_iterator it = str.begin() ; it != str.end() ; ++it)
- {
- if (*it == hierarchySeparator)
- {
- result /= fromModifiedUTF7(string(begin, it));
- begin = it + 1;
- }
- }
-
- if (begin != str.end())
- {
- result /= fromModifiedUTF7(string(begin, str.end()));
- }
-
- return (result);
-}
-
-
-const string IMAPUtils::toModifiedUTF7
- (const char hierarchySeparator, const folder::path::component& text)
-{
- // We will replace the hierarchy separator with an equivalent
- // UTF-7 sequence, so we compute it here...
- const char base64alphabet[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,=";
-
- const unsigned int hs = static_cast <unsigned int>(static_cast <unsigned char>(hierarchySeparator));
-
- string hsUTF7;
- hsUTF7.resize(3);
-
- hsUTF7[0] = base64alphabet[0];
- hsUTF7[1] = base64alphabet[(hs & 0xF0) >> 4];
- hsUTF7[2] = base64alphabet[(hs & 0x0F) << 2];
-
- // iconv() is buggy with UTF-8 to UTF-7 conversion, so we do it "by hand".
- // This code is largely inspired from "imap/utf7.c", in mutt 1.4.
- // Copyright (C) 2000 Edmund Grimley Evans <[email protected]>
-
- // WARNING: This may throw "exceptions::charset_conv_error"
- const string cvt = text.getConvertedText(charset(charsets::UTF_8));
-
- // In the worst case we convert 2 chars to 7 chars.
- // For example: "\x10&\x10&..." -> "&ABA-&-&ABA-&-...".
- string out;
- out.reserve((cvt.length() / 2) * 7 + 6);
-
- int b = 0, k = 0;
- bool base64 = false;
-
- size_t remaining = cvt.length();
-
- for (size_t i = 0, len = cvt.length() ; i < len ; )
- {
- const unsigned char c = cvt[i];
-
- // Replace hierarchy separator with an equivalent UTF-7 Base64 sequence
- if (!base64 && c == hierarchySeparator)
- {
- out += "&" + hsUTF7 + "-";
-
- ++i;
- --remaining;
- continue;
- }
-
- size_t n = 0;
- int ch = 0;
-
- if (c < 0x80)
- ch = c, n = 0;
- else if (c < 0xc2)
- return "";
- else if (c < 0xe0)
- ch = c & 0x1f, n = 1;
- else if (c < 0xf0)
- ch = c & 0x0f, n = 2;
- else if (c < 0xf8)
- ch = c & 0x07, n = 3;
- else if (c < 0xfc)
- ch = c & 0x03, n = 4;
- else if (c < 0xfe)
- ch = c & 0x01, n = 5;
- else
- return "";
-
- if (n > remaining)
- return ""; // error
-
- ++i;
- --remaining;
-
- for (size_t j = 0 ; j < n ; j++)
- {
- if ((cvt[i + j] & 0xc0) != 0x80)
- return ""; // error
-
- ch = (ch << 6) | (cvt[i + j] & 0x3f);
- }
-
- if (n > 1 && !(ch >> (n * 5 + 1)))
- return ""; // error
-
- i += n;
- remaining -= n;
-
- if (ch < 0x20 || ch >= 0x7f)
- {
- if (!base64)
- {
- out += '&';
- base64 = true;
- b = 0;
- k = 10;
- }
-
- if (ch & ~0xffff)
- ch = 0xfffe;
-
- out += base64alphabet[b | ch >> k];
-
- k -= 6;
-
- for ( ; k >= 0 ; k -= 6)
- out += base64alphabet[(ch >> k) & 0x3f];
-
- b = (ch << (-k)) & 0x3f;
- k += 16;
- }
- else
- {
- if (base64)
- {
- if (k > 10)
- out += base64alphabet[b];
-
- out += '-';
- base64 = false;
- }
-
- out += static_cast <char>(ch);
-
- if (ch == '&')
- out += '-';
- }
- }
-
- if (base64)
- {
- if (k > 10)
- out += base64alphabet[b];
-
- out += '-';
- }
-
- return (out);
-}
-
-
-const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text)
-{
- // Transcode from modified UTF-7 (RFC-2060).
- string out;
- out.reserve(text.length());
-
- bool inB64sequence = false;
- unsigned char prev = 0;
-
- for (string::const_iterator it = text.begin() ; it != text.end() ; ++it)
- {
- const unsigned char c = *it;
-
- switch (c)
- {
- // Start of Base64 sequence
- case '&':
- {
- if (!inB64sequence)
- {
- inB64sequence = true;
- out += '+';
- }
- else
- {
- out += '&';
- }
-
- break;
- }
- // End of Base64 sequence (or "&-" --> "&")
- case '-':
- {
- if (inB64sequence && prev == '&')
- out += '&';
- else
- out += '-';
-
- inB64sequence = false;
- break;
- }
- // ',' is used instead of '/' in modified Base64
- case ',':
- {
- out += (inB64sequence ? '/' : ',');
- break;
- }
- default:
- {
- out += c;
- break;
- }
-
- }
-
- prev = c;
- }
-
- // Store it as UTF-8 by default
- string cvt;
- charset::convert(out, cvt,
- charset(charsets::UTF_7), charset(charsets::UTF_8));
-
- return (folder::path::component(cvt, charset(charsets::UTF_8)));
-}
-
-
-int IMAPUtils::folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list)
-{
- // Get folder type
- int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS;
- const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
-
- for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
- it != flags.end() ; ++it)
- {
- if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
- type &= ~folder::TYPE_CONTAINS_MESSAGES;
- }
-
- if (type & folder::TYPE_CONTAINS_MESSAGES)
- type &= ~folder::TYPE_CONTAINS_FOLDERS;
-
- return (type);
-}
-
-
-int IMAPUtils::folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list)
-{
- // Get folder flags
- int folderFlags = folder::FLAG_CHILDREN;
- const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
-
- for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
- it != flags.end() ; ++it)
- {
- if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
- folderFlags |= folder::FLAG_NO_OPEN;
- else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS)
- folderFlags &= ~folder::FLAG_CHILDREN;
- }
-
- return (folderFlags);
-}
-
-
-int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list* list)
-{
- const std::vector <IMAPParser::flag*>& flagList = list->flags();
- int flags = 0;
-
- for (std::vector <IMAPParser::flag*>::const_iterator
- it = flagList.begin() ; it != flagList.end() ; ++it)
- {
- switch ((*it)->type())
- {
- case IMAPParser::flag::ANSWERED:
- flags |= message::FLAG_REPLIED;
- break;
- case IMAPParser::flag::FLAGGED:
- flags |= message::FLAG_MARKED;
- break;
- case IMAPParser::flag::DELETED:
- flags |= message::FLAG_DELETED;
- break;
- case IMAPParser::flag::SEEN:
- flags |= message::FLAG_SEEN;
- break;
- case IMAPParser::flag::DRAFT:
- flags |= message::FLAG_DRAFT;
- break;
-
- default:
- //case IMAPParser::flag::UNKNOWN:
- break;
- }
- }
-
- return (flags);
-}
-
-
-const string IMAPUtils::messageFlagList(const int flags)
-{
- std::vector <string> flagList;
-
- if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered");
- if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged");
- if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted");
- if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen");
- if (flags & message::FLAG_DRAFT) flagList.push_back("\\Draft");
-
- if (!flagList.empty())
- {
- std::ostringstream res;
- res.imbue(std::locale::classic());
-
- res << "(";
-
- if (flagList.size() >= 2)
- {
- std::copy(flagList.begin(), flagList.end() - 1,
- std::ostream_iterator <string>(res, " "));
- }
-
- res << *(flagList.end() - 1) << ")";
-
- return (res.str());
- }
-
- return "";
-}
-
-
-// static
-const string IMAPUtils::dateTime(const vmime::datetime& date)
-{
- std::ostringstream res;
- res.imbue(std::locale::classic());
-
- // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
- // SPACE time SPACE zone <">
- //
- // time ::= 2digit ":" 2digit ":" 2digit
- // ;; Hours minutes seconds
- // zone ::= ("+" / "-") 4digit
- // ;; Signed four-digit value of hhmm representing
- // ;; hours and minutes west of Greenwich
- res << '"';
-
- // Date
- if (date.getDay() < 10) res << ' ';
- res << date.getDay();
-
- res << '-';
-
- static const char* monthNames[12] =
- { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
- res << monthNames[std::min(std::max(date.getMonth() - 1, 0), 11)];
-
- res << '-';
-
- if (date.getYear() < 10) res << '0';
- if (date.getYear() < 100) res << '0';
- if (date.getYear() < 1000) res << '0';
- res << date.getYear();
-
- res << ' ';
-
- // Time
- if (date.getHour() < 10) res << '0';
- res << date.getHour() << ':';
-
- if (date.getMinute() < 10) res << '0';
- res << date.getMinute() << ':';
-
- if (date.getSecond() < 10) res << '0';
- res << date.getSecond();
-
- res << ' ';
-
- // Zone
- const int zs = (date.getZone() < 0 ? -1 : 1);
- const int zh = (date.getZone() * zs) / 60;
- const int zm = (date.getZone() * zs) % 60;
-
- res << (zs < 0 ? '-' : '+');
-
- if (zh < 10) res << '0';
- res << zh;
-
- if (zm < 10) res << '0';
- res << zm;
-
- res << '"';
-
-
- return (res.str());
-}
-
-
-// static
-const string IMAPUtils::buildFetchRequest
- (shared_ptr <IMAPConnection> cnt, const messageSet& msgs, const fetchAttributes& options)
-{
- // Example:
- // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
- // S: * 2 FETCH ....
- // S: * 3 FETCH ....
- // S: * 4 FETCH ....
- // S: A654 OK FETCH completed
-
- std::vector <string> items;
-
- if (options.has(fetchAttributes::SIZE))
- items.push_back("RFC822.SIZE");
-
- if (options.has(fetchAttributes::FLAGS))
- items.push_back("FLAGS");
-
- if (options.has(fetchAttributes::STRUCTURE))
- items.push_back("BODYSTRUCTURE");
-
- if (options.has(fetchAttributes::UID))
- {
- items.push_back("UID");
-
- // Also fetch MODSEQ if CONDSTORE is supported
- if (cnt->hasCapability("CONDSTORE") && !cnt->isMODSEQDisabled())
- items.push_back("MODSEQ");
- }
-
- if (options.has(fetchAttributes::FULL_HEADER))
- items.push_back("RFC822.HEADER");
- else
- {
- if (options.has(fetchAttributes::ENVELOPE))
- items.push_back("ENVELOPE");
-
- std::vector <string> headerFields;
-
- if (options.has(fetchAttributes::CONTENT_INFO))
- headerFields.push_back("CONTENT_TYPE");
-
- if (options.has(fetchAttributes::IMPORTANCE))
- {
- headerFields.push_back("IMPORTANCE");
- headerFields.push_back("X-PRIORITY");
- }
-
- // Also add custom header fields to fetch, if any
- const std::vector <string> customHeaderFields = options.getHeaderFields();
- std::copy(customHeaderFields.begin(), customHeaderFields.end(), std::back_inserter(headerFields));
-
- if (!headerFields.empty())
- {
- string list;
-
- for (std::vector <string>::iterator it = headerFields.begin() ;
- it != headerFields.end() ; ++it)
- {
- if (it != headerFields.begin())
- list += " ";
-
- list += *it;
- }
-
- items.push_back("BODY[HEADER.FIELDS (" + list + ")]");
- }
- }
-
- // Build the request text
- std::ostringstream command;
- command.imbue(std::locale::classic());
-
- if (msgs.isUIDSet())
- command << "UID FETCH " << messageSetToSequenceSet(msgs) << " (";
- else
- command << "FETCH " << messageSetToSequenceSet(msgs) << " (";
-
- for (std::vector <string>::const_iterator it = items.begin() ;
- it != items.end() ; ++it)
- {
- if (it != items.begin()) command << " ";
- command << *it;
- }
-
- command << ")";
-
- return command.str();
-}
-
-
-// static
-void IMAPUtils::convertAddressList
- (const IMAPParser::address_list& src, mailboxList& dest)
-{
- for (std::vector <IMAPParser::address*>::const_iterator
- it = src.addresses().begin() ; it != src.addresses().end() ; ++it)
- {
- const IMAPParser::address& addr = **it;
-
- text name;
- text::decodeAndUnfold(addr.addr_name()->value(), &name);
-
- string email = addr.addr_mailbox()->value()
- + "@" + addr.addr_host()->value();
-
- dest.appendMailbox(make_shared <mailbox>(name, email));
- }
-}
-
-
-
-class IMAPUIDMessageSetEnumerator : public messageSetEnumerator
-{
-public:
-
- IMAPUIDMessageSetEnumerator()
- : m_first(true)
- {
- }
-
- void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range)
- {
- if (!m_first)
- m_oss << ",";
-
- if (range.getFirst() == range.getLast())
- m_oss << range.getFirst();
- else
- m_oss << range.getFirst() << ":" << range.getLast();
-
- m_first = false;
- }
-
- void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range)
- {
- if (!m_first)
- m_oss << ",";
-
- if (range.getFirst() == range.getLast())
- m_oss << range.getFirst();
- else
- m_oss << range.getFirst() << ":" << range.getLast();
-
- m_first = false;
- }
-
- const std::string str() const
- {
- return m_oss.str();
- }
-
-private:
-
- std::ostringstream m_oss;
- bool m_first;
-};
-
-
-class IMAPMessageSetEnumerator : public messageSetEnumerator
-{
-public:
-
- void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range)
- {
- for (int i = range.getFirst(), last = range.getLast() ; i <= last ; ++i)
- m_list.push_back(i);
- }
-
- void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */)
- {
- // Not used
- }
-
- const std::vector <int>& list() const
- {
- return m_list;
- }
-
-public:
-
- std::vector <int> m_list;
-};
-
-
-
-// static
-const string IMAPUtils::messageSetToSequenceSet(const messageSet& msgs)
-{
- IMAPUIDMessageSetEnumerator en;
- msgs.enumerate(en);
-
- return en.str();
-}
-
-
-// static
-const std::vector <int> IMAPUtils::messageSetToNumberList(const messageSet& msgs)
-{
- IMAPMessageSetEnumerator en;
- msgs.enumerate(en);
-
- return en.list();
-}
-
-
-} // imap
-} // net
-} // vmime
-
-
-#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
-