xref: /haiku/src/apps/poorman/PoorManWindow.cpp (revision 6c4a44e36ba846c54467103f884d65dfa13e7fcb)
1 /* PoorManWindow.cpp
2  *
3  *	Philip Harrison
4  *	Started: 4/25/2004
5  *	Version: 0.1
6  */
7 
8 #include "PoorManWindow.h"
9 
10 #include <string.h>
11 #include <time.h>
12 #include <arpa/inet.h>
13 
14 #include <Alert.h>
15 #include <Box.h>
16 #include <Catalog.h>
17 #include <Directory.h>
18 #include <File.h>
19 #include <FindDirectory.h>
20 #include <LayoutBuilder.h>
21 #include <Locale.h>
22 #include <Menu.h>
23 #include <MenuBar.h>
24 #include <MenuItem.h>
25 #include <OS.h>
26 #include <Path.h>
27 #include <ScrollBar.h>
28 #include <ScrollView.h>
29 #include <StringView.h>
30 #include <TypeConstants.h>
31 
32 #include "PoorManApplication.h"
33 #include "PoorManPreferencesWindow.h"
34 #include "PoorManView.h"
35 #include "PoorManServer.h"
36 #include "PoorManLogger.h"
37 #include "constants.h"
38 
39 
40 #undef B_TRANSLATION_CONTEXT
41 #define B_TRANSLATION_CONTEXT "PoorMan"
42 #define DATE_FORMAT B_SHORT_DATE_FORMAT
43 #define TIME_FORMAT B_MEDIUM_TIME_FORMAT
44 
45 
46 PoorManWindow::PoorManWindow(BRect frame)
47 	:
48 	BWindow(frame, STR_APP_NAME, B_TITLED_WINDOW, 0),
49 	fStatus(false),
50 	fHits(0),
51 	fPrefWindow(NULL),
52 	fLogFile(NULL),
53 	fServer(NULL)
54 {
55 	//preferences init
56 	fWebDirectory.SetTo(STR_DEFAULT_WEB_DIRECTORY);
57 	fIndexFileName.SetTo("index.html");
58 	fDirListFlag = false;
59 
60 	fLogConsoleFlag = true;
61 	fLogFileFlag = false;
62 	fLogPath.SetTo("");
63 
64 	fMaxConnections = (int16)32;
65 
66 	fIsZoomed = true;
67 	fLastWidth = 318.0f;
68 	fLastHeight = 320.0f;
69 	this->fFrame = frame;
70 	fSetwindowFrame.Set(112.0f, 60.0f, 492.0f, 340.0f);
71 
72 	// PoorMan Window
73 	SetSizeLimits(318, 1600, 53, 1200);
74 	// limit the size of the size of the window
75 
76 	// -----------------------------------------------------------------
77 	// Three Labels
78 
79 	// Status String
80 	fStatusView = new BStringView("Status View", B_TRANSLATE("Status: Stopped"));
81 
82 	// Directory String
83 	fDirView = new BStringView("Dir View", B_TRANSLATE("Directory: (none)"));
84 
85 	// Hits String
86 	fHitsView = new BStringView("Hit View", B_TRANSLATE("Hits: 0"));
87 
88 	// -----------------------------------------------------------------
89 	// Logging View
90 
91 	fLoggingView = new BTextView(STR_TXT_VIEW, B_WILL_DRAW );
92 
93 	fLoggingView->MakeEditable(false);	// user cannot change the text
94 	fLoggingView->MakeSelectable(true);
95 	fLoggingView->SetViewColor(WHITE);
96 	fLoggingView->SetStylable(true);
97 
98 	// create the scroll view
99 	fScrollView = new BScrollView("Scroll View", fLoggingView,
100 					B_WILL_DRAW | B_FRAME_EVENTS | B_FOLLOW_ALL_SIDES,
101 					// Make sure articles on border do not occur when resizing
102 					false, true);
103 	fLoggingView->MakeFocus(true);
104 
105 
106 	// -----------------------------------------------------------------
107 	// menu bar
108 	fFileMenuBar = new BMenuBar("File Menu Bar");
109 
110 	// menus
111 	fFileMenu = BuildFileMenu();
112 	if (fFileMenu)
113 		fFileMenuBar->AddItem(fFileMenu);
114 
115 	fEditMenu = BuildEditMenu();
116 	if (fEditMenu)
117 		fFileMenuBar->AddItem(fEditMenu);
118 
119 	fControlsMenu = BuildControlsMenu();
120 	if (fControlsMenu)
121 		fFileMenuBar->AddItem(fControlsMenu);
122 
123 	// File Panels
124 	BWindow* change_title;
125 
126 	fSaveConsoleFilePanel = new BFilePanel(B_SAVE_PANEL, new BMessenger(this),
127 						NULL, B_FILE_NODE, false,
128 						new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE));
129 	change_title = fSaveConsoleFilePanel->Window();
130 	change_title->SetTitle(STR_FILEPANEL_SAVE_CONSOLE);
131 
132 	fSaveConsoleSelectionFilePanel = new BFilePanel(B_SAVE_PANEL,
133 						new BMessenger(this), NULL, B_FILE_NODE, false,
134 						new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION));
135 	change_title = fSaveConsoleSelectionFilePanel->Window();
136 	change_title->SetTitle(STR_FILEPANEL_SAVE_CONSOLE_SELECTION);
137 
138 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
139 		.SetInsets(0)
140 		.Add(fFileMenuBar)
141 		.AddGroup(B_VERTICAL, B_USE_SMALL_SPACING)
142 			.SetInsets(B_USE_WINDOW_INSETS)
143 			.AddGroup(B_HORIZONTAL)
144 				.Add(fStatusView)
145 				.AddGlue()
146 				.Add(fHitsView)
147 				.End()
148 			.AddGroup(B_HORIZONTAL)
149 				.Add(fDirView)
150 				.AddGlue()
151 				.End()
152 			.Add(fScrollView);
153 
154 	pthread_rwlock_init(&fLogFileLock, NULL);
155 }
156 
157 
158 PoorManWindow::~PoorManWindow()
159 {
160 	delete fServer;
161 	delete fLogFile;
162 	pthread_rwlock_destroy(&fLogFileLock);
163 }
164 
165 
166 void
167 PoorManWindow::MessageReceived(BMessage* message)
168 {
169 	switch (message->what) {
170 		case MSG_MENU_FILE_SAVE_AS:
171 			fSaveConsoleFilePanel->Show();
172 			break;
173 		case MSG_FILE_PANEL_SAVE_CONSOLE:
174 			printf("FilePanel: Save console\n");
175 			SaveConsole(message, false);
176 			break;
177 		case MSG_MENU_FILE_SAVE_SELECTION:
178 			fSaveConsoleSelectionFilePanel->Show();
179 			break;
180 		case MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION:
181 			printf("FilePanel: Save console selection\n");
182 			SaveConsole(message, true);
183 			break;
184 		case MSG_FILE_PANEL_SELECT_WEB_DIR:
185 			fPrefWindow->MessageReceived(message);
186 			break;
187 		case MSG_MENU_EDIT_PREF:
188 			fPrefWindow = new PoorManPreferencesWindow(fSetwindowFrame,
189 				STR_WIN_NAME_PREF);
190 			fPrefWindow->Show();
191 			break;
192 		case MSG_MENU_CTRL_RUN:
193 			if (fStatus)
194 				StopServer();
195 			else
196 				StartServer();
197 			break;
198 		case MSG_MENU_CTRL_CLEAR_HIT:
199 			SetHits(0);
200 			//UpdateHitsLabel();
201 			break;
202 		case MSG_MENU_CTRL_CLEAR_CONSOLE:
203 			fLoggingView->SelectAll();
204 			fLoggingView->Delete();
205 			break;
206 		case MSG_MENU_CTRL_CLEAR_LOG:
207 			FILE* f;
208 			f = fopen(fLogPath.String(), "w");
209 			fclose(f);
210 			break;
211 		case MSG_LOG: {
212 			if (!fLogConsoleFlag && !fLogFileFlag)
213 				break;
214 
215 			time_t time;
216 			in_addr_t address;
217 			rgb_color color;
218 			const void* pointer;
219 			ssize_t size;
220 			const char* msg;
221 			BString line;
222 
223 			if (message->FindString("cstring", &msg) != B_OK)
224 				break;
225 			if (message->FindData("time_t", B_TIME_TYPE, &pointer, &size) != B_OK)
226 				time = -1;
227 			else
228 				time = *static_cast<const time_t*>(pointer);
229 
230 			if (message->FindData("in_addr_t", B_ANY_TYPE, &pointer, &size) != B_OK)
231 				address = INADDR_NONE;
232 			else
233 				address = *static_cast<const in_addr_t*>(pointer);
234 
235 			if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK)
236 				color = BLACK;
237 			else
238 				color = *static_cast<const rgb_color*>(pointer);
239 
240 			if (time != -1) {
241 				BString timeString;
242 				if (BLocale::Default()->FormatDateTime(&timeString, time,
243 						DATE_FORMAT, TIME_FORMAT) == B_OK) {
244 					line << '[' << timeString << "]: ";
245 				}
246 			}
247 
248 			if (address != INADDR_NONE) {
249 				char addr[INET_ADDRSTRLEN];
250 				struct in_addr sin_addr;
251 				sin_addr.s_addr = address;
252 				if (inet_ntop(AF_INET, &sin_addr, addr, sizeof(addr)) != NULL) {
253 					addr[strlen(addr)] = '\0';
254 					line << '(' << addr << ") ";
255 				}
256 			}
257 
258 			line << msg;
259 
260 			text_run run;
261 			text_run_array runs;
262 
263 			run.offset = 0;
264 			run.color = color;
265 
266 			runs.count = 1;
267 			runs.runs[0] = run;
268 
269 			if (Lock()) {
270 				if (fLogConsoleFlag) {
271 					fLoggingView->Insert(fLoggingView->TextLength(),
272 						line.String(), line.Length(), &runs);
273 					fLoggingView->ScrollToOffset(fLoggingView->TextLength());
274 				}
275 
276 				if (fLogFileFlag) {
277 					if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
278 						fLogFile->Write(line.String(), line.Length());
279 						pthread_rwlock_unlock(&fLogFileLock);
280 					}
281 				}
282 
283 				Unlock();
284 			}
285 
286 			break;
287 		}
288 		default:
289 			BWindow::MessageReceived(message);
290 			break;
291 	}
292 }
293 
294 
295 void
296 PoorManWindow::FrameMoved(BPoint origin)
297 {
298 	fFrame.left = origin.x;
299 	fFrame.top = origin.y;
300 }
301 
302 
303 void
304 PoorManWindow::FrameResized(float width, float height)
305 {
306 	if (fIsZoomed) {
307 		fLastWidth  = width;
308 		fLastHeight = height;
309 	}
310 }
311 
312 
313 bool
314 PoorManWindow::QuitRequested()
315 {
316 	if (fStatus) {
317 		time_t now = time(NULL);
318 		BString timeString;
319 		BLocale::Default()->FormatDateTime(&timeString, now,
320 			DATE_FORMAT, TIME_FORMAT);
321 
322 		BString line;
323 		line << "[" << timeString << "]: " << B_TRANSLATE("Shutting down.")
324 			<< "\n";
325 
326 		if (fLogConsoleFlag) {
327 			fLoggingView->Insert(fLoggingView->TextLength(),
328 				line, line.Length());
329 			fLoggingView->ScrollToOffset(fLoggingView->TextLength());
330 		}
331 
332 		if (fLogFileFlag) {
333 			if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
334 				fLogFile->Write(line, line.Length());
335 				pthread_rwlock_unlock(&fLogFileLock);
336 			}
337 		}
338 
339 		fServer->Stop();
340 		fStatus = false;
341 		UpdateStatusLabelAndMenuItem();
342 	}
343 
344 	SaveSettings();
345 	be_app_messenger.SendMessage(B_QUIT_REQUESTED);
346 	return true;
347 }
348 
349 
350 void
351 PoorManWindow::Zoom(BPoint origin, float width, float height)
352 {
353 	if (fIsZoomed) {
354 		// Change to the Minimal size
355 		fIsZoomed = false;
356 		ResizeTo(318, 53);
357 	} else {
358 		// Change to the Zoomed size
359 		fIsZoomed = true;
360 		ResizeTo(fLastWidth, fLastHeight);
361 	}
362 }
363 
364 
365 void
366 PoorManWindow::SetHits(uint32 num)
367 {
368 	fHits = num;
369 	UpdateHitsLabel();
370 }
371 
372 
373 // Private: Methods ------------------------------------------
374 
375 
376 BMenu*
377 PoorManWindow::BuildFileMenu() const
378 {
379 	BMenu* ptrFileMenu = new BMenu(STR_MNU_FILE);
380 
381 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_AS,
382 		new BMessage(MSG_MENU_FILE_SAVE_AS), CMD_FILE_SAVE_AS));
383 
384 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_SELECTION,
385 		new BMessage(MSG_MENU_FILE_SAVE_SELECTION)));
386 
387 	ptrFileMenu->AddSeparatorItem();
388 
389 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_QUIT,
390 		new BMessage(B_QUIT_REQUESTED), CMD_FILE_QUIT));
391 
392 	return ptrFileMenu;
393 }
394 
395 
396 BMenu*
397 PoorManWindow::BuildEditMenu() const
398 {
399 	BMenu* ptrEditMenu = new BMenu(STR_MNU_EDIT);
400 
401 	BMenuItem* CopyMenuItem = new BMenuItem(STR_MNU_EDIT_COPY,
402 		new BMessage(B_COPY), CMD_EDIT_COPY);
403 
404 	ptrEditMenu->AddItem(CopyMenuItem);
405 	CopyMenuItem->SetTarget(fLoggingView, NULL);
406 
407 	ptrEditMenu->AddSeparatorItem();
408 
409 	BMenuItem* SelectAllMenuItem = new BMenuItem(STR_MNU_EDIT_SELECT_ALL,
410 	new BMessage(B_SELECT_ALL), CMD_EDIT_SELECT_ALL);
411 
412 	ptrEditMenu->AddItem(SelectAllMenuItem);
413 	SelectAllMenuItem->SetTarget(fLoggingView, NULL);
414 
415 	ptrEditMenu->AddSeparatorItem();
416 
417 	BMenuItem* PrefMenuItem = new BMenuItem(STR_MNU_EDIT_PREF,
418 		new BMessage(MSG_MENU_EDIT_PREF));
419 	ptrEditMenu->AddItem(PrefMenuItem);
420 
421 	return ptrEditMenu;
422 }
423 
424 
425 BMenu*
426 PoorManWindow::BuildControlsMenu() const
427 {
428 	BMenu* ptrControlMenu = new BMenu(STR_MNU_CTRL);
429 
430 	BMenuItem* RunServerMenuItem = new BMenuItem(STR_MNU_CTRL_RUN_SERVER,
431 		new BMessage(MSG_MENU_CTRL_RUN));
432 	RunServerMenuItem->SetMarked(false);
433 	ptrControlMenu->AddItem(RunServerMenuItem);
434 
435 	BMenuItem* ClearHitCounterMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_HIT_COUNTER,
436 		new BMessage(MSG_MENU_CTRL_CLEAR_HIT));
437 	ptrControlMenu->AddItem(ClearHitCounterMenuItem);
438 
439 	ptrControlMenu->AddSeparatorItem();
440 
441 	BMenuItem* ClearConsoleLogMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_CONSOLE,
442 		new BMessage(MSG_MENU_CTRL_CLEAR_CONSOLE));
443 	ptrControlMenu->AddItem(ClearConsoleLogMenuItem);
444 
445 	BMenuItem* ClearLogFileMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_LOG_FILE,
446 		new BMessage(MSG_MENU_CTRL_CLEAR_LOG));
447 	ptrControlMenu->AddItem(ClearLogFileMenuItem);
448 
449 	return ptrControlMenu;
450 }
451 
452 
453 void
454 PoorManWindow::SetDirLabel(const char* name)
455 {
456 	BString dirPath(B_TRANSLATE("Directory: "));
457 	dirPath.Append(name);
458 
459 	if (Lock()) {
460 		fDirView->SetText(dirPath.String());
461 		Unlock();
462 	}
463 }
464 
465 
466 void
467 PoorManWindow::UpdateStatusLabelAndMenuItem()
468 {
469 	if (Lock()) {
470 		if (fStatus)
471 			fStatusView->SetText(B_TRANSLATE("Status: Running"));
472 		else
473 			fStatusView->SetText(B_TRANSLATE("Status: Stopped"));
474 		fControlsMenu->FindItem(STR_MNU_CTRL_RUN_SERVER)->SetMarked(fStatus);
475 		Unlock();
476 	}
477 }
478 
479 
480 void
481 PoorManWindow::UpdateHitsLabel()
482 {
483 	if (Lock()) {
484 		sprintf(fHitsLabel, B_TRANSLATE("Hits: %lu"), GetHits());
485 		fHitsView->SetText(fHitsLabel);
486 
487 		Unlock();
488 	}
489 }
490 
491 
492 status_t
493 PoorManWindow::SaveConsole(BMessage* message, bool selection)
494 {
495 	entry_ref	ref;
496 	const char* name;
497 	BPath		path;
498 	BEntry		entry;
499 	status_t	err = B_OK;
500 	FILE*		f;
501 
502 	err = message->FindRef("directory", &ref);
503 	if (err != B_OK)
504 		return err;
505 
506 	err = message->FindString("name", &name);
507 	if (err != B_OK)
508 		return err;
509 
510 	err = entry.SetTo(&ref);
511 	if (err != B_OK)
512 		return err;
513 
514 	entry.GetPath(&path);
515 	path.Append(name);
516 
517 	if (!(f = fopen(path.Path(), "w")))
518 		return B_ERROR;
519 
520 	if (!selection) {
521 		// write the data to the file
522 		err = fwrite(fLoggingView->Text(), 1, fLoggingView->TextLength(), f);
523 	} else {
524 		// find the selected text and write it to a file
525 		int32 start = 0, end = 0;
526 		fLoggingView->GetSelection(&start, &end);
527 
528 		BString buffer;
529 		char * buffData = buffer.LockBuffer(end - start + 1);
530 		// copy the selected text from the TextView to the buffer
531 		fLoggingView->GetText(start, end - start, buffData);
532 		buffer.UnlockBuffer(end - start + 1);
533 
534 		err = fwrite(buffer.String(), 1, end - start + 1, f);
535 	}
536 
537 	fclose(f);
538 
539 	return err;
540 }
541 
542 
543 void
544 PoorManWindow::DefaultSettings()
545 {
546 	BAlert* serverAlert = new BAlert(B_TRANSLATE("Error Server"),
547 		STR_ERR_CANT_START, B_TRANSLATE("OK"));
548 	serverAlert->SetFlags(serverAlert->Flags() | B_CLOSE_ON_ESCAPE);
549 	BAlert* dirAlert = new BAlert(B_TRANSLATE("Error Dir"),
550 		STR_ERR_WEB_DIR, B_TRANSLATE("Cancel"), B_TRANSLATE("Select"),
551 		B_TRANSLATE("Default"), B_WIDTH_AS_USUAL, B_OFFSET_SPACING);
552 	dirAlert->SetShortcut(0, B_ESCAPE);
553 	int32 buttonIndex = dirAlert->Go();
554 
555 	switch (buttonIndex) {
556 		case 0:
557 			if (Lock())
558 				Quit();
559 			be_app_messenger.SendMessage(B_QUIT_REQUESTED);
560 			break;
561 
562 		case 1:
563 			fPrefWindow = new PoorManPreferencesWindow(
564 					fSetwindowFrame,
565 					STR_WIN_NAME_PREF);
566 			fPrefWindow->ShowWebDirFilePanel();
567 			break;
568 
569 		case 2:
570 			if (create_directory(STR_DEFAULT_WEB_DIRECTORY, 0755) != B_OK) {
571 				serverAlert->Go();
572 				if (Lock())
573 					Quit();
574 				be_app_messenger.SendMessage(B_QUIT_REQUESTED);
575 				break;
576 			}
577 			BAlert* dirCreatedAlert =
578 				new BAlert(B_TRANSLATE("Dir Created"), STR_DIR_CREATED,
579 					B_TRANSLATE("OK"));
580 			dirCreatedAlert->SetFlags(dirCreatedAlert->Flags() | B_CLOSE_ON_ESCAPE);
581 			dirCreatedAlert->Go();
582 			SetWebDir(STR_DEFAULT_WEB_DIRECTORY);
583 			be_app->PostMessage(kStartServer);
584 			break;
585 	}
586 }
587 
588 
589 status_t
590 PoorManWindow::ReadSettings()
591 {
592 	BPath p;
593 	BFile f;
594 	BMessage m;
595 
596 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
597 		return B_ERROR;
598 	p.Append(STR_SETTINGS_FILE_NAME);
599 
600 	f.SetTo(p.Path(), B_READ_ONLY);
601 	if (f.InitCheck() != B_OK)
602 		return B_ERROR;
603 
604 	if (m.Unflatten(&f) != B_OK)
605 		return B_ERROR;
606 
607 	if (MSG_PREF_FILE != m.what)
608 		return B_ERROR;
609 
610 	//site tab
611 	if (m.FindString("fWebDirectory", &fWebDirectory) != B_OK)
612 		fWebDirectory.SetTo(STR_DEFAULT_WEB_DIRECTORY);
613 	if (m.FindString("fIndexFileName", &fIndexFileName) != B_OK)
614 		fIndexFileName.SetTo("index.html");
615 	if (m.FindBool("fDirListFlag", &fDirListFlag) != B_OK)
616 		fDirListFlag = false;
617 
618 	//logging tab
619 	if (m.FindBool("fLogConsoleFlag", &fLogConsoleFlag) != B_OK)
620 		fLogConsoleFlag = true;
621 	if (m.FindBool("fLogFileFlag", &fLogFileFlag) != B_OK)
622 		fLogFileFlag = false;
623 	if (m.FindString("fLogPath", &fLogPath) != B_OK)
624 		fLogPath.SetTo("");
625 
626 	//advance tab
627 	if (m.FindInt16("fMaxConnections", &fMaxConnections) != B_OK)
628 		fMaxConnections = (int16)32;
629 
630 	//windows' position and size
631 	if (m.FindRect("frame", &fFrame) != B_OK)
632 		fFrame.Set(82.0f, 30.0f, 400.0f, 350.0f);
633 	if (m.FindRect("fSetwindowFrame", &fSetwindowFrame) != B_OK)
634 		fSetwindowFrame.Set(112.0f, 60.0f, 492.0f, 340.0f);
635 	if (m.FindBool("fIsZoomed", &fIsZoomed) != B_OK)
636 		fIsZoomed = true;
637 	if (m.FindFloat("fLastWidth", &fLastWidth) != B_OK)
638 		fLastWidth = 318.0f;
639 	if (m.FindFloat("fLastHeight", &fLastHeight) != B_OK)
640 		fLastHeight = 320.0f;
641 
642 	fIsZoomed?ResizeTo(fLastWidth, fLastHeight):ResizeTo(318, 53);
643 	MoveTo(fFrame.left, fFrame.top);
644 
645 	fLogFile = new BFile(fLogPath.String(), B_CREATE_FILE | B_WRITE_ONLY
646 		| B_OPEN_AT_END);
647 	if (fLogFile->InitCheck() != B_OK) {
648 		fLogFileFlag = false;
649 		//log it to console, "log to file unavailable."
650 		return B_OK;
651 	}
652 
653 	SetDirLabel(fWebDirectory.String());
654 
655 	return B_OK;
656 }
657 
658 
659 status_t
660 PoorManWindow::SaveSettings()
661 {
662 	BPath p;
663 	BFile f;
664 	BMessage m(MSG_PREF_FILE);
665 
666 	//site tab
667 	m.AddString("fWebDirectory", fWebDirectory);
668 	m.AddString("fIndexFileName", fIndexFileName);
669 	m.AddBool("fDirListFlag", fDirListFlag);
670 
671 	//logging tab
672 	m.AddBool("fLogConsoleFlag", fLogConsoleFlag);
673 	m.AddBool("fLogFileFlag", fLogFileFlag);
674 	m.AddString("fLogPath", fLogPath);
675 
676 	//advance tab
677 	m.AddInt16("fMaxConnections", fMaxConnections);
678 
679 	//windows' position and size
680 	m.AddRect("frame", fFrame);
681 	m.AddRect("fSetwindowFrame", fSetwindowFrame);
682 	m.AddBool("fIsZoomed", fIsZoomed);
683 	m.AddFloat("fLastWidth", fLastWidth);
684 	m.AddFloat("fLastHeight", fLastHeight);
685 
686 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
687 		return B_ERROR;
688 	p.Append(STR_SETTINGS_FILE_NAME);
689 
690 	f.SetTo(p.Path(), B_WRITE_ONLY | B_ERASE_FILE | B_CREATE_FILE);
691 	if (f.InitCheck() != B_OK)
692 		return B_ERROR;
693 
694 	if (m.Flatten(&f) != B_OK)
695 		return B_ERROR;
696 
697 	return B_OK;
698 }
699 
700 
701 status_t
702 PoorManWindow::StartServer()
703 {
704 	if (fServer == NULL)
705 		fServer = new PoorManServer(fWebDirectory.String(), fMaxConnections,
706 			fDirListFlag, fIndexFileName.String());
707 
708 	poorman_log(B_TRANSLATE("Starting up... "));
709 	if (fServer->Run() != B_OK) {
710 		return B_ERROR;
711 	}
712 
713 	fStatus = true;
714 	UpdateStatusLabelAndMenuItem();
715 	poorman_log(B_TRANSLATE("done.\n"), false, INADDR_NONE, GREEN);
716 
717 	return B_OK;
718 }
719 
720 
721 status_t
722 PoorManWindow::StopServer()
723 {
724 	if (fServer == NULL)
725 		return B_ERROR;
726 
727 	poorman_log(B_TRANSLATE("Shutting down.\n"));
728 	fServer->Stop();
729 	fStatus = false;
730 	UpdateStatusLabelAndMenuItem();
731 	return B_OK;
732 }
733 
734 
735 void
736 PoorManWindow::SetLogPath(const char* str)
737 {
738 	if (!strcmp(fLogPath, str))
739 		return;
740 
741 	BFile* temp = new BFile(str, B_CREATE_FILE | B_WRITE_ONLY | B_OPEN_AT_END);
742 
743 	if (temp->InitCheck() != B_OK) {
744 		delete temp;
745 		return;
746 	}
747 
748 	if (pthread_rwlock_wrlock(&fLogFileLock) == 0) {
749 		delete fLogFile;
750 		fLogFile = temp;
751 		pthread_rwlock_unlock(&fLogFileLock);
752 	} else {
753 		delete temp;
754 		return;
755 	}
756 
757 	fLogPath.SetTo(str);
758 }
759