xref: /haiku/src/preferences/mail/ConfigWindow.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
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 
11 
12 #include "ConfigWindow.h"
13 #include "CenterContainer.h"
14 #include "Account.h"
15 #include "AutoConfigWindow.h"
16 
17 #include <Application.h>
18 #include <ListView.h>
19 #include <ScrollView.h>
20 #include <StringView.h>
21 #include <Button.h>
22 #include <CheckBox.h>
23 #include <MenuField.h>
24 #include <TextControl.h>
25 #include <TextView.h>
26 #include <MenuItem.h>
27 #include <Screen.h>
28 #include <PopUpMenu.h>
29 #include <MenuBar.h>
30 #include <TabView.h>
31 #include <Box.h>
32 #include <Alert.h>
33 #include <Bitmap.h>
34 #include <Roster.h>
35 #include <Resources.h>
36 #include <Region.h>
37 
38 #include <AppFileInfo.h>
39 #include <Entry.h>
40 #include <Directory.h>
41 #include <FindDirectory.h>
42 #include <Path.h>
43 
44 #include <Catalog.h>
45 #include <Locale.h>
46 
47 #include <MailSettings.h>
48 
49 #include <new>
50 #include <stdio.h>
51 #include <string.h>
52 
53 #include <MDRLanguage.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 const char *kEMail = "bemaildaemon-talk@bug-br.org.br";
66 const char *kMailto = "mailto:bemaildaemon-talk@bug-br.org.br";
67 const char *kBugsitePretty = "Bug-Tracker at SourceForge.net";
68 const char *kBugsite = "http://sourceforge.net/tracker/?func=add&group_id=26926&atid=388726";
69 const char *kWebsite = "http://www.haiku-os.org";
70 const rgb_color kLinkColor = { 40, 40, 180, 255 };
71 
72 
73 const uint32 kMsgAccountSelected = 'acsl';
74 const uint32 kMsgAddAccount = 'adac';
75 const uint32 kMsgRemoveAccount = 'rmac';
76 
77 const uint32 kMsgIntervalUnitChanged = 'iuch';
78 
79 const uint32 kMsgShowStatusWindowChanged = 'shst';
80 const uint32 kMsgStatusLookChanged = 'lkch';
81 const uint32 kMsgStatusWorkspaceChanged = 'wsch';
82 
83 const uint32 kMsgApplySettings = 'apst';
84 const uint32 kMsgSaveSettings = 'svst';
85 const uint32 kMsgRevertSettings = 'rvst';
86 const uint32 kMsgCancelSettings = 'cnst';
87 
88 class AccountsListView : public BListView {
89 	public:
90 		AccountsListView(BRect rect) : BListView(rect,NULL,B_SINGLE_SELECTION_LIST,B_FOLLOW_ALL) {}
91 		virtual	void KeyDown(const char *bytes, int32 numBytes) {
92 			if (numBytes != 1)
93 				return;
94 
95 			if ((*bytes == B_DELETE) || (*bytes == B_BACKSPACE))
96 				Window()->PostMessage(kMsgRemoveAccount);
97 
98 			BListView::KeyDown(bytes,numBytes);
99 		}
100 };
101 
102 class BitmapView : public BView
103 {
104 	public:
105 		BitmapView(BBitmap *bitmap) : BView(bitmap->Bounds(), NULL,
106 			B_FOLLOW_NONE, B_WILL_DRAW)
107 		{
108 			fBitmap = bitmap;
109 
110 			SetDrawingMode(B_OP_ALPHA);
111 			SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
112 		}
113 
114 		~BitmapView()
115 		{
116 			delete fBitmap;
117 		}
118 
119 		virtual void AttachedToWindow()
120 		{
121 			SetViewColor(Parent()->ViewColor());
122 
123 			MoveTo((Parent()->Bounds().Width() - Bounds().Width()) / 2,
124 				Frame().top);
125 		}
126 
127 		virtual void Draw(BRect updateRect)
128 		{
129 			DrawBitmap(fBitmap, updateRect, updateRect);
130 		}
131 
132 	private:
133 		BBitmap *fBitmap;
134 };
135 
136 
137 class AboutTextView : public BTextView
138 {
139 	public:
140 		AboutTextView(BRect rect) : BTextView(rect, NULL,
141 			rect.OffsetToCopy(B_ORIGIN), B_FOLLOW_NONE, B_WILL_DRAW)
142 		{
143 			int32 major = 0,middle = 0,minor = 0,variety = 0,internal = 1;
144 
145 			// get version information for app
146 
147 			app_info appInfo;
148 			if (be_app->GetAppInfo(&appInfo) == B_OK) {
149 				BFile file(&appInfo.ref, B_READ_ONLY);
150 				if (file.InitCheck() == B_OK) {
151 					BAppFileInfo info(&file);
152 					if (info.InitCheck() == B_OK) {
153 						version_info versionInfo;
154 						if (info.GetVersionInfo(&versionInfo,
155 							B_APP_VERSION_KIND) == B_OK) {
156 							major = versionInfo.major;
157 							middle = versionInfo.middle;
158 							minor = versionInfo.minor;
159 							variety = versionInfo.variety;
160 							internal = versionInfo.internal;
161 						}
162 					}
163 				}
164 			}
165 			// prepare version variety string
166 			const char *varietyStrings[] = {"Development","Alpha","Beta","Gamma","Golden master","Final"};
167 			char varietyString[32];
168 			strcpy(varietyString,varietyStrings[variety % 6]);
169 			if (variety < 5)
170 				sprintf(varietyString + strlen(varietyString),"/%li",internal);
171 
172 			char s[512];
173 			sprintf(s,	"Mail Daemon Replacement\n\n"
174 						"by Haiku, Inc. All rights reserved.\n\n"
175 						"Version %ld.%ld.%ld %s\n\n"
176 						"See LICENSE file included in the installation package for more information.\n\n\n\n"
177 						"You can contact us at:\n"
178 						"%s\n\n"
179 						"Please submit bug reports using the %s\n\n"
180 						"Project homepage at:\n%s",
181 						major,middle,minor,varietyString,
182 						kEMail,kBugsitePretty,kWebsite);
183 
184 			SetText(s);
185 			MakeEditable(false);
186 			MakeSelectable(false);
187 
188 			SetAlignment(B_ALIGN_CENTER);
189 			SetStylable(true);
190 
191 			// aethetical changes
192 			BFont font;
193 			GetFont(&font);
194 			font.SetSize(24);
195 			SetFontAndColor(0,23,&font,B_FONT_SIZE);
196 
197 			// center the view vertically
198 			rect = TextRect();  rect.OffsetTo(0,(Bounds().Height() - TextHeight(0,42)) / 2);
199 			SetTextRect(rect);
200 
201 			// set the link regions
202 			int start = strstr(s,kEMail) - s;
203 			int finish = start + strlen(kEMail);
204 			GetTextRegion(start,finish,&fMail);
205 			SetFontAndColor(start,finish,NULL,0,&kLinkColor);
206 
207 			start = strstr(s,kBugsitePretty) - s;
208 			finish = start + strlen(kBugsitePretty);
209 			GetTextRegion(start,finish,&fBugsite);
210 			SetFontAndColor(start,finish,NULL,0,&kLinkColor);
211 
212 			start = strstr(s,kWebsite) - s;
213 			finish = start + strlen(kWebsite);
214 			GetTextRegion(start,finish,&fWebsite);
215 			SetFontAndColor(start,finish,NULL,0,&kLinkColor);
216 		}
217 
218 		virtual void Draw(BRect updateRect)
219 		{
220 			BTextView::Draw(updateRect);
221 
222 			BRect rect(fMail.Frame());
223 			StrokeLine(BPoint(rect.left,rect.bottom-2),BPoint(rect.right,rect.bottom-2));
224 			rect = fBugsite.Frame();
225 			StrokeLine(BPoint(rect.left,rect.bottom-2),BPoint(rect.right,rect.bottom-2));
226 			rect = fWebsite.Frame();
227 			StrokeLine(BPoint(rect.left,rect.bottom-2),BPoint(rect.right,rect.bottom-2));
228 		}
229 
230 		virtual void MouseDown(BPoint point)
231 		{
232 			if (fMail.Contains(point)) {
233 				char *arg[] = {(char *)kMailto,NULL};
234 				be_roster->Launch("text/x-email",1,arg);
235 			} else if (fBugsite.Contains(point)) {
236 				char *arg[] = {(char *)kBugsite,NULL};
237 				be_roster->Launch("text/html",1,arg);
238 			} else if (fWebsite.Contains(point)) {
239 				char *arg[] = {(char *)kWebsite, NULL};
240 				be_roster->Launch("text/html", 1, arg);
241 			}
242 		}
243 
244 	private:
245 		BRegion	fWebsite,fMail,fBugsite;
246 };
247 
248 
249 //	#pragma mark -
250 
251 
252 ConfigWindow::ConfigWindow()
253 	:
254 	BWindow(BRect(100.0, 100.0, 580.0, 540.0), "E-mail", B_TITLED_WINDOW,
255 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE | B_NOT_RESIZABLE),
256 	fLastSelectedAccount(NULL),
257 	fSaveSettings(false)
258 {
259 	// create controls
260 
261 	BRect rect(Bounds());
262 	BView *top = new BView(rect, NULL, B_FOLLOW_ALL, 0);
263 	top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
264 	AddChild(top);
265 
266 	// determine font height
267 	font_height fontHeight;
268 	top->GetFontHeight(&fontHeight);
269 	int32 height = (int32)(fontHeight.ascent + fontHeight.descent
270 		+ fontHeight.leading) + 5;
271 
272 	rect.InsetBy(5, 5);	rect.bottom -= 11 + height;
273 	BTabView *tabView = new BTabView(rect, NULL);
274 
275 	BView *view;
276 	rect = tabView->Bounds();
277 	rect.bottom -= tabView->TabHeight() + 4;
278 	tabView->AddTab(view = new BView(rect, NULL, B_FOLLOW_ALL, 0));
279 	tabView->TabAt(0)->SetLabel(B_TRANSLATE("Accounts"));
280 	view->SetViewColor(top->ViewColor());
281 
282 	// accounts listview
283 
284 	rect = view->Bounds().InsetByCopy(8, 8);
285 	rect.right = 140 - B_V_SCROLL_BAR_WIDTH;
286 	rect.bottom -= height + 12;
287 	fAccountsListView = new AccountsListView(rect);
288 	view->AddChild(new BScrollView(NULL, fAccountsListView, B_FOLLOW_ALL, 0,
289 		false, true));
290 	rect.right += B_V_SCROLL_BAR_WIDTH;
291 
292 	rect.top = rect.bottom + 8;  rect.bottom = rect.top + height;
293 	BRect sizeRect = rect;
294 	sizeRect.right = sizeRect.left + 30 + view->StringWidth(
295 		B_TRANSLATE("Add"));
296 	view->AddChild(new BButton(sizeRect, NULL, B_TRANSLATE("Add"),
297 		new BMessage(kMsgAddAccount), B_FOLLOW_BOTTOM));
298 
299 	sizeRect.left = sizeRect.right+3;
300 	sizeRect.right = sizeRect.left + 30 + view->StringWidth(
301 		B_TRANSLATE("Remove"));
302 	view->AddChild(fRemoveButton = new BButton(
303 		sizeRect, NULL, B_TRANSLATE("Remove"),
304 		new BMessage(kMsgRemoveAccount), B_FOLLOW_BOTTOM));
305 
306 	// accounts config view
307 	rect = view->Bounds();
308 	rect.left = fAccountsListView->Frame().right + B_V_SCROLL_BAR_WIDTH + 16;
309 	rect.right -= 10;
310 	view->AddChild(fConfigView = new CenterContainer(rect));
311 
312 	MakeHowToView();
313 
314 	// general settings
315 
316 	rect = tabView->Bounds();
317 	rect.bottom -= tabView->TabHeight() + 4;
318 	tabView->AddTab(view = new CenterContainer(rect));
319 	tabView->TabAt(1)->SetLabel(B_TRANSLATE("Settings"));
320 
321 	rect = view->Bounds().InsetByCopy(8, 8);
322 	rect.right -= 1;
323 	rect.bottom = rect.top + height * 5 + 15;
324 	BBox *box = new BBox(rect);
325 	box->SetLabel(B_TRANSLATE("Mail checking"));
326 	view->AddChild(box);
327 
328 	rect = box->Bounds().InsetByCopy(8, 8);
329 	rect.top += 7;
330 	rect.bottom = rect.top + height + 5;
331 	BRect tile = rect.OffsetByCopy(0, 1);
332 	int32 labelWidth = (int32)view->StringWidth(B_TRANSLATE("Check every")) + 6;
333 	tile.right = 80 + labelWidth;
334 	fIntervalControl = new BTextControl(tile, "time",
335 		B_TRANSLATE("Check every"), NULL, NULL);
336 	fIntervalControl->SetDivider(labelWidth);
337 	box->AddChild(fIntervalControl);
338 
339 	BPopUpMenu *frequencyPopUp = new BPopUpMenu(B_EMPTY_STRING);
340 	const char *frequencyStrings[] = {
341 		B_TRANSLATE("never"),
342 		B_TRANSLATE("minutes"),
343 		B_TRANSLATE("hours"),
344 		B_TRANSLATE("days")};
345 	BMenuItem *item;
346 	for (int32 i = 0; i < 4; i++) {
347 		frequencyPopUp->AddItem(item = new BMenuItem(frequencyStrings[i],
348 			new BMessage(kMsgIntervalUnitChanged)));
349 		if (i == 1)
350 			item->SetMarked(true);
351 	}
352 	tile.left = tile.right + 5;
353 	tile.right = rect.right;
354 	tile.OffsetBy(0,-1);
355 	fIntervalUnitField = new BMenuField(tile, "frequency", B_EMPTY_STRING,
356 		frequencyPopUp);
357 	fIntervalUnitField->SetDivider(0.0);
358 	box->AddChild(fIntervalUnitField);
359 
360 	rect.OffsetBy(0,height + 9);
361 	rect.bottom -= 2;
362 	fPPPActiveCheckBox = new BCheckBox(rect, "ppp active",
363 		B_TRANSLATE("Only when dial-up is connected"), NULL);
364 	box->AddChild(fPPPActiveCheckBox);
365 
366 	rect.OffsetBy(0,height + 9);
367 	rect.bottom -= 2;
368 	fPPPActiveSendCheckBox = new BCheckBox(rect, "ppp activesend",
369 		B_TRANSLATE("Schedule outgoing mail when dial-up is disconnected"),
370 		NULL);
371 	box->AddChild(fPPPActiveSendCheckBox);
372 
373 	// Miscellaneous settings box
374 
375 	rect = box->Frame();  rect.bottom = rect.top + 3 * height + 30;
376 	box = new BBox(rect);
377 	box->SetLabel(B_TRANSLATE("Miscellaneous"));
378 	view->AddChild(box);
379 
380 	BPopUpMenu *statusPopUp = new BPopUpMenu(B_EMPTY_STRING);
381 	const char *statusModes[] = {
382 		B_TRANSLATE("Never"),
383 		B_TRANSLATE("While sending"),
384 		B_TRANSLATE("While sending and receiving"),
385 		B_TRANSLATE("Always")};
386 	BMessage *msg;
387 	for (int32 i = 0; i < 4; i++) {
388 		statusPopUp->AddItem(item = new BMenuItem(statusModes[i],
389 			msg = new BMessage(kMsgShowStatusWindowChanged)));
390 		msg->AddInt32("ShowStatusWindow", i);
391 		if (i == 0)
392 			item->SetMarked(true);
393 	}
394 	rect = box->Bounds().InsetByCopy(8,8);
395 	rect.top += 7;
396 	rect.bottom = rect.top + height + 5;
397 	labelWidth
398 		= (int32)view->StringWidth(
399 			B_TRANSLATE("Show connection status window:"))	+ 8;
400 	fStatusModeField = new BMenuField(rect, "show status",
401 		B_TRANSLATE("Show connection status window:"), statusPopUp);
402 	fStatusModeField->SetDivider(labelWidth);
403 	box->AddChild(fStatusModeField);
404 
405 	rect = fStatusModeField->Frame();;
406 	rect.OffsetBy(0, rect.Height() + 10);
407 	BButton *button = new BButton(rect, B_EMPTY_STRING,
408 		B_TRANSLATE("Edit mailbox menu…"),
409 		msg = new BMessage(B_REFS_RECEIVED));
410 	button->ResizeToPreferred();
411 	box->AddChild(button);
412 	button->SetTarget(BMessenger("application/x-vnd.Be-TRAK"));
413 
414 	BPath path;
415 	find_directory(B_USER_SETTINGS_DIRECTORY, &path);
416 	path.Append("Mail/Menu Links");
417 	BEntry entry(path.Path());
418 	if (entry.InitCheck() == B_OK && entry.Exists()) {
419 		entry_ref ref;
420 		entry.GetRef(&ref);
421 		msg->AddRef("refs", &ref);
422 	}
423 	else
424 		button->SetEnabled(false);
425 
426 	rect = button->Frame();
427 	rect.OffsetBy(rect.Width() + 30,0);
428 	fAutoStartCheckBox = new BCheckBox(rect, "start daemon",
429 		B_TRANSLATE("Start mail services on startup"), NULL);
430 	fAutoStartCheckBox->ResizeToPreferred();
431 	box->AddChild(fAutoStartCheckBox);
432 
433 	// save/revert buttons
434 
435 	top->AddChild(tabView);
436 
437 	rect = tabView->Frame();
438 	rect.top = rect.bottom + 5;
439 	rect.bottom = rect.top + height + 5;
440 	BButton *saveButton = new BButton(rect, "apply", B_TRANSLATE("Apply"),
441 		new BMessage(kMsgSaveSettings));
442 	float w,h;
443 	saveButton->GetPreferredSize(&w, &h);
444 	saveButton->ResizeTo(w, h);
445 	saveButton->MoveTo(rect.right - w, rect.top);
446 	top->AddChild(saveButton);
447 
448 	BButton *revertButton = new BButton(rect, "revert", B_TRANSLATE("Revert"),
449 		new BMessage(kMsgRevertSettings));
450 	revertButton->GetPreferredSize(&w, &h);
451 	revertButton->ResizeTo(w,h);
452 	revertButton->MoveTo(saveButton->Frame().left - 25 - w, rect.top);
453 	top->AddChild(revertButton);
454 
455 	LoadSettings();
456 		// this will also move our window to the stored position
457 
458 	fAccountsListView->SetSelectionMessage(new BMessage(kMsgAccountSelected));
459 	fAccountsListView->MakeFocus(true);
460 }
461 
462 
463 ConfigWindow::~ConfigWindow()
464 {
465 }
466 
467 
468 void
469 ConfigWindow::MakeHowToView()
470 {
471 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
472 	BResources *resources = BApplication::AppResources();
473 	if (resources) {
474 		size_t length;
475 		char *buffer = (char *)resources->FindResource(B_LARGE_ICON_TYPE, 101,
476 			&length);
477 		if (buffer) {
478 			BBitmap *bitmap = new (nothrow) BBitmap(BRect(0, 0, 63, 63),
479 				B_CMAP8);
480 			if (bitmap && bitmap->InitCheck() == B_OK) {
481 				// copy and enlarge a 32x32 8-bit bitmap
482 				char *bits = (char *)bitmap->Bits();
483 				for (int32 i = 0, j = -64; i < (int32)length; i++) {
484 					if ((i % 32) == 0)
485 						j += 64;
486 
487 					char *b = bits + (i << 1) + j;
488 					b[0] = b[1] = b[64] = b[65] = buffer[i];
489 				}
490 				fConfigView->AddChild(new BitmapView(bitmap));
491 			} else
492 				delete bitmap;
493 		}
494 	}
495 #else
496 	app_info info;
497 	if (be_app->GetAppInfo(&info) == B_OK) {
498 		BFile appFile(&info.ref, B_READ_ONLY);
499 		BAppFileInfo appFileInfo(&appFile);
500 		if (appFileInfo.InitCheck() == B_OK) {
501 			BBitmap *bitmap = new (nothrow) BBitmap(BRect(0, 0, 63, 63),
502 				B_RGBA32);
503 			if (appFileInfo.GetIcon(bitmap, B_LARGE_ICON) == B_OK) {
504 				fConfigView->AddChild(new BitmapView(bitmap));
505 			} else
506 				delete bitmap;
507 		}
508 	}
509 #endif // HAIKU_TARGET_PLATFORM_HAIKU
510 
511 	BRect rect = fConfigView->Bounds();
512 	BTextView *text = new BTextView(rect, NULL, rect, B_FOLLOW_NONE,
513 		B_WILL_DRAW);
514 	text->SetViewColor(fConfigView->Parent()->ViewColor());
515 	text->SetAlignment(B_ALIGN_CENTER);
516 	text->SetText(B_TRANSLATE(
517 		"\n\nCreate a new account with the Add button.\n\n"
518 		"Remove an account with the Remove button on the selected item.\n\n"
519 		"Select an item in the list to change its settings."));
520 	rect = text->Bounds();
521 	text->ResizeTo(rect.Width(), text->TextHeight(0, 42));
522 	text->SetTextRect(rect);
523 
524 	text->MakeEditable(false);
525 	text->MakeSelectable(false);
526 
527 	fConfigView->AddChild(text);
528 
529 	static_cast<CenterContainer *>(fConfigView)->Layout();
530 }
531 
532 
533 void
534 ConfigWindow::LoadSettings()
535 {
536 	Accounts::Delete();
537 	Accounts::Create(fAccountsListView, fConfigView);
538 
539 	// load in general settings
540 	BMailSettings settings;
541 	status_t status = SetToGeneralSettings(&settings);
542 	if (status == B_OK) {
543 		// move own window
544 		MoveTo(settings.ConfigWindowFrame().LeftTop());
545 	} else {
546 		fprintf(stderr, B_TRANSLATE("Error retrieving general settings: %s\n"),
547 			strerror(status));
548 	}
549 
550 	BScreen screen(this);
551 	BRect screenFrame(screen.Frame().InsetByCopy(0, 5));
552 	if (!screenFrame.Contains(Frame().LeftTop())
553 		|| !screenFrame.Contains(Frame().RightBottom()))
554 		status = B_ERROR;
555 
556 	if (status != B_OK) {
557 		// center window on screen
558 		MoveTo((screenFrame.Width() - Frame().Width()) / 2,
559 			(screenFrame.Height() - Frame().Height()) / 2);
560 	}
561 }
562 
563 
564 void
565 ConfigWindow::SaveSettings()
566 {
567 	// remove config views
568 	((CenterContainer *)fConfigView)->DeleteChildren();
569 
570 	/*** save general settings ***/
571 
572 	// figure out time interval
573 	float interval;
574 	sscanf(fIntervalControl->Text(),"%f",&interval);
575 	float multiplier = 0;
576 	switch (fIntervalUnitField->Menu()->IndexOf(
577 			fIntervalUnitField->Menu()->FindMarked())) {
578 		case 1:		// minutes
579 			multiplier = 60;
580 			break;
581 		case 2:		// hours
582 			multiplier = 60 * 60;
583 			break;
584 		case 3:		// days
585 			multiplier = 24 * 60 * 60;
586 			break;
587 	}
588 	time_t time = (time_t)(multiplier * interval);
589 
590 	// apply and save general settings
591 	BMailSettings settings;
592 	if (fSaveSettings) {
593 		settings.SetAutoCheckInterval(time * 1e6);
594 		settings.SetCheckOnlyIfPPPUp(fPPPActiveCheckBox->Value()
595 			== B_CONTROL_ON);
596 		settings.SetSendOnlyIfPPPUp(fPPPActiveSendCheckBox->Value()
597 			== B_CONTROL_ON);
598 		settings.SetDaemonAutoStarts(fAutoStartCheckBox->Value()
599 			== B_CONTROL_ON);
600 
601 		// status mode (alway, fetching/retrieving, ...)
602 		int32 index = fStatusModeField->Menu()->IndexOf(
603 			fStatusModeField->Menu()->FindMarked());
604 		settings.SetShowStatusWindow(index);
605 
606 	} else {
607 		// restore status window look
608 		settings.SetStatusWindowLook(settings.StatusWindowLook());
609 	}
610 
611 	settings.SetConfigWindowFrame(Frame());
612 	settings.Save();
613 
614 	/*** save accounts ***/
615 
616 	if (fSaveSettings)
617 		Accounts::Save();
618 
619 	// start the mail_daemon if auto start was selected
620 	if (fSaveSettings && fAutoStartCheckBox->Value() == B_CONTROL_ON
621 		&& !be_roster->IsRunning("application/x-vnd.Be-POST"))
622 	{
623 		be_roster->Launch("application/x-vnd.Be-POST");
624 	}
625 }
626 
627 
628 bool
629 ConfigWindow::QuitRequested()
630 {
631 	SaveSettings();
632 
633 	Accounts::Delete();
634 
635 	be_app->PostMessage(B_QUIT_REQUESTED);
636 	return true;
637 }
638 
639 
640 void
641 ConfigWindow::MessageReceived(BMessage *msg)
642 {
643 	BRect autoConfigRect(0, 0, 400, 300);
644 	BRect frame;
645 
646 	AutoConfigWindow *autoConfigWindow = NULL;
647 	switch (msg->what) {
648 		case kMsgAccountSelected:
649 		{
650 			int32 index;
651 			if (msg->FindInt32("index", &index) != B_OK || index < 0) {
652 				// deselect current item
653 				((CenterContainer *)fConfigView)->DeleteChildren();
654 				MakeHowToView();
655 				break;
656 			}
657 			AccountItem *item = (AccountItem *)fAccountsListView->ItemAt(index);
658 			if (item)
659 				item->account->Selected(item->type);
660 			break;
661 		}
662 		case kMsgAddAccount:
663 		{
664 			frame = Frame();
665 			autoConfigRect.OffsetTo(
666 				frame.left + (frame.Width() - autoConfigRect.Width()) / 2,
667 				frame.top + (frame.Width() - autoConfigRect.Height()) / 2);
668 			autoConfigWindow = new AutoConfigWindow(autoConfigRect, this);
669 			autoConfigWindow->Show();
670 			break;
671 		}
672 		case kMsgRemoveAccount:
673 		{
674 			int32 index = fAccountsListView->CurrentSelection();
675 			if (index >= 0) {
676 				AccountItem *item = (AccountItem *)fAccountsListView->ItemAt(
677 					index);
678 				if (item != NULL) {
679 					item->account->Remove(item->type);
680 					MakeHowToView();
681 				}
682 			}
683 			break;
684 		}
685 
686 		case kMsgIntervalUnitChanged:
687 		{
688 			int32 index;
689 			if (msg->FindInt32("index",&index) == B_OK)
690 				fIntervalControl->SetEnabled(index != 0);
691 			break;
692 		}
693 
694 		case kMsgShowStatusWindowChanged:
695 		{
696 			// the status window stuff is the only "live" setting
697 			BMessenger messenger("application/x-vnd.Be-POST");
698 			if (messenger.IsValid())
699 				messenger.SendMessage(msg);
700 			break;
701 		}
702 
703 		case kMsgRevertSettings:
704 			RevertToLastSettings();
705 			break;
706 		case kMsgSaveSettings:
707 			fSaveSettings = true;
708 			SaveSettings();
709 			MakeHowToView();
710 			break;
711 
712 		default:
713 			BWindow::MessageReceived(msg);
714 			break;
715 	}
716 }
717 
718 
719 status_t
720 ConfigWindow::SetToGeneralSettings(BMailSettings *settings)
721 {
722 	if (!settings)
723 		return B_BAD_VALUE;
724 
725 	status_t status = settings->InitCheck();
726 	if (status != B_OK)
727 		return status;
728 
729 	// retrieval frequency
730 
731 	time_t interval = time_t(settings->AutoCheckInterval() / 1e6L);
732 	char text[25];
733 	text[0] = 0;
734 	int timeIndex = 0;
735 	if (interval >= 60) {
736 		timeIndex = 1;
737 		sprintf(text, "%ld", interval / (60));
738 	}
739 	if (interval >= (60*60)) {
740 		timeIndex = 2;
741 		sprintf(text, "%ld", interval / (60*60));
742 	}
743 	if (interval >= (60*60*24)) {
744 		timeIndex = 3;
745 		sprintf(text, "%ld", interval / (60*60*24));
746 	}
747 	fIntervalControl->SetText(text);
748 
749 	if (BMenuItem *item = fIntervalUnitField->Menu()->ItemAt(timeIndex))
750 		item->SetMarked(true);
751 	fIntervalControl->SetEnabled(timeIndex != 0);
752 
753 	fPPPActiveCheckBox->SetValue(settings->CheckOnlyIfPPPUp());
754 	fPPPActiveSendCheckBox->SetValue(settings->SendOnlyIfPPPUp());
755 
756 	fAutoStartCheckBox->SetValue(settings->DaemonAutoStarts());
757 
758 	if (BMenuItem *item
759 			= fStatusModeField->Menu()->ItemAt(settings->ShowStatusWindow()))
760 		item->SetMarked(true);
761 
762 	return B_OK;
763 }
764 
765 
766 void
767 ConfigWindow::RevertToLastSettings()
768 {
769 	// revert general settings
770 	BMailSettings settings;
771 
772 	// restore status window look
773 	settings.SetStatusWindowLook(settings.StatusWindowLook());
774 
775 	status_t status = SetToGeneralSettings(&settings);
776 	if (status != B_OK) {
777 		char text[256];
778 		sprintf(text, B_TRANSLATE(
779 				"\nThe general settings couldn't be reverted.\n\n"
780 				"Error retrieving general settings:\n%s\n"),
781 			strerror(status));
782 		(new BAlert("Error", text, "OK", NULL, NULL, B_WIDTH_AS_USUAL,
783 			B_WARNING_ALERT))->Go();
784 	}
785 
786 	// revert account data
787 
788 	if (fAccountsListView->CurrentSelection() != -1)
789 		((CenterContainer *)fConfigView)->DeleteChildren();
790 
791 	Accounts::Delete();
792 	Accounts::Create(fAccountsListView,fConfigView);
793 
794 	if (fConfigView->CountChildren() == 0)
795 		MakeHowToView();
796 }
797