diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 91e5fa5e06..49fd0cc7df 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -314,6 +314,9 @@ AddFilesToHaikuImage system data artwork : $(logoArtwork) ; AddDirectoryToHaikuImage system data sounds ; +# Add mail provider infos. +AddFilesToHaikuImage home config settings Mail ProviderInfo : $(HAIKU_PROVIDER_INFOS) ; + # Mail spell check dictionaries local spellFiles = words geekspeak ; spellFiles = $(spellFiles:G=spell) ; diff --git a/src/preferences/mail/Account.cpp b/src/preferences/mail/Account.cpp index 12248f6d85..c5a32d9f5c 100644 --- a/src/preferences/mail/Account.cpp +++ b/src/preferences/mail/Account.cpp @@ -645,7 +645,7 @@ void Accounts::Create(BListView *listView, BView *configView) } -void Accounts::NewAccount() +Account* Accounts::NewAccount() { Account *account = new Account(); gAccounts.AddItem(account); @@ -653,6 +653,7 @@ void Accounts::NewAccount() if (gListView) gListView->Select(gListView->IndexOf(account->fAccountItem)); + return account; } diff --git a/src/preferences/mail/Account.h b/src/preferences/mail/Account.h index 9f5a2a8a0d..c6c141133d 100644 --- a/src/preferences/mail/Account.h +++ b/src/preferences/mail/Account.h @@ -93,7 +93,7 @@ class Accounts { public: static void Create(BListView *listView,BView *configView); - static void NewAccount(); + static Account* NewAccount(); static void Save(); static void Delete(); diff --git a/src/preferences/mail/AutoConfig.cpp b/src/preferences/mail/AutoConfig.cpp new file mode 100644 index 0000000000..59bf3fb7e0 --- /dev/null +++ b/src/preferences/mail/AutoConfig.cpp @@ -0,0 +1,192 @@ +#include "AutoConfig.h" +#include "DNSQuery.h" + +#include +#include +#include +#include +#include +#include + + +status_t +AutoConfig::GetInfoFromMailAddress(const char* email, provider_info *info) +{ + BString provider = ExtractProvider(email); + + // first check the database + if (LoadProviderInfo(provider, info) == B_OK) + return B_OK; + + // fallback try to read MX record + if (GetMXRecord(provider.String(), info) == B_OK) + return B_ENTRY_NOT_FOUND; + + // if no MX record received guess a name + GuessServerName(provider.String(), info); + return B_ENTRY_NOT_FOUND; +} + + +status_t +AutoConfig::GetMXRecord(const char* provider, provider_info *info) +{ + BObjectList mxList; + DNSQuery dnsQuery; + if (dnsQuery.GetMXRecords(provider, &mxList) != B_OK) + return B_ERROR; + + mx_record *mxRec = mxList.ItemAt(0); + if (mxRec == NULL) + return B_ERROR; + + info->imap_server = mxRec->serverName; + info->pop_server = mxRec->serverName; + info->smtp_server = mxRec->serverName; + + info->authentification_pop = 0; + info->authentification_smtp = 0; + info->username_pattern = 0; + return B_OK; + +} + + +status_t +AutoConfig::GuessServerName(const char* provider, provider_info* info) +{ + info->imap_server = "mail."; + info->imap_server += provider; + info->pop_server = "mail."; + info->pop_server += provider; + info->smtp_server = "mail."; + info->smtp_server += provider; + + info->authentification_pop = 0; + info->authentification_smtp = 0; + info->username_pattern = 0; + return B_OK; +} + + +void +AutoConfig::PrintProviderInfo(provider_info* pInfo) +{ + printf("Provider: %s:\n", pInfo->provider.String()); + printf("pop_mail_host: %s\n", pInfo->pop_server.String()); + printf("imap_mail_host: %s\n", pInfo->imap_server.String()); + printf("smtp_host: %s\n", pInfo->smtp_server.String()); + printf("pop authentification: %i\n", int(pInfo->authentification_pop)); + printf("smtp authentification: %i\n", + int(pInfo->authentification_smtp)); + printf("username_pattern: %i\n", + int(pInfo->username_pattern)); +} + + +BString +AutoConfig::ExtractProvider(const char* email) +{ + BString emailS(email); + BString provider; + int32 at = emailS.FindLast("@"); + emailS.CopyInto(provider, at + 1, emailS.Length() - at); + return provider; +} + + + +status_t +AutoConfig::LoadProviderInfo(const BString &provider, provider_info* info) +{ + BPath path; + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status != B_OK) + return status; + path.Append(INFO_DIR); + BDirectory infoDir(path.Path()); + + BFile infoFile(&infoDir, provider.String(), B_READ_ONLY); + if (infoFile.InitCheck() != B_OK) + return B_ENTRY_NOT_FOUND; + + info->provider = provider; + if (ReadProviderInfo(&infoFile, info) == true) + return B_OK; + + return B_ERROR; +} + + +bool +AutoConfig::ReadProviderInfo(BNode *node, provider_info* info) +{ + bool infoFound = false; + char buffer[255]; + + // server + ssize_t size; + size = node->ReadAttr(ATTR_NAME_POPSERVER, B_STRING_TYPE, 0, &buffer, 255); + if (size > 0) { + info->pop_server = buffer; + infoFound = true; + } + size = node->ReadAttr(ATTR_NAME_IMAPSERVER, B_STRING_TYPE, 0, &buffer, 255); + if (size > 0) { + info->imap_server = buffer; + infoFound = true; + } + size = node->ReadAttr(ATTR_NAME_SMTPSERVER, B_STRING_TYPE, 0, &buffer, 255); + if (size > 0) { + info->smtp_server = buffer; + infoFound = true; + } + + // authentification type + int32 authType; + size = node->ReadAttr(ATTR_NAME_AUTHPOP, B_INT32_TYPE, 0, &authType, + sizeof(int32)); + if (size == sizeof(int32)) { + info->authentification_pop = authType; + infoFound = true; + } + size = node->ReadAttr(ATTR_NAME_AUTHSMTP, B_INT32_TYPE, 0, &authType, + sizeof(int32)); + if (size == sizeof(int32)) { + info->authentification_smtp = authType; + infoFound = true; + } + + // ssl + int32 ssl; + size = node->ReadAttr(ATTR_NAME_POPSSL, B_INT32_TYPE, 0, &ssl, + sizeof(int32)); + if (size == sizeof(int32)) { + info->ssl_pop = ssl; + infoFound = true; + } + size = node->ReadAttr(ATTR_NAME_IMAPSSL, B_INT32_TYPE, 0, &ssl, + sizeof(int32)); + if (size == sizeof(int32)) { + info->ssl_imap = ssl; + infoFound = true; + } + size = node->ReadAttr(ATTR_NAME_SMTPSSL, B_INT32_TYPE, 0, &ssl, + sizeof(int32)); + if (size == sizeof(int32)) { + info->ssl_smtp = ssl; + infoFound = true; + } + + // username pattern + int32 pattern; + size = node->ReadAttr(ATTR_NAME_USERNAME, B_INT32_TYPE, 0, &pattern, + sizeof(int32)); + if (size == sizeof(int32)) { + info->username_pattern = pattern; + infoFound = true; + } + + return infoFound; +} + diff --git a/src/preferences/mail/AutoConfig.h b/src/preferences/mail/AutoConfig.h new file mode 100644 index 0000000000..3ae1fddc53 --- /dev/null +++ b/src/preferences/mail/AutoConfig.h @@ -0,0 +1,81 @@ +#ifndef AUTO_CONFIG_H +#define AUTO_CONFIG_H + + +#include +#include +#include + +#define INFO_DIR "Mail/ProviderInfo" + +#define ATTR_NAME_POPSERVER "POP Server" +#define ATTR_NAME_IMAPSERVER "IMAP Server" +#define ATTR_NAME_SMTPSERVER "SMTP Server" +#define ATTR_NAME_AUTHPOP "POP Authentification" +#define ATTR_NAME_AUTHSMTP "SMTP Authentification" +#define ATTR_NAME_POPSSL "POP SSL" +#define ATTR_NAME_IMAPSSL "IMAP SSL" +#define ATTR_NAME_SMTPSSL "SMTP SSL" +#define ATTR_NAME_USERNAME "Username Pattern" + + +/* +ATTR_NAME_AUTHPOP: + 0 plain text + 1 APOP + +ATTR_NAME_AUTHSMTP: + 0 none + 1 ESMTP + 2 POP3 before SMTP + +ATTR_NAME_USERNAME: + 0 username is the email address (default) + 1 username is the local-part of the email address local-part@domain.net + 2 no username is proposed +*/ + + + +struct provider_info +{ + BString provider; + + BString pop_server; + BString imap_server; + BString smtp_server; + + int32 authentification_pop; + int32 authentification_smtp; + + int32 ssl_pop; + int32 ssl_imap; + int32 ssl_smtp; + + int32 username_pattern; +}; + + +class AutoConfig +{ + public: + status_t GetInfoFromMailAddress(const char* email, + provider_info *info); + + // for debug + void PrintProviderInfo(provider_info* pInfo); + + private: + status_t GetMXRecord(const char* provider, provider_info *info); + status_t GuessServerName(const char* provider, + provider_info *info); + + BString ExtractProvider(const char* email); + status_t LoadProviderInfo(const BString &provider, provider_info* info); + bool ReadProviderInfo(BNode *node, provider_info* info); + +}; + + + +#endif \ No newline at end of file diff --git a/src/preferences/mail/AutoConfigView.cpp b/src/preferences/mail/AutoConfigView.cpp new file mode 100644 index 0000000000..7856a36938 --- /dev/null +++ b/src/preferences/mail/AutoConfigView.cpp @@ -0,0 +1,537 @@ +#include "AutoConfigView.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +AutoConfigView::AutoConfigView(BRect rect, AutoConfig &config) + : BBox(rect), + fAutoConfig(config) +{ + int32 stepSize = 30; + int32 divider = 100; + BPoint topLeft(20, 20); + BPoint rightDown(rect.Width() - 20, 20 + stepSize); + + // type view + BPopUpMenu *chainsPopUp = new BPopUpMenu(B_EMPTY_STRING); + const char *chainModes[] = { + "Receive Mail Only", + "Send Mail Only", + "Send and Receive Mail"}; + BMenuItem *item; + for (int32 i = 0;i < 3;i++) + chainsPopUp->AddItem(item = new BMenuItem(chainModes[i], NULL)); + + fTypeField = new BMenuField(BRect(topLeft, rightDown),NULL, + "Account Type:",chainsPopUp); + fTypeField->SetDivider(divider); + fTypeField->Menu()->ItemAt(2)->SetMarked(true); + //fAccount->SetType(2); + AddChild(fTypeField); + + // protocol view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fInProtocolsField = SetupProtokolView(BRect(topLeft, rightDown)); + if(fInProtocolsField){ + fTypeField->SetDivider(divider); + AddChild(fInProtocolsField); + } + + // search for smtp ref + GetSMTPAddonRef(&fSMTPAddonRef); + + // email view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fEmailView = new BTextControl(BRect(topLeft, rightDown), + "email", "E-mail Address", "", + new BMessage(kEMailChangedMsg)); + fEmailView->SetDivider(divider); + AddChild(fEmailView); + + // login name view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fLoginNameView = new BTextControl(BRect(topLeft, rightDown), + "login", "Login Name", "", + NULL); + fLoginNameView->SetDivider(divider); + AddChild(fLoginNameView); + + // password view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fPasswordView = new BTextControl(BRect(topLeft, rightDown), + "password", "Password", "", + NULL); + fPasswordView->SetDivider(divider); + fPasswordView->TextView()->HideTyping(true); + AddChild(fPasswordView); + + // account view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fAccountNameView = new BTextControl(BRect(topLeft, rightDown), + "account", "Account Name", "", + NULL); + fAccountNameView->SetDivider(divider); + AddChild(fAccountNameView); + + // name view + topLeft.y+= stepSize; + rightDown.y+= stepSize; + fNameView = new BTextControl(BRect(topLeft, rightDown), + "name", "Real Name", "", + NULL); + AddChild(fNameView); + fNameView->SetDivider(divider); + +} + + +void +AutoConfigView::AttachedToWindow() +{ + fEmailView->SetTarget(this); + fEmailView->MakeFocus(true); +} + + +void +AutoConfigView::MessageReceived(BMessage *msg) +{ + BString text, login; + switch (msg->what) + { + case kEMailChangedMsg: + { + text = fLoginNameView->Text(); + if (text == "") + ProposeUsername(); + fLoginNameView->MakeFocus(); + fLoginNameView->TextView()->SelectAll(); + + text = fAccountNameView->Text(); + if (text == "") + fAccountNameView->SetText(fEmailView->Text()); + break; + } + default: + BView::MessageReceived(msg); + break; + } +} + + +bool +AutoConfigView::GetBasicAccountInfo(account_info &info) +{ + status_t status = B_OK; + + BMenuItem* item = fTypeField->Menu()->FindMarked(); + info.type = fTypeField->Menu()->IndexOf(item); + + BString inboundProtocolName = ""; + item = fInProtocolsField->Menu()->FindMarked(); + if (item) { + inboundProtocolName = item->Label(); + item->Message()->FindRef("protocol", &(info.inboundProtocol)); + } + else + status = B_ERROR; + + if (inboundProtocolName.FindFirst("IMAP") >= 0) + info.inboundType = IMAP; + else + info.inboundType = POP; + + info.outboundProtocol = fSMTPAddonRef; + info.name = fNameView->Text(); + info.accountName = fAccountNameView->Text(); + info.email = fEmailView->Text(); + info.loginName = fLoginNameView->Text(); + info.password = fPasswordView->Text(); + + return status; +} + + +BMenuField* +AutoConfigView::SetupProtokolView(BRect rect) +{ + BPopUpMenu *menu = new BPopUpMenu("Choose Protocol"); + + for (int i = 0; i < 2; i++) { + BPath path; + status_t status = find_directory((i == 0) ? B_USER_ADDONS_DIRECTORY : + B_BEOS_ADDONS_DIRECTORY, &path); + if (status != B_OK) + return NULL; + + path.Append("mail_daemon"); + path.Append("inbound_protocols"); + + BDirectory dir(path.Path()); + entry_ref protocolRef; + while (dir.GetNextRef(&protocolRef) == B_OK) + { + char name[B_FILE_NAME_LENGTH]; + BEntry entry(&protocolRef); + entry.GetName(name); + + BMenuItem *item; + BMessage *msg = new BMessage(kProtokollChangedMsg); + menu->AddItem(item = new BMenuItem(name, msg)); + msg->AddRef("protocol",&protocolRef); + + //if (*ref == protocolRef) + item->SetMarked(true); + } + } + + BMenuField *protocolsMenuField = new BMenuField(rect, NULL, NULL, menu); + protocolsMenuField->ResizeToPreferred(); + return protocolsMenuField; +} + + +status_t +AutoConfigView::GetSMTPAddonRef(entry_ref *ref) +{ + for (int i = 0; i < 2; i++) { + BPath path; + status_t status = find_directory((i == 0) ? B_USER_ADDONS_DIRECTORY : + B_BEOS_ADDONS_DIRECTORY, &path); + if (status != B_OK) + { + return B_ERROR; + } + + path.Append("mail_daemon"); + path.Append("outbound_protocols"); + + BDirectory dir(path.Path()); + + while (dir.GetNextRef(ref) == B_OK) + { + return B_OK; + } + } + + return B_ERROR; +} + + +BString +AutoConfigView::ExtractLocalPart(const char* email) +{ + BString emailS(email); + BString localPart; + int32 at = emailS.FindLast("@"); + emailS.CopyInto(localPart, 0, at); + return localPart; +} + + +void +AutoConfigView::ProposeUsername() +{ + const char* email = fEmailView->Text(); + provider_info info; + status_t status = fAutoConfig.GetInfoFromMailAddress(email, &info); + if (status == B_OK) { + BString localPart = ExtractLocalPart(email); + switch (info.username_pattern) { + case 0: + // username is the mail address + fLoginNameView->SetText(email); + break; + case 1: + // username is the local-part + fLoginNameView->SetText(localPart.String()); + break; + case 2: + // do nothing + break; + } + } + else { + fLoginNameView->SetText(email); + } +} + + +bool +AutoConfigView::IsValidMailAddress(BString email) +{ + int32 atPos = email.FindFirst("@"); + if (atPos < 0) + return false; + BString provider; + email.CopyInto(provider, atPos + 1, email.Length() - atPos); + if (provider.FindLast(".") < 0) + return false; + return true; +} + + +ServerSettingsView::ServerSettingsView(BRect rect, const account_info &info) + : BView(rect, NULL,B_FOLLOW_ALL,0), + fInboundAccount(false), + fOutboundAccount(false), + fInboundAuthMenu(NULL), + fOutboundAuthMenu(NULL), + fInboundEncrItemStart(NULL), + fOutboundEncrItemStart(NULL) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + int32 divider = 120; + + switch (info.type) { + case 0: + fInboundAccount = true; + break; + case 1: + fOutboundAccount = true; + break; + case 2: + fInboundAccount = true; + fOutboundAccount = true; + break; + } + // inbound + BRect boxRect = Bounds(); + boxRect.bottom/= 2; + boxRect.bottom-= 5; + + BBox *box = new BBox(boxRect); + box->SetLabel("Inbound"); + AddChild(box); + + BString serverName; + if (info.inboundType == IMAP) + serverName = info.providerInfo.imap_server; + else + serverName = info.providerInfo.pop_server; + + fInboundNameView = new BTextControl(BRect(10, 20, rect.Width() - 20, 35), + "inbound", "Server Name", + serverName.String(), + new BMessage(kServerChangedMsg)); + fInboundNameView->SetDivider(divider); + + box->AddChild(fInboundNameView); + + GetAuthEncrMenu(info.inboundProtocol, &fInboundAuthMenu, + &fInboundEncryptionMenu); + if (fInboundAuthMenu) { + int authID = info.providerInfo.authentification_pop; + if (info.inboundType == POP) + fInboundAuthMenu->Menu()->ItemAt(authID)->SetMarked(true); + fInboundAuthItemStart = fInboundAuthMenu->Menu()->FindMarked(); + box->AddChild(fInboundAuthMenu); + fInboundAuthMenu->SetDivider(divider); + fInboundAuthMenu->MoveTo(10, 50); + } + if (fInboundEncryptionMenu) { + BMenuItem *item = NULL; + if (info.inboundType == POP) { + item = fInboundEncryptionMenu->Menu() + ->ItemAt(info.providerInfo.ssl_pop); + item->SetMarked(true); + fInboundEncryptionMenu->MoveTo(10, 80); + } + if (info.inboundType == IMAP) { + item = fInboundEncryptionMenu->Menu() + ->ItemAt(info.providerInfo.ssl_imap); + if (item) + item->SetMarked(true); + fInboundEncryptionMenu->MoveTo(10, 50); + } + fInboundEncrItemStart = fInboundEncryptionMenu->Menu()->FindMarked(); + box->AddChild(fInboundEncryptionMenu); + fInboundEncryptionMenu->SetDivider(divider); + } + + if (!fInboundAccount) { + fInboundNameView->SetEnabled(false); + if (fInboundAuthMenu) + fInboundAuthMenu->SetEnabled(false); + } + + // outbound + boxRect = Bounds(); + boxRect.top = boxRect.bottom / 2; + boxRect.top+= 5; + + box = new BBox(boxRect); + box->SetLabel("Outbound"); + AddChild(box); + + serverName = info.providerInfo.smtp_server; + fOutboundNameView = new BTextControl(BRect(10, 20, rect.Width() - 20, 30), + "outbound", "Server Name", + serverName.String(), + new BMessage(kServerChangedMsg)); + fOutboundNameView->SetDivider(divider); + + box->AddChild(fOutboundNameView); + + GetAuthEncrMenu(info.outboundProtocol, &fOutboundAuthMenu, + &fOutboundEncryptionMenu); + if (fOutboundAuthMenu) { + BMenuItem *item = fOutboundAuthMenu->Menu() + ->ItemAt(info.providerInfo.authentification_smtp); + item->SetMarked(true); + fOutboundAuthItemStart = item; + box->AddChild(fOutboundAuthMenu); + fOutboundAuthMenu->SetDivider(divider); + fOutboundAuthMenu->MoveTo(10, 50); + } + if (fOutboundEncryptionMenu) { + BMenuItem *item = fOutboundEncryptionMenu->Menu() + ->ItemAt(info.providerInfo.ssl_smtp); + if (item) + item->SetMarked(true); + fOutboundEncrItemStart = item; + box->AddChild(fOutboundEncryptionMenu); + fOutboundEncryptionMenu->SetDivider(divider); + fOutboundEncryptionMenu->MoveTo(10, 80); + } + + if (!fOutboundAccount) { + fOutboundNameView->SetEnabled(false); + if (fOutboundAuthMenu) + fOutboundAuthMenu->SetEnabled(false); + } + +} + + +void +ServerSettingsView::GetServerInfo(account_info &info) +{ + if (info.inboundType == IMAP) { + info.providerInfo.imap_server = fInboundNameView->Text(); + if (fInboundEncryptionMenu) { + BMenuItem* item = fInboundEncryptionMenu->Menu()->FindMarked(); + if (item) + info.providerInfo.ssl_imap = fInboundEncryptionMenu->Menu() + ->IndexOf(item); + } + } else { + info.providerInfo.pop_server = fInboundNameView->Text(); + BMenuItem* item = NULL; + if (fInboundAuthMenu) { + item = fInboundAuthMenu->Menu()->FindMarked(); + if (item) + info.providerInfo.authentification_pop = fInboundAuthMenu + ->Menu() + ->IndexOf(item); + } + if (fInboundEncryptionMenu) { + item = fInboundEncryptionMenu->Menu()->FindMarked(); + if (item) + info.providerInfo.ssl_pop = fInboundEncryptionMenu->Menu() + ->IndexOf(item); + } + } + info.providerInfo.smtp_server = fOutboundNameView->Text(); + BMenuItem* item = NULL; + if (fOutboundAuthMenu) { + item = fOutboundAuthMenu->Menu()->FindMarked(); + if (item) + info.providerInfo.authentification_smtp = fOutboundAuthMenu->Menu() + ->IndexOf(item); + } + + if (fOutboundEncryptionMenu) { + item = fOutboundEncryptionMenu->Menu()->FindMarked(); + if (item) + info.providerInfo.ssl_smtp = fOutboundEncryptionMenu->Menu() + ->IndexOf(item); + } + DetectMenuChanges(); +} + + +void +ServerSettingsView::DetectMenuChanges() +{ + bool changed = false; + if (fInboundAuthMenu) { + BMenuItem *item = fInboundAuthMenu->Menu()->FindMarked(); + if (fInboundAuthItemStart != item) + changed = true; + } + if (fInboundEncryptionMenu) { + BMenuItem *item = fInboundEncryptionMenu->Menu()->FindMarked(); + if (fInboundEncrItemStart != item) + changed = true; + } + if (fOutboundAuthMenu) { + BMenuItem *item = fOutboundAuthMenu->Menu()->FindMarked(); + if (fOutboundAuthItemStart != item) + changed = true; + } + if (fOutboundEncryptionMenu) { + BMenuItem *item = fOutboundEncryptionMenu->Menu()->FindMarked(); + if (fOutboundEncrItemStart != item) + changed = true; + } + if (changed) { + BMessage msg(kServerChangedMsg); + BMessenger messenger(NULL, Window()->Looper()); + messenger.SendMessage(&msg); + } +} + + +void +ServerSettingsView::GetAuthEncrMenu(const entry_ref &ref, + BMenuField **authField, + BMenuField **sslField) +{ +// TODO: These menus being NULL is not correctly handled everywhere +// in this class. + BMessage dummyMsg; + BView *(* instantiate_config)(BMessage *,BMessage *); + BPath addon(&ref); + image_id image = load_add_on(addon.Path()); + if (image < B_OK) { + *authField = NULL; + *sslField = NULL; + return; + } + + if (get_image_symbol(image,"instantiate_config_panel", + B_SYMBOL_TYPE_TEXT,(void **)&instantiate_config) < B_OK) + { + unload_add_on(image); + image = B_MISSING_SYMBOL; + *authField = NULL; + *sslField = NULL; + return; + } + + BView *view = (*instantiate_config)(&dummyMsg, &dummyMsg); + *authField = (BMenuField *)(view->FindView("auth_method")); + *sslField = (BMenuField *)(view->FindView("flavor")); + + view->RemoveChild(*authField); + view->RemoveChild(*sslField); + delete view; + unload_add_on(image); +} diff --git a/src/preferences/mail/AutoConfigView.h b/src/preferences/mail/AutoConfigView.h new file mode 100644 index 0000000000..c48b83ef8d --- /dev/null +++ b/src/preferences/mail/AutoConfigView.h @@ -0,0 +1,101 @@ +#ifndef AUTO_CONFIG_VIEW_H +#define AUTO_CONFIG_VIEW_H + +#include "AutoConfig.h" + +#include +#include +#include +#include +#include +#include + + +const int32 kNameChangedMsg = '?nch'; +const int32 kEMailChangedMsg = '?ech'; +const int32 kProtokollChangedMsg = '?pch'; +const int32 kServerChangedMsg = '?sch'; + +enum inbound_type +{ + POP, + IMAP +}; + + +struct account_info +{ + int32 type; + inbound_type inboundType; + entry_ref inboundProtocol; + entry_ref outboundProtocol; + BString name; + BString accountName; + BString email; + BString loginName; + BString password; + provider_info providerInfo; +}; + + +class AutoConfigView : public BBox +{ + public: + AutoConfigView(BRect rect, AutoConfig &config); + + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage *msg); + + bool GetBasicAccountInfo(account_info &info); + bool IsValidMailAddress(BString email); + + private: + BMenuField* SetupProtokolView(BRect rect); + status_t GetSMTPAddonRef(entry_ref *ref); + + BString ExtractLocalPart(const char* email); + void ProposeUsername(); + + entry_ref fSMTPAddonRef; + BMenuField *fTypeField; + BMenuField *fInProtocolsField; + BTextControl *fNameView; + BTextControl *fAccountNameView; + BTextControl *fEmailView; + BTextControl *fLoginNameView; + BTextControl *fPasswordView; + + // ref to the parent autoconfig so you only ones read the database + AutoConfig &fAutoConfig; +}; + + +class ServerSettingsView : public BView +{ + public: + ServerSettingsView(BRect rect, const account_info &info); + + void GetServerInfo(account_info &info); + + private: + void DetectMenuChanges(); + void GetAuthEncrMenu(const entry_ref &ref, + BMenuField **authField, + BMenuField **sslField); + bool fInboundAccount; + bool fOutboundAccount; + BTextControl *fInboundNameView; + BMenuField *fInboundAuthMenu; + BMenuField *fInboundEncryptionMenu; + BTextControl *fOutboundNameView; + BMenuField *fOutboundAuthMenu; + BMenuField *fOutboundEncryptionMenu; + + BMenuItem *fInboundAuthItemStart; + BMenuItem *fInboundEncrItemStart; + BMenuItem *fOutboundAuthItemStart; + BMenuItem *fOutboundEncrItemStart; +}; + + +#endif \ No newline at end of file diff --git a/src/preferences/mail/AutoConfigWindow.cpp b/src/preferences/mail/AutoConfigWindow.cpp new file mode 100644 index 0000000000..9327de63c3 --- /dev/null +++ b/src/preferences/mail/AutoConfigWindow.cpp @@ -0,0 +1,202 @@ +#include "AutoConfigWindow.h" + +#include "AutoConfig.h" +#include "AutoConfigView.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + + +AutoConfigWindow::AutoConfigWindow(BRect rect, BWindow *parent) + : BWindow(rect, "Create New Account", B_TITLED_WINDOW_LOOK, + B_MODAL_APP_WINDOW_FEEL, + B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT, + B_ALL_WORKSPACES), + fParentWindow(parent), + fAccount(NULL), + fMainConfigState(true), + fServerConfigState(false), + fAutoConfigServer(true) +{ + fRootView = new BView(Bounds(), "root auto config view", + B_FOLLOW_ALL_SIDES, B_NAVIGABLE); + fRootView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(fRootView); + + int32 buttonHeight = 25; + int32 buttonWidth = 50; + BRect buttonRect = Bounds(); + buttonRect.InsetBy(5,5); + buttonRect.top = buttonRect.bottom - buttonHeight; + buttonRect.left = buttonRect.right - 2 * buttonWidth - 5; + buttonRect.right = buttonRect.left + buttonWidth; + fBackButton = new BButton(buttonRect, "back", "Back", + new BMessage(kBackMsg)); + fBackButton->SetEnabled(false); + fRootView->AddChild(fBackButton); + + buttonRect.left+= 5 + buttonWidth; + buttonRect.right = buttonRect.left + buttonWidth; + fNextButton = new BButton(buttonRect, "ok", "Ok", new BMessage(kOkMsg)); + fRootView->AddChild(fNextButton); + + fBoxRect = Bounds(); + fBoxRect.InsetBy(5,5); + fBoxRect.bottom-= buttonHeight + 5; + + fMainView = new AutoConfigView(fBoxRect, fAutoConfig); + fMainView->SetLabel("Account Settings"); + fRootView->AddChild(fMainView); +} + + +AutoConfigWindow::~AutoConfigWindow() +{ + +} + + +void +AutoConfigWindow::MessageReceived(BMessage* msg) +{ + status_t status = B_ERROR; + BAlert* invalidMailAlert = NULL; + switch (msg->what) + { + case kOkMsg: + { + if (fMainConfigState) { + fMainView->GetBasicAccountInfo(fAccountInfo); + if (!fMainView->IsValidMailAddress(fAccountInfo.email)) { + invalidMailAlert = new BAlert("invalidMailAlert", + "Enter a valid e-mail address.", + "Ok"); + invalidMailAlert->Go(); + return; + } + if (fAutoConfigServer) { + status = fAutoConfig.GetInfoFromMailAddress(fAccountInfo.email.String(), + &(fAccountInfo.providerInfo)); + } + if(status == B_OK){ + fParentWindow->Lock(); + GenerateBasicAccount(); + fParentWindow->Unlock(); + Quit(); + } + fMainConfigState = false; + fServerConfigState = true; + fMainView->Hide(); + + fServerView = new ServerSettingsView(fBoxRect, fAccountInfo); + fRootView->AddChild(fServerView); + + fBackButton->SetEnabled(true); + } + else{ + fServerView->GetServerInfo(fAccountInfo); + fParentWindow->Lock(); + GenerateBasicAccount(); + fParentWindow->Unlock(); + Quit(); + } + break; + } + case kBackMsg: + { + if(fServerConfigState){ + fServerView->GetServerInfo(fAccountInfo); + + fMainConfigState = true; + fServerConfigState = false; + + fRootView->RemoveChild(fServerView); + delete fServerView; + + fMainView->Show(); + fBackButton->SetEnabled(false); + } + break; + } + case kServerChangedMsg: + { + fAutoConfigServer = false; + break; + } + default: + BWindow::MessageReceived(msg); + break; + } +} + + +bool +AutoConfigWindow::QuitRequested(void) +{ + return(TRUE); +} + + + + +Account* +AutoConfigWindow::GenerateBasicAccount() +{ + if(!fAccount){ + fAccount = Accounts::NewAccount(); + fAccount->SetType(fAccountInfo.type); + fAccount->SetName(fAccountInfo.accountName.String()); + fAccount->SetRealName(fAccountInfo.name.String()); + fAccount->SetReturnAddress(fAccountInfo.email.String()); + + BMailChain *inbound = fAccount->Inbound(); + + BString inServerName; + int32 authType = 0; + int32 ssl = 0; + if (fAccountInfo.inboundType == IMAP) { + inServerName = fAccountInfo.providerInfo.imap_server; + ssl = fAccountInfo.providerInfo.ssl_imap; + } + else { + inServerName = fAccountInfo.providerInfo.pop_server; + authType = fAccountInfo.providerInfo.authentification_pop; + ssl = fAccountInfo.providerInfo.ssl_pop; + } + if (fAccountInfo.type == INBOUND_TYPE + || fAccountInfo.type == IN_AND_OUTBOUND_TYPE) + { + BMessage inboundArchive; + inboundArchive.AddString("server", inServerName); + inboundArchive.AddInt32("auth_method", authType); + inboundArchive.AddInt32("flavor", ssl); + inboundArchive.AddString("username", fAccountInfo.loginName); + inboundArchive.AddString("password", fAccountInfo.password); + inbound->SetFilter(0, inboundArchive, fAccountInfo.inboundProtocol); + } + + if (fAccountInfo.type == OUTBOUND_TYPE + || fAccountInfo.type == IN_AND_OUTBOUND_TYPE) + { + BMailChain *outbound = fAccount->Outbound(); + BMessage outboundArchive; + outboundArchive.AddString("server", + fAccountInfo.providerInfo.smtp_server); + outboundArchive.AddString("username", fAccountInfo.loginName); + outboundArchive.AddString("password", fAccountInfo.password); + outboundArchive.AddInt32("auth_method", + fAccountInfo.providerInfo.authentification_smtp); + outboundArchive.AddInt32("flavor", fAccountInfo.providerInfo.ssl_smtp); + outbound->SetFilter(1, outboundArchive, + fAccountInfo.outboundProtocol); + } + } + return fAccount; +} diff --git a/src/preferences/mail/AutoConfigWindow.h b/src/preferences/mail/AutoConfigWindow.h new file mode 100644 index 0000000000..b40ab59ea6 --- /dev/null +++ b/src/preferences/mail/AutoConfigWindow.h @@ -0,0 +1,48 @@ +#ifndef AUTO_CONFIG_WINDOW_H +#define AUTO_CONFIG_WINDOW_H + +#include "Account.h" +#include "AutoConfigView.h" + +#include +#include +#include +#include + + +//message constants +const int32 kBackMsg = '?bac'; +const int32 kOkMsg = '?bok'; + +class AutoConfigWindow : public BWindow +{ + public: + AutoConfigWindow(BRect rect, BWindow *parent); + ~AutoConfigWindow(); + virtual void MessageReceived(BMessage *msg); + virtual bool QuitRequested(void); + + private: + account_info fAccountInfo; + + Account* GenerateBasicAccount(); + + BView *fRootView; + BRect fBoxRect; + BWindow *fParentWindow; + Account *fAccount; + AutoConfigView *fMainView; + ServerSettingsView *fServerView; + BButton *fBackButton; + BButton *fNextButton; + + bool fMainConfigState; + bool fServerConfigState; + bool fAutoConfigServer; + + AutoConfig fAutoConfig; +}; + + + +#endif \ No newline at end of file diff --git a/src/preferences/mail/ConfigWindow.cpp b/src/preferences/mail/ConfigWindow.cpp index ad9f628611..119e2c935b 100644 --- a/src/preferences/mail/ConfigWindow.cpp +++ b/src/preferences/mail/ConfigWindow.cpp @@ -10,6 +10,7 @@ #include "ConfigWindow.h" #include "CenterContainer.h" #include "Account.h" +#include "AutoConfigWindow.h" #include #include @@ -610,6 +611,10 @@ ConfigWindow::QuitRequested() void ConfigWindow::MessageReceived(BMessage *msg) { + BRect autoConfigRect(0, 0, 400, 300); + BRect frame; + + AutoConfigWindow *autoConfigWindow = NULL; switch (msg->what) { case kMsgAccountSelected: { @@ -627,7 +632,12 @@ ConfigWindow::MessageReceived(BMessage *msg) } case kMsgAddAccount: { - Accounts::NewAccount(); + frame = Frame(); + autoConfigRect.OffsetTo(frame.left + (frame.Width() - autoConfigRect.Width()) / 2, + frame.top + (frame.Width() - autoConfigRect.Height()) / 2); + autoConfigWindow = new AutoConfigWindow(autoConfigRect, + this); + autoConfigWindow->Show(); break; } case kMsgRemoveAccount: diff --git a/src/preferences/mail/DNSQuery.cpp b/src/preferences/mail/DNSQuery.cpp new file mode 100644 index 0000000000..52709cc1a2 --- /dev/null +++ b/src/preferences/mail/DNSQuery.cpp @@ -0,0 +1,457 @@ +#include "DNSQuery.h" + +#include +#include +#include + +#include + +// #define DEBUG 1 + +#undef PRINT +#ifdef DEBUG +#define PRINT(a...) printf(a) +#else +#define PRINT(a...) +#endif + +static vint32 gID = 1; + + +BRawNetBuffer::BRawNetBuffer() +{ + _Init(NULL, 0); +} + + +BRawNetBuffer::BRawNetBuffer(off_t size) +{ + _Init(NULL, 0); + fBuffer.SetSize(size); +} + + +BRawNetBuffer::BRawNetBuffer(const void* buf, size_t size) +{ + _Init(buf, size); +} + + +status_t +BRawNetBuffer::AppendUint16(uint16 value) +{ + uint16 netVal = B_HOST_TO_BENDIAN_INT16(value); + ssize_t sizeW = fBuffer.WriteAt(fWritePosition, &netVal, sizeof(uint16)); + if (sizeW == B_NO_MEMORY) + return B_NO_MEMORY; + fWritePosition += sizeof(uint16); + return B_OK; +} + + +status_t +BRawNetBuffer::AppendString(const char* string) +{ + size_t length = strlen(string) + 1; + ssize_t sizeW = fBuffer.WriteAt(fWritePosition, string, length); + if (sizeW == B_NO_MEMORY) + return B_NO_MEMORY; + fWritePosition += length; + return B_OK; +} + + +status_t +BRawNetBuffer::ReadUint16(uint16& value) +{ + uint16 netVal; + ssize_t sizeW = fBuffer.ReadAt(fReadPosition, &netVal, sizeof(uint16)); + if (sizeW == 0) + return B_ERROR; + value= B_BENDIAN_TO_HOST_INT16(netVal); + fReadPosition += sizeof(uint16); + return B_OK; +} + + +status_t +BRawNetBuffer::ReadUint32(uint32& value) +{ + uint32 netVal; + ssize_t sizeW = fBuffer.ReadAt(fReadPosition, &netVal, sizeof(uint32)); + if (sizeW == 0) + return B_ERROR; + value= B_BENDIAN_TO_HOST_INT32(netVal); + fReadPosition += sizeof(uint32); + return B_OK; +} + + +status_t +BRawNetBuffer::ReadString(BString& string) +{ + char* buffer = (char*)fBuffer.Buffer(); + buffer = &buffer[fReadPosition]; + + // if the string is compressed we have to follow the links to the + // sub strings + while (*buffer != 0) { + if (uint8(*buffer) == 192) { + // found a pointer mark + buffer++; + // pointer takes 2 byte + fReadPosition = fReadPosition + 1; + off_t pos = uint8(*buffer); + _ReadSubString(string, pos); + break; + } + string.Append(buffer, 1); + buffer++; + fReadPosition++; + } + fReadPosition++; + return B_OK; +} + + +status_t +BRawNetBuffer::SkipReading(off_t skip) +{ + if (fReadPosition + skip > fBuffer.BufferLength()) + return B_ERROR; + fReadPosition += skip; + return B_OK; +} + + +void +BRawNetBuffer::_Init(const void* buf, size_t size) +{ + fWritePosition = 0; + fReadPosition = 0; + fBuffer.WriteAt(fWritePosition, buf, size); +} + + +void +BRawNetBuffer::_ReadSubString(BString& string, off_t pos) +{ + // sub strings have no links to other substrings so we can read it in one + // piece + char* buffer = (char*)fBuffer.Buffer(); + string.Append(&buffer[pos]); +} + + +// #pragma mark - DNSTools + + +void +DNSTools::GetDNSServers(BObjectList* serverList) +{ +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + + + register FILE* fp = fopen("/etc/resolv.conf", "r"); + if (fp == NULL) { + fprintf(stderr, "failed to open '/etc/resolv.conf' to " + "read nameservers: %s\n", strerror(errno)); + return; + } + + int nserv = 0; + char buf[1024]; + register char *cp; //, **pp; +// register int n; + int MAXNS = 2; + + // read the config file + while (fgets(buf, sizeof(buf), fp) != NULL) { + // skip comments + if (*buf == ';' || *buf == '#') + continue; + + // read nameservers to query + if (MATCH(buf, "nameserver") && nserv < MAXNS) { +// char sbuf[2]; + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + cp[strcspn(cp, ";# \t\n")] = '\0'; + if ((*cp != '\0') && (*cp != '\n')) { + serverList->AddItem(new BString(cp)); + nserv++; + } + } + continue; + } + + fclose(fp); +} + + +BString +DNSTools::ConvertToDNSName(const BString& string) +{ + BString outString = string; + int32 dot, lastDot, diff; + + dot = string.FindFirst("."); + if (dot != B_ERROR) { + outString.Prepend((char*)&dot, 1); + // because we prepend a char add 1 more + lastDot = dot + 1; + + while (true) { + dot = outString.FindFirst(".", lastDot + 1); + if (dot == B_ERROR) + break; + + // set a counts to the dot + diff = dot - 1 - lastDot; + outString[lastDot] = (char)diff; + lastDot = dot; + } + } else + lastDot = 0; + + diff = outString.CountChars() - 1 - lastDot; + outString[lastDot] = (char)diff; + + return outString; +} + + +BString +DNSTools::ConvertFromDNSName(const BString& string) +{ + BString outString = string; + int32 dot = string[0]; + int32 nextDot = dot; + outString.Remove(0, sizeof(char)); + while (true) { + dot = outString[nextDot]; + if (dot == 0) + break; + // set a "." + outString[nextDot] = '.'; + nextDot+= dot + 1; + } + return outString; +} + + +// #pragma mark - DNSQuery +// see http://tools.ietf.org/html/rfc1035 for more information about DNS + + +DNSQuery::DNSQuery() +{ +} + + +DNSQuery::~DNSQuery() +{ +} + + +status_t +DNSQuery::ReadDNSServer(in_addr* add) +{ + // list owns the items + BObjectList dnsServerList(5, true); + DNSTools::GetDNSServers(&dnsServerList); + BString* firstDNS = dnsServerList.ItemAt(0); + int status = -1; + if (firstDNS) + status = inet_aton(firstDNS->String(), add); + else + return B_ERROR; + + if (status != 1) + return B_ERROR; + PRINT("dns server found: %s \n", firstDNS->String()); + return B_OK; +} + + +status_t +DNSQuery::GetMXRecords(BString serverName, BObjectList* mxList, + bigtime_t timeout) +{ + // get the DNS server to ask for the mx record + in_addr dnsAddress; + if (ReadDNSServer(&dnsAddress) != B_OK) + return B_ERROR; + + // create dns query package + BRawNetBuffer buffer; + dns_header header; + _SetMXHeader(&header); + _AppendQueryHeader(buffer, &header); + + BString serverNameConv = DNSTools::ConvertToDNSName(serverName); + buffer.AppendString(serverNameConv.String()); + buffer.AppendUint16(uint16(MX_RECORD)); + buffer.AppendUint16(uint16(1)); + + // send the buffer + PRINT("send buffer\n"); + BNetAddress netAddress(dnsAddress, 53); + BNetEndpoint netEndpoint(SOCK_DGRAM); + if (netEndpoint.InitCheck() != B_OK) + return B_ERROR; + + if (netEndpoint.Connect(netAddress) != B_OK) + return B_ERROR; + PRINT("Connected\n"); + +#ifdef DEBUG + int32 bytesSend = +#endif + netEndpoint.Send(buffer.Data(), buffer.Size()); + PRINT("bytes send %i\n", int(bytesSend)); + + // receive buffer + BRawNetBuffer receiBuffer(512); + netEndpoint.SetTimeout(timeout); +#ifdef DEBUG + int32 bytesRecei = +#endif + netEndpoint.ReceiveFrom(receiBuffer.Data(), 512, netAddress); + PRINT("bytes received %i\n", int(bytesRecei)); + dns_header receiHeader; + + _ReadQueryHeader(receiBuffer, &receiHeader); + PRINT("Package contains :"); + PRINT("%d Questions, ", receiHeader.q_count); + PRINT("%d Answers, ", receiHeader.ans_count); + PRINT("%d Authoritative Servers, ", receiHeader.auth_count); + PRINT("%d Additional records\n", receiHeader.add_count); + + // remove name and Question + BString dummyS; + uint16 dummy; + receiBuffer.ReadString(dummyS); + receiBuffer.ReadUint16(dummy); + receiBuffer.ReadUint16(dummy); + + bool mxRecordFound = false; + for (int i = 0; i < receiHeader.ans_count; i++) { + resource_record_head rrHead; + _ReadResourceRecord(receiBuffer, &rrHead); + if (rrHead.type == MX_RECORD) { + mx_record *mxRec = new mx_record; + _ReadMXRecord(receiBuffer, mxRec); + PRINT("MX record found pri %i, name %s\n", + mxRec->priority, + mxRec->serverName.String()); + // Add mx record to the list + mxList->AddItem(mxRec); + mxRecordFound = true; + } else { + buffer.SkipReading(rrHead.dataLength); + } + } + + if (!mxRecordFound) + return B_ERROR; + + return B_OK; +} + + +uint16 +DNSQuery::_GetUniqueID() +{ + int32 nextId= atomic_add(&gID, 1); + // just to be sure + if (nextId > 65529) + nextId = 0; + return nextId; +} + + +void +DNSQuery::_SetMXHeader(dns_header* header) +{ + header->id = _GetUniqueID(); + header->qr = 0; //This is a query + header->opcode = 0; //This is a standard query + header->aa = 0; //Not Authoritative + header->tc = 0; //This message is not truncated + header->rd = 1; //Recursion Desired + header->ra = 0; //Recursion not available! hey we dont have it (lol) + header->z = 0; + header->rcode = 0; + header->q_count = 1; //we have only 1 question + header->ans_count = 0; + header->auth_count = 0; + header->add_count = 0; +} + + +void +DNSQuery::_AppendQueryHeader(BRawNetBuffer& buffer, const dns_header* header) +{ + buffer.AppendUint16(header->id); + uint16 data = 0; + data |= header->rcode; + data |= header->z << 4; + data |= header->ra << 7; + data |= header->rd << 8; + data |= header->tc << 9; + data |= header->aa << 10; + data |= header->opcode << 11; + data |= header->qr << 15; + buffer.AppendUint16(data); + buffer.AppendUint16(header->q_count); + buffer.AppendUint16(header->ans_count); + buffer.AppendUint16(header->auth_count); + buffer.AppendUint16(header->add_count); +} + + +void +DNSQuery::_ReadQueryHeader(BRawNetBuffer& buffer, dns_header* header) +{ + buffer.ReadUint16(header->id); + uint16 data = 0; + buffer.ReadUint16(data); + header->rcode = data & 0x0F; + header->z = (data >> 4) & 0x07; + header->ra = (data >> 7) & 0x01; + header->rd = (data >> 8) & 0x01; + header->tc = (data >> 9) & 0x01; + header->aa = (data >> 10) & 0x01; + header->opcode = (data >> 11) & 0x0F; + header->qr = (data >> 15) & 0x01; + buffer.ReadUint16(header->q_count); + buffer.ReadUint16(header->ans_count); + buffer.ReadUint16(header->auth_count); + buffer.ReadUint16(header->add_count); +} + + +void +DNSQuery::_ReadMXRecord(BRawNetBuffer& buffer, mx_record* mxRecord) +{ + buffer.ReadUint16(mxRecord->priority); + buffer.ReadString(mxRecord->serverName); + mxRecord->serverName = DNSTools::ConvertFromDNSName(mxRecord->serverName); +} + + +void +DNSQuery::_ReadResourceRecord(BRawNetBuffer& buffer, + resource_record_head *rrHead) +{ + buffer.ReadString(rrHead->name); + buffer.ReadUint16(rrHead->type); + buffer.ReadUint16(rrHead->dataClass); + buffer.ReadUint32(rrHead->ttl); + buffer.ReadUint16(rrHead->dataLength); +} diff --git a/src/preferences/mail/DNSQuery.h b/src/preferences/mail/DNSQuery.h new file mode 100644 index 0000000000..c64fec623c --- /dev/null +++ b/src/preferences/mail/DNSQuery.h @@ -0,0 +1,112 @@ +#ifndef DNS_QUERY_H +#define DNS_QUERY_H + + +#include +#include +#include +#include + + +#include + +#define MX_RECORD 15 + +struct mx_record { + uint16 priority; + BString serverName; +}; + + +class BRawNetBuffer { +public: + BRawNetBuffer(); + BRawNetBuffer(off_t size); + BRawNetBuffer(const void* buf, size_t size); + + // functions like in BNetBuffer but no type and size info is writen. + // functions return B_NO_MEMORY or B_OK + status_t AppendUint16(uint16 value); + status_t AppendString(const char* string); + + status_t ReadUint16(uint16& value); + status_t ReadUint32(uint32& value); + status_t ReadString(BString& string); + + status_t SkipReading(off_t off); + + void *Data(void) const { return (void*)fBuffer.Buffer(); } + size_t Size(void) const { return fBuffer.BufferLength(); } + size_t SetSize(off_t size) { return fBuffer.SetSize(size); } + void SetWritePosition(off_t pos) { fWritePosition = pos; } + +private: + void _Init(const void* buf, size_t size); + void _ReadSubString(BString& string, off_t pos); + off_t fWritePosition; + off_t fReadPosition; + BMallocIO fBuffer; +}; + + +class DNSTools { +public: + static void GetDNSServers(BObjectList* serverList); + static BString ConvertToDNSName(const BString& string); + static BString ConvertFromDNSName(const BString& string); +}; + +// see also http://prasshhant.blogspot.com/2007/03/dns-query.html +struct dns_header { + uint16 id; // A 16 bit identifier + + unsigned char qr :1; // query (0), or a response (1) + unsigned char opcode :4; // A four bit field + unsigned char aa :1; // Authoritative Answer + unsigned char tc :1; // Truncated Message + unsigned char rd :1; // Recursion Desired + unsigned char ra :1; // Recursion Available + unsigned char z :3; // Reserved for future use + unsigned char rcode :4; // Response code + + uint16 q_count; // number of question entries + uint16 ans_count; // number of answer entries + uint16 auth_count; // number of authority entries + uint16 add_count; // number of resource entries +}; + +// resource record without resource data +struct resource_record_head { + BString name; + uint16 type; + uint16 dataClass; + uint32 ttl; + uint16 dataLength; +}; + + +class DNSQuery { +public: + DNSQuery(); + ~DNSQuery(); + status_t ReadDNSServer(in_addr* add); + status_t GetMXRecords(BString serverName, + BObjectList* mxList, + bigtime_t timeout = 500000); + +private: + uint16 _GetUniqueID(); + void _SetMXHeader(dns_header* header); + void _AppendQueryHeader(BRawNetBuffer& buffer, + const dns_header* header); + void _ReadQueryHeader(BRawNetBuffer& buffer, + dns_header* header); + void _ReadMXRecord(BRawNetBuffer& buffer, + mx_record* mxRecord); + + void _ReadResourceRecord(BRawNetBuffer& buffer, + resource_record_head* rrHead); +}; + + +#endif // DNS_QUERY_H diff --git a/src/preferences/mail/Jamfile b/src/preferences/mail/Jamfile index 3e8797611d..8b25a438df 100644 --- a/src/preferences/mail/Jamfile +++ b/src/preferences/mail/Jamfile @@ -6,10 +6,14 @@ if $(TARGET_PLATFORM) != haiku { UsePublicHeaders mail ; } +UsePublicHeaders [ FDirName add-ons mail_daemon ] ; UsePrivateHeaders mail ; SubDirHdrs [ FDirName $(HAIKU_TOP) headers os add-ons mail_daemon ] ; +# for BObjectList.h +UsePrivateHeaders shared ; + # TODO(bga): E-mail preferences does not really need to link against the # OpenSSL libraries. Remove this after problems with the runtile loader are # sorted up. Details here: @@ -31,11 +35,15 @@ if $(USE_SSL) { Preference E-mail : Account.cpp + AutoConfig.cpp + AutoConfigWindow.cpp + AutoConfigView.cpp CenterContainer.cpp ConfigViews.cpp ConfigWindow.cpp - main.cpp - : be libmail.so + DNSQuery.cpp + main.cpp + : be libmail.so $(HAIKU_NETWORK_LIBS) $(TARGET_NETAPI_LIB) : e-mail.rdef ; @@ -46,3 +54,6 @@ if $(USE_SSL) { Package haiku-maildaemon-cvs : E-mail : boot beos preferences ; + +SubInclude HAIKU_TOP src preferences mail ProviderInfo ; + diff --git a/src/preferences/mail/ProviderInfo/Jamfile b/src/preferences/mail/ProviderInfo/Jamfile new file mode 100644 index 0000000000..ac5a1e095e --- /dev/null +++ b/src/preferences/mail/ProviderInfo/Jamfile @@ -0,0 +1,26 @@ +SubDir HAIKU_TOP src preferences mail ProviderInfo ; + +SetSubDirSupportedPlatformsBeOSCompatible ; + +HAIKU_PROVIDER_INFOS = + aol.com + arcor.de + cern.ch + freenet.de + gmx.de + googlemail.com + lycos.de + mymail.ch + netcologne.de + o2online.de + physik.rwth-aachen.de + rwth-aachen.de + t-online.de + web.de + yahoo.de +; + +for file in $(HAIKU_PROVIDER_INFOS) { + ResAttr $(file) : "$(file).rdef" : true ; +} + diff --git a/src/preferences/mail/ProviderInfo/aol.com.rdef b/src/preferences/mail/ProviderInfo/aol.com.rdef new file mode 100644 index 0000000000..a140325b9e --- /dev/null +++ b/src/preferences/mail/ProviderInfo/aol.com.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.aol.com"; +resource(2, "IMAP Server") "imap.aol.com"; +resource(3, "SMTP Server") "smtp.aol.com"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 1; diff --git a/src/preferences/mail/ProviderInfo/arcor.de.rdef b/src/preferences/mail/ProviderInfo/arcor.de.rdef new file mode 100644 index 0000000000..c8a9927aa2 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/arcor.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop3.arcor.de"; +resource(2, "IMAP Server") "imap.arcor.de"; +resource(3, "SMTP Server") "mail.arcor.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 1; diff --git a/src/preferences/mail/ProviderInfo/cern.ch.rdef b/src/preferences/mail/ProviderInfo/cern.ch.rdef new file mode 100644 index 0000000000..3936bdfd98 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/cern.ch.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.cern.ch"; +resource(2, "IMAP Server") "imap.cern.ch"; +resource(3, "SMTP Server") "mail.cern.ch"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 1; +resource(7, "IMAP SSL") 1; +resource(8, "SMTP SSL") 1; +resource(9, "Username Pattern") 2; diff --git a/src/preferences/mail/ProviderInfo/freenet.de.rdef b/src/preferences/mail/ProviderInfo/freenet.de.rdef new file mode 100644 index 0000000000..dfcd82507e --- /dev/null +++ b/src/preferences/mail/ProviderInfo/freenet.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "mx.freenet.de"; +resource(2, "IMAP Server") "mx.freenet.de"; +resource(3, "SMTP Server") "mx.freenet.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 0; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/gmx.de.rdef b/src/preferences/mail/ProviderInfo/gmx.de.rdef new file mode 100644 index 0000000000..62b41c05fc --- /dev/null +++ b/src/preferences/mail/ProviderInfo/gmx.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.gmx.net"; +resource(2, "IMAP Server") "imap.gmx.net"; +resource(3, "SMTP Server") "mail.gmx.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 0; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/googlemail.com.rdef b/src/preferences/mail/ProviderInfo/googlemail.com.rdef new file mode 100644 index 0000000000..bcd44cb76d --- /dev/null +++ b/src/preferences/mail/ProviderInfo/googlemail.com.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.googlemail.com"; +resource(2, "IMAP Server") "imap.googlemail.com"; +resource(3, "SMTP Server") "smtp.googlemail.com"; +resource(4, "POP Authentification") 1; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 1; +resource(7, "IMAP SSL") 1; +resource(8, "SMTP SSL") 1; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/lycos.de.rdef b/src/preferences/mail/ProviderInfo/lycos.de.rdef new file mode 100644 index 0000000000..1019cb4d01 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/lycos.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.premiummail.lycos.de"; +resource(2, "IMAP Server") ""; +resource(3, "SMTP Server") "smtp.premiummail.lycos.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/mymail.ch.rdef b/src/preferences/mail/ProviderInfo/mymail.ch.rdef new file mode 100644 index 0000000000..c74c3c1f3c --- /dev/null +++ b/src/preferences/mail/ProviderInfo/mymail.ch.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "mail.mymail.ch"; +resource(2, "IMAP Server") "mail.mymail.ch"; +resource(3, "SMTP Server") "mail.mymail.ch"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 1; diff --git a/src/preferences/mail/ProviderInfo/netcologne.de.rdef b/src/preferences/mail/ProviderInfo/netcologne.de.rdef new file mode 100644 index 0000000000..b8d670a94b --- /dev/null +++ b/src/preferences/mail/ProviderInfo/netcologne.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop3.netcologne.de"; +resource(2, "IMAP Server") ""; +resource(3, "SMTP Server") "smtp.netcologne.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 2; diff --git a/src/preferences/mail/ProviderInfo/o2online.de.rdef b/src/preferences/mail/ProviderInfo/o2online.de.rdef new file mode 100644 index 0000000000..dd5c21c655 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/o2online.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.o2online.de"; +resource(2, "IMAP Server") "imap.o2online.de"; +resource(3, "SMTP Server") "mail.o2online.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/physik.rwth-aachen.de.rdef b/src/preferences/mail/ProviderInfo/physik.rwth-aachen.de.rdef new file mode 100644 index 0000000000..a6b521686a --- /dev/null +++ b/src/preferences/mail/ProviderInfo/physik.rwth-aachen.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "mailbox.rwth-aachen.de"; +resource(2, "IMAP Server") "mailbox.rwth-aachen.de"; +resource(3, "SMTP Server") "relay-auth.rwth-aachen.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 2; diff --git a/src/preferences/mail/ProviderInfo/rwth-aachen.de.rdef b/src/preferences/mail/ProviderInfo/rwth-aachen.de.rdef new file mode 100644 index 0000000000..a6b521686a --- /dev/null +++ b/src/preferences/mail/ProviderInfo/rwth-aachen.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "mailbox.rwth-aachen.de"; +resource(2, "IMAP Server") "mailbox.rwth-aachen.de"; +resource(3, "SMTP Server") "relay-auth.rwth-aachen.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 2; diff --git a/src/preferences/mail/ProviderInfo/t-online.de.rdef b/src/preferences/mail/ProviderInfo/t-online.de.rdef new file mode 100644 index 0000000000..d445aa082b --- /dev/null +++ b/src/preferences/mail/ProviderInfo/t-online.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "popmail.t-online.de"; +resource(2, "IMAP Server") ""; +resource(3, "SMTP Server") "smtpmail.t-online.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 0; diff --git a/src/preferences/mail/ProviderInfo/web.de.rdef b/src/preferences/mail/ProviderInfo/web.de.rdef new file mode 100644 index 0000000000..47e71ea796 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/web.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop3.web.de"; +resource(2, "IMAP Server") "imap.web.net"; +resource(3, "SMTP Server") "smtp.web.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 1; diff --git a/src/preferences/mail/ProviderInfo/yahoo.de.rdef b/src/preferences/mail/ProviderInfo/yahoo.de.rdef new file mode 100644 index 0000000000..7eafb75611 --- /dev/null +++ b/src/preferences/mail/ProviderInfo/yahoo.de.rdef @@ -0,0 +1,9 @@ +resource(1, "POP Server") "pop.mail.yahoo.de"; +resource(2, "IMAP Server") ""; +resource(3, "SMTP Server") "smtp.mail.yahoo.de"; +resource(4, "POP Authentification") 0; +resource(5, "SMTP Authentification") 1; +resource(6, "POP SSL") 0; +resource(7, "IMAP SSL") 0; +resource(8, "SMTP SSL") 0; +resource(9, "Username Pattern") 1;