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