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