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