haiku/src/preferences/mail/Account.cpp
DarkWyrm 5fb9e9cec7 Automatically select the main item for a newly-created account
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19680 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-01-02 20:16:21 +00:00

675 lines
15 KiB
C++

/* Account - provides an "account" view on the mail chains
**
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/
#include "Account.h"
#include "ConfigViews.h"
#include "CenterContainer.h"
#include <ListView.h>
#include <ListItem.h>
#include <TextControl.h>
#include <MenuField.h>
#include <PopUpMenu.h>
#include <MenuItem.h>
#include <Box.h>
#include <Alert.h>
#include <List.h>
#include <String.h>
#include <FindDirectory.h>
#include <Entry.h>
#include <Path.h>
#include <MailSettings.h>
#include <stdio.h>
#include <MDRLanguage.h>
static BList gAccounts;
static BListView *gListView;
static BView *gConfigView;
const char *kInboundFilterAddOnPath = "mail_daemon/inbound_filters";
const char *kOutboundFilterAddOnPath = "mail_daemon/outbound_filters";
const char *kSystemFilterAddOnPath = "mail_daemon/system_filters";
const char *kInboundProtocolAddOnPath = "mail_daemon/inbound_protocols";
const char *kOutboundProtocolAddOnPath = "mail_daemon/outbound_protocols";
//---------------------------------------------------------------------------------------
// #pragma mark -
AccountItem::AccountItem(const char *label,Account *account,int32 type)
: BStringItem(label),
account(account),
type(type)
{
}
AccountItem::~AccountItem()
{
}
void AccountItem::Update(BView *owner, const BFont *font)
{
if (type == ACCOUNT_ITEM)
font = be_bold_font;
BStringItem::Update(owner,font);
}
void AccountItem::DrawItem(BView *owner, BRect rect, bool complete)
{
owner->PushState();
if (type == ACCOUNT_ITEM)
{
// BFont font;
// owner->GetFont(&font);
// font.SetFace(B_BOLD_FACE);
owner->SetFont(be_bold_font); //&font);
}
BStringItem::DrawItem(owner,rect,complete);
owner->PopState();
}
//---------------------------------------------------------------------------------------
// #pragma mark -
Account::Account(BMailChain *inbound,BMailChain *outbound)
: fInbound(inbound),
fOutbound(outbound),
fAccountItem(NULL),
fInboundItem(NULL),
fOutboundItem(NULL),
fFilterItem(NULL)
{
fSettings = fInbound ? fInbound : fOutbound;
BString label;
if (fSettings)
label << fSettings->Name();
else
label << MDR_DIALECT_CHOICE ("Unnamed","名称未定");
fAccountItem = new AccountItem(label.String(),this,ACCOUNT_ITEM);
fInboundItem = new AccountItem(MDR_DIALECT_CHOICE (" · Incoming"," - 受信"),this,INBOUND_ITEM);
fOutboundItem = new AccountItem(MDR_DIALECT_CHOICE (" · Outgoing"," - 送信"),this,OUTBOUND_ITEM);
fFilterItem = new AccountItem(MDR_DIALECT_CHOICE (" · E-mail Filters"," - フィルタ"),this,FILTER_ITEM);
}
Account::~Account()
{
if (gListView)
{
gListView->RemoveItem(fAccountItem);
gListView->RemoveItem(fInboundItem);
gListView->RemoveItem(fOutboundItem);
gListView->RemoveItem(fFilterItem);
}
delete fAccountItem; delete fFilterItem;
delete fInboundItem; delete fOutboundItem;
delete fInbound;
delete fOutbound;
}
void Account::AddToListView()
{
if (!gListView)
return;
gListView->AddItem(fAccountItem);
if (fInbound)
gListView->AddItem(fInboundItem);
if (fOutbound)
gListView->AddItem(fOutboundItem);
if (fOutbound || fInbound)
gListView->AddItem(fFilterItem);
}
void Account::SetName(const char *name)
{
if (fInbound)
fInbound->SetName(name);
if (fOutbound)
fOutbound->SetName(name);
if (name && *name)
{
fAccountItem->SetText(name);
gListView->InvalidateItem(gListView->IndexOf(fAccountItem));
}
}
const char *Account::Name() const
{
if (fInbound)
return fInbound->Name();
if (fOutbound)
return fOutbound->Name();
return NULL;
}
void Account::SetRealName(const char *realName)
{
BMessage *msg;
if (fInbound && (msg = fInbound->MetaData()) != NULL)
{
if (msg->ReplaceString("real_name",realName) < B_OK)
msg->AddString("real_name",realName);
}
if (fOutbound && (msg = fOutbound->MetaData()) != NULL)
{
if (msg->ReplaceString("real_name",realName) < B_OK)
msg->AddString("real_name",realName);
}
}
const char *Account::RealName() const
{
if (fInbound && fInbound->MetaData())
return fInbound->MetaData()->FindString("real_name");
if (fOutbound && fOutbound->MetaData())
return fOutbound->MetaData()->FindString("real_name");
if (fInbound)
fInbound->MetaData()->PrintToStream();
return NULL;
}
void Account::SetReturnAddress(const char *returnAddress)
{
BMessage *msg;
if (fInbound && (msg = fInbound->MetaData()) != NULL)
{
if (msg->ReplaceString("reply_to",returnAddress) < B_OK)
msg->AddString("reply_to",returnAddress);
}
if (fOutbound && (msg = fOutbound->MetaData()) != NULL)
{
if (msg->ReplaceString("reply_to",returnAddress) < B_OK)
msg->AddString("reply_to",returnAddress);
}
}
const char *Account::ReturnAddress() const
{
if (fInbound && fInbound->MetaData())
return fInbound->MetaData()->FindString("reply_to");
if (fOutbound && fOutbound->MetaData())
return fOutbound->MetaData()->FindString("reply_to");
return NULL;
}
void Account::CopyMetaData(BMailChain *targetChain, BMailChain *sourceChain)
{
BMessage *otherMsg, *thisMsg;
if (sourceChain && (otherMsg = sourceChain->MetaData()) != NULL
&& (thisMsg = targetChain->MetaData()) != NULL)
{
const char *string;
if ((string = otherMsg->FindString("real_name")) != NULL)
{
if (thisMsg->ReplaceString("real_name",string) < B_OK)
thisMsg->AddString("real_name",string);
}
if ((string = otherMsg->FindString("reply_to")) != NULL)
{
if (thisMsg->ReplaceString("reply_to",string) < B_OK)
thisMsg->AddString("reply_to",string);
}
if ((string = sourceChain->Name()) != NULL)
targetChain->SetName(string);
}
}
void Account::CreateInbound()
{
if (!(fInbound = NewMailChain()))
{
(new BAlert(
MDR_DIALECT_CHOICE ("E-mail","メール"),
MDR_DIALECT_CHOICE ("Could not create inbound chain.","受信チェーンは作成できませんでした。"),
MDR_DIALECT_CHOICE ("OK","了解")))->Go();
return;
}
fInbound->SetChainDirection(inbound);
BPath path,addOnPath;
find_directory(B_USER_ADDONS_DIRECTORY,&addOnPath);
BMessage msg;
entry_ref ref;
// Protocol
path = addOnPath;
path.Append(kInboundProtocolAddOnPath);
path.Append("POP3");
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kInboundProtocolAddOnPath);
path.Append("POP3");
}
BEntry(path.Path()).GetRef(&ref);
fInbound->AddFilter(msg,ref);
// Message Parser
path = addOnPath;
path.Append(kSystemFilterAddOnPath);
path.Append("Message Parser");
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kSystemFilterAddOnPath);
path.Append("Message Parser");
}
BEntry(path.Path()).GetRef(&ref);
fInbound->AddFilter(msg,ref);
// New Mail Notification
path = addOnPath;
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("New Mail Notification", "着信通知方法"));
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("New Mail Notification", "着信通知方法"));
}
BEntry(path.Path()).GetRef(&ref);
fInbound->AddFilter(msg,ref);
// Inbox
path = addOnPath;
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("Inbox", "受信箱"));
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("Inbox", "受信箱"));
}
BEntry(path.Path()).GetRef(&ref);
fInbound->AddFilter(msg,ref);
// set already made account settings
CopyMetaData(fInbound,fOutbound);
}
void Account::CreateOutbound()
{
if (!(fOutbound = NewMailChain()))
{
(new BAlert(
MDR_DIALECT_CHOICE ("E-mail","メール"),
MDR_DIALECT_CHOICE ("Could not create outbound chain.","送信チェーンは作成できませんでした。"),
MDR_DIALECT_CHOICE ("Ok","了解")))->Go();
return;
}
fOutbound->SetChainDirection(outbound);
BPath path,addOnPath;
find_directory(B_USER_ADDONS_DIRECTORY,&addOnPath);
BMessage msg;
entry_ref ref;
path = addOnPath;
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("Outbox", "送信箱"));
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kSystemFilterAddOnPath);
path.Append(MDR_DIALECT_CHOICE ("Outbox", "送信箱"));
}
BEntry(path.Path()).GetRef(&ref);
fOutbound->AddFilter(msg,ref);
path = addOnPath;
path.Append(kOutboundProtocolAddOnPath);
path.Append("SMTP");
if (!BEntry(path.Path()).Exists()) {
find_directory(B_BEOS_ADDONS_DIRECTORY,&path);
path.Append(kOutboundProtocolAddOnPath);
path.Append("SMTP");
}
BEntry(path.Path()).GetRef(&ref);
fOutbound->AddFilter(msg,ref);
// set already made account settings
CopyMetaData(fOutbound,fInbound);
}
void Account::SetType(int32 type)
{
if (type < INBOUND_TYPE || type > IN_AND_OUTBOUND_TYPE)
return;
int32 index = gListView->IndexOf(fAccountItem) + 1;
// missing inbound
if ((type == INBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Inbound())
{
if (!fInbound)
CreateInbound();
if (fInbound)
gListView->AddItem(fInboundItem,index);
}
if (Inbound())
index++;
// missing outbound
if ((type == OUTBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE) && !Outbound())
{
if (!fOutbound)
CreateOutbound();
if (fOutbound)
gListView->AddItem(fOutboundItem,index);
}
if (Outbound())
index++;
// missing filter
if (!gListView->HasItem(fFilterItem))
gListView->AddItem(fFilterItem,index);
// remove inbound
if (type == OUTBOUND_TYPE && Inbound())
gListView->RemoveItem(fInboundItem);
// remove outbound
if (type == INBOUND_TYPE && Outbound())
gListView->RemoveItem(fOutboundItem);
}
int32 Account::Type() const
{
return Inbound() ? (Outbound() ? 2 : 0) : (Outbound() ? 1 : -1);
}
void Account::Selected(int32 type)
{
if (!gConfigView)
return;
gConfigView->Hide();
((CenterContainer *)gConfigView)->DeleteChildren();
switch (type)
{
case ACCOUNT_ITEM:
gConfigView->AddChild(new AccountConfigView(gConfigView->Bounds(),this));
break;
case INBOUND_ITEM:
{
if (!fInbound)
break;
int32 count = fInbound->CountFilters();
for (int32 i = 0;;i++)
{
BMessage *msg = new BMessage();
entry_ref *ref = new entry_ref;
// we just want to have the first and the last two filters:
// Protocol, Parser, Notifier, Folder
if (i == 2)
{
i = count - 2;
if (i < 2) // defensive programming...
i = 3;
}
if (fInbound->GetFilter(i,msg,ref) < B_OK)
{
delete msg;
delete ref;
break;
}
// the filter view takes ownership of "msg" and "ref"
FilterConfigView *view;
if (i == 0)
view = new ProtocolsConfigView(fInbound,i,msg,ref);
else
view = new FilterConfigView(fInbound,i,msg,ref);
if (view->InitCheck() >= B_OK)
gConfigView->AddChild(view);
else
delete view;
}
break;
}
case OUTBOUND_ITEM:
{
if (!fOutbound)
break;
// we just want to have the first and the last filter here
int32 count = fOutbound->CountFilters();
for (int32 i = 0;i < count;i += count-1)
{
BMessage *msg = new BMessage();
entry_ref *ref = new entry_ref;
if (fOutbound->GetFilter(i,msg,ref) < B_OK)
{
delete msg;
delete ref;
break;
}
// the filter view takes ownership of "msg" and "ref"
if (FilterConfigView *view = new FilterConfigView(fOutbound,i,msg,ref))
{
if (view->InitCheck() >= B_OK)
gConfigView->AddChild(view);
else
delete view;
}
}
break;
}
case FILTER_ITEM:
{
gConfigView->AddChild(new FiltersConfigView(gConfigView->Bounds(),this));
break;
}
}
((CenterContainer *)gConfigView)->Layout();
gConfigView->Show();
}
void Account::Remove(int32 type)
{
// this should only be called if necessary, but if it's used
// in the GUI, this will always be the case
((CenterContainer *)gConfigView)->DeleteChildren();
switch (type)
{
case ACCOUNT_ITEM:
gListView->RemoveItem(fAccountItem);
gListView->RemoveItem(fInboundItem);
gListView->RemoveItem(fOutboundItem);
gListView->RemoveItem(fFilterItem);
return;
case INBOUND_ITEM:
if (!fInbound || !gListView)
return;
gListView->RemoveItem(fInboundItem);
if (!Outbound())
gListView->RemoveItem(fFilterItem);
break;
case OUTBOUND_ITEM:
if (!fOutbound || !gListView)
return;
gListView->RemoveItem(fOutboundItem);
if (!Inbound())
gListView->RemoveItem(fFilterItem);
break;
}
}
BMailChain *Account::Inbound() const
{
return gListView && gListView->HasItem(fInboundItem) ? fInbound : NULL;
}
BMailChain *Account::Outbound() const
{
return gListView && gListView->HasItem(fOutboundItem) ? fOutbound : NULL;
}
void Account::Save()
{
if (Inbound())
fInbound->Save();
else
Delete(INBOUND_TYPE);
if (Outbound())
fOutbound->Save();
else
Delete(OUTBOUND_TYPE);
}
void Account::Delete(int32 type)
{
if (fInbound && (type == INBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE))
fInbound->Delete();
if (fOutbound && (type == OUTBOUND_TYPE || type == IN_AND_OUTBOUND_TYPE))
fOutbound->Delete();
}
// #pragma mark -
int Accounts::Compare(const void *_a, const void *_b)
{
const char *a = (*(Account **)_a)->Name();
const char *b = (*(Account **)_b)->Name();
if (!a)
return b != 0;
return strcasecmp(a,b);
}
void Accounts::Create(BListView *listView, BView *configView)
{
gListView = listView;
gConfigView = configView;
BList inbound,outbound;
GetInboundMailChains(&inbound);
GetOutboundMailChains(&outbound);
// create inbound accounts and assign matching outbound chains
for (int32 i = inbound.CountItems();i-- > 0;)
{
BMailChain *inChain = (BMailChain *)inbound.ItemAt(i);
BMailChain *outChain = NULL;
for (int32 j = outbound.CountItems();j-- > 0;)
{
outChain = (BMailChain *)outbound.ItemAt(j);
if (!strcmp(inChain->Name(),outChain->Name()))
break;
outChain = NULL;
}
gAccounts.AddItem(new Account(inChain,outChain));
inbound.RemoveItem(i);
if (outChain)
outbound.RemoveItem(outChain);
}
// create remaining outbound only accounts
for (int32 i = outbound.CountItems();i-- > 0;)
{
BMailChain *outChain = (BMailChain *)outbound.ItemAt(i);
gAccounts.AddItem(new Account(NULL,outChain));
outbound.RemoveItem(i);
}
// sort the list alphabetically
gAccounts.SortItems(Accounts::Compare);
for (int32 i = 0;Account *account = (Account *)gAccounts.ItemAt(i);i++)
account->AddToListView();
}
void Accounts::NewAccount()
{
Account *account = new Account();
gAccounts.AddItem(account);
account->AddToListView();
if (gListView)
gListView->Select(gListView->IndexOf(account->fAccountItem));
}
void Accounts::Save()
{
for (int32 i = gAccounts.CountItems();i-- > 0;)
((Account *)gAccounts.ItemAt(i))->Save();
}
void Accounts::Delete()
{
for (int32 i = gAccounts.CountItems();i-- > 0;)
{
Account *account = (Account *)gAccounts.RemoveItem(i);
delete account;
}
}