1/*
2 * Copyright 2007-2011, Haiku, Inc. All rights reserved.
3 * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "AutoConfigView.h"
9
10#include <pwd.h>
11
12#include <Catalog.h>
13#include <Directory.h>
14#include <Entry.h>
15#include <FindDirectory.h>
16#include <Message.h>
17#include <MenuItem.h>
18#include <Path.h>
19#include <PopUpMenu.h>
20#include <String.h>
21#include <Window.h>
22
23#include <MailSettings.h>
24
25
26#undef B_TRANSLATION_CONTEXT
27#define B_TRANSLATION_CONTEXT "E-Mail"
28
29
30AutoConfigView::AutoConfigView(BRect rect, AutoConfig &config)
31	:
32	BBox(rect),
33	fAutoConfig(config)
34{
35	int32 stepSize = 30;
36	int32 divider = 100;
37	BPoint topLeft(20, 20);
38	BPoint rightDown(rect.Width() - 20, 20 + stepSize);
39
40	// protocol view
41	topLeft.y += stepSize;
42	rightDown.y += stepSize;
43	fInProtocolsField = SetupProtocolView(BRect(topLeft, rightDown));
44	if (fInProtocolsField)
45		AddChild(fInProtocolsField);
46
47	// search for smtp ref
48	GetSMTPAddonRef(&fSMTPAddonRef);
49
50	// email view
51	topLeft.y += stepSize;
52	rightDown.y += stepSize;
53	fEmailView = new BTextControl(BRect(topLeft, rightDown), "email",
54		B_TRANSLATE("E-mail address:"), "", new BMessage(kEMailChangedMsg));
55	fEmailView->SetDivider(divider);
56	AddChild(fEmailView);
57
58	// login name view
59	topLeft.y += stepSize;
60	rightDown.y += stepSize;
61	fLoginNameView = new BTextControl(BRect(topLeft, rightDown),
62		"login", B_TRANSLATE("Login name:"), "", NULL);
63	fLoginNameView->SetDivider(divider);
64	AddChild(fLoginNameView);
65
66	// password view
67	topLeft.y += stepSize;
68	rightDown.y += stepSize;
69	fPasswordView = new BTextControl(BRect(topLeft, rightDown), "password",
70		B_TRANSLATE("Password:"), "", NULL);
71	fPasswordView->SetDivider(divider);
72	fPasswordView->TextView()->HideTyping(true);
73	AddChild(fPasswordView);
74
75	// account view
76	topLeft.y += stepSize;
77	rightDown.y += stepSize;
78	fAccountNameView = new BTextControl(BRect(topLeft, rightDown), "account",
79		B_TRANSLATE("Account name:"), "", NULL);
80	fAccountNameView->SetDivider(divider);
81	AddChild(fAccountNameView);
82
83	// name view
84	topLeft.y += stepSize;
85	rightDown.y += stepSize;
86	fNameView = new BTextControl(BRect(topLeft, rightDown), "name",
87		B_TRANSLATE("Real name:"), "", NULL);
88	AddChild(fNameView);
89	fNameView->SetDivider(divider);
90
91	struct passwd* passwd = getpwent();
92	if (passwd != NULL)
93		fNameView->SetText(passwd->pw_gecos);
94}
95
96
97void
98AutoConfigView::AttachedToWindow()
99{
100	fEmailView->SetTarget(this);
101	fEmailView->MakeFocus(true);
102}
103
104
105void
106AutoConfigView::MessageReceived(BMessage *msg)
107{
108	BString text, login;
109	switch (msg->what)
110	{
111		case kEMailChangedMsg:
112		{
113			text = fLoginNameView->Text();
114			if (text == "")
115				ProposeUsername();
116			fLoginNameView->MakeFocus();
117			fLoginNameView->TextView()->SelectAll();
118
119			text = fAccountNameView->Text();
120			if (text == "")
121				fAccountNameView->SetText(fEmailView->Text());
122			break;
123		}
124		default:
125			BView::MessageReceived(msg);
126			break;
127	}
128}
129
130
131bool
132AutoConfigView::GetBasicAccountInfo(account_info &info)
133{
134	status_t status = B_OK;
135
136	BString inboundProtocolName = "";
137	BMenuItem* item = fInProtocolsField->Menu()->FindMarked();
138	if (item) {
139		inboundProtocolName = item->Label();
140		item->Message()->FindRef("protocol", &(info.inboundProtocol));
141	}
142	else
143		status = B_ERROR;
144
145	if (inboundProtocolName.FindFirst("IMAP") >= 0)
146		info.inboundType = IMAP;
147	else
148		info.inboundType = POP;
149
150	info.outboundProtocol = fSMTPAddonRef;
151	info.name = fNameView->Text();
152	info.accountName = fAccountNameView->Text();
153	info.email = fEmailView->Text();
154	info.loginName = fLoginNameView->Text();
155	info.password = fPasswordView->Text();
156
157	return status;
158}
159
160
161BMenuField*
162AutoConfigView::SetupProtocolView(BRect rect)
163{
164	BPopUpMenu *menu = new BPopUpMenu(B_TRANSLATE("Choose Protocol"));
165
166	for (int i = 0; i < 2; i++) {
167		BPath path;
168		status_t status = find_directory((i == 0) ? B_USER_ADDONS_DIRECTORY :
169			B_BEOS_ADDONS_DIRECTORY, &path);
170		if (status != B_OK)
171			return NULL;
172
173		path.Append("mail_daemon");
174		path.Append("inbound_protocols");
175
176		BDirectory dir(path.Path());
177		entry_ref protocolRef;
178		while (dir.GetNextRef(&protocolRef) == B_OK)
179		{
180			char name[B_FILE_NAME_LENGTH];
181			BEntry entry(&protocolRef);
182			entry.GetName(name);
183
184			BMenuItem *item;
185			BMessage *msg = new BMessage(kProtokollChangedMsg);
186			menu->AddItem(item = new BMenuItem(name, msg));
187			msg->AddRef("protocol", &protocolRef);
188
189			item->SetMarked(true);
190		}
191	}
192
193	// make imap default protocol if existing
194	BMenuItem* imapItem =  menu->FindItem("IMAP");
195	if (imapItem)
196		imapItem->SetMarked(true);
197
198	BMenuField *protocolsMenuField = new BMenuField(rect, NULL, NULL, menu);
199	protocolsMenuField->ResizeToPreferred();
200	return protocolsMenuField;
201}
202
203
204status_t
205AutoConfigView::GetSMTPAddonRef(entry_ref *ref)
206{
207	directory_which which[] = {
208		B_USER_ADDONS_DIRECTORY,
209		B_BEOS_ADDONS_DIRECTORY
210	};
211
212	for (size_t i = 0; i < sizeof(which) / sizeof(which[0]); i++) {
213		BPath path;
214		status_t status = find_directory(which[i], &path);
215		if (status != B_OK)
216			return B_ERROR;
217
218		path.Append("mail_daemon");
219		path.Append("outbound_protocols");
220		path.Append("SMTP");
221
222		BEntry entry(path.Path());
223		if (entry.Exists() && entry.GetRef(ref) == B_OK)
224			return B_OK;
225	}
226
227	return B_FILE_NOT_FOUND;
228}
229
230
231BString
232AutoConfigView::ExtractLocalPart(const char* email)
233{
234	BString emailS(email);
235	BString localPart;
236	int32 at = emailS.FindLast("@");
237	emailS.CopyInto(localPart, 0, at);
238	return localPart;
239}
240
241
242void
243AutoConfigView::ProposeUsername()
244{
245	const char* email = fEmailView->Text();
246	provider_info info;
247	status_t status = fAutoConfig.GetInfoFromMailAddress(email, &info);
248	if (status == B_OK) {
249		BString localPart = ExtractLocalPart(email);
250		switch (info.username_pattern) {
251			case 0:
252				// username is the mail address
253				fLoginNameView->SetText(email);
254				break;
255			case 1:
256				// username is the local-part
257				fLoginNameView->SetText(localPart.String());
258				break;
259			case 2:
260				// do nothing
261				break;
262		}
263	}
264	else {
265		fLoginNameView->SetText(email);
266	}
267}
268
269
270bool
271AutoConfigView::IsValidMailAddress(BString email)
272{
273	int32 atPos = email.FindFirst("@");
274	if (atPos < 0)
275		return false;
276	BString provider;
277	email.CopyInto(provider, atPos + 1, email.Length() - atPos);
278	if (provider.FindLast(".") < 0)
279		return false;
280	return true;
281}
282
283
284// #pragma mark -
285
286
287ServerSettingsView::ServerSettingsView(BRect rect, const account_info &info)
288	:
289	BView(rect, NULL,B_FOLLOW_ALL,0),
290	fInboundAccount(true),
291	fOutboundAccount(true),
292	fInboundAuthMenu(NULL),
293	fOutboundAuthMenu(NULL),
294	fInboundEncrItemStart(NULL),
295	fOutboundEncrItemStart(NULL),
296	fImageId(-1)
297{
298	SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
299
300	int32 divider = 120;
301
302	fInboundAccount = true;
303	fOutboundAccount = true;
304
305	// inbound
306	BRect boxRect = Bounds();
307	boxRect.bottom /= 2;
308	boxRect.bottom -= 5;
309
310	BBox *box = new BBox(boxRect);
311	box->SetLabel(B_TRANSLATE("Incoming"));
312	AddChild(box);
313
314	BString serverName;
315	if (info.inboundType == IMAP)
316		serverName = info.providerInfo.imap_server;
317	else
318		serverName = info.providerInfo.pop_server;
319
320	fInboundNameView = new BTextControl(BRect(10, 20, rect.Width() - 20, 35),
321		"inbound", B_TRANSLATE("Server Name:"), serverName.String(),
322		new BMessage(kServerChangedMsg));
323	fInboundNameView->SetDivider(divider);
324
325	box->AddChild(fInboundNameView);
326
327	GetAuthEncrMenu(info.inboundProtocol, &fInboundAuthMenu,
328		&fInboundEncryptionMenu);
329	if (fInboundAuthMenu != NULL) {
330		int authID = info.providerInfo.authentification_pop;
331		if (info.inboundType == POP)
332			fInboundAuthMenu->Menu()->ItemAt(authID)->SetMarked(true);
333		fInboundAuthItemStart = fInboundAuthMenu->Menu()->FindMarked();
334		box->AddChild(fInboundAuthMenu);
335		fInboundAuthMenu->SetDivider(divider);
336		fInboundAuthMenu->MoveTo(10, 50);
337	}
338	if (fInboundEncryptionMenu) {
339		BMenuItem *item = NULL;
340		if (info.inboundType == POP) {
341			item = fInboundEncryptionMenu->Menu()->ItemAt(
342				info.providerInfo.ssl_pop);
343			if (item != NULL)
344				item->SetMarked(true);
345			fInboundEncryptionMenu->MoveTo(10, 80);
346		}
347		if (info.inboundType == IMAP) {
348			item = fInboundEncryptionMenu->Menu()->ItemAt(
349				info.providerInfo.ssl_imap);
350			if (item != NULL)
351				item->SetMarked(true);
352			fInboundEncryptionMenu->MoveTo(10, 50);
353		}
354		fInboundEncrItemStart = fInboundEncryptionMenu->Menu()->FindMarked();
355		box->AddChild(fInboundEncryptionMenu);
356		fInboundEncryptionMenu->SetDivider(divider);
357	}
358
359	if (!fInboundAccount) {
360		fInboundNameView->SetEnabled(false);
361		if (fInboundAuthMenu)
362			fInboundAuthMenu->SetEnabled(false);
363	}
364
365	// outbound
366	boxRect = Bounds();
367	boxRect.top = boxRect.bottom / 2;
368	boxRect.top += 5;
369
370	box = new BBox(boxRect);
371	box->SetLabel(B_TRANSLATE("Outgoing"));
372	AddChild(box);
373
374	serverName = info.providerInfo.smtp_server;
375	fOutboundNameView = new BTextControl(BRect(10, 20, rect.Width() - 20, 30),
376		"outbound", B_TRANSLATE("Server name:"), serverName.String(),
377		new BMessage(kServerChangedMsg));
378	fOutboundNameView->SetDivider(divider);
379
380	box->AddChild(fOutboundNameView);
381
382	GetAuthEncrMenu(info.outboundProtocol, &fOutboundAuthMenu,
383		&fOutboundEncryptionMenu);
384	if (fOutboundAuthMenu != NULL) {
385		BMenuItem *item = fOutboundAuthMenu->Menu()->ItemAt(
386			info.providerInfo.authentification_smtp);
387		if (item != NULL)
388			item->SetMarked(true);
389		fOutboundAuthItemStart = item;
390		box->AddChild(fOutboundAuthMenu);
391		fOutboundAuthMenu->SetDivider(divider);
392		fOutboundAuthMenu->MoveTo(10, 50);
393	}
394	if (fOutboundEncryptionMenu != NULL) {
395		BMenuItem *item = fOutboundEncryptionMenu->Menu()->ItemAt(
396			info.providerInfo.ssl_smtp);
397		if (item != NULL)
398			item->SetMarked(true);
399		fOutboundEncrItemStart = item;
400		box->AddChild(fOutboundEncryptionMenu);
401		fOutboundEncryptionMenu->SetDivider(divider);
402		fOutboundEncryptionMenu->MoveTo(10, 80);
403	}
404
405	if (!fOutboundAccount) {
406		fOutboundNameView->SetEnabled(false);
407		if (fOutboundAuthMenu)
408			fOutboundAuthMenu->SetEnabled(false);
409	}
410
411}
412
413
414ServerSettingsView::~ServerSettingsView()
415{
416	RemoveChild(fInboundAuthMenu);
417	RemoveChild(fInboundEncryptionMenu);
418	delete fInboundAuthMenu;
419	delete fInboundEncryptionMenu;
420	unload_add_on(fImageId);
421}
422
423
424void
425ServerSettingsView::GetServerInfo(account_info &info)
426{
427	if (info.inboundType == IMAP) {
428		info.providerInfo.imap_server = fInboundNameView->Text();
429		if (fInboundEncryptionMenu != NULL) {
430			BMenuItem* item = fInboundEncryptionMenu->Menu()->FindMarked();
431			if (item != NULL) {
432				info.providerInfo.ssl_imap
433					= fInboundEncryptionMenu->Menu()->IndexOf(item);
434			}
435		}
436	} else {
437		info.providerInfo.pop_server = fInboundNameView->Text();
438		BMenuItem* item = NULL;
439		if (fInboundAuthMenu != NULL) {
440			item = fInboundAuthMenu->Menu()->FindMarked();
441			if (item != NULL) {
442				info.providerInfo.authentification_pop
443					= fInboundAuthMenu->Menu()->IndexOf(item);
444			}
445		}
446		if (fInboundEncryptionMenu != NULL) {
447			item = fInboundEncryptionMenu->Menu()->FindMarked();
448			if (item != NULL) {
449				info.providerInfo.ssl_pop
450					= fInboundEncryptionMenu->Menu()->IndexOf(item);
451			}
452		}
453	}
454	info.providerInfo.smtp_server = fOutboundNameView->Text();
455	BMenuItem* item = NULL;
456	if (fOutboundAuthMenu != NULL) {
457		item = fOutboundAuthMenu->Menu()->FindMarked();
458		if (item != NULL) {
459			info.providerInfo.authentification_smtp
460				= fOutboundAuthMenu->Menu()->IndexOf(item);
461		}
462	}
463
464	if (fOutboundEncryptionMenu != NULL) {
465		item = fOutboundEncryptionMenu->Menu()->FindMarked();
466		if (item != NULL) {
467			info.providerInfo.ssl_smtp
468				= fOutboundEncryptionMenu->Menu()->IndexOf(item);
469		}
470	}
471	DetectMenuChanges();
472}
473
474
475void
476ServerSettingsView::DetectMenuChanges()
477{
478	bool changed = false;
479	if (fInboundAuthMenu != NULL) {
480		BMenuItem *item = fInboundAuthMenu->Menu()->FindMarked();
481		if (fInboundAuthItemStart != item)
482			changed = true;
483	}
484	if (fInboundEncryptionMenu != NULL) {
485		BMenuItem *item = fInboundEncryptionMenu->Menu()->FindMarked();
486		if (fInboundEncrItemStart != item)
487			changed = true;
488	}
489	if (fOutboundAuthMenu != NULL) {
490		BMenuItem *item = fOutboundAuthMenu->Menu()->FindMarked();
491		if (fOutboundAuthItemStart != item)
492			changed = true;
493	}
494	if (fOutboundEncryptionMenu != NULL) {
495		BMenuItem *item = fOutboundEncryptionMenu->Menu()->FindMarked();
496		if (fOutboundEncrItemStart != item)
497			changed = true;
498	}
499	if (changed) {
500		BMessage msg(kServerChangedMsg);
501		BMessenger messenger(NULL, Window()->Looper());
502		messenger.SendMessage(&msg);
503	}
504}
505
506
507void
508ServerSettingsView::GetAuthEncrMenu(entry_ref protocol,
509	BMenuField **authField, BMenuField **sslField)
510{
511	BMailAccountSettings dummySettings;
512	BView *view = CreateConfigView(protocol, dummySettings.InboundSettings(),
513		dummySettings, &fImageId);
514
515	*authField = (BMenuField *)view->FindView("auth_method");
516	*sslField = (BMenuField *)view->FindView("flavor");
517
518	view->RemoveChild(*authField);
519	view->RemoveChild(*sslField);
520	delete view;
521}
522