1 /* 2 * Copyright 2007-2010, Haiku, Inc. All rights reserved. 3 * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 //! main E-Mail config window 10 #include <new> 11 #include <stdio.h> 12 #include <string.h> 13 14 #include <Application.h> 15 #include <Catalog.h> 16 #include <ListView.h> 17 #include <ScrollView.h> 18 #include <StringView.h> 19 #include <Button.h> 20 #include <CheckBox.h> 21 #include <MenuField.h> 22 #include <TextControl.h> 23 #include <TextView.h> 24 #include <MenuItem.h> 25 #include <Screen.h> 26 #include <PopUpMenu.h> 27 #include <MenuBar.h> 28 #include <TabView.h> 29 #include <Box.h> 30 #include <Alert.h> 31 #include <Bitmap.h> 32 #include <Roster.h> 33 #include <Resources.h> 34 #include <Region.h> 35 36 #include <AppFileInfo.h> 37 #include <Entry.h> 38 #include <Directory.h> 39 #include <FindDirectory.h> 40 #include <Path.h> 41 42 #include <Catalog.h> 43 #include <Locale.h> 44 45 #include <MailDaemon.h> 46 #include <MailSettings.h> 47 48 #include "AutoConfigWindow.h" 49 #include "ConfigWindow.h" 50 #include "CenterContainer.h" 51 52 #undef B_TRANSLATE_CONTEXT 53 #define B_TRANSLATE_CONTEXT "Config Window" 54 55 56 using std::nothrow; 57 58 // define if you want to have an apply button 59 //#define HAVE_APPLY_BUTTON 60 61 const char *kEMail = "bemaildaemon-talk@bug-br.org.br"; 62 const char *kMailto = "mailto:bemaildaemon-talk@bug-br.org.br"; 63 const char *kBugsitePretty = "Bug-Tracker at SourceForge.net"; 64 const char *kBugsite = "http://sourceforge.net/tracker/?func=add&group_id=26926&atid=388726"; 65 const char *kWebsite = "http://www.haiku-os.org"; 66 const rgb_color kLinkColor = { 40, 40, 180, 255 }; 67 68 69 const uint32 kMsgAccountsRightClicked = 'arcl'; 70 const uint32 kMsgAccountSelected = 'acsl'; 71 const uint32 kMsgAddAccount = 'adac'; 72 const uint32 kMsgRemoveAccount = 'rmac'; 73 74 const uint32 kMsgIntervalUnitChanged = 'iuch'; 75 76 const uint32 kMsgShowStatusWindowChanged = 'shst'; 77 const uint32 kMsgStatusLookChanged = 'lkch'; 78 const uint32 kMsgStatusWorkspaceChanged = 'wsch'; 79 80 const uint32 kMsgSaveSettings = 'svst'; 81 const uint32 kMsgRevertSettings = 'rvst'; 82 const uint32 kMsgCancelSettings = 'cnst'; 83 84 85 86 AccountItem::AccountItem(const char* label, BMailAccountSettings* account, 87 item_types type) 88 : 89 BStringItem(label), 90 fAccount(account), 91 fType(type), 92 fConfigPanel(NULL) 93 { 94 } 95 96 97 void 98 AccountItem::Update(BView* owner, const BFont* font) 99 { 100 if (fType == ACCOUNT_ITEM) 101 font = be_bold_font; 102 103 BStringItem::Update(owner,font); 104 } 105 106 107 void 108 AccountItem::DrawItem(BView* owner, BRect rect, bool complete) 109 { 110 owner->PushState(); 111 if (fType == ACCOUNT_ITEM) 112 owner->SetFont(be_bold_font); 113 114 BStringItem::DrawItem(owner, rect, complete); 115 owner->PopState(); 116 } 117 118 119 void 120 AccountItem::SetConfigPanel(BView* panel) 121 { 122 fConfigPanel = panel; 123 } 124 125 126 BView* 127 AccountItem::ConfigPanel() 128 { 129 return fConfigPanel; 130 } 131 132 133 // #pragma mark - 134 135 136 class AccountsListView : public BListView { 137 public: 138 AccountsListView(BRect rect, BHandler* target) 139 : 140 BListView(rect, NULL, B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL), 141 fTarget(target) 142 { 143 } 144 145 void 146 KeyDown(const char *bytes, int32 numBytes) 147 { 148 if (numBytes != 1) 149 return; 150 151 if ((*bytes == B_DELETE) || (*bytes == B_BACKSPACE)) 152 Window()->PostMessage(kMsgRemoveAccount); 153 154 BListView::KeyDown(bytes,numBytes); 155 } 156 157 void 158 MouseDown(BPoint point) 159 { 160 BListView::MouseDown(point); 161 162 BPoint dummy; 163 uint32 buttons; 164 GetMouse(&dummy, &buttons); 165 if (buttons != B_SECONDARY_MOUSE_BUTTON) 166 return; 167 168 int32 index = IndexOf(point); 169 if (index < 0) 170 return; 171 172 BMessage message(kMsgAccountsRightClicked); 173 ConvertToScreen(&point); 174 message.AddPoint("point", point); 175 message.AddInt32("index", index); 176 BMessenger messenger(fTarget); 177 messenger.SendMessage(&message); 178 } 179 180 private: 181 BHandler* fTarget; 182 }; 183 184 185 class BitmapView : public BView 186 { 187 public: 188 BitmapView(BBitmap *bitmap) : BView(bitmap->Bounds(), NULL, 189 B_FOLLOW_NONE, B_WILL_DRAW) 190 { 191 fBitmap = bitmap; 192 193 SetDrawingMode(B_OP_ALPHA); 194 SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 195 } 196 197 ~BitmapView() 198 { 199 delete fBitmap; 200 } 201 202 virtual void AttachedToWindow() 203 { 204 SetViewColor(Parent()->ViewColor()); 205 206 MoveTo((Parent()->Bounds().Width() - Bounds().Width()) / 2, 207 Frame().top); 208 } 209 210 virtual void Draw(BRect updateRect) 211 { 212 DrawBitmap(fBitmap, updateRect, updateRect); 213 } 214 215 private: 216 BBitmap *fBitmap; 217 }; 218 219 220 class AboutTextView : public BTextView 221 { 222 public: 223 AboutTextView(BRect rect) : BTextView(rect, NULL, 224 rect.OffsetToCopy(B_ORIGIN), B_FOLLOW_NONE, B_WILL_DRAW) 225 { 226 int32 major = 0,middle = 0,minor = 0,variety = 0,internal = 1; 227 228 // get version information for app 229 230 app_info appInfo; 231 if (be_app->GetAppInfo(&appInfo) == B_OK) { 232 BFile file(&appInfo.ref, B_READ_ONLY); 233 if (file.InitCheck() == B_OK) { 234 BAppFileInfo info(&file); 235 if (info.InitCheck() == B_OK) { 236 version_info versionInfo; 237 if (info.GetVersionInfo(&versionInfo, 238 B_APP_VERSION_KIND) == B_OK) { 239 major = versionInfo.major; 240 middle = versionInfo.middle; 241 minor = versionInfo.minor; 242 variety = versionInfo.variety; 243 internal = versionInfo.internal; 244 } 245 } 246 } 247 } 248 // prepare version variety string 249 const char *varietyStrings[] = {B_TRANSLATE("Development"), 250 B_TRANSLATE("Alpha"),B_TRANSLATE("Beta"),B_TRANSLATE("Gamma"), 251 B_TRANSLATE("Golden master"),B_TRANSLATE("Final")}; 252 char varietyString[32]; 253 strcpy(varietyString,varietyStrings[variety % 6]); 254 if (variety < 5) 255 sprintf(varietyString + strlen(varietyString),"/%li",internal); 256 257 char s[512]; 258 sprintf(s, B_TRANSLATE("Mail Daemon Replacement\n\n" 259 "by Haiku, Inc. All rights reserved.\n\n" 260 "Version %ld.%ld.%ld %s\n\n" 261 "See LICENSE file included in the installation package " 262 "for more information.\n\n\n\n" 263 "You can contact us at:\n" 264 "%s\n\n" 265 "Please submit bug reports using the %s\n\n" 266 "Project homepage at:\n%s"), 267 major,middle,minor,varietyString, 268 kEMail,kBugsitePretty,kWebsite); 269 270 SetText(s); 271 MakeEditable(false); 272 MakeSelectable(false); 273 274 SetAlignment(B_ALIGN_CENTER); 275 SetStylable(true); 276 277 // aethetical changes 278 BFont font; 279 GetFont(&font); 280 font.SetSize(24); 281 SetFontAndColor(0,23,&font,B_FONT_SIZE); 282 283 // center the view vertically 284 rect = TextRect(); 285 rect.OffsetTo(0,(Bounds().Height() - TextHeight(0,42)) / 2); 286 SetTextRect(rect); 287 288 // set the link regions 289 int start = strstr(s,kEMail) - s; 290 int finish = start + strlen(kEMail); 291 GetTextRegion(start,finish,&fMail); 292 SetFontAndColor(start,finish,NULL,0,&kLinkColor); 293 294 start = strstr(s,kBugsitePretty) - s; 295 finish = start + strlen(kBugsitePretty); 296 GetTextRegion(start,finish,&fBugsite); 297 SetFontAndColor(start,finish,NULL,0,&kLinkColor); 298 299 start = strstr(s,kWebsite) - s; 300 finish = start + strlen(kWebsite); 301 GetTextRegion(start,finish,&fWebsite); 302 SetFontAndColor(start,finish,NULL,0,&kLinkColor); 303 } 304 305 virtual void Draw(BRect updateRect) 306 { 307 BTextView::Draw(updateRect); 308 309 BRect rect(fMail.Frame()); 310 StrokeLine(BPoint(rect.left,rect.bottom-2), 311 BPoint(rect.right,rect.bottom-2)); 312 rect = fBugsite.Frame(); 313 StrokeLine(BPoint(rect.left,rect.bottom-2), 314 BPoint(rect.right,rect.bottom-2)); 315 rect = fWebsite.Frame(); 316 StrokeLine(BPoint(rect.left,rect.bottom-2), 317 BPoint(rect.right,rect.bottom-2)); 318 } 319 320 virtual void MouseDown(BPoint point) 321 { 322 if (fMail.Contains(point)) { 323 char *arg[] = {(char *)kMailto,NULL}; 324 be_roster->Launch("text/x-email",1,arg); 325 } else if (fBugsite.Contains(point)) { 326 char *arg[] = {(char *)kBugsite,NULL}; 327 be_roster->Launch("text/html",1,arg); 328 } else if (fWebsite.Contains(point)) { 329 char *arg[] = {(char *)kWebsite, NULL}; 330 be_roster->Launch("text/html", 1, arg); 331 } 332 } 333 334 private: 335 BRegion fWebsite,fMail,fBugsite; 336 }; 337 338 339 // #pragma mark - 340 341 342 ConfigWindow::ConfigWindow() 343 : 344 BWindow(BRect(100.0, 100.0, 580.0, 540.0), B_TRANSLATE_SYSTEM_NAME("E-mail"), 345 B_TITLED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE 346 | B_NOT_RESIZABLE), 347 fLastSelectedAccount(NULL), 348 fSaveSettings(false) 349 { 350 // create controls 351 BRect rect(Bounds()); 352 BView *top = new BView(rect, NULL, B_FOLLOW_ALL, 0); 353 top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 354 AddChild(top); 355 356 // determine font height 357 font_height fontHeight; 358 top->GetFontHeight(&fontHeight); 359 int32 height = (int32)(fontHeight.ascent + fontHeight.descent 360 + fontHeight.leading) + 5; 361 362 rect.InsetBy(5, 5); rect.bottom -= 11 + height; 363 BTabView *tabView = new BTabView(rect, NULL); 364 365 BView *view; 366 rect = tabView->Bounds(); 367 rect.bottom -= tabView->TabHeight() + 4; 368 tabView->AddTab(view = new BView(rect, NULL, B_FOLLOW_ALL, 0)); 369 tabView->TabAt(0)->SetLabel(B_TRANSLATE("Accounts")); 370 view->SetViewColor(top->ViewColor()); 371 372 // accounts listview 373 374 rect = view->Bounds().InsetByCopy(8, 8); 375 rect.right = 140 - B_V_SCROLL_BAR_WIDTH; 376 rect.bottom -= height + 12; 377 fAccountsListView = new AccountsListView(rect, this); 378 view->AddChild(new BScrollView(NULL, fAccountsListView, B_FOLLOW_ALL, 0, 379 false, true)); 380 rect.right += B_V_SCROLL_BAR_WIDTH; 381 382 rect.top = rect.bottom + 8; rect.bottom = rect.top + height; 383 BRect sizeRect = rect; 384 sizeRect.right = sizeRect.left + 30 + view->StringWidth( 385 B_TRANSLATE("Add")); 386 view->AddChild(new BButton(sizeRect, NULL, B_TRANSLATE("Add"), 387 new BMessage(kMsgAddAccount), B_FOLLOW_BOTTOM)); 388 389 sizeRect.left = sizeRect.right+3; 390 sizeRect.right = sizeRect.left + 30 + view->StringWidth( 391 B_TRANSLATE("Remove")); 392 view->AddChild(fRemoveButton = new BButton( 393 sizeRect, NULL, B_TRANSLATE("Remove"), 394 new BMessage(kMsgRemoveAccount), B_FOLLOW_BOTTOM)); 395 396 // accounts config view 397 rect = view->Bounds(); 398 rect.left = fAccountsListView->Frame().right + B_V_SCROLL_BAR_WIDTH + 16; 399 rect.right -= 10; 400 fConfigView = new CenterContainer(rect); 401 view->AddChild(fConfigView); 402 403 _MakeHowToView(); 404 405 // general settings 406 407 rect = tabView->Bounds(); 408 rect.bottom -= tabView->TabHeight() + 4; 409 tabView->AddTab(view = new CenterContainer(rect)); 410 tabView->TabAt(1)->SetLabel(B_TRANSLATE("Settings")); 411 412 rect = view->Bounds().InsetByCopy(8, 8); 413 rect.right -= 1; 414 rect.bottom = rect.top + height * 5 + 15; 415 BBox *box = new BBox(rect); 416 box->SetLabel(B_TRANSLATE("Mail checking")); 417 view->AddChild(box); 418 419 rect = box->Bounds().InsetByCopy(8, 8); 420 rect.top += 7; 421 rect.bottom = rect.top + height + 5; 422 BRect tile = rect.OffsetByCopy(0, 1); 423 int32 labelWidth = (int32)view->StringWidth(B_TRANSLATE("Check every")) + 6; 424 tile.right = 80 + labelWidth; 425 fIntervalControl = new BTextControl(tile, "time", 426 B_TRANSLATE("Check every"), NULL, NULL); 427 fIntervalControl->SetDivider(labelWidth); 428 box->AddChild(fIntervalControl); 429 430 BPopUpMenu* frequencyPopUp = new BPopUpMenu(B_EMPTY_STRING); 431 const char* frequencyStrings[] = { 432 B_TRANSLATE("never"), 433 B_TRANSLATE("minutes"), 434 B_TRANSLATE("hours"), 435 B_TRANSLATE("days")}; 436 437 for (int32 i = 0; i < 4; i++) { 438 BMenuItem* item = new BMenuItem(frequencyStrings[i], 439 new BMessage(kMsgIntervalUnitChanged)); 440 frequencyPopUp->AddItem(item); 441 } 442 tile.left = tile.right + 5; 443 tile.right = rect.right; 444 tile.OffsetBy(0,-1); 445 fIntervalUnitField = new BMenuField(tile, "frequency", B_EMPTY_STRING, 446 frequencyPopUp); 447 fIntervalUnitField->SetDivider(0.0); 448 box->AddChild(fIntervalUnitField); 449 450 rect.OffsetBy(0,height + 9); 451 rect.bottom -= 2; 452 fPPPActiveCheckBox = new BCheckBox(rect, "ppp active", 453 B_TRANSLATE("Only when dial-up is connected"), NULL); 454 box->AddChild(fPPPActiveCheckBox); 455 456 rect.OffsetBy(0,height + 9); 457 rect.bottom -= 2; 458 fPPPActiveSendCheckBox = new BCheckBox(rect, "ppp activesend", 459 B_TRANSLATE("Schedule outgoing mail when dial-up is disconnected"), 460 NULL); 461 box->AddChild(fPPPActiveSendCheckBox); 462 463 // Miscellaneous settings box 464 465 rect = box->Frame(); rect.bottom = rect.top + 3 * height + 30; 466 box = new BBox(rect); 467 box->SetLabel(B_TRANSLATE("Miscellaneous")); 468 view->AddChild(box); 469 470 BPopUpMenu *statusPopUp = new BPopUpMenu(B_EMPTY_STRING); 471 const char *statusModes[] = { 472 B_TRANSLATE("Never"), 473 B_TRANSLATE("While sending"), 474 B_TRANSLATE("While sending and receiving"), 475 B_TRANSLATE("Always")}; 476 for (int32 i = 0; i < 4; i++) { 477 BMessage* msg = new BMessage(kMsgShowStatusWindowChanged); 478 BMenuItem* item = new BMenuItem(statusModes[i], msg); 479 statusPopUp->AddItem(item); 480 msg->AddInt32("ShowStatusWindow", i); 481 } 482 rect = box->Bounds().InsetByCopy(8,8); 483 rect.top += 7; 484 rect.bottom = rect.top + height + 5; 485 labelWidth = (int32)view->StringWidth( 486 B_TRANSLATE("Show connection status window:")) + 8; 487 fStatusModeField = new BMenuField(rect, "show status", 488 B_TRANSLATE("Show connection status window:"), statusPopUp); 489 fStatusModeField->SetDivider(labelWidth); 490 box->AddChild(fStatusModeField); 491 492 rect = fStatusModeField->Frame();; 493 rect.OffsetBy(0, rect.Height() + 10); 494 BMessage* msg = new BMessage(B_REFS_RECEIVED); 495 BButton *button = new BButton(rect, B_EMPTY_STRING, 496 B_TRANSLATE("Edit mailbox menu…"), msg); 497 button->ResizeToPreferred(); 498 box->AddChild(button); 499 button->SetTarget(BMessenger("application/x-vnd.Be-TRAK")); 500 501 BPath path; 502 find_directory(B_USER_SETTINGS_DIRECTORY, &path); 503 path.Append("Mail/Menu Links"); 504 BEntry entry(path.Path()); 505 if (entry.InitCheck() == B_OK && entry.Exists()) { 506 entry_ref ref; 507 entry.GetRef(&ref); 508 msg->AddRef("refs", &ref); 509 } 510 else 511 button->SetEnabled(false); 512 513 rect = button->Frame(); 514 rect.OffsetBy(rect.Width() + 30,0); 515 fAutoStartCheckBox = new BCheckBox(rect, "start daemon", 516 B_TRANSLATE("Start mail services on startup"), NULL); 517 fAutoStartCheckBox->ResizeToPreferred(); 518 box->AddChild(fAutoStartCheckBox); 519 520 // save/revert buttons 521 522 top->AddChild(tabView); 523 524 rect = tabView->Frame(); 525 rect.top = rect.bottom + 5; 526 rect.bottom = rect.top + height + 5; 527 BButton *saveButton = new BButton(rect, "apply", B_TRANSLATE("Apply"), 528 new BMessage(kMsgSaveSettings)); 529 float w,h; 530 saveButton->GetPreferredSize(&w, &h); 531 saveButton->ResizeTo(w, h); 532 saveButton->MoveTo(rect.right - w, rect.top); 533 top->AddChild(saveButton); 534 535 BButton *revertButton = new BButton(rect, "revert", B_TRANSLATE("Revert"), 536 new BMessage(kMsgRevertSettings)); 537 revertButton->GetPreferredSize(&w, &h); 538 revertButton->ResizeTo(w,h); 539 revertButton->MoveTo(saveButton->Frame().left - 25 - w, rect.top); 540 top->AddChild(revertButton); 541 542 _LoadSettings(); 543 // this will also move our window to the stored position 544 545 fAccountsListView->SetSelectionMessage(new BMessage(kMsgAccountSelected)); 546 fAccountsListView->MakeFocus(true); 547 } 548 549 550 ConfigWindow::~ConfigWindow() 551 { 552 while (fAccounts.CountItems() > 0) 553 _RemoveAccount(fAccounts.ItemAt(0)); 554 for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++) 555 delete fToDeleteAccounts.ItemAt(i); 556 } 557 558 559 void 560 ConfigWindow::_MakeHowToView() 561 { 562 app_info info; 563 if (be_app->GetAppInfo(&info) == B_OK) { 564 BFile appFile(&info.ref, B_READ_ONLY); 565 BAppFileInfo appFileInfo(&appFile); 566 if (appFileInfo.InitCheck() == B_OK) { 567 BBitmap *bitmap = new (nothrow) BBitmap(BRect(0, 0, 63, 63), 568 B_RGBA32); 569 if (appFileInfo.GetIcon(bitmap, B_LARGE_ICON) == B_OK) { 570 fConfigView->AddChild(new BitmapView(bitmap)); 571 } else 572 delete bitmap; 573 } 574 } 575 576 BRect rect = fConfigView->Bounds(); 577 BTextView *text = new BTextView(rect, NULL, rect, B_FOLLOW_NONE, 578 B_WILL_DRAW); 579 text->SetViewColor(fConfigView->Parent()->ViewColor()); 580 text->SetAlignment(B_ALIGN_CENTER); 581 text->SetText(B_TRANSLATE( 582 "\n\nCreate a new account with the Add button.\n\n" 583 "Remove an account with the Remove button on the selected item.\n\n" 584 "Select an item in the list to change its settings.")); 585 rect = text->Bounds(); 586 text->ResizeTo(rect.Width(), text->TextHeight(0, 42)); 587 text->SetTextRect(rect); 588 589 text->MakeEditable(false); 590 text->MakeSelectable(false); 591 592 fConfigView->AddChild(text); 593 594 fConfigView->Layout(); 595 } 596 597 598 void 599 ConfigWindow::_LoadSettings() 600 { 601 // load accounts 602 for (int i = 0; i < fAccounts.CountItems(); i++) 603 delete fAccounts.ItemAt(i); 604 fAccounts.MakeEmpty(); 605 606 _LoadAccounts(); 607 608 // load in general settings 609 BMailSettings settings; 610 status_t status = _SetToGeneralSettings(&settings); 611 if (status == B_OK) { 612 // move own window 613 MoveTo(settings.ConfigWindowFrame().LeftTop()); 614 } else { 615 fprintf(stderr, B_TRANSLATE("Error retrieving general settings: %s\n"), 616 strerror(status)); 617 } 618 619 BScreen screen(this); 620 BRect screenFrame(screen.Frame().InsetByCopy(0, 5)); 621 if (!screenFrame.Contains(Frame().LeftTop()) 622 || !screenFrame.Contains(Frame().RightBottom())) 623 status = B_ERROR; 624 625 if (status != B_OK) { 626 // center window on screen 627 MoveTo((screenFrame.Width() - Frame().Width()) / 2, 628 (screenFrame.Height() - Frame().Height()) / 2); 629 } 630 } 631 632 633 void 634 ConfigWindow::_LoadAccounts() 635 { 636 BMailAccounts accounts; 637 for (int32 i = 0; i < accounts.CountAccounts(); i++) 638 fAccounts.AddItem(new BMailAccountSettings(*accounts.AccountAt(i))); 639 640 for (int i = 0; i < fAccounts.CountItems(); i++) { 641 BMailAccountSettings* account = fAccounts.ItemAt(i); 642 _AddAccountToView(account); 643 } 644 } 645 646 647 void 648 ConfigWindow::_SaveSettings() 649 { 650 // remove config views (trigger view archive) 651 fConfigView->DeleteChildren(); 652 653 // collect changed accounts 654 BMessage changedAccounts(kMsgAccountsChanged); 655 for (int32 i = 0; i < fAccounts.CountItems(); i++) { 656 BMailAccountSettings* account = fAccounts.ItemAt(i); 657 if (account && account->HasBeenModified()) 658 changedAccounts.AddInt32("account", account->AccountID()); 659 } 660 for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++) { 661 BMailAccountSettings* account = fToDeleteAccounts.ItemAt(i); 662 changedAccounts.AddInt32("account", account->AccountID()); 663 } 664 665 // cleanup account directory 666 for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++) { 667 BMailAccountSettings* account = fToDeleteAccounts.ItemAt(i); 668 BEntry entry(account->AccountFile()); 669 entry.Remove(); 670 delete account; 671 } 672 fToDeleteAccounts.MakeEmpty(); 673 674 /*** save general settings ***/ 675 676 // figure out time interval 677 float interval; 678 sscanf(fIntervalControl->Text(),"%f",&interval); 679 float multiplier = 0; 680 switch (fIntervalUnitField->Menu()->IndexOf( 681 fIntervalUnitField->Menu()->FindMarked())) { 682 case 1: // minutes 683 multiplier = 60; 684 break; 685 case 2: // hours 686 multiplier = 60 * 60; 687 break; 688 case 3: // days 689 multiplier = 24 * 60 * 60; 690 break; 691 } 692 time_t time = (time_t)(multiplier * interval); 693 694 // apply and save general settings 695 BMailSettings settings; 696 if (fSaveSettings) { 697 settings.SetAutoCheckInterval(time * 1e6); 698 settings.SetCheckOnlyIfPPPUp(fPPPActiveCheckBox->Value() 699 == B_CONTROL_ON); 700 settings.SetSendOnlyIfPPPUp(fPPPActiveSendCheckBox->Value() 701 == B_CONTROL_ON); 702 settings.SetDaemonAutoStarts(fAutoStartCheckBox->Value() 703 == B_CONTROL_ON); 704 705 // status mode (alway, fetching/retrieving, ...) 706 int32 index = fStatusModeField->Menu()->IndexOf( 707 fStatusModeField->Menu()->FindMarked()); 708 settings.SetShowStatusWindow(index); 709 710 } else { 711 // restore status window look 712 settings.SetStatusWindowLook(settings.StatusWindowLook()); 713 } 714 715 settings.SetConfigWindowFrame(Frame()); 716 settings.Save(); 717 718 /*** save accounts ***/ 719 720 if (fSaveSettings) { 721 for (int i = 0; i < fAccounts.CountItems(); i++) 722 fAccounts.ItemAt(i)->Save(); 723 } 724 725 BMessenger messenger("application/x-vnd.Be-POST"); 726 if (messenger.IsValid()) { 727 // server should reload general settings 728 messenger.SendMessage(kMsgSettingsUpdated); 729 // notify server about changed accounts 730 messenger.SendMessage(&changedAccounts); 731 } 732 733 // start the mail_daemon if auto start was selected 734 if (fSaveSettings && fAutoStartCheckBox->Value() == B_CONTROL_ON 735 && !be_roster->IsRunning("application/x-vnd.Be-POST")) 736 { 737 be_roster->Launch("application/x-vnd.Be-POST"); 738 } 739 } 740 741 742 bool 743 ConfigWindow::QuitRequested() 744 { 745 _SaveSettings(); 746 747 be_app->PostMessage(B_QUIT_REQUESTED); 748 return true; 749 } 750 751 752 void 753 ConfigWindow::MessageReceived(BMessage *msg) 754 { 755 BRect autoConfigRect(0, 0, 400, 300); 756 BRect frame; 757 758 AutoConfigWindow *autoConfigWindow = NULL; 759 switch (msg->what) { 760 case kMsgAccountsRightClicked: 761 { 762 BPoint point; 763 msg->FindPoint("point", &point); 764 int32 index = msg->FindInt32("index"); 765 AccountItem* clickedItem = dynamic_cast<AccountItem*>( 766 fAccountsListView->ItemAt(index)); 767 if (clickedItem == NULL || clickedItem->GetType() != ACCOUNT_ITEM) 768 break; 769 770 BPopUpMenu rightClickMenu("accounts", false, false); 771 772 BMenuItem* inMenuItem = new BMenuItem("Incoming", NULL); 773 BMenuItem* outMenuItem = new BMenuItem("Outgoing", NULL); 774 rightClickMenu.AddItem(inMenuItem); 775 rightClickMenu.AddItem(outMenuItem); 776 777 BMailAccountSettings* settings = clickedItem->GetAccount(); 778 if (settings->IsInboundEnabled()) 779 inMenuItem->SetMarked(true); 780 if (settings->IsOutboundEnabled()) 781 outMenuItem->SetMarked(true); 782 783 BMenuItem* selectedItem = rightClickMenu.Go(point); 784 if (selectedItem == NULL) 785 break; 786 if (selectedItem == inMenuItem) { 787 AccountItem* item = dynamic_cast<AccountItem*>( 788 fAccountsListView->ItemAt(index + 1)); 789 if (item == NULL) 790 break; 791 if (settings->IsInboundEnabled()) { 792 settings->SetInboundEnabled(false); 793 item->SetEnabled(false); 794 } else { 795 settings->SetInboundEnabled(true); 796 item->SetEnabled(true); 797 } 798 } else { 799 AccountItem* item = dynamic_cast<AccountItem*>( 800 fAccountsListView->ItemAt(index + 2)); 801 if (item == NULL) 802 break; 803 if (settings->IsOutboundEnabled()) { 804 settings->SetOutboundEnabled(false); 805 item->SetEnabled(false); 806 } else { 807 settings->SetOutboundEnabled(true); 808 item->SetEnabled(true); 809 } 810 } 811 } 812 813 case kMsgAccountSelected: 814 { 815 int32 index; 816 if (msg->FindInt32("index", &index) != B_OK || index < 0) { 817 // deselect current item 818 fConfigView->DeleteChildren(); 819 _MakeHowToView(); 820 break; 821 } 822 AccountItem *item = (AccountItem *)fAccountsListView->ItemAt(index); 823 if (item) 824 _AccountSelected(item); 825 break; 826 } 827 828 case kMsgAddAccount: 829 { 830 frame = Frame(); 831 autoConfigRect.OffsetTo( 832 frame.left + (frame.Width() - autoConfigRect.Width()) / 2, 833 frame.top + (frame.Width() - autoConfigRect.Height()) / 2); 834 autoConfigWindow = new AutoConfigWindow(autoConfigRect, this); 835 autoConfigWindow->Show(); 836 break; 837 } 838 839 case kMsgRemoveAccount: 840 { 841 int32 index = fAccountsListView->CurrentSelection(); 842 if (index >= 0) { 843 AccountItem *item = (AccountItem *)fAccountsListView->ItemAt( 844 index); 845 if (item != NULL) { 846 _RemoveAccount(item->GetAccount()); 847 _MakeHowToView(); 848 } 849 } 850 break; 851 } 852 853 case kMsgIntervalUnitChanged: 854 { 855 int32 index; 856 if (msg->FindInt32("index",&index) == B_OK) 857 fIntervalControl->SetEnabled(index != 0); 858 break; 859 } 860 861 case kMsgShowStatusWindowChanged: 862 { 863 // the status window stuff is the only "live" setting 864 BMessenger messenger("application/x-vnd.Be-POST"); 865 if (messenger.IsValid()) 866 messenger.SendMessage(msg); 867 break; 868 } 869 870 case kMsgRevertSettings: 871 _RevertToLastSettings(); 872 break; 873 874 case kMsgSaveSettings: 875 fSaveSettings = true; 876 _SaveSettings(); 877 AccountUpdated(fLastSelectedAccount); 878 _MakeHowToView(); 879 fAccountsListView->DeselectAll(); 880 break; 881 882 default: 883 BWindow::MessageReceived(msg); 884 break; 885 } 886 } 887 888 889 BMailAccountSettings* 890 ConfigWindow::AddAccount() 891 { 892 BMailAccountSettings* account = new BMailAccountSettings; 893 if (!account) 894 return NULL; 895 fAccounts.AddItem(account); 896 _AddAccountToView(account); 897 return account; 898 } 899 900 901 void 902 ConfigWindow::AccountUpdated(BMailAccountSettings* account) 903 { 904 if (account == NULL) 905 return; 906 907 for (int i = 0; i < fAccountsListView->CountItems(); i++) { 908 AccountItem* item = (AccountItem*)fAccountsListView->ItemAt(i); 909 if (item->GetAccount() == account) { 910 if (item->GetType() == ACCOUNT_ITEM) { 911 item->SetText(account->Name()); 912 fAccountsListView->Invalidate(); 913 } 914 } 915 } 916 } 917 918 919 status_t 920 ConfigWindow::_SetToGeneralSettings(BMailSettings *settings) 921 { 922 if (!settings) 923 return B_BAD_VALUE; 924 925 status_t status = settings->InitCheck(); 926 if (status != B_OK) 927 return status; 928 929 // retrieval frequency 930 931 time_t interval = time_t(settings->AutoCheckInterval() / 1e6L); 932 char text[25]; 933 text[0] = 0; 934 int timeIndex = 0; 935 if (interval >= 60) { 936 timeIndex = 1; 937 sprintf(text, "%ld", interval / (60)); 938 } 939 if (interval >= (60*60)) { 940 timeIndex = 2; 941 sprintf(text, "%ld", interval / (60*60)); 942 } 943 if (interval >= (60*60*24)) { 944 timeIndex = 3; 945 sprintf(text, "%ld", interval / (60*60*24)); 946 } 947 fIntervalControl->SetText(text); 948 949 if (BMenuItem *item = fIntervalUnitField->Menu()->ItemAt(timeIndex)) 950 item->SetMarked(true); 951 fIntervalControl->SetEnabled(timeIndex != 0); 952 953 fPPPActiveCheckBox->SetValue(settings->CheckOnlyIfPPPUp()); 954 fPPPActiveSendCheckBox->SetValue(settings->SendOnlyIfPPPUp()); 955 956 fAutoStartCheckBox->SetValue(settings->DaemonAutoStarts()); 957 958 int32 showStatusIndex = settings->ShowStatusWindow(); 959 BMenuItem *item = fStatusModeField->Menu()->ItemAt(showStatusIndex); 960 if (item) { 961 item->SetMarked(true); 962 // send live update to the server by simulating a menu click 963 BMessage msg(kMsgShowStatusWindowChanged); 964 msg.AddInt32("ShowStatusWindow", showStatusIndex); 965 PostMessage(&msg); 966 } 967 968 return B_OK; 969 } 970 971 972 void 973 ConfigWindow::_RevertToLastSettings() 974 { 975 // revert general settings 976 BMailSettings settings; 977 978 // restore status window look 979 settings.SetStatusWindowLook(settings.StatusWindowLook()); 980 981 status_t status = _SetToGeneralSettings(&settings); 982 if (status != B_OK) { 983 char text[256]; 984 sprintf(text, B_TRANSLATE( 985 "\nThe general settings couldn't be reverted.\n\n" 986 "Error retrieving general settings:\n%s\n"), 987 strerror(status)); 988 (new BAlert(B_TRANSLATE("Error"), text, B_TRANSLATE("OK"), NULL, NULL, 989 B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(); 990 } 991 992 // revert account data 993 994 if (fAccountsListView->CurrentSelection() != -1) 995 fConfigView->DeleteChildren(); 996 997 for (int32 i = 0; i < fAccounts.CountItems(); i++) { 998 BMailAccountSettings* account = fAccounts.ItemAt(i); 999 _RemoveAccountFromListView(account); 1000 delete account; 1001 } 1002 fAccounts.MakeEmpty(); 1003 _LoadAccounts(); 1004 1005 if (fConfigView->CountChildren() == 0) 1006 _MakeHowToView(); 1007 } 1008 1009 1010 void 1011 ConfigWindow::_AddAccountToView(BMailAccountSettings* account) 1012 { 1013 BString label; 1014 label << account->Name(); 1015 1016 AccountItem* item; 1017 item = new AccountItem(label, account, ACCOUNT_ITEM); 1018 fAccountsListView->AddItem(item); 1019 1020 item = new AccountItem(B_TRANSLATE(" · Incoming"), account, INBOUND_ITEM); 1021 fAccountsListView->AddItem(item); 1022 if (!account->IsInboundEnabled()) 1023 item->SetEnabled(false); 1024 1025 item = new AccountItem(B_TRANSLATE(" · Outgoing"), account, 1026 OUTBOUND_ITEM); 1027 fAccountsListView->AddItem(item); 1028 if (!account->IsOutboundEnabled()) 1029 item->SetEnabled(false); 1030 1031 item = new AccountItem(B_TRANSLATE(" · E-mail filters"), account, 1032 FILTER_ITEM); 1033 fAccountsListView->AddItem(item); 1034 } 1035 1036 1037 void 1038 ConfigWindow::_RemoveAccount(BMailAccountSettings* account) 1039 { 1040 _RemoveAccountFromListView(account); 1041 fAccounts.RemoveItem(account); 1042 fToDeleteAccounts.AddItem(account); 1043 } 1044 1045 1046 void 1047 ConfigWindow::_RemoveAccountFromListView(BMailAccountSettings* account) 1048 { 1049 for (int i = 0; i < fAccountsListView->CountItems(); i++) { 1050 AccountItem* item = (AccountItem*)fAccountsListView->ItemAt(i); 1051 if (item->GetAccount() == account) { 1052 fAccountsListView->RemoveItem(i); 1053 fConfigView->RemoveChild(item->ConfigPanel()); 1054 delete item; 1055 i--; 1056 } 1057 } 1058 } 1059 1060 1061 void 1062 ConfigWindow::_AccountSelected(AccountItem* item) 1063 { 1064 AccountUpdated(fLastSelectedAccount); 1065 1066 BMailAccountSettings* account = item->GetAccount(); 1067 fLastSelectedAccount = account; 1068 1069 fConfigView->Hide(); 1070 fConfigView->DeleteChildren(); 1071 1072 BView* view = NULL; 1073 switch (item->GetType()) { 1074 case ACCOUNT_ITEM: 1075 view = new AccountConfigView(fConfigView->Bounds(), account); 1076 break; 1077 1078 case INBOUND_ITEM: 1079 { 1080 view = new InProtocolsConfigView(account); 1081 break; 1082 } 1083 1084 case OUTBOUND_ITEM: 1085 { 1086 view = new OutProtocolsConfigView(account); 1087 break; 1088 } 1089 1090 case FILTER_ITEM: 1091 { 1092 view = new FiltersConfigView(fConfigView->Bounds(), *account); 1093 break; 1094 } 1095 } 1096 if (view) { 1097 item->SetConfigPanel(view); 1098 fConfigView->AddChild(view); 1099 } 1100 1101 fConfigView->Layout(); 1102 fConfigView->Show(); 1103 } 1104