From 9192d4dcf36ca64087e0702be1ef464c1e49d208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 15 Dec 2011 00:36:07 +0100 Subject: [PATCH] Started working on the IMAP add-on itself. * Renamed imap_config.cpp to ConfigView.cpp, IMAPFolderConfig.(h|cpp) to FolderConfigWindow.(h|cpp). * Got the latter to build. * Added Settings class to simplify and unify the BMessage based settings access. * Removed the InboundProtocol[Thread] implementation from the build for now. --- headers/private/mail/ServerConnection.h | 48 -- .../imap/{imap_config.cpp => ConfigView.cpp} | 24 +- ...olderConfig.cpp => FolderConfigWindow.cpp} | 49 +-- ...MAPFolderConfig.h => FolderConfigWindow.h} | 10 +- .../mail_daemon/inbound_protocols/imap/IMAP.h | 143 ++++++ .../imap/IMAPConnectionWorker.cpp | 53 +++ .../imap/IMAPConnectionWorker.h | 38 ++ .../inbound_protocols/imap/Jamfile | 19 +- .../inbound_protocols/imap/Settings.cpp | 87 ++++ .../inbound_protocols/imap/Settings.h | 32 ++ .../imap/imap_lib/Commands.cpp | 50 +-- .../imap/imap_lib/Commands.h | 16 +- .../imap/imap_lib/Protocol.cpp | 31 +- .../imap/imap_lib/Protocol.h | 6 +- src/kits/mail/Jamfile | 1 - src/kits/mail/ServerConnection.cpp | 410 ------------------ 16 files changed, 445 insertions(+), 572 deletions(-) delete mode 100644 headers/private/mail/ServerConnection.h rename src/add-ons/mail_daemon/inbound_protocols/imap/{imap_config.cpp => ConfigView.cpp} (85%) rename src/add-ons/mail_daemon/inbound_protocols/imap/{IMAPFolderConfig.cpp => FolderConfigWindow.cpp} (87%) rename src/add-ons/mail_daemon/inbound_protocols/imap/{IMAPFolderConfig.h => FolderConfigWindow.h} (82%) create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAP.h create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp create mode 100644 src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h delete mode 100644 src/kits/mail/ServerConnection.cpp diff --git a/headers/private/mail/ServerConnection.h b/headers/private/mail/ServerConnection.h deleted file mode 100644 index 041f1b6223..0000000000 --- a/headers/private/mail/ServerConnection.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2010-2011, Haiku Inc. All Rights Reserved. - * Copyright 2010 Clemens Zeidler. All rights reserved. - * - * Distributed under the terms of the MIT License. - */ -#ifndef SERVER_CONNECTION_H -#define SERVER_CONNECTION_H - - -#include "SupportDefs.h" - - -namespace BPrivate { - - -class AbstractConnection; - - -class ServerConnection { -public: - ServerConnection(); - ~ServerConnection(); - - status_t ConnectSSL(const char* server, - uint32 port = 993); - - status_t ConnectSocket(const char* server, - uint32 port = 143); - status_t Disconnect(); - - status_t WaitForData(bigtime_t timeout); - - ssize_t Read(char* buffer, uint32 length); - ssize_t Write(const char* buffer, uint32 length); - -private: - AbstractConnection* fConnection; -}; - - -} // namespace BPrivate - - -using BPrivate::ServerConnection; - - -#endif // SERVER_CONNECTION_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_config.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/ConfigView.cpp similarity index 85% rename from src/add-ons/mail_daemon/inbound_protocols/imap/imap_config.cpp rename to src/add-ons/mail_daemon/inbound_protocols/imap/ConfigView.cpp index 2a22ed76c5..4f21f1ad7a 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_config.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/ConfigView.cpp @@ -18,7 +18,7 @@ #include #include -#include "IMAPFolderConfig.h" +#include "FolderConfigWindow.h" #undef B_TRANSLATION_CONTEXT @@ -28,11 +28,11 @@ const uint32 kMsgOpenIMAPFolder = '&OIF'; -class IMAPConfig : public BMailProtocolConfigView { +class ConfigView : public BMailProtocolConfigView { public: - IMAPConfig(MailAddonSettings& settings, + ConfigView(MailAddonSettings& settings, BMailAccountSettings& accountSettings); - virtual ~IMAPConfig(); + virtual ~ConfigView(); virtual status_t Archive(BMessage *into, bool deep = true) const; virtual void GetPreferredSize(float *width, float *height); @@ -40,13 +40,13 @@ public: virtual void AttachedToWindow(); private: - BMailFileConfigView* fFileView; + BMailFileConfigView* fFileView; BButton* fIMAPFolderButton; MailAddonSettings& fAddonSettings; }; -IMAPConfig::IMAPConfig(MailAddonSettings& settings, +ConfigView::ConfigView(MailAddonSettings& settings, BMailAccountSettings& accountSettings) : BMailProtocolConfigView(B_MAIL_PROTOCOL_HAS_USERNAME @@ -93,13 +93,13 @@ IMAPConfig::IMAPConfig(MailAddonSettings& settings, } -IMAPConfig::~IMAPConfig() +ConfigView::~ConfigView() { } status_t -IMAPConfig::Archive(BMessage *into, bool deep) const +ConfigView::Archive(BMessage *into, bool deep) const { fFileView->Archive(into, deep); return BMailProtocolConfigView::Archive(into, deep); @@ -107,7 +107,7 @@ IMAPConfig::Archive(BMessage *into, bool deep) const void -IMAPConfig::GetPreferredSize(float *width, float *height) +ConfigView::GetPreferredSize(float *width, float *height) { BMailProtocolConfigView::GetPreferredSize(width,height); *height -= 20; @@ -115,7 +115,7 @@ IMAPConfig::GetPreferredSize(float *width, float *height) void -IMAPConfig::MessageReceived(BMessage* message) +ConfigView::MessageReceived(BMessage* message) { switch (message->what) { case kMsgOpenIMAPFolder: @@ -135,7 +135,7 @@ IMAPConfig::MessageReceived(BMessage* message) void -IMAPConfig::AttachedToWindow() +ConfigView::AttachedToWindow() { fIMAPFolderButton->SetTarget(this); } @@ -148,5 +148,5 @@ BView* instantiate_config_panel(MailAddonSettings& settings, BMailAccountSettings& accountSettings) { - return new IMAPConfig(settings, accountSettings); + return new ConfigView(settings, accountSettings); } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp similarity index 87% rename from src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp rename to src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp index cada937b37..5c895b92ee 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.cpp @@ -5,7 +5,7 @@ */ -#include "IMAPFolderConfig.h" +#include "FolderConfigWindow.h" #include #include @@ -17,7 +17,7 @@ #include #include -#include +#include "Settings.h" #undef B_TRANSLATION_CONTEXT @@ -311,30 +311,15 @@ FolderConfigWindow::_LoadFolders() B_TRANSLATE("Fetching IMAP folders, have patience...")); status->Show(); - BString server; - fSettings.FindString("server", &server); - int32 ssl; - fSettings.FindInt32("flavor", &ssl); - bool useSSL = false; - if (ssl == 1) - useSSL = true; + fProtocol.Connect(fSettings.ServerAddress(), fSettings.Username(), + fSettings.Password(), fSettings.UseSSL()); - BString username; - fSettings.FindString("username", &username); - - BString password; - char* passwd = get_passwd(&fSettings, "cpasswd"); - if (passwd != NULL) { - password = passwd; - delete[] passwd; - } - - fProtocol.Connect(server, username, password, useSSL); + // TODO: don't get all of them at once, but retrieve them level by level fFolderList.clear(); fProtocol.GetFolders(fFolderList); - for (unsigned int i = 0; i < fFolderList.size(); i++) { - FolderInfo& info = fFolderList[i]; - CheckBoxItem* item = new CheckBoxItem(info.folder, info.subscribed); + for (size_t i = 0; i < fFolderList.size(); i++) { + IMAP::FolderEntry& entry = fFolderList[i]; + CheckBoxItem* item = new CheckBoxItem(entry.folder, entry.subscribed); fFolderListView->AddItem(item); item->SetListView(fFolderListView); } @@ -358,10 +343,10 @@ void FolderConfigWindow::_ApplyChanges() { bool haveChanges = false; - for (unsigned int i = 0; i < fFolderList.size(); i++) { - FolderInfo& info = fFolderList[i]; + for (size_t i = 0; i < fFolderList.size(); i++) { + IMAP::FolderEntry& entry = fFolderList[i]; CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i); - if ((info.subscribed != item->Checked())) { + if (entry.subscribed != item->Checked()) { haveChanges = true; break; } @@ -373,13 +358,13 @@ FolderConfigWindow::_ApplyChanges() "IMAP folders, have patience...")); status->Show(); - for (unsigned int i = 0; i < fFolderList.size(); i++) { - FolderInfo& info = fFolderList[i]; + for (size_t i = 0; i < fFolderList.size(); i++) { + IMAP::FolderEntry& entry = fFolderList[i]; CheckBoxItem* item = (CheckBoxItem*)fFolderListView->ItemAt(i); - if (info.subscribed && !item->Checked()) - fProtocol.UnsubscribeFolder(info.folder); - else if (!info.subscribed && item->Checked()) - fProtocol.SubscribeFolder(info.folder); + if (entry.subscribed && !item->Checked()) + fProtocol.UnsubscribeFolder(entry.folder); + else if (!entry.subscribed && item->Checked()) + fProtocol.SubscribeFolder(entry.folder); } status->PostMessage(B_QUIT_REQUESTED); diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.h similarity index 82% rename from src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h rename to src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.h index f9a8fde127..d89187842f 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPFolderConfig.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/FolderConfigWindow.h @@ -3,8 +3,8 @@ * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. */ -#ifndef IMAP_FOLDER_CONFIG_H -#define IMAP_FOLDER_CONFIG_H +#ifndef FOLDER_CONFIG_WINDOW_H +#define FOLDER_CONFIG_WINDOW_H #include @@ -15,6 +15,7 @@ #include #include "Protocol.h" +#include "Settings.h" class FolderConfigWindow : public BWindow { @@ -28,14 +29,15 @@ private: void _LoadFolders(); void _ApplyChanges(); +private: + const Settings fSettings; IMAP::Protocol fProtocol; BListView* fFolderListView; BButton* fApplyButton; - const BMessage fSettings; IMAP::FolderList fFolderList; BStringView* fQuotaView; }; -#endif //IMAP_FOLDER_CONFIG_H +#endif // FOLDER_CONFIG_WINDOW_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAP.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAP.h new file mode 100644 index 0000000000..2a1eadd0d4 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAP.h @@ -0,0 +1,143 @@ +/* + * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ +#ifndef IMAP_H +#define IMAP_H + + +#include "MailProtocol.h" + +#include +#include +#include + +#include "MailSettings.h" + +#include "Protocol.h" +#include "IMAPStorage.h" + + +class DispatcherIMAPListener : public IMAPMailboxListener { +public: + DispatcherIMAPListener(MailProtocol& protocol, + IMAPStorage& storage); + + bool Lock(); + void Unlock(); + + void HeaderFetched(int32 uid, BPositionIO* data, + bool bodyIsComming); + void BodyFetched(int32 uid, BPositionIO* data); + + void NewMessagesToFetch(int32 nMessages); + void FetchEnd(); +private: + MailProtocol& fProtocol; + IMAPStorage& fStorage; +}; + + +class IMAPInboundProtocol; + + +/*! Just wait for a IDLE (watching) IMAP response in this thread. */ +class IMAPMailboxThread { +public: + IMAPMailboxThread(IMAPInboundProtocol& protocol, + IMAPMailbox& mailbox); + ~IMAPMailboxThread(); + + bool IsWatching(); + status_t SyncAndStartWatchingMailbox(); + status_t StopWatchingMailbox(); + +private: + static status_t _WatchThreadFunction(void* data); + void _Watch(); + +private: + IMAPInboundProtocol& fProtocol; + IMAPMailbox& fIMAPMailbox; + + BLocker fLock; + bool fIsWatching; + + thread_id fThread; + sem_id fWatchSyncSem; +}; + + +class IMAPInboundProtocol; + + +class MailboxWatcher : public BHandler { +public: + MailboxWatcher(IMAPInboundProtocol* protocol); + ~MailboxWatcher(); + + void StartWatching(const char* mailboxDir); + void MessageReceived(BMessage* message); +private: + node_ref fWatchDir; + IMAPInboundProtocol* fProtocol; +}; + + +class IMAPInboundProtocol : public InboundProtocol { +public: + IMAPInboundProtocol( + BMailAccountSettings* settings, + const char* mailbox); + virtual ~IMAPInboundProtocol(); + + //! thread safe interface + virtual status_t Connect(const char* server, + const char* username, const char* password, + bool useSSL = true, int32 port = -1); + virtual status_t Disconnect(); + status_t Reconnect(); + bool IsConnected(); + + virtual void SetStopNow(); + + void AddedToLooper(); + void UpdateSettings(const BMessage& settings); + + bool InterestingEntry(const entry_ref& ref); + + virtual status_t SyncMessages(); + virtual status_t FetchBody(const entry_ref& ref); + virtual status_t MarkMessageAsRead(const entry_ref& ref, + read_flags flag = B_READ); + + virtual status_t DeleteMessage(const entry_ref& ref); + virtual status_t AppendMessage(const entry_ref& ref); + + virtual status_t DeleteMessage(node_ref& node); + //! these should be thread save + virtual void FileRenamed(const entry_ref& from, + const entry_ref& to); + virtual void FileDeleted(const node_ref& node); + +protected: + BString fServer; + BString fUsername; + BString fPassword; + bool fUseSSL; + bool fIsConnected; + + BString fMailboxName; + BPath fMailboxPath; + + IMAPStorage fStorage; + IMAPMailbox fIMAPMailbox; + DispatcherIMAPListener fDispatcherIMAPListener; + + MailboxWatcher* fINBOXWatcher; + IMAPMailboxThread* fIMAPMailboxThread; +}; + + +#endif // IMAP_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp new file mode 100644 index 0000000000..03bc0b0da8 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.cpp @@ -0,0 +1,53 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "IMAPConnectionWorker.h" + + +IMAPConnectionWorker::IMAPConnectionWorker(IMAP::Protocol& protocol, + StringList& mailboxes) + : + fProtocol(protocol) +{ +} + + +IMAPConnectionWorker::~IMAPConnectionWorker() +{ +} + + +status_t +IMAPConnectionWorker::Start(bool usePush) +{ + fThread = spawn_thread(&_Worker, "imap connection worker", + B_NORMAL_PRIORITY, this); + if (fThread < 0) + return fThread; + + resume_thread(fThread); + return B_OK; +} + + +void +IMAPConnectionWorker::Stop() +{ +} + + +status_t +IMAPConnectionWorker::_Worker() +{ + return B_OK; +} + + +/*static*/ status_t +IMAPConnectionWorker::_Worker(void* self) +{ + return ((IMAPConnectionWorker*)self)->_Worker(); +} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h new file mode 100644 index 0000000000..57c1911532 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/IMAPConnectionWorker.h @@ -0,0 +1,38 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef IMAP_CONNECTION_WORKER_H +#define IMAP_CONNECTION_WORKER_H + + +#include +#include + +#include "Protocol.h" + + +class IMAPConnectionWorker { +public: + IMAPConnectionWorker(IMAP::Protocol& protocol, + StringList& mailboxes); + virtual ~IMAPConnectionWorker(); + + status_t Start(bool usePush); + void Stop(); + +private: + status_t _Worker(); + static status_t _Worker(void* self); + +private: + IMAP::Protocol& fProtocol; + BString fIdleBox; + StringList fOtherBoxes; + + BLocker fLocker; + thread_id fThread; +}; + + +#endif // IMAP_CONNECTION_WORKER_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile index 17a83c8df8..cdfb84a8d4 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Jamfile @@ -16,14 +16,16 @@ UseLibraryHeaders linprog alm ; SubDirHdrs [ FDirName $(HAIKU_TOP) headers os add-ons mail_daemon ] ; local sources = - imap_config.cpp - IMAPInboundProtocol.cpp - IMAPRootInboundProtocol.cpp - IMAPFolderConfig.cpp +# IMAPInboundProtocol.cpp +# IMAPRootInboundProtocol.cpp + ConfigView.cpp + FolderConfigWindow.cpp + IMAPConnectionWorker.cpp + Settings.cpp + # imap_lib Commands.cpp Protocol.cpp - IMAPStorage.cpp Response.cpp ; @@ -40,12 +42,11 @@ Addon IMAP : $(sources) : - be libmail.so localestub $(TARGET_NETWORK_LIBS) libalm.so - libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ] + be libmail.so localestub $(TARGET_NETWORK_LIBS) libbnetapi.so + libalm.so libshared.a [ TargetLibsupc++ ] [ TargetLibstdc++ ] ; -SEARCH on [ FGristFiles Commands.cpp IMAPMailbox.cpp - IMAPProtocol.cpp IMAPStorage.cpp Response.cpp ] +SEARCH on [ FGristFiles Commands.cpp Protocol.cpp Response.cpp ] = [ FDirName $(HAIKU_TOP) src add-ons mail_daemon inbound_protocols imap imap_lib ] ; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp new file mode 100644 index 0000000000..a872b9eb60 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.cpp @@ -0,0 +1,87 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Settings.h" + +#include + + +Settings::Settings(const BMessage& archive) + : + fMessage(archive) +{ +} + + +Settings::~Settings() +{ +} + + +BNetworkAddress +Settings::ServerAddress() const +{ + return BNetworkAddress(Server(), Port()); +} + + +BString +Settings::Server() const +{ + BString server; + if (fMessage.FindString("server", &server) == B_OK) + return server; + + return ""; +} + + +uint16 +Settings::Port() const +{ + int32 port; + if (fMessage.FindInt32("port", &port) == B_OK) + return port; + + return UseSSL() ? 993 : 143; +} + + +bool +Settings::UseSSL() const +{ + int32 flavor; + if (fMessage.FindInt32("flavor", &flavor) == B_OK) + return flavor == 1; + + return false; +} + + +BString +Settings::Username() const +{ + BString username; + if (fMessage.FindString("username", &username) == B_OK) + return username; + + return ""; +} + + +BString +Settings::Password() const +{ + BString password; + char* passwd = get_passwd(&fMessage, "cpasswd"); + if (passwd != NULL) { + password = passwd; + delete[] passwd; + return password; + } + + return ""; +} diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h new file mode 100644 index 0000000000..72a66ae640 --- /dev/null +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/Settings.h @@ -0,0 +1,32 @@ +/* + * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ +#ifndef SETTINGS_H +#define SETTINGS_H + + +#include +#include + + +class Settings { +public: + Settings(const BMessage& archive); + ~Settings(); + + BNetworkAddress ServerAddress() const; + + BString Server() const; + uint16 Port() const; + bool UseSSL() const; + + BString Username() const; + BString Password() const; + +private: + const BMessage& fMessage; +}; + + +#endif // SETTINGS_H diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp index 4c07b16eb0..aef6ba3fef 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.cpp @@ -628,18 +628,33 @@ FlagsHandler::HandleUntagged(const BString& response) // #pragma mark - +ListCommand::ListCommand(const char* prefix, bool subscribedOnly) + : + fPrefix(prefix), + fSubscribedOnly(subscribedOnly) +{ +} + + BString ListCommand::CommandString() { - fFolders.clear(); - return "LIST \"\" \"*\""; + BString command = _Command(); + command += " \"\" \""; + if (fPrefix != NULL) + command << fPrefix << "%"; + else + command += "*"; + command += "\""; + + return command; } bool ListCommand::HandleUntagged(Response& response) { - if (response.IsCommand("LIST") && response.IsStringAt(3)) { + if (response.IsCommand(_Command()) && response.IsStringAt(3)) { fFolders.push_back(response.StringAt(3)); return true; } @@ -655,33 +670,10 @@ ListCommand::FolderList() } -// #pragma mark - - - -BString -ListSubscribedCommand::CommandString() +const char* +ListCommand::_Command() const { - fFolders.clear(); - return "LSUB \"\" \"*\""; -} - - -bool -ListSubscribedCommand::HandleUntagged(Response& response) -{ - if (response.IsCommand("LSUB") && response.IsStringAt(3)) { - fFolders.push_back(response.StringAt(3)); - return true; - } - - return false; -} - - -const StringList& -ListSubscribedCommand::FolderList() -{ - return fFolders; + return fSubscribedOnly ? "LSUB" : "LIST"; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h index 6af04f7b74..8d01cc7551 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Commands.h @@ -246,25 +246,21 @@ public: class ListCommand : public Command, public Handler { public: + ListCommand(const char* prefix, + bool subscribedOnly); + BString CommandString(); bool HandleUntagged(Response& response); const StringList& FolderList(); private: - StringList fFolders; -}; - - -class ListSubscribedCommand : public Command, public Handler { -public: - BString CommandString(); - bool HandleUntagged(Response& response); - - const StringList& FolderList(); + const char* _Command() const; private: + const char* fPrefix; StringList fFolders; + bool fSubscribedOnly; }; diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp index 9b7c60f67f..585172f627 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.cpp @@ -123,16 +123,16 @@ Protocol::GetFolders(FolderList& folders) return status; for (unsigned int i = 0; i < allFolders.size(); i++) { - FolderInfo info; - info.folder = allFolders[i]; + FolderEntry entry; + entry.folder = allFolders[i]; for (unsigned int a = 0; a < subscribedFolders.size(); a++) { if (allFolders[i] == subscribedFolders[a] || allFolders[i].ICompare("INBOX") == 0) { - info.subscribed = true; + entry.subscribed = true; break; } } - folders.push_back(info); + folders.push_back(entry); } // you could be subscribed to a folder which not exist currently, add them: @@ -147,10 +147,10 @@ Protocol::GetFolders(FolderList& folders) if (isInlist) continue; - FolderInfo info; - info.folder = subscribedFolders[a]; - info.subscribed = true; - folders.push_back(info); + FolderEntry entry; + entry.folder = subscribedFolders[a]; + entry.subscribed = true; + folders.push_back(entry); } return B_OK; @@ -344,8 +344,11 @@ Protocol::_Disconnect() { fOngoingCommands.clear(); fIsConnected = false; + delete fBufferedSocket; + fBufferedSocket = NULL; delete fSocket; fSocket = NULL; + return B_OK; } @@ -353,12 +356,12 @@ Protocol::_Disconnect() status_t Protocol::_GetAllFolders(StringList& folders) { - ListCommand listCommand; - status_t status = ProcessCommand(listCommand); + ListCommand command(NULL, false); + status_t status = ProcessCommand(command); if (status != B_OK) return status; - folders = listCommand.FolderList(); + folders = command.FolderList(); return status; } @@ -366,12 +369,12 @@ Protocol::_GetAllFolders(StringList& folders) status_t Protocol::_GetSubscribedFolders(StringList& folders) { - ListSubscribedCommand listSubscribedCommand; - status_t status = ProcessCommand(listSubscribedCommand); + ListCommand command(NULL, true); + status_t status = ProcessCommand(command); if (status != B_OK) return status; - folders = listSubscribedCommand.FolderList(); + folders = command.FolderList(); return status; } diff --git a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h index 1244d1bfe9..0df14b1881 100644 --- a/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h +++ b/src/add-ons/mail_daemon/inbound_protocols/imap/imap_lib/Protocol.h @@ -36,9 +36,9 @@ typedef BObjectList HandlerList; typedef std::map CommandIDMap; -class FolderInfo { +class FolderEntry { public: - FolderInfo() + FolderEntry() : subscribed(false) { @@ -47,7 +47,7 @@ public: BString folder; bool subscribed; }; -typedef std::vector FolderList; +typedef std::vector FolderList; class Protocol { diff --git a/src/kits/mail/Jamfile b/src/kits/mail/Jamfile index 6f6bcdd9ed..1a08cca4c0 100644 --- a/src/kits/mail/Jamfile +++ b/src/kits/mail/Jamfile @@ -31,7 +31,6 @@ local sources = NodeMessage.cpp numailkit.cpp ProtocolConfigView.cpp - ServerConnection.cpp ; diff --git a/src/kits/mail/ServerConnection.cpp b/src/kits/mail/ServerConnection.cpp deleted file mode 100644 index 3afdbd833d..0000000000 --- a/src/kits/mail/ServerConnection.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright 2010-2011, Haiku, Inc. All rights reserved. - * Copyright 2010, Clemens Zeidler - * Distributed under the terms of the MIT License. - */ - - -#include "ServerConnection.h" - -#include -#include -#include - -#ifdef USE_SSL -# include -# include -#endif - -#include -#include -#include - - -#define DEBUG_SERVER_CONNECTION -#ifdef DEBUG_SERVER_CONNECTION -# include -# define TRACE(x...) printf(x) -#else -# define TRACE(x...) ; -#endif - - -namespace BPrivate { - - -class AbstractConnection { -public: - virtual ~AbstractConnection(); - - virtual status_t Connect(const char* server, uint32 port) = 0; - virtual status_t Disconnect() = 0; - - virtual status_t WaitForData(bigtime_t timeout) = 0; - - virtual ssize_t Read(char* buffer, uint32 length) = 0; - virtual ssize_t Write(const char* buffer, uint32 length) = 0; -}; - - -class SocketConnection : public AbstractConnection { -public: - SocketConnection(); - - status_t Connect(const char* server, uint32 port); - status_t Disconnect(); - - status_t WaitForData(bigtime_t timeout); - - ssize_t Read(char* buffer, uint32 length); - ssize_t Write(const char* buffer, uint32 length); - -protected: - int fSocket; -}; - - -#ifdef USE_SSL - - -class InitSSL { -public: - InitSSL() - { - if (SSL_library_init() != 1) { - fInit = false; - return; - } - - // use combination of more or less random this pointer and system time - int64 seed = (int64)this + system_time(); - RAND_seed(&seed, sizeof(seed)); - - fInit = true; - return; - }; - - - status_t InitCheck() - { - return fInit ? B_OK : B_ERROR; - } - -private: - bool fInit; -}; - - -class SSLConnection : public SocketConnection { -public: - SSLConnection(); - - status_t Connect(const char* server, uint32 port); - status_t Disconnect(); - - status_t WaitForData(bigtime_t timeout); - - ssize_t Read(char* buffer, uint32 length); - ssize_t Write(const char* buffer, uint32 length); - -private: - SSL_CTX* fCTX; - SSL* fSSL; - BIO* fBIO; -}; - - -static InitSSL gInitSSL; - - -#endif // USE_SSL - - -AbstractConnection::~AbstractConnection() -{ -} - - -// #pragma mark - - - -ServerConnection::ServerConnection() - : - fConnection(NULL) -{ -} - - -ServerConnection::~ServerConnection() -{ - if (fConnection != NULL) - fConnection->Disconnect(); - delete fConnection; -} - - -status_t -ServerConnection::ConnectSSL(const char* server, uint32 port) -{ -#ifdef USE_SSL - delete fConnection; - fConnection = new SSLConnection; - return fConnection->Connect(server, port); -#else - return B_ERROR; -#endif -} - - -status_t -ServerConnection::ConnectSocket(const char* server, uint32 port) -{ - delete fConnection; - fConnection = new SocketConnection; - return fConnection->Connect(server, port); -} - - -status_t -ServerConnection::Disconnect() -{ - if (fConnection == NULL) - return B_ERROR; - return fConnection->Disconnect(); -} - - -status_t -ServerConnection::WaitForData(bigtime_t timeout) -{ - if (fConnection == NULL) - return B_ERROR; - return fConnection->WaitForData(timeout); -} - - -ssize_t -ServerConnection::Read(char* buffer, uint32 nBytes) -{ - if (fConnection == NULL) - return B_ERROR; - return fConnection->Read(buffer, nBytes); -} - - -ssize_t -ServerConnection::Write(const char* buffer, uint32 nBytes) -{ - if (fConnection == NULL) - return B_ERROR; - return fConnection->Write(buffer, nBytes); -} - - -// #pragma mark - - - -SocketConnection::SocketConnection() - : - fSocket(-1) -{ -} - - -status_t -SocketConnection::Connect(const char* server, uint32 port) -{ - if (fSocket >= 0) - Disconnect(); - - TRACE("SocketConnection to server %s:%i\n", server, (int)port); - - BNetworkAddress address; - status_t status = address.SetTo(server, port); - if (status != B_OK) { - TRACE("%s: Address Error: %s\n", __func__, strerror(status)); - return status; - } - - TRACE("Server resolves to %s\n", address.ToString().String()); - - fSocket = socket(address.Family(), SOCK_STREAM, 0); - if (fSocket < 0) { - TRACE("%s: Socket Error: %s\n", __func__, strerror(errno)); - return errno; - } - - int result = connect(fSocket, address, address.Length()); - if (result < 0) { - TRACE("%s: Connect Error: %s\n", __func__, strerror(errno)); - close(fSocket); - return errno; - } - - TRACE("SocketConnection: connected\n"); - - return B_OK; -} - - -status_t -SocketConnection::Disconnect() -{ - close(fSocket); - fSocket = -1; - return B_OK; -} - - -status_t -SocketConnection::WaitForData(bigtime_t timeout) -{ - struct pollfd entry; - entry.fd = fSocket; - entry.events = POLLIN; - - int timeoutMillis = -1; - if (timeout > 0) - timeoutMillis = timeout / 1000; - - int result = poll(&entry, 1, timeoutMillis); - if (result == 0) - return B_TIMED_OUT; - if (result < 0) - return errno; - - return B_OK; -} - - -ssize_t -SocketConnection::Read(char* buffer, uint32 length) -{ - ssize_t bytesReceived = recv(fSocket, buffer, length, 0); - if (bytesReceived < 0) - return errno; - - return bytesReceived; -} - - -ssize_t -SocketConnection::Write(const char* buffer, uint32 length) -{ - ssize_t bytesWritten = send(fSocket, buffer, length, 0); - if (bytesWritten < 0) - return errno; - - return bytesWritten; -} - - -// #pragma mark - - - -#ifdef USE_SSL - - -SSLConnection::SSLConnection() - : - fCTX(NULL), - fSSL(NULL), - fBIO(NULL) -{ -} - - -status_t -SSLConnection::Connect(const char* server, uint32 port) -{ - if (fSSL != NULL) - Disconnect(); - - if (gInitSSL.InitCheck() != B_OK) - return B_ERROR; - - status_t status = SocketConnection::Connect(server, port); - if (status != B_OK) - return status; - - fCTX = SSL_CTX_new(SSLv23_method()); - fSSL = SSL_new(fCTX); - fBIO = BIO_new_socket(fSocket, BIO_NOCLOSE); - SSL_set_bio(fSSL, fBIO, fBIO); - - if (SSL_connect(fSSL) <= 0) { - TRACE("SSLConnection can't connect\n"); - SocketConnection::Disconnect(); - return B_ERROR; - } - - TRACE("SSLConnection connected\n"); - return B_OK; -} - - -status_t -SSLConnection::Disconnect() -{ - TRACE("SSLConnection::Disconnect()\n"); - - if (fSSL) - SSL_shutdown(fSSL); - if (fCTX) - SSL_CTX_free(fCTX); - if (fBIO) - BIO_free(fBIO); - - fSSL = NULL; - fCTX = NULL; - fBIO = NULL; - return SocketConnection::Disconnect(); -} - - -status_t -SSLConnection::WaitForData(bigtime_t timeout) -{ - if (fSSL == NULL) - return B_NO_INIT; - if (SSL_pending(fSSL) > 0) - return B_OK; - - return SocketConnection::WaitForData(timeout); -} - - -ssize_t -SSLConnection::Read(char* buffer, uint32 length) -{ - if (fSSL == NULL) - return B_NO_INIT; - - int bytesRead = SSL_read(fSSL, buffer, length); - if (bytesRead > 0) - return bytesRead; - - // TODO: translate SSL error codes! - return B_ERROR; -} - - -ssize_t -SSLConnection::Write(const char* buffer, uint32 length) -{ - if (fSSL == NULL) - return B_NO_INIT; - - int bytesWritten = SSL_write(fSSL, buffer, length); - if (bytesWritten > 0) - return bytesWritten; - - // TODO: translate SSL error codes! - return B_ERROR; -} - - -#endif // USE_SSL - - -} // namespace BPrivate