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