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