xref: /haiku/src/apps/poorman/PoorManWindow.cpp (revision 97901ec593ec4dd50ac115c1c35a6d72f6e489a5)
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 	saveConsoleFilePanel = new BFilePanel(
187 						B_SAVE_PANEL,
188 						new BMessenger(this),
189 						NULL,
190 						B_FILE_NODE,
191 						false,
192 						new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE));
193 
194 	change_title = saveConsoleFilePanel->Window();
195 	change_title->SetTitle(STR_FILEPANEL_SAVE_CONSOLE);
196 
197 	saveConsoleSelectionFilePanel = new BFilePanel(
198 						B_SAVE_PANEL,
199 						new BMessenger(this),
200 						NULL,
201 						B_FILE_NODE,
202 						false,
203 						new BMessage(MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION));
204 
205 	change_title = saveConsoleSelectionFilePanel->Window();
206 	change_title->SetTitle(STR_FILEPANEL_SAVE_CONSOLE_SELECTION);
207 
208 
209 	AddChild(FileMenuBar);
210 
211 	pthread_rwlock_init(&fLogFileLock, NULL);
212 }
213 
214 
215 PoorManWindow::~PoorManWindow()
216 {
217 	delete fServer;
218 	delete fLogViewFont;
219 	delete fLogFile;
220 	pthread_rwlock_destroy(&fLogFileLock);
221 }
222 
223 
224 void
225 PoorManWindow::MessageReceived(BMessage* message)
226 {
227 	switch (message->what) {
228 	case MSG_MENU_FILE_SAVE_AS:
229 		saveConsoleFilePanel->Show();
230 		break;
231 	case MSG_FILE_PANEL_SAVE_CONSOLE:
232 		printf("FilePanel: Save console\n");
233 		SaveConsole(message, false);
234 		break;
235 	case MSG_MENU_FILE_SAVE_SELECTION:
236 		saveConsoleSelectionFilePanel->Show();
237 		break;
238 	case MSG_FILE_PANEL_SAVE_CONSOLE_SELECTION:
239 		printf("FilePanel: Save console selection\n");
240 		SaveConsole(message, true);
241 		break;
242 	case MSG_FILE_PANEL_SELECT_WEB_DIR:
243 		prefWindow->MessageReceived(message);
244 		break;
245 	case MSG_MENU_EDIT_PREF:
246 		prefWindow = new PoorManPreferencesWindow(
247 			setwindow_frame,
248 			STR_WIN_NAME_PREF);
249 		prefWindow->Show();
250 		break;
251 	case MSG_MENU_CTRL_RUN:
252 		if (status)
253 			StopServer();
254 		else
255 			StartServer();
256 		break;
257 	case MSG_MENU_CTRL_CLEAR_HIT:
258 		SetHits(0);
259 		//UpdateHitsLabel();
260 		break;
261 	case MSG_MENU_CTRL_CLEAR_CONSOLE:
262 		loggingView->SelectAll();
263 		loggingView->Delete();
264 		break;
265 	case MSG_MENU_CTRL_CLEAR_LOG:
266 		FILE * f;
267 		f = fopen(log_path.String(), "w");
268 		fclose(f);
269 		break;
270 	case MSG_LOG: {
271 		if (!log_console_flag && !log_file_flag)
272 			break;
273 
274 		time_t time;
275 		in_addr_t address;
276 		rgb_color color;
277 		const void* pointer;
278 		ssize_t size;
279 		const char* msg;
280 		BString line;
281 
282 		if (message->FindString("cstring", &msg) != B_OK)
283 			break;
284 		if (message->FindData("time_t", B_TIME_TYPE, &pointer, &size) != B_OK)
285 			time = -1;
286 		else
287 			time = *static_cast<const time_t*>(pointer);
288 
289 		if (message->FindData("in_addr_t", B_ANY_TYPE, &pointer, &size) != B_OK)
290 			address = INADDR_NONE;
291 		else
292 			address = *static_cast<const in_addr_t*>(pointer);
293 
294 		if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK)
295 			color = BLACK;
296 		else
297 			color = *static_cast<const rgb_color*>(pointer);
298 
299 		if (time != -1) {
300 			char timeString[26];
301 			if (ctime_r(&time, timeString) != NULL) {
302 				timeString[24] = '\0';
303 				line << '[' << timeString << "]: ";
304 			}
305 		}
306 
307 		if (address != INADDR_NONE) {
308 			char addr[INET_ADDRSTRLEN];
309 			struct in_addr sin_addr;
310 			sin_addr.s_addr = address;
311 			if (inet_ntop(AF_INET, &sin_addr, addr, sizeof(addr)) != NULL) {
312 				addr[strlen(addr)] = '\0';
313 				line << '(' << addr << ") ";
314 			}
315 		}
316 
317 		line << msg;
318 
319 		text_run run;
320 		text_run_array runs;
321 
322 		run.offset = 0;
323 		run.font = *fLogViewFont;
324 		run.color = color;
325 
326 		runs.count = 1;
327 		runs.runs[0] = run;
328 
329 		if (Lock()) {
330 			if (log_console_flag) {
331 				loggingView->Insert(loggingView->TextLength(),
332 					line.String(), line.Length(), &runs);
333 				loggingView->ScrollToOffset(loggingView->TextLength());
334 			}
335 
336 			if (log_file_flag) {
337 				if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
338 					fLogFile->Write(line.String(), line.Length());
339 					pthread_rwlock_unlock(&fLogFileLock);
340 				}
341 			}
342 
343 			Unlock();
344 		}
345 
346 		break;
347 	}
348 	default:
349 		BWindow::MessageReceived(message);
350 		break;
351 	}
352 }
353 
354 
355 void
356 PoorManWindow::FrameMoved(BPoint origin)
357 {
358 	frame.left = origin.x;
359 	frame.top = origin.y;
360 }
361 
362 
363 void
364 PoorManWindow::FrameResized(float width, float height)
365 {
366 	if (is_zoomed) {
367 		last_width  = width;
368 		last_height = height;
369 	}
370 }
371 
372 
373 bool
374 PoorManWindow::QuitRequested()
375 {
376 	if (status) {
377 		time_t now = time(NULL);
378 		char line[] = "[Thu Jan  1 00:00:00 1970]: Shutting down.\n";
379 
380 		ctime_r(&now, line + 1);
381 		line[25] = ']';
382 		line[26] = ' ';
383 
384 		if (log_console_flag) {
385 				loggingView->Insert(loggingView->TextLength(),
386 					line, strlen(line));
387 				loggingView->ScrollToOffset(loggingView->TextLength());
388 		}
389 
390 		if (log_file_flag) {
391 			if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
392 					fLogFile->Write(line, strlen(line));
393 					pthread_rwlock_unlock(&fLogFileLock);
394 			}
395 		}
396 
397 		fServer->Stop();
398 		status = false;
399 		UpdateStatusLabelAndMenuItem();
400 	}
401 
402 	SaveSettings();
403 	be_app_messenger.SendMessage(B_QUIT_REQUESTED);
404 	return true;
405 }
406 
407 
408 void
409 PoorManWindow::Zoom(BPoint origin, float width, float height)
410 {
411 	if (is_zoomed) {
412 		// Change to the Minimal size
413 		is_zoomed = false;
414 		ResizeTo(318, 53);
415 	} else {
416 		// Change to the Zoomed size
417 		is_zoomed = true;
418 		ResizeTo(last_width, last_height);
419 	}
420 }
421 
422 
423 void
424 PoorManWindow::SetHits(uint32 num)
425 {
426 	hits = num;
427 	UpdateHitsLabel();
428 }
429 
430 
431 // Private: Methods ------------------------------------------
432 
433 
434 BMenu *
435 PoorManWindow::BuildFileMenu() const
436 {
437 	BMenu * ptrFileMenu = new BMenu(STR_MNU_FILE);
438 
439 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_AS,
440 		new BMessage(MSG_MENU_FILE_SAVE_AS), CMD_FILE_SAVE_AS));
441 
442 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_SELECTION,
443 		new BMessage(MSG_MENU_FILE_SAVE_SELECTION)));
444 
445 	ptrFileMenu->AddSeparatorItem();
446 
447 	// about box
448 	BMenuItem * AboutItem = new BMenuItem(STR_MNU_FILE_ABOUT,
449 		new BMessage(B_ABOUT_REQUESTED));
450 	AboutItem->SetTarget(NULL, be_app);
451 	ptrFileMenu->AddItem(AboutItem);
452 
453 	ptrFileMenu->AddSeparatorItem();
454 
455 
456 	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_QUIT,
457 		new BMessage(B_QUIT_REQUESTED), CMD_FILE_QUIT));
458 
459 	return ptrFileMenu;
460 }
461 
462 
463 BMenu *
464 PoorManWindow::BuildEditMenu() const
465 {
466 	BMenu * ptrEditMenu = new BMenu(STR_MNU_EDIT);
467 
468 	BMenuItem * CopyMenuItem = new BMenuItem(STR_MNU_EDIT_COPY,
469 		new BMessage(B_COPY), CMD_EDIT_COPY);
470 
471 	ptrEditMenu->AddItem(CopyMenuItem);
472 	CopyMenuItem->SetTarget(loggingView, NULL);
473 
474 	ptrEditMenu->AddSeparatorItem();
475 
476 	BMenuItem * SelectAllMenuItem = new BMenuItem(STR_MNU_EDIT_SELECT_ALL,
477 	new BMessage(B_SELECT_ALL), CMD_EDIT_SELECT_ALL);
478 
479 	ptrEditMenu->AddItem(SelectAllMenuItem);
480 	SelectAllMenuItem->SetTarget(loggingView, NULL);
481 
482 	ptrEditMenu->AddSeparatorItem();
483 
484 	BMenuItem * PrefMenuItem = new BMenuItem(STR_MNU_EDIT_PREF,
485 		new BMessage(MSG_MENU_EDIT_PREF));
486 	ptrEditMenu->AddItem(PrefMenuItem);
487 
488 	return ptrEditMenu;
489 }
490 
491 
492 BMenu *
493 PoorManWindow::BuildControlsMenu() const
494 {
495 	BMenu * ptrControlMenu = new BMenu(STR_MNU_CTRL);
496 
497 	BMenuItem * RunServerMenuItem = new BMenuItem(STR_MNU_CTRL_RUN_SERVER,
498 		new BMessage(MSG_MENU_CTRL_RUN));
499 	RunServerMenuItem->SetMarked(false);
500 	ptrControlMenu->AddItem(RunServerMenuItem);
501 
502 	BMenuItem * ClearHitCounterMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_HIT_COUNTER,
503 		new BMessage(MSG_MENU_CTRL_CLEAR_HIT));
504 	ptrControlMenu->AddItem(ClearHitCounterMenuItem);
505 
506 	ptrControlMenu->AddSeparatorItem();
507 
508 	BMenuItem * ClearConsoleLogMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_CONSOLE,
509 		new BMessage(MSG_MENU_CTRL_CLEAR_CONSOLE));
510 	ptrControlMenu->AddItem(ClearConsoleLogMenuItem);
511 
512 	BMenuItem * ClearLogFileMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_LOG_FILE,
513 		new BMessage(MSG_MENU_CTRL_CLEAR_LOG));
514 	ptrControlMenu->AddItem(ClearLogFileMenuItem);
515 
516 	return ptrControlMenu;
517 }
518 
519 
520 void
521 PoorManWindow::SetDirLabel(const char * name)
522 {
523 	BString dirPath("Directory: ");
524 	dirPath.Append(name);
525 
526 	if (Lock()) {
527 		dirView->SetText(dirPath.String());
528 		Unlock();
529 	}
530 }
531 
532 
533 void
534 PoorManWindow::UpdateStatusLabelAndMenuItem()
535 {
536 	if (Lock()) {
537 		if (status)
538 			statusView->SetText("Status: Running");
539 		else
540 			statusView->SetText("Status: Stopped");
541 		ControlsMenu->FindItem(STR_MNU_CTRL_RUN_SERVER)->SetMarked(status);
542 		Unlock();
543 	}
544 }
545 
546 
547 void
548 PoorManWindow::UpdateHitsLabel()
549 {
550 	if (Lock()) {
551 		sprintf(hitsLabel, "Hits: %lu", GetHits());
552 		hitsView->SetText(hitsLabel);
553 
554 		Unlock();
555 	}
556 }
557 
558 
559 status_t
560 PoorManWindow::SaveConsole(BMessage * message, bool selection)
561 {
562 	entry_ref	ref;
563 	const char	* name;
564 	BPath		path;
565 	BEntry		entry;
566 	status_t	err = B_OK;
567 	FILE		*f;
568 
569 	if ((err = message->FindRef("directory", &ref)) != B_OK)
570 		return err;
571 
572 	if ((err = message->FindString("name", &name)) != B_OK)
573 		return err;
574 
575 	if ((err = entry.SetTo(&ref)) != B_OK)
576 		return err;
577 
578 	entry.GetPath(&path);
579 	path.Append(name);
580 
581 	if (!(f = fopen(path.Path(), "w")))
582 		return B_ERROR;
583 
584 	if (!selection) {
585 		// write the data to the file
586 		err = fwrite(loggingView->Text(), 1, loggingView->TextLength(), f);
587 	} else {
588 		// find the selected text and write it to a file
589 		int32 start = 0, end = 0;
590 		loggingView->GetSelection(&start, &end);
591 
592 		BString buffer;
593 		char * buffData = buffer.LockBuffer(end - start + 1);
594 		// copy the selected text from the TextView to the buffer
595 		loggingView->GetText(start, end - start, buffData);
596 		buffer.UnlockBuffer(end - start + 1);
597 
598 		err = fwrite(buffer.String(), 1, end - start + 1, f);
599 	}
600 	fclose(f);
601 
602 	return err;
603 }
604 
605 
606 void
607 PoorManWindow::DefaultSettings()
608 {
609 	BAlert* serverAlert = new BAlert("Error Server", STR_ERR_CANT_START, "OK");
610 	BAlert* dirAlert = new BAlert("Error Dir", STR_ERR_WEB_DIR,
611 		"Cancel", "Select", "Default", B_WIDTH_AS_USUAL, B_OFFSET_SPACING);
612 	dirAlert->SetShortcut(0, B_ESCAPE);
613 	int32 buttonIndex = dirAlert->Go();
614 
615 	switch (buttonIndex) {
616 		case 0:
617 			if (Lock())
618 				Quit();
619 			be_app_messenger.SendMessage(B_QUIT_REQUESTED);
620 			break;
621 
622 		case 1:
623 			prefWindow = new PoorManPreferencesWindow(
624 					setwindow_frame,
625 					STR_WIN_NAME_PREF);
626 			prefWindow->ShowWebDirFilePanel();
627 			break;
628 
629 		case 2:
630 			if (create_directory(STR_DEFAULT_WEB_DIRECTORY, 0755) != B_OK) {
631 				serverAlert->Go();
632 				if (Lock())
633 					Quit();
634 				be_app_messenger.SendMessage(B_QUIT_REQUESTED);
635 				break;
636 			}
637 			BAlert* dirCreatedAlert =
638 				new BAlert("Dir Created", STR_DIR_CREATED, "OK");
639 			dirCreatedAlert->Go();
640 			SetWebDir(STR_DEFAULT_WEB_DIRECTORY);
641 			be_app->PostMessage(kStartServer);
642 			break;
643 	}
644 }
645 
646 
647 status_t
648 PoorManWindow::ReadSettings()
649 {
650 	BPath p;
651 	BFile f;
652 	BMessage m;
653 
654 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
655 		return B_ERROR;
656 	p.Append(STR_SETTINGS_FILE_NAME);
657 
658 	f.SetTo(p.Path(), B_READ_ONLY);
659 	if (f.InitCheck() != B_OK)
660 		return B_ERROR;
661 
662 	if (m.Unflatten(&f) != B_OK)
663 		return B_ERROR;
664 
665 	if (MSG_PREF_FILE != m.what)
666 		return B_ERROR;
667 
668 	//site tab
669 	if (m.FindString("web_directory", &web_directory) != B_OK)
670 		web_directory.SetTo(STR_DEFAULT_WEB_DIRECTORY);
671 	if (m.FindString("index_file_name", &index_file_name) != B_OK)
672 		index_file_name.SetTo("index.html");
673 	if (m.FindBool("dir_list_flag", &dir_list_flag) != B_OK)
674 		dir_list_flag = false;
675 
676 	//logging tab
677 	if (m.FindBool("log_console_flag", &log_console_flag) != B_OK)
678 		log_console_flag = true;
679 	if (m.FindBool("log_file_flag", &log_file_flag) != B_OK)
680 		log_file_flag = false;
681 	if (m.FindString("log_path", &log_path) != B_OK)
682 		log_path.SetTo("");
683 
684 	//advance tab
685 	if (m.FindInt16("max_connections", &max_connections) != B_OK)
686 		max_connections = (int16)32;
687 
688 	//windows' position and size
689 	if (m.FindRect("frame", &frame) != B_OK)
690 		frame.Set(82.0f, 30.0f, 400.0f, 350.0f);
691 	if (m.FindRect("setwindow_frame", &setwindow_frame) != B_OK)
692 		setwindow_frame.Set(112.0f, 60.0f, 492.0f, 340.0f);
693 	if (m.FindBool("is_zoomed", &is_zoomed) != B_OK)
694 		is_zoomed = true;
695 	if (m.FindFloat("last_width", &last_width) != B_OK)
696 		last_width = 318.0f;
697 	if (m.FindFloat("last_height", &last_height) != B_OK)
698 		last_height = 320.0f;
699 
700 	is_zoomed?ResizeTo(last_width, last_height):ResizeTo(318, 53);
701 	MoveTo(frame.left, frame.top);
702 
703 	fLogFile = new BFile(log_path.String(), B_CREATE_FILE | B_WRITE_ONLY
704 		| B_OPEN_AT_END);
705 	if (fLogFile->InitCheck() != B_OK) {
706 		log_file_flag = false;
707 		//log it to console, "log to file unavailable."
708 		return B_OK;
709 	}
710 
711 	SetDirLabel(web_directory.String());
712 
713 	return B_OK;
714 }
715 
716 
717 status_t
718 PoorManWindow::SaveSettings()
719 {
720 	BPath p;
721 	BFile f;
722 	BMessage m(MSG_PREF_FILE);
723 
724 	//site tab
725 	m.AddString("web_directory", web_directory);
726 	m.AddString("index_file_name", index_file_name);
727 	m.AddBool("dir_list_flag", dir_list_flag);
728 
729 	//logging tab
730 	m.AddBool("log_console_flag", log_console_flag);
731 	m.AddBool("log_file_flag", log_file_flag);
732 	m.AddString("log_path", log_path);
733 
734 	//advance tab
735 	m.AddInt16("max_connections", max_connections);
736 
737 	//windows' position and size
738 	m.AddRect("frame", frame);
739 	m.AddRect("setwindow_frame", setwindow_frame);
740 	m.AddBool("is_zoomed", is_zoomed);
741 	m.AddFloat("last_width", last_width);
742 	m.AddFloat("last_height", last_height);
743 
744 	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
745 		return B_ERROR;
746 	p.Append(STR_SETTINGS_FILE_NAME);
747 
748 	f.SetTo(p.Path(), B_WRITE_ONLY | B_ERASE_FILE | B_CREATE_FILE);
749 	if (f.InitCheck() != B_OK)
750 		return B_ERROR;
751 
752 	if (m.Flatten(&f) != B_OK)
753 		return B_ERROR;
754 
755 	return B_OK;
756 }
757 
758 
759 status_t
760 PoorManWindow::StartServer()
761 {
762 	if (fServer == NULL)
763 		fServer = new PoorManServer(
764 			web_directory.String(),
765 			max_connections,
766 			dir_list_flag,
767 			index_file_name.String());
768 
769 	poorman_log("Starting up... ");
770 	if (fServer->Run() != B_OK) {
771 		return B_ERROR;
772 	}
773 
774 	status = true;
775 	UpdateStatusLabelAndMenuItem();
776 	poorman_log("done.\n", false, INADDR_NONE, GREEN);
777 
778 	return B_OK;
779 }
780 
781 
782 status_t
783 PoorManWindow::StopServer()
784 {
785 	if (fServer == NULL)
786 		return B_ERROR;
787 
788 	poorman_log("Shutting down.\n");
789 	fServer->Stop();
790 	status = false;
791 	UpdateStatusLabelAndMenuItem();
792 	return B_OK;
793 }
794 
795 
796 void
797 PoorManWindow::SetLogPath(const char* str)
798 {
799 	if (!strcmp(log_path, str))
800 		return;
801 
802 	BFile* temp = new BFile(str, B_CREATE_FILE | B_WRITE_ONLY | B_OPEN_AT_END);
803 
804 	if (temp->InitCheck() != B_OK) {
805 		delete temp;
806 		return;
807 	}
808 
809 	if (pthread_rwlock_wrlock(&fLogFileLock) == 0) {
810 		delete fLogFile;
811 		fLogFile = temp;
812 		pthread_rwlock_unlock(&fLogFileLock);
813 	} else {
814 		delete temp;
815 		return;
816 	}
817 
818 	log_path.SetTo(str);
819 }
820