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