xref: /haiku/src/preferences/mail/AutoConfigView.cpp (revision 98057dd02a2411868fd4c35f7a48d20acfd92c23)
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_TRANSLATE_CONTEXT
27 #define B_TRANSLATE_CONTEXT "E-Mail"
28 
29 
30 AutoConfigView::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 
97 void
98 AutoConfigView::AttachedToWindow()
99 {
100 	fEmailView->SetTarget(this);
101 	fEmailView->MakeFocus(true);
102 }
103 
104 
105 void
106 AutoConfigView::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 
131 bool
132 AutoConfigView::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 
161 BMenuField*
162 AutoConfigView::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 
204 status_t
205 AutoConfigView::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 
231 BString
232 AutoConfigView::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 
242 void
243 AutoConfigView::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 
270 bool
271 AutoConfigView::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 
287 ServerSettingsView::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 
414 ServerSettingsView::~ServerSettingsView()
415 {
416 	RemoveChild(fInboundAuthMenu);
417 	RemoveChild(fInboundEncryptionMenu);
418 	delete fInboundAuthMenu;
419 	delete fInboundEncryptionMenu;
420 	unload_add_on(fImageId);
421 }
422 
423 
424 void
425 ServerSettingsView::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 
475 void
476 ServerSettingsView::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 
507 void
508 ServerSettingsView::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