xref: /haiku/src/preferences/mail/ConfigWindow.cpp (revision 5e7964b0a929555415798dea3373db9ac4611caa)
1 /*
2  * Copyright 2007-2016 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 
11 
12 #include "ConfigWindow.h"
13 
14 #include <new>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <Alert.h>
19 #include <AppFileInfo.h>
20 #include <Application.h>
21 #include <Bitmap.h>
22 #include <Box.h>
23 #include <Button.h>
24 #include <Catalog.h>
25 #include <CheckBox.h>
26 #include <ControlLook.h>
27 #include <Directory.h>
28 #include <Entry.h>
29 #include <FindDirectory.h>
30 #include <LayoutBuilder.h>
31 #include <ListView.h>
32 #include <Locale.h>
33 #include <MailDaemon.h>
34 #include <MailSettings.h>
35 #include <MenuBar.h>
36 #include <MenuField.h>
37 #include <MenuItem.h>
38 #include <Path.h>
39 #include <PopUpMenu.h>
40 #include <Region.h>
41 #include <Resources.h>
42 #include <Roster.h>
43 #include <Screen.h>
44 #include <ScrollView.h>
45 #include <SeparatorView.h>
46 #include <StringView.h>
47 #include <TabView.h>
48 #include <TextControl.h>
49 #include <TextView.h>
50 
51 #include <MailPrivate.h>
52 
53 #include "AutoConfigWindow.h"
54 
55 
56 #undef B_TRANSLATION_CONTEXT
57 #define B_TRANSLATION_CONTEXT "Config Window"
58 
59 
60 using std::nothrow;
61 
62 // define if you want to have an apply button
63 //#define HAVE_APPLY_BUTTON
64 
65 
66 const uint32 kMsgAccountsRightClicked = 'arcl';
67 const uint32 kMsgAccountSelected = 'acsl';
68 const uint32 kMsgAddAccount = 'adac';
69 const uint32 kMsgRemoveAccount = 'rmac';
70 
71 const uint32 kMsgIntervalUnitChanged = 'iuch';
72 
73 const uint32 kMsgShowStatusWindowChanged = 'shst';
74 const uint32 kMsgStatusLookChanged = 'lkch';
75 const uint32 kMsgStatusWorkspaceChanged = 'wsch';
76 
77 const uint32 kMsgSaveSettings = 'svst';
78 const uint32 kMsgRevertSettings = 'rvst';
79 const uint32 kMsgCancelSettings = 'cnst';
80 
81 
82 
83 AccountItem::AccountItem(const char* label, BMailAccountSettings* account,
84 	item_types type)
85 	:
86 	BStringItem(label),
87 	fAccount(account),
88 	fType(type)
89 {
90 }
91 
92 
93 void
94 AccountItem::Update(BView* owner, const BFont* font)
95 {
96 	if (fType == ACCOUNT_ITEM)
97 		font = be_bold_font;
98 
99 	BStringItem::Update(owner, font);
100 }
101 
102 
103 void
104 AccountItem::DrawItem(BView* owner, BRect rect, bool complete)
105 {
106 	owner->PushState();
107 	if (fType == ACCOUNT_ITEM)
108 		owner->SetFont(be_bold_font);
109 
110 	BStringItem::DrawItem(owner, rect, complete);
111 	owner->PopState();
112 }
113 
114 
115 //	#pragma mark -
116 
117 
118 class AccountsListView : public BListView {
119 public:
120 	AccountsListView(BHandler* target)
121 		:
122 		BListView(NULL, B_SINGLE_SELECTION_LIST),
123 		fTarget(target)
124 	{
125 	}
126 
127 	void
128 	KeyDown(const char *bytes, int32 numBytes)
129 	{
130 		if (numBytes != 1)
131 			return;
132 
133 		if ((*bytes == B_DELETE) || (*bytes == B_BACKSPACE))
134 			Window()->PostMessage(kMsgRemoveAccount);
135 
136 		BListView::KeyDown(bytes,numBytes);
137 	}
138 
139 	void
140 	MouseDown(BPoint point)
141 	{
142 		BListView::MouseDown(point);
143 
144 		BPoint dummy;
145 		uint32 buttons;
146 		GetMouse(&dummy, &buttons);
147 		if (buttons != B_SECONDARY_MOUSE_BUTTON)
148 			return;
149 
150 		int32 index = IndexOf(point);
151 		if (index < 0)
152 			return;
153 
154 		BMessage message(kMsgAccountsRightClicked);
155 		ConvertToScreen(&point);
156 		message.AddPoint("point", point);
157 		message.AddInt32("index", index);
158 		BMessenger messenger(fTarget);
159 		messenger.SendMessage(&message);
160 	}
161 
162 private:
163 			BHandler*			fTarget;
164 };
165 
166 
167 class BitmapView : public BView {
168 	public:
169 		BitmapView(BBitmap *bitmap)
170 			:
171 			BView(NULL, B_WILL_DRAW)
172 		{
173 			fBitmap = bitmap;
174 
175 			SetDrawingMode(B_OP_ALPHA);
176 			SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
177 			SetExplicitSize(bitmap->Bounds().Size());
178 		}
179 
180 		~BitmapView()
181 		{
182 			delete fBitmap;
183 		}
184 
185 		virtual void AttachedToWindow()
186 		{
187 			AdoptParentColors();
188 		}
189 
190 		virtual void Draw(BRect updateRect)
191 		{
192 			DrawBitmap(fBitmap, updateRect, updateRect);
193 		}
194 
195 	private:
196 		BBitmap *fBitmap;
197 };
198 
199 
200 //	#pragma mark -
201 
202 
203 ConfigWindow::ConfigWindow()
204 	:
205 	BWindow(BRect(100, 100, 600, 540), B_TRANSLATE_SYSTEM_NAME("E-mail"),
206 		B_TITLED_WINDOW,
207 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_AUTO_UPDATE_SIZE_LIMITS),
208 	fLastSelectedAccount(NULL),
209 	fSaveSettings(false)
210 {
211 	BTabView* tabView = new BTabView("tab", B_WIDTH_FROM_WIDEST);
212 	tabView->SetBorder(B_NO_BORDER);
213 
214 	// accounts listview
215 
216 	BView* view = new BView("accounts", 0);
217 	tabView->AddTab(view);
218 	tabView->TabAt(0)->SetLabel(B_TRANSLATE("Accounts"));
219 
220 	fAccountsListView = new AccountsListView(this);
221 	fAccountsListView->SetExplicitPreferredSize(BSize(
222 		fAccountsListView->StringWidth("W") * 22, B_SIZE_UNSET));
223 
224 	BButton* addButton = new BButton(NULL, B_TRANSLATE("Add"),
225 		new BMessage(kMsgAddAccount));
226 	fRemoveButton = new BButton(NULL, B_TRANSLATE("Remove"),
227 		new BMessage(kMsgRemoveAccount));
228 
229 	fConfigView = new BView(NULL, 0);
230 	fConfigView->SetLayout(new BGroupLayout(B_VERTICAL));
231 	fConfigView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
232 	fConfigView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
233 
234 	BScrollView* scroller = new BScrollView(NULL, fAccountsListView, 0,
235 		false, true);
236 
237 	BLayoutBuilder::Group<>(view, B_HORIZONTAL)
238 		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
239 			B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
240 		.AddGroup(B_VERTICAL)
241 			.Add(scroller)
242 			.AddGroup(B_HORIZONTAL)
243 				.Add(addButton)
244 				.Add(fRemoveButton)
245 			.End()
246 		.End()
247 		.Add(fConfigView, 2.0f);
248 
249 	_ReplaceConfigView(_BuildHowToView());
250 
251 	// general settings
252 
253 	view = new BView("general", 0);
254 	view->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED));
255 	tabView->AddTab(view);
256 	tabView->TabAt(1)->SetLabel(B_TRANSLATE("Settings"));
257 
258 	fCheckMailCheckBox = new BCheckBox("check", B_TRANSLATE("Check every"),
259 		NULL);
260 	fIntervalControl = new BTextControl("time", B_TRANSLATE("minutes"), NULL,
261 		NULL);
262 
263 	BPopUpMenu* statusPopUp = new BPopUpMenu(B_EMPTY_STRING);
264 	const char* statusModes[] = {
265 		B_TRANSLATE_COMMENT("Never", "show status window"),
266 		B_TRANSLATE("While sending"),
267 		B_TRANSLATE("While sending and receiving")};
268 	for (size_t i = 0; i < sizeof(statusModes) / sizeof(statusModes[0]); i++) {
269 		BMessage* msg = new BMessage(kMsgShowStatusWindowChanged);
270 		BMenuItem* item = new BMenuItem(statusModes[i], msg);
271 		statusPopUp->AddItem(item);
272 		msg->AddInt32("ShowStatusWindow", i);
273 	}
274 
275 	fStatusModeField = new BMenuField("show status",
276 		B_TRANSLATE("Show notifications:"), statusPopUp);
277 
278 	BMessage* msg = new BMessage(B_REFS_RECEIVED);
279 	BButton* editMenuButton = new BButton(B_EMPTY_STRING,
280 		B_TRANSLATE("Edit mailbox menu…"), msg);
281 	editMenuButton->SetTarget(BMessenger("application/x-vnd.Be-TRAK"));
282 
283 	BPath path;
284 	find_directory(B_USER_SETTINGS_DIRECTORY, &path);
285 	path.Append("Mail/Menu Links");
286 	BEntry entry(path.Path());
287 	if (entry.InitCheck() == B_OK && entry.Exists()) {
288 		entry_ref ref;
289 		entry.GetRef(&ref);
290 		msg->AddRef("refs", &ref);
291 	} else
292 		editMenuButton->SetEnabled(false);
293 
294 	BLayoutBuilder::Group<>(view, B_VERTICAL)
295 		.SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
296 			B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING)
297 //		.AddGlue()
298 		.AddGroup(B_HORIZONTAL, 0.f)
299 			.AddGlue()
300 			.Add(fCheckMailCheckBox)
301 			.AddStrut(be_control_look->DefaultLabelSpacing())
302 			.Add(fIntervalControl->CreateTextViewLayoutItem())
303 			.AddStrut(be_control_look->DefaultLabelSpacing())
304 			.Add(fIntervalControl->CreateLabelLayoutItem())
305 			.AddGlue()
306 		.End()
307 		.AddGroup(B_HORIZONTAL, 0.f)
308 			.AddGlue()
309 			.Add(fStatusModeField->CreateLabelLayoutItem())
310 			.Add(fStatusModeField->CreateMenuBarLayoutItem())
311 			.AddGlue()
312 		.End()
313 		.Add(editMenuButton)
314 		.AddGlue();
315 
316 	// save/revert buttons
317 
318 	BButton* applyButton = new BButton("apply", B_TRANSLATE("Apply"),
319 		new BMessage(kMsgSaveSettings));
320 	BButton* revertButton = new BButton("revert", B_TRANSLATE("Revert"),
321 		new BMessage(kMsgRevertSettings));
322 
323 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
324 		.SetInsets(0, B_USE_DEFAULT_SPACING, 0, B_USE_WINDOW_SPACING)
325 		.Add(tabView)
326 		.Add(new BSeparatorView(B_HORIZONTAL))
327 		.AddGroup(B_HORIZONTAL, 0)
328 			.Add(revertButton)
329 			.AddGlue()
330 			.Add(applyButton)
331 			.SetInsets(B_USE_WINDOW_SPACING, B_USE_DEFAULT_SPACING,
332 				B_USE_WINDOW_SPACING, 0);
333 
334 	_LoadSettings();
335 
336 	fAccountsListView->SetSelectionMessage(new BMessage(kMsgAccountSelected));
337 	fAccountsListView->MakeFocus(true);
338 
339 	ResizeToPreferred();
340 	CenterOnScreen();
341 }
342 
343 
344 ConfigWindow::~ConfigWindow()
345 {
346 	while (fAccounts.CountItems() > 0)
347 		_RemoveAccount(fAccounts.ItemAt(0));
348 	for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++)
349 		delete fToDeleteAccounts.ItemAt(i);
350 }
351 
352 
353 BView*
354 ConfigWindow::_BuildHowToView()
355 {
356 	BView* groupView = new BView("howTo", 0);
357 
358 	BitmapView* bitmapView = NULL;
359 	app_info info;
360 	if (be_app->GetAppInfo(&info) == B_OK) {
361 		BFile appFile(&info.ref, B_READ_ONLY);
362 		BAppFileInfo appFileInfo(&appFile);
363 		if (appFileInfo.InitCheck() == B_OK) {
364 			BBitmap* bitmap = new (std::nothrow) BBitmap(BRect(0, 0, 63, 63),
365 				B_RGBA32);
366 			if (appFileInfo.GetIcon(bitmap, B_LARGE_ICON) == B_OK)
367 				bitmapView = new BitmapView(bitmap);
368 			else
369 				delete bitmap;
370 		}
371 	}
372 
373 	fHowToTextView = new BTextView(NULL, B_WILL_DRAW);
374 	fHowToTextView->SetAlignment(B_ALIGN_CENTER);
375 	fHowToTextView->SetText(B_TRANSLATE(
376 		"Create a new account with the Add button.\n\n"
377 		"Remove an account with the Remove button on the selected item.\n\n"
378 		"Select an item in the list to change its settings."));
379 
380 	fHowToTextView->MakeEditable(false);
381 	fHowToTextView->MakeSelectable(false);
382 
383 	BFont font(be_plain_font);
384 	float fontFactor = font.Size() / 12.0f;
385 
386 	fHowToTextView->SetExplicitPreferredSize(
387 		BSize(300 * fontFactor,400 * fontFactor));
388 
389 	rgb_color textColor = ui_color(B_PANEL_TEXT_COLOR);
390 	fHowToTextView->SetFontAndColor(&font, B_FONT_ALL, &textColor);
391 
392 	BLayoutBuilder::Group<>(groupView, B_VERTICAL)
393 		.AddGlue()
394 		.Add(fHowToTextView)
395 		.AddGlue();
396 
397 	if (bitmapView != NULL)
398 		groupView->GetLayout()->AddView(1, bitmapView);
399 
400 	fHowToTextView->AdoptSystemColors();
401 
402 	return groupView;
403 }
404 
405 
406 void
407 ConfigWindow::_LoadSettings()
408 {
409 	// load accounts
410 	for (int i = 0; i < fAccounts.CountItems(); i++)
411 		delete fAccounts.ItemAt(i);
412 	fAccounts.MakeEmpty();
413 
414 	_LoadAccounts();
415 
416 	// load in general settings
417 	BMailSettings settings;
418 	status_t status = _SetToGeneralSettings(&settings);
419 	if (status != B_OK) {
420 		fprintf(stderr, B_TRANSLATE("Error retrieving general settings: %s\n"),
421 			strerror(status));
422 	}
423 }
424 
425 
426 void
427 ConfigWindow::_LoadAccounts()
428 {
429 	BMailAccounts accounts;
430 	for (int32 i = 0; i < accounts.CountAccounts(); i++)
431 		fAccounts.AddItem(new BMailAccountSettings(*accounts.AccountAt(i)));
432 
433 	for (int i = 0; i < fAccounts.CountItems(); i++) {
434 		BMailAccountSettings* account = fAccounts.ItemAt(i);
435 		_AddAccountToView(account);
436 	}
437 }
438 
439 
440 void
441 ConfigWindow::_SaveSettings()
442 {
443 	// collect changed accounts
444 	BMessage changedAccounts(BPrivate::kMsgAccountsChanged);
445 	for (int32 i = 0; i < fAccounts.CountItems(); i++) {
446 		BMailAccountSettings* account = fAccounts.ItemAt(i);
447 		if (account && account->HasBeenModified())
448 			changedAccounts.AddInt32("account", account->AccountID());
449 	}
450 	for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++) {
451 		BMailAccountSettings* account = fToDeleteAccounts.ItemAt(i);
452 		changedAccounts.AddInt32("account", account->AccountID());
453 	}
454 
455 	// cleanup account directory
456 	for (int32 i = 0; i < fToDeleteAccounts.CountItems(); i++) {
457 		BMailAccountSettings* account = fToDeleteAccounts.ItemAt(i);
458 		BEntry entry(account->AccountFile());
459 		entry.Remove();
460 		delete account;
461 	}
462 	fToDeleteAccounts.MakeEmpty();
463 
464 	// Apply and save general settings
465 
466 	BMailSettings settings;
467 	if (fSaveSettings) {
468 		bigtime_t interval = 0;
469 		if (fCheckMailCheckBox->Value() == B_CONTROL_ON) {
470 			// figure out time interval
471 			float floatInterval;
472 			sscanf(fIntervalControl->Text(), "%f", &floatInterval);
473 			interval = bigtime_t(60000000L * floatInterval);
474 		}
475 
476 		settings.SetAutoCheckInterval(interval);
477 		settings.SetDaemonAutoStarts(!fAccounts.IsEmpty());
478 
479 		// status mode (alway, fetching/retrieving, ...)
480 		int32 index = fStatusModeField->Menu()->IndexOf(
481 			fStatusModeField->Menu()->FindMarked());
482 		settings.SetShowStatusWindow(index);
483 
484 		settings.Save();
485 	}
486 
487 	// Save accounts
488 
489 	if (fSaveSettings) {
490 		for (int i = 0; i < fAccounts.CountItems(); i++)
491 			fAccounts.ItemAt(i)->Save();
492 	}
493 
494 	BMessenger messenger(B_MAIL_DAEMON_SIGNATURE);
495 	if (messenger.IsValid()) {
496 		// server should reload general settings
497 		messenger.SendMessage(BPrivate::kMsgSettingsUpdated);
498 		// notify server about changed accounts
499 		messenger.SendMessage(&changedAccounts);
500 	}
501 
502 	// Start/stop the mail_daemon depending on the settings
503 	BMailDaemon daemon;
504 	if (fSaveSettings) {
505 		if (settings.DaemonAutoStarts() && !daemon.IsRunning())
506 			daemon.Launch();
507 		else if (!settings.DaemonAutoStarts() && daemon.IsRunning())
508 			daemon.Quit();
509 	}
510 }
511 
512 
513 bool
514 ConfigWindow::QuitRequested()
515 {
516 	_SaveSettings();
517 
518 	be_app->PostMessage(B_QUIT_REQUESTED);
519 	return true;
520 }
521 
522 
523 void
524 ConfigWindow::MessageReceived(BMessage *msg)
525 {
526 	float fontFactor = be_plain_font->Size() / 12.0f;
527 	BRect autoConfigRect(0, 0, 400 * fontFactor, 300 * fontFactor);
528 	BRect frame;
529 
530 	AutoConfigWindow *autoConfigWindow = NULL;
531 	switch (msg->what) {
532 		case B_COLORS_UPDATED:
533 		{
534 			rgb_color textColor;
535 			if (msg->FindColor(ui_color_name(B_PANEL_TEXT_COLOR), &textColor)
536 					== B_OK) {
537 				BFont font;
538 				fHowToTextView->SetFontAndColor(&font, 0, &textColor);
539 			}
540 			break;
541 		}
542 
543 		case kMsgAccountsRightClicked:
544 		{
545 			BPoint point;
546 			msg->FindPoint("point", &point);
547 			int32 index = msg->FindInt32("index");
548 			AccountItem* clickedItem = dynamic_cast<AccountItem*>(
549 				fAccountsListView->ItemAt(index));
550 			if (clickedItem == NULL || clickedItem->Type() != ACCOUNT_ITEM)
551 				break;
552 
553 			BPopUpMenu rightClickMenu("accounts", false, false);
554 
555 			BMenuItem* inMenuItem = new BMenuItem(B_TRANSLATE("Incoming"),
556 				NULL);
557 			BMenuItem* outMenuItem = new BMenuItem(B_TRANSLATE("Outgoing"),
558 				NULL);
559 			rightClickMenu.AddItem(inMenuItem);
560 			rightClickMenu.AddItem(outMenuItem);
561 
562 			BMailAccountSettings* settings = clickedItem->Account();
563 			if (settings->IsInboundEnabled())
564 				inMenuItem->SetMarked(true);
565 			if (settings->IsOutboundEnabled())
566 				outMenuItem->SetMarked(true);
567 
568 			BMenuItem* selectedItem = rightClickMenu.Go(point);
569 			if (selectedItem == NULL)
570 				break;
571 			if (selectedItem == inMenuItem) {
572 				AccountItem* item = dynamic_cast<AccountItem*>(
573 					fAccountsListView->ItemAt(index + 1));
574 				if (item == NULL)
575 					break;
576 				if (settings->IsInboundEnabled()) {
577 					settings->SetInboundEnabled(false);
578 					item->SetEnabled(false);
579 				} else {
580 					settings->SetInboundEnabled(true);
581 					item->SetEnabled(true);
582 				}
583 			} else {
584 				AccountItem* item = dynamic_cast<AccountItem*>(
585 					fAccountsListView->ItemAt(index + 2));
586 				if (item == NULL)
587 					break;
588 				if (settings->IsOutboundEnabled()) {
589 					settings->SetOutboundEnabled(false);
590 					item->SetEnabled(false);
591 				} else {
592 					settings->SetOutboundEnabled(true);
593 					item->SetEnabled(true);
594 				}
595 			}
596 		}
597 
598 		case kMsgAccountSelected:
599 		{
600 			int32 index;
601 			if (msg->FindInt32("index", &index) != B_OK || index < 0) {
602 				// deselect current item
603 				_ReplaceConfigView(_BuildHowToView());
604 				break;
605 			}
606 			AccountItem* item = (AccountItem*)fAccountsListView->ItemAt(index);
607 			if (item != NULL)
608 				_AccountSelected(item);
609 			break;
610 		}
611 
612 		case kMsgAddAccount:
613 		{
614 			frame = Frame();
615 			autoConfigRect.OffsetTo(
616 				frame.left + (frame.Width() - autoConfigRect.Width()) / 2,
617 				frame.top + (frame.Width() - autoConfigRect.Height()) / 2);
618 			autoConfigWindow = new AutoConfigWindow(autoConfigRect, this);
619 			autoConfigWindow->Show();
620 			break;
621 		}
622 
623 		case kMsgRemoveAccount:
624 		{
625 			int32 index = fAccountsListView->CurrentSelection();
626 			if (index >= 0) {
627 				AccountItem *item = (AccountItem *)fAccountsListView->ItemAt(
628 					index);
629 				if (item != NULL) {
630 					_RemoveAccount(item->Account());
631 					_ReplaceConfigView(_BuildHowToView());
632 				}
633 			}
634 			break;
635 		}
636 
637 		case kMsgIntervalUnitChanged:
638 		{
639 			int32 index;
640 			if (msg->FindInt32("index",&index) == B_OK)
641 				fIntervalControl->SetEnabled(index != 0);
642 			break;
643 		}
644 
645 		case kMsgShowStatusWindowChanged:
646 		{
647 			// the status window stuff is the only "live" setting
648 			BMessenger messenger("application/x-vnd.Be-POST");
649 			if (messenger.IsValid())
650 				messenger.SendMessage(msg);
651 			break;
652 		}
653 
654 		case kMsgRevertSettings:
655 			_RevertToLastSettings();
656 			break;
657 
658 		case kMsgSaveSettings:
659 			fSaveSettings = true;
660 			_SaveSettings();
661 			AccountUpdated(fLastSelectedAccount);
662 			_ReplaceConfigView(_BuildHowToView());
663 			fAccountsListView->DeselectAll();
664 			break;
665 
666 		default:
667 			BWindow::MessageReceived(msg);
668 			break;
669 	}
670 }
671 
672 
673 BMailAccountSettings*
674 ConfigWindow::AddAccount()
675 {
676 	BMailAccountSettings* account = new BMailAccountSettings;
677 	if (!account)
678 		return NULL;
679 	fAccounts.AddItem(account);
680 	_AddAccountToView(account);
681 	return account;
682 }
683 
684 
685 void
686 ConfigWindow::AccountUpdated(BMailAccountSettings* account)
687 {
688 	if (account == NULL)
689 		return;
690 
691 	for (int i = 0; i < fAccountsListView->CountItems(); i++) {
692 		AccountItem* item = (AccountItem*)fAccountsListView->ItemAt(i);
693 		if (item->Account() == account) {
694 			if (item->Type() == ACCOUNT_ITEM) {
695 				item->SetText(account->Name());
696 				fAccountsListView->Invalidate();
697 			}
698 		}
699 	}
700 }
701 
702 
703 status_t
704 ConfigWindow::_SetToGeneralSettings(BMailSettings* settings)
705 {
706 	if (settings == NULL)
707 		return B_BAD_VALUE;
708 
709 	status_t status = settings->InitCheck();
710 	if (status != B_OK)
711 		return status;
712 
713 	// retrieval frequency
714 	uint32 interval = uint32(settings->AutoCheckInterval() / 60000000L);
715 	fCheckMailCheckBox->SetValue(interval != 0 ? B_CONTROL_ON : B_CONTROL_OFF);
716 
717 	if (interval == 0)
718 		interval = 5;
719 
720 	BString intervalText;
721 	intervalText.SetToFormat("%" B_PRIu32, interval);
722 	fIntervalControl->SetText(intervalText.String());
723 
724 	int32 showStatusIndex = settings->ShowStatusWindow();
725 	BMenuItem* item = fStatusModeField->Menu()->ItemAt(showStatusIndex);
726 	if (item != NULL) {
727 		item->SetMarked(true);
728 		// send live update to the server by simulating a menu click
729 		BMessage msg(kMsgShowStatusWindowChanged);
730 		msg.AddInt32("ShowStatusWindow", showStatusIndex);
731 		PostMessage(&msg);
732 	}
733 
734 	return B_OK;
735 }
736 
737 
738 void
739 ConfigWindow::_RevertToLastSettings()
740 {
741 	// revert general settings
742 	BMailSettings settings;
743 
744 	status_t status = _SetToGeneralSettings(&settings);
745 	if (status != B_OK) {
746 		char text[256];
747 		sprintf(text, B_TRANSLATE(
748 				"\nThe general settings couldn't be reverted.\n\n"
749 				"Error retrieving general settings:\n%s\n"),
750 			strerror(status));
751 		BAlert* alert = new BAlert(B_TRANSLATE("Error"), text,
752 			B_TRANSLATE("OK"), NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
753 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
754 		alert->Go();
755 	}
756 
757 	// revert account data
758 
759 	if (fAccountsListView->CurrentSelection() != -1)
760 		_ReplaceConfigView(_BuildHowToView());
761 
762 	for (int32 i = 0; i < fAccounts.CountItems(); i++) {
763 		BMailAccountSettings* account = fAccounts.ItemAt(i);
764 		_RemoveAccountFromListView(account);
765 		delete account;
766 	}
767 
768 	fAccounts.MakeEmpty();
769 	_LoadAccounts();
770 }
771 
772 
773 void
774 ConfigWindow::_AddAccountToView(BMailAccountSettings* account)
775 {
776 	BString label;
777 	label << account->Name();
778 
779 	AccountItem* item;
780 	item = new AccountItem(label, account, ACCOUNT_ITEM);
781 	fAccountsListView->AddItem(item);
782 
783 	item = new AccountItem(B_TRANSLATE("\t\t· Incoming"), account, INBOUND_ITEM);
784 	fAccountsListView->AddItem(item);
785 	if (!account->IsInboundEnabled())
786 		item->SetEnabled(false);
787 
788 	item = new AccountItem(B_TRANSLATE("\t\t· Outgoing"), account,
789 		OUTBOUND_ITEM);
790 	fAccountsListView->AddItem(item);
791 	if (!account->IsOutboundEnabled())
792 		item->SetEnabled(false);
793 
794 	item = new AccountItem(B_TRANSLATE("\t\t· E-mail filters"), account,
795 		FILTER_ITEM);
796 	fAccountsListView->AddItem(item);
797 }
798 
799 
800 void
801 ConfigWindow::_RemoveAccount(BMailAccountSettings* account)
802 {
803 	_RemoveAccountFromListView(account);
804 	fAccounts.RemoveItem(account);
805 	fToDeleteAccounts.AddItem(account);
806 }
807 
808 
809 void
810 ConfigWindow::_RemoveAccountFromListView(BMailAccountSettings* account)
811 {
812 	if (fLastSelectedAccount == account) {
813 		_ReplaceConfigView(_BuildHowToView());
814 		fLastSelectedAccount = NULL;
815 	}
816 
817 	for (int i = fAccountsListView->CountItems(); i-- > 0;) {
818 		AccountItem* item = (AccountItem*)fAccountsListView->ItemAt(i);
819 		if (item->Account() == account) {
820 			fAccountsListView->RemoveItem(i);
821 			delete item;
822 		}
823 	}
824 }
825 
826 
827 void
828 ConfigWindow::_AccountSelected(AccountItem* item)
829 {
830 	AccountUpdated(fLastSelectedAccount);
831 
832 	BMailAccountSettings* account = item->Account();
833 	fLastSelectedAccount = account;
834 
835 	BView* view = NULL;
836 	switch (item->Type()) {
837 		case ACCOUNT_ITEM:
838 			view = new AccountConfigView(account);
839 			break;
840 
841 		case INBOUND_ITEM:
842 			view = new ProtocolSettingsView(account->InboundAddOnRef(),
843 				*account, account->InboundSettings());
844 			break;
845 
846 		case OUTBOUND_ITEM:
847 			view = new ProtocolSettingsView(account->OutboundAddOnRef(),
848 				*account, account->OutboundSettings());
849 			break;
850 
851 		case FILTER_ITEM:
852 			view = new FiltersConfigView(*account);
853 			break;
854 	}
855 
856 	_ReplaceConfigView(view);
857 }
858 
859 
860 void
861 ConfigWindow::_ReplaceConfigView(BView* view)
862 {
863 	while (BView* child = fConfigView->ChildAt(0)) {
864 		fConfigView->RemoveChild(child);
865 		delete child;
866 	}
867 
868 	if (view != NULL)
869 		fConfigView->AddChild(view);
870 }
871