Chat-O-Matic/application/ProtocolManager.cpp
Jaidyn Ann c0580dfc17 Save disabling of accounts, make persistent
If the user disables an account, this saves it so that on any
subsequent start-ups, the account won't be connected until the user
explicitly re-enables it.

ProtocolSettings were reworked to allow for publicly loading/saving
settings from BMessages, rather than solely from BViews.

In addition, all program-side disabling, enabling, and toggling of
accounts has been consolidated into ProtocolManager. This makes life
easier for other parts of the program that have to do these things
anyway.
2021-08-16 11:58:27 -05:00

283 lines
5.9 KiB
C++

/*
* Copyright 2009-2011, Andrea Anzani. All rights reserved.
* Copyright 2021, Jaidyn Levesque. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Andrea Anzani, andrea.anzani@gmail.com
* Jaidyn Levesque, jadedctrl@teknik.io
*/
#include <stdio.h>
#include <image.h>
#include <Bitmap.h>
#include <Directory.h>
#include <Entry.h>
#include <Handler.h>
#include "Account.h"
#include "AppMessages.h"
#include "ChatProtocolMessages.h"
#include "ProtocolManager.h"
#include "ProtocolSettings.h"
#include "ChatProtocol.h"
#include "MainWindow.h"
#include "Server.h"
#include "TheApp.h"
#include "Utils.h"
static ProtocolManager* fInstance = NULL;
bool
ProtocolManager::Init(BDirectory dir, BHandler* target)
{
BEntry entry;
BPath path;
bool ret = false;
dir.Rewind();
while (dir.GetNextEntry(&entry) == B_OK) {
path = BPath(&entry);
// Load protocol addon
image_id id = load_add_on(path.Path());
if (id < 0)
continue;
// If add-on's API version fits then load accounts…
ChatProtocolAddOn* addOn = new ChatProtocolAddOn(id, path.Path());
if (addOn->Version() != APP_VERSION)
continue;
ret = true;
// If add-on has multiple protocols, also load them
for (int32 i = 0; i < addOn->CountProtocols(); i++) {
ChatProtocolAddOn* subAddOn = addOn;
if (i > 0)
subAddOn = new ChatProtocolAddOn(id, path.Path(), i);
ChatProtocol* proto = subAddOn->Protocol();
fAddOnMap.AddItem(proto->Signature(), subAddOn);
_LoadAccounts(path.Path(), subAddOn, i, target);
delete proto;
}
}
return ret;
}
ProtocolManager::ProtocolManager()
{
}
ProtocolManager*
ProtocolManager::Get()
{
if (fInstance == NULL)
fInstance = new ProtocolManager();
return fInstance;
}
uint32
ProtocolManager::CountProtocolAddOns() const
{
return fAddOnMap.CountItems();
}
ChatProtocolAddOn*
ProtocolManager::ProtocolAddOnAt(uint32 i) const
{
return fAddOnMap.ValueAt(i);
}
ChatProtocolAddOn*
ProtocolManager::ProtocolAddOn(const char* signature)
{
return fAddOnMap.ValueFor(signature);
}
uint32
ProtocolManager::CountProtocolInstances() const
{
return fProtocolMap.CountItems();
}
ChatProtocol*
ProtocolManager::ProtocolInstanceAt(uint32 i) const
{
return fProtocolMap.ValueAt(i);
}
ChatProtocol*
ProtocolManager::ProtocolInstance(bigtime_t identifier)
{
return fProtocolMap.ValueFor(identifier);
}
void
ProtocolManager::AddAccount(ChatProtocolAddOn* addOn, const char* account,
BHandler* target)
{
// If already active, don't double-dip!
bool active = false;
_Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == true)
return;
bigtime_t instanceId = system_time();
ChatProtocol* cayap = addOn->Protocol();
Account* acc =
new Account(instanceId, cayap, account, addOn->Signature(), target);
// If account is disabled, just let it go
if (acc->InitCheck() == B_DONT_DO_THAT) {
delete acc;
return;
}
// Send a "whoops" notification if hits a failure
else if (acc->InitCheck() != B_OK) {
BMessage error(APP_ACCOUNT_FAILED);
cayap->Icon()->Archive(&error);
error.AddString("name", account);
_MainWin()->MessageReceived(&error);
return;
}
fProtocolMap.AddItem(instanceId, cayap);
_Server()->AddProtocolLooper(instanceId, cayap);
}
void
ProtocolManager::EnableAccount(ProtocolSettings* settings, const char* account)
{
BMessage* msg = NULL;
if (settings->Load(account, &msg) == B_OK) {
if (msg->HasBool("disabled"))
msg->ReplaceBool("disabled", false);
else
msg->AddBool("disabled", false);
settings->Save(account, *msg);
}
AddAccount(settings->AddOn(), account, _MainWin());
}
void
ProtocolManager::DisableAccount(ProtocolSettings* settings, const char* account)
{
bool active = false;
int64 instance
= _Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == false)
return;
BMessage* msg = NULL;
if (settings->Load(account, &msg) == B_OK) {
if (msg->HasBool("disabled"))
msg->ReplaceBool("disabled", true);
else
msg->AddBool("disabled", true);
settings->Save(account, *msg);
}
BMessage remove(IM_MESSAGE);
remove.AddInt32("im_what", IM_PROTOCOL_DISABLE);
remove.AddInt64("instance", instance);
_MainWin()->PostMessage(&remove);
}
void
ProtocolManager::ToggleAccount(ProtocolSettings* settings, const char* account)
{
bool active = false;
int64 instance
= _Server()->GetActiveAccounts().ValueFor(BString(account), &active);
if (active == true)
DisableAccount(settings, account);
else
EnableAccount(settings, account);
}
void
ProtocolManager::_LoadAccounts(const char* image_path, ChatProtocolAddOn* addOn,
int protoIndex, BHandler* target)
{
// Find accounts path for this protocol
BPath path(AccountPath(addOn->Signature(), addOn->Protocol()->Signature()));
if (path.InitCheck() != B_OK)
return;
BDirectory dir(path.Path());
BEntry entry;
bool firstDone = false;
while (dir.GetNextEntry(&entry) == B_OK)
_LoadAccount(addOn, entry, target);
}
void
ProtocolManager::_LoadAccount(const char* imagePath, BEntry accountEntry,
int protoIndex, BHandler* target)
{
image_id id = load_add_on(imagePath);
if (id < 0)
return;
// If add-on's API version fits then load accounts…
ChatProtocolAddOn* addOn = new ChatProtocolAddOn(id, imagePath, protoIndex);
if (addOn->Version() != APP_VERSION)
return;
_LoadAccount(addOn, accountEntry, target);
}
void
ProtocolManager::_LoadAccount(ChatProtocolAddOn* addOn, BEntry accountEntry,
BHandler* target)
{
BFile file(&accountEntry, B_READ_ONLY);
BMessage msg;
if (msg.Unflatten(&file) == B_OK) {
char buffer[B_PATH_NAME_LENGTH];
if (accountEntry.GetName(buffer) == B_OK) {
printf("Found %s for protocol %s!\n", buffer, addOn->Protocol()->Signature());
AddAccount(addOn, buffer, target);
}
}
}
MainWindow*
ProtocolManager::_MainWin()
{
return ((TheApp*)be_app)->GetMainWindow();
}
Server*
ProtocolManager::_Server()
{
MainWindow* win = _MainWin();
return win ? win->GetServer() : NULL;
}