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.
This commit is contained in:
Axel Dörfler
2015-01-06 15:20:35 +01:00
parent 1704480100
commit 9192d4dcf3
16 changed files with 445 additions and 572 deletions
-48
View File
@@ -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
@@ -18,7 +18,7 @@
#include <ProtocolConfigView.h>
#include <MailPrivate.h>
#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);
}
@@ -5,7 +5,7 @@
*/
#include "IMAPFolderConfig.h"
#include "FolderConfigWindow.h"
#include <Catalog.h>
#include <ControlLook.h>
@@ -17,7 +17,7 @@
#include <ALMGroup.h>
#include <StringForSize.h>
#include <crypt.h>
#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);
@@ -3,8 +3,8 @@
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* 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 <Button.h>
@@ -15,6 +15,7 @@
#include <MailSettings.h>
#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
@@ -0,0 +1,143 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_H
#define IMAP_H
#include "MailProtocol.h"
#include <Handler.h>
#include <Locker.h>
#include <Message.h>
#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
@@ -0,0 +1,53 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* 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();
}
@@ -0,0 +1,38 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_CONNECTION_WORKER_H
#define IMAP_CONNECTION_WORKER_H
#include <Locker.h>
#include <String.h>
#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
@@ -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 ] ;
@@ -0,0 +1,87 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "Settings.h"
#include <crypt.h>
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 "";
}
@@ -0,0 +1,32 @@
/*
* Copyright 2011, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef SETTINGS_H
#define SETTINGS_H
#include <Message.h>
#include <NetworkAddress.h>
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
@@ -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";
}
@@ -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;
};
@@ -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;
}
@@ -36,9 +36,9 @@ typedef BObjectList<Handler> HandlerList;
typedef std::map<int32, Command*> CommandIDMap;
class FolderInfo {
class FolderEntry {
public:
FolderInfo()
FolderEntry()
:
subscribed(false)
{
@@ -47,7 +47,7 @@ public:
BString folder;
bool subscribed;
};
typedef std::vector<FolderInfo> FolderList;
typedef std::vector<FolderEntry> FolderList;
class Protocol {
-1
View File
@@ -31,7 +31,6 @@ local sources =
NodeMessage.cpp
numailkit.cpp
ProtocolConfigView.cpp
ServerConnection.cpp
;
-410
View File
@@ -1,410 +0,0 @@
/*
* Copyright 2010-2011, Haiku, Inc. All rights reserved.
* Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#include "ServerConnection.h"
#include <errno.h>
#include <sys/poll.h>
#include <unistd.h>
#ifdef USE_SSL
# include <openssl/ssl.h>
# include <openssl/rand.h>
#endif
#include <Autolock.h>
#include <Locker.h>
#include <NetworkAddress.h>
#define DEBUG_SERVER_CONNECTION
#ifdef DEBUG_SERVER_CONNECTION
# include <stdio.h>
# 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