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
AutoConfigView(AutoConfig & config)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
AttachedToWindow()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
MessageReceived(BMessage * msg)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
GetBasicAccountInfo(account_info & info)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*
_SetupProtocolMenu()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
_GetSMTPAddOnRef(entry_ref * ref)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
_ExtractLocalPart(const char * email)222 AutoConfigView::_ExtractLocalPart(const char* email)
223 {
224 const char* at = strrchr(email, '@');
225 return BString(email, at - email);
226 }
227
228
229 void
_ProposeUsername()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
IsValidMailAddress(BString email)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
ServerSettingsView(const account_info & info)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
~ServerSettingsView()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
GetServerInfo(account_info & info)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
_DetectMenuChanges()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
_HasMarkedChanged(BMenuField * field,BMenuItem * originalItem)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
_GetAuthEncrMenu(entry_ref protocol,BMenuField * & authField,BMenuField * & sslField)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