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