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
47PoorManWindow::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
159PoorManWindow::~PoorManWindow()
160{
161	delete fServer;
162	delete fLogFile;
163	pthread_rwlock_destroy(&fLogFileLock);
164}
165
166
167void
168PoorManWindow::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			const char* 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->FindString("addr", &address) != B_OK)
232				address = NULL;
233
234			if (message->FindData("rgb_color", B_RGB_COLOR_TYPE, &pointer, &size) != B_OK)
235				color = BLACK;
236			else
237				color = *static_cast<const rgb_color*>(pointer);
238
239			if (time != -1) {
240				BString timeString;
241				if (BDateTimeFormat().Format(timeString, time, DATE_FORMAT,
242						TIME_FORMAT) == B_OK) {
243					line << '[' << timeString << "]: ";
244				}
245			}
246
247			if (address != NULL) {
248				line << '(' << address << ") ";
249			}
250
251			line << msg;
252
253			text_run run;
254			text_run_array runs;
255
256			run.offset = 0;
257			run.color = color;
258
259			runs.count = 1;
260			runs.runs[0] = run;
261
262			if (Lock()) {
263				if (fLogConsoleFlag) {
264					fLoggingView->Insert(fLoggingView->TextLength(),
265						line.String(), line.Length(), &runs);
266					fLoggingView->ScrollToOffset(fLoggingView->TextLength());
267				}
268
269				if (fLogFileFlag) {
270					if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
271						fLogFile->Write(line.String(), line.Length());
272						pthread_rwlock_unlock(&fLogFileLock);
273					}
274				}
275
276				Unlock();
277			}
278
279			break;
280		}
281		default:
282			BWindow::MessageReceived(message);
283			break;
284	}
285}
286
287
288void
289PoorManWindow::FrameMoved(BPoint origin)
290{
291	fFrame.left = origin.x;
292	fFrame.top = origin.y;
293}
294
295
296void
297PoorManWindow::FrameResized(float width, float height)
298{
299	if (fIsZoomed) {
300		fLastWidth  = width;
301		fLastHeight = height;
302	}
303}
304
305
306bool
307PoorManWindow::QuitRequested()
308{
309	if (fStatus) {
310		time_t now = time(NULL);
311		BString timeString;
312		BDateTimeFormat().Format(timeString, now, DATE_FORMAT, TIME_FORMAT);
313
314		BString line;
315		line << "[" << timeString << "]: " << B_TRANSLATE("Shutting down.")
316			<< "\n";
317
318		if (fLogConsoleFlag) {
319			fLoggingView->Insert(fLoggingView->TextLength(),
320				line, line.Length());
321			fLoggingView->ScrollToOffset(fLoggingView->TextLength());
322		}
323
324		if (fLogFileFlag) {
325			if (pthread_rwlock_rdlock(&fLogFileLock) == 0) {
326				fLogFile->Write(line, line.Length());
327				pthread_rwlock_unlock(&fLogFileLock);
328			}
329		}
330
331		fServer->Stop();
332		fStatus = false;
333		UpdateStatusLabelAndMenuItem();
334	}
335
336	SaveSettings();
337	be_app_messenger.SendMessage(B_QUIT_REQUESTED);
338	return true;
339}
340
341
342void
343PoorManWindow::Zoom(BPoint origin, float width, float height)
344{
345	if (fIsZoomed) {
346		// Change to the Minimal size
347		fIsZoomed = false;
348		ResizeTo(318, 53);
349	} else {
350		// Change to the Zoomed size
351		fIsZoomed = true;
352		ResizeTo(fLastWidth, fLastHeight);
353	}
354}
355
356
357void
358PoorManWindow::SetHits(uint32 num)
359{
360	fHits = num;
361	UpdateHitsLabel();
362}
363
364
365// Private: Methods ------------------------------------------
366
367
368BMenu*
369PoorManWindow::BuildFileMenu() const
370{
371	BMenu* ptrFileMenu = new BMenu(STR_MNU_FILE);
372
373	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_AS,
374		new BMessage(MSG_MENU_FILE_SAVE_AS), CMD_FILE_SAVE_AS));
375
376	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_SAVE_SELECTION,
377		new BMessage(MSG_MENU_FILE_SAVE_SELECTION)));
378
379	ptrFileMenu->AddSeparatorItem();
380
381	ptrFileMenu->AddItem(new BMenuItem(STR_MNU_FILE_QUIT,
382		new BMessage(B_QUIT_REQUESTED), CMD_FILE_QUIT));
383
384	return ptrFileMenu;
385}
386
387
388BMenu*
389PoorManWindow::BuildEditMenu() const
390{
391	BMenu* ptrEditMenu = new BMenu(STR_MNU_EDIT);
392
393	BMenuItem* CopyMenuItem = new BMenuItem(STR_MNU_EDIT_COPY,
394		new BMessage(B_COPY), CMD_EDIT_COPY);
395
396	ptrEditMenu->AddItem(CopyMenuItem);
397	CopyMenuItem->SetTarget(fLoggingView, NULL);
398
399	ptrEditMenu->AddSeparatorItem();
400
401	BMenuItem* SelectAllMenuItem = new BMenuItem(STR_MNU_EDIT_SELECT_ALL,
402	new BMessage(B_SELECT_ALL), CMD_EDIT_SELECT_ALL);
403
404	ptrEditMenu->AddItem(SelectAllMenuItem);
405	SelectAllMenuItem->SetTarget(fLoggingView, NULL);
406
407	ptrEditMenu->AddSeparatorItem();
408
409	BMenuItem* PrefMenuItem = new BMenuItem(STR_MNU_EDIT_PREF,
410		new BMessage(MSG_MENU_EDIT_PREF));
411	ptrEditMenu->AddItem(PrefMenuItem);
412
413	return ptrEditMenu;
414}
415
416
417BMenu*
418PoorManWindow::BuildControlsMenu() const
419{
420	BMenu* ptrControlMenu = new BMenu(STR_MNU_CTRL);
421
422	BMenuItem* RunServerMenuItem = new BMenuItem(STR_MNU_CTRL_RUN_SERVER,
423		new BMessage(MSG_MENU_CTRL_RUN));
424	RunServerMenuItem->SetMarked(false);
425	ptrControlMenu->AddItem(RunServerMenuItem);
426
427	BMenuItem* ClearHitCounterMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_HIT_COUNTER,
428		new BMessage(MSG_MENU_CTRL_CLEAR_HIT));
429	ptrControlMenu->AddItem(ClearHitCounterMenuItem);
430
431	ptrControlMenu->AddSeparatorItem();
432
433	BMenuItem* ClearConsoleLogMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_CONSOLE,
434		new BMessage(MSG_MENU_CTRL_CLEAR_CONSOLE));
435	ptrControlMenu->AddItem(ClearConsoleLogMenuItem);
436
437	BMenuItem* ClearLogFileMenuItem = new BMenuItem(STR_MNU_CTRL_CLEAR_LOG_FILE,
438		new BMessage(MSG_MENU_CTRL_CLEAR_LOG));
439	ptrControlMenu->AddItem(ClearLogFileMenuItem);
440
441	return ptrControlMenu;
442}
443
444
445void
446PoorManWindow::SetDirLabel(const char* name)
447{
448	BString dirPath(B_TRANSLATE("Directory: "));
449	dirPath.Append(name);
450
451	if (Lock()) {
452		fDirView->SetText(dirPath.String());
453		Unlock();
454	}
455}
456
457
458void
459PoorManWindow::UpdateStatusLabelAndMenuItem()
460{
461	if (Lock()) {
462		if (fStatus)
463			fStatusView->SetText(B_TRANSLATE("Status: Running"));
464		else
465			fStatusView->SetText(B_TRANSLATE("Status: Stopped"));
466		fControlsMenu->FindItem(STR_MNU_CTRL_RUN_SERVER)->SetMarked(fStatus);
467		Unlock();
468	}
469}
470
471
472void
473PoorManWindow::UpdateHitsLabel()
474{
475	if (Lock()) {
476		sprintf(fHitsLabel, B_TRANSLATE("Hits: %lu"), GetHits());
477		fHitsView->SetText(fHitsLabel);
478
479		Unlock();
480	}
481}
482
483
484status_t
485PoorManWindow::SaveConsole(BMessage* message, bool selection)
486{
487	entry_ref	ref;
488	const char* name;
489	BPath		path;
490	BEntry		entry;
491	status_t	err = B_OK;
492	FILE*		f;
493
494	err = message->FindRef("directory", &ref);
495	if (err != B_OK)
496		return err;
497
498	err = message->FindString("name", &name);
499	if (err != B_OK)
500		return err;
501
502	err = entry.SetTo(&ref);
503	if (err != B_OK)
504		return err;
505
506	entry.GetPath(&path);
507	path.Append(name);
508
509	if (!(f = fopen(path.Path(), "w")))
510		return B_ERROR;
511
512	if (!selection) {
513		// write the data to the file
514		err = fwrite(fLoggingView->Text(), 1, fLoggingView->TextLength(), f);
515	} else {
516		// find the selected text and write it to a file
517		int32 start = 0, end = 0;
518		fLoggingView->GetSelection(&start, &end);
519
520		BString buffer;
521		char * buffData = buffer.LockBuffer(end - start + 1);
522		// copy the selected text from the TextView to the buffer
523		fLoggingView->GetText(start, end - start, buffData);
524		buffer.UnlockBuffer(end - start + 1);
525
526		err = fwrite(buffer.String(), 1, end - start + 1, f);
527	}
528
529	fclose(f);
530
531	return err;
532}
533
534
535void
536PoorManWindow::DefaultSettings()
537{
538	BAlert* serverAlert = new BAlert(B_TRANSLATE("Error Server"),
539		STR_ERR_CANT_START, B_TRANSLATE("OK"));
540	serverAlert->SetFlags(serverAlert->Flags() | B_CLOSE_ON_ESCAPE);
541	BAlert* dirAlert = new BAlert(B_TRANSLATE("Error Dir"),
542		STR_ERR_WEB_DIR, B_TRANSLATE("Cancel"), B_TRANSLATE("Select"),
543		B_TRANSLATE("Create public_html"), B_WIDTH_AS_USUAL, B_OFFSET_SPACING);
544	dirAlert->SetShortcut(0, B_ESCAPE);
545	int32 buttonIndex = dirAlert->Go();
546
547	switch (buttonIndex) {
548		case 0:
549			if (Lock())
550				Quit();
551			be_app_messenger.SendMessage(B_QUIT_REQUESTED);
552			break;
553
554		case 1:
555			fPrefWindow = new PoorManPreferencesWindow(
556					fSetwindowFrame,
557					STR_WIN_NAME_PREF);
558			fPrefWindow->ShowWebDirFilePanel();
559			break;
560
561		case 2:
562			if (create_directory(STR_DEFAULT_WEB_DIRECTORY, 0755) != B_OK) {
563				serverAlert->Go();
564				if (Lock())
565					Quit();
566				be_app_messenger.SendMessage(B_QUIT_REQUESTED);
567				break;
568			}
569			BAlert* dirCreatedAlert =
570				new BAlert(B_TRANSLATE("Dir Created"), STR_DIR_CREATED,
571					B_TRANSLATE("OK"));
572			dirCreatedAlert->SetFlags(dirCreatedAlert->Flags() | B_CLOSE_ON_ESCAPE);
573			dirCreatedAlert->Go();
574			SetWebDir(STR_DEFAULT_WEB_DIRECTORY);
575			be_app->PostMessage(kStartServer);
576			break;
577	}
578}
579
580
581status_t
582PoorManWindow::ReadSettings()
583{
584	BPath p;
585	BFile f;
586	BMessage m;
587
588	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
589		return B_ERROR;
590	p.Append(STR_SETTINGS_FILE_NAME);
591
592	f.SetTo(p.Path(), B_READ_ONLY);
593	if (f.InitCheck() != B_OK)
594		return B_ERROR;
595
596	if (m.Unflatten(&f) != B_OK)
597		return B_ERROR;
598
599	if (MSG_PREF_FILE != m.what)
600		return B_ERROR;
601
602	//site tab
603	if (m.FindString("fWebDirectory", &fWebDirectory) != B_OK)
604		fWebDirectory.SetTo(STR_DEFAULT_WEB_DIRECTORY);
605	if (m.FindString("fIndexFileName", &fIndexFileName) != B_OK)
606		fIndexFileName.SetTo("index.html");
607	if (m.FindBool("fDirListFlag", &fDirListFlag) != B_OK)
608		fDirListFlag = false;
609
610	//logging tab
611	if (m.FindBool("fLogConsoleFlag", &fLogConsoleFlag) != B_OK)
612		fLogConsoleFlag = true;
613	if (m.FindBool("fLogFileFlag", &fLogFileFlag) != B_OK)
614		fLogFileFlag = false;
615	if (m.FindString("fLogPath", &fLogPath) != B_OK)
616		fLogPath.SetTo("");
617
618	//advance tab
619	if (m.FindInt16("fMaxConnections", &fMaxConnections) != B_OK)
620		fMaxConnections = (int16)32;
621
622	//windows' position and size
623	if (m.FindRect("frame", &fFrame) != B_OK)
624		fFrame.Set(82.0f, 30.0f, 400.0f, 350.0f);
625	if (m.FindRect("fSetwindowFrame", &fSetwindowFrame) != B_OK)
626		fSetwindowFrame.Set(112.0f, 60.0f, 492.0f, 340.0f);
627	if (m.FindBool("fIsZoomed", &fIsZoomed) != B_OK)
628		fIsZoomed = true;
629	if (m.FindFloat("fLastWidth", &fLastWidth) != B_OK)
630		fLastWidth = 318.0f;
631	if (m.FindFloat("fLastHeight", &fLastHeight) != B_OK)
632		fLastHeight = 320.0f;
633
634	fIsZoomed?ResizeTo(fLastWidth, fLastHeight):ResizeTo(318, 53);
635	MoveTo(fFrame.left, fFrame.top);
636
637	fLogFile = new BFile(fLogPath.String(), B_CREATE_FILE | B_WRITE_ONLY
638		| B_OPEN_AT_END);
639	if (fLogFile->InitCheck() != B_OK) {
640		fLogFileFlag = false;
641		//log it to console, "log to file unavailable."
642		return B_OK;
643	}
644
645	SetDirLabel(fWebDirectory.String());
646
647	return B_OK;
648}
649
650
651status_t
652PoorManWindow::SaveSettings()
653{
654	BPath p;
655	BFile f;
656	BMessage m(MSG_PREF_FILE);
657
658	//site tab
659	m.AddString("fWebDirectory", fWebDirectory);
660	m.AddString("fIndexFileName", fIndexFileName);
661	m.AddBool("fDirListFlag", fDirListFlag);
662
663	//logging tab
664	m.AddBool("fLogConsoleFlag", fLogConsoleFlag);
665	m.AddBool("fLogFileFlag", fLogFileFlag);
666	m.AddString("fLogPath", fLogPath);
667
668	//advance tab
669	m.AddInt16("fMaxConnections", fMaxConnections);
670
671	//windows' position and size
672	m.AddRect("frame", fFrame);
673	m.AddRect("fSetwindowFrame", fSetwindowFrame);
674	m.AddBool("fIsZoomed", fIsZoomed);
675	m.AddFloat("fLastWidth", fLastWidth);
676	m.AddFloat("fLastHeight", fLastHeight);
677
678	if (find_directory(B_USER_SETTINGS_DIRECTORY, &p) != B_OK)
679		return B_ERROR;
680	p.Append(STR_SETTINGS_FILE_NAME);
681
682	f.SetTo(p.Path(), B_WRITE_ONLY | B_ERASE_FILE | B_CREATE_FILE);
683	if (f.InitCheck() != B_OK)
684		return B_ERROR;
685
686	if (m.Flatten(&f) != B_OK)
687		return B_ERROR;
688
689	return B_OK;
690}
691
692
693status_t
694PoorManWindow::StartServer()
695{
696	if (fServer == NULL)
697		fServer = new PoorManServer(fWebDirectory.String(), fMaxConnections,
698			fDirListFlag, fIndexFileName.String());
699
700	poorman_log(B_TRANSLATE("Starting up... "));
701	if (fServer->Run() != B_OK) {
702		return B_ERROR;
703	}
704
705	fStatus = true;
706	UpdateStatusLabelAndMenuItem();
707	poorman_log(B_TRANSLATE("done.\n"), false, NULL, GREEN);
708
709	return B_OK;
710}
711
712
713status_t
714PoorManWindow::StopServer()
715{
716	if (fServer == NULL)
717		return B_ERROR;
718
719	poorman_log(B_TRANSLATE("Shutting down.\n"));
720	fServer->Stop();
721	fStatus = false;
722	UpdateStatusLabelAndMenuItem();
723	return B_OK;
724}
725
726
727void
728PoorManWindow::SetLogPath(const char* str)
729{
730	if (!strcmp(fLogPath, str))
731		return;
732
733	BFile* temp = new BFile(str, B_CREATE_FILE | B_WRITE_ONLY | B_OPEN_AT_END);
734
735	if (temp->InitCheck() != B_OK) {
736		delete temp;
737		return;
738	}
739
740	if (pthread_rwlock_wrlock(&fLogFileLock) == 0) {
741		delete fLogFile;
742		fLogFile = temp;
743		pthread_rwlock_unlock(&fLogFileLock);
744	} else {
745		delete temp;
746		return;
747	}
748
749	fLogPath.SetTo(str);
750}
751