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