1 // Icecast2winDlg.cpp : implementation file
2 //
3 
4 #include "stdafx.h"
5 #include "Icecast2win.h"
6 #include "Icecast2winDlg.h"
7 #include <process.h>
8 
9 #include <libxml/xmlmemory.h>
10 #include <libxml/parser.h>
11 #include <libxml/tree.h>
12 #include <stdlib.h>
13 #include <curl/curl.h>
14 
15 extern "C" {
16 #include "thread/thread.h"
17 #include "avl/avl.h"
18 #include "log/log.h"
19 #include "global.h"
20 #include "httpp/httpp.h"
21 #include "net/sock.h"
22 #include "connection.h"
23 #include "refbuf.h"
24 #include "client.h"
25 #include "stats.h"
26 #include "xslt.h"
27 }
28 
29 #include <afxinet.h>
30 
31 #ifdef _DEBUG
32 #define new DEBUG_NEW
33 #undef THIS_FILE
34 static char THIS_FILE[] = __FILE__;
35 #endif
36 
37 #define ICECAST_VERSION "2.x"
38 CEdit	*g_accessControl;
39 CEdit	*g_errorControl;
40 CIcecast2winDlg	*g_mainDialog;
41 bool	g_tailAccess = false;
42 bool	g_tailError = false;
43 CString gConfigurationSave;
44 
45 char	gTitleSource[1024] = "";
46 char	gTitleName[1024] = "";
47 
48 #define MAXSTATSPERSOURCE 60
49 #define MAXSOURCES 1024
50 
51 typedef struct tagElement {
52 	CString	name;
53 	CString	value;
54 	int		titleFlag;
55 } Element;
56 
57 typedef struct tagElementAdditional {
58 	CString source;
59 	CString	name;
60 	CString	value;
61 	int		titleFlag;
62 } ElementAdditional;
63 
64 
65 typedef struct tagMainElement {
66 	CString	source;
67 	long	numStats;
68 	Element	stats[MAXSTATSPERSOURCE];
69 	int		populated;
70 } MainElement;
71 
72 typedef struct tagMainElementAdditional {
73 	long	numStats;
74 	ElementAdditional	stats[MAXSTATSPERSOURCE];
75 } MainElementAdditional;
76 
77 
78 MainElement gStats[MAXSOURCES];
79 MainElement gGlobalStats;
80 MainElementAdditional	gAdditionalGlobalStats;
81 
82 long	numMainStats;
83 
84 extern "C" {
85 	int main(int argc, char **argv);
86 }
87 
88 
AddToAdditionalGlobalStats(CString source,CString name)89 void AddToAdditionalGlobalStats(CString source, CString name) {
90 	int foundit = 0;
91 	for (int i=0;i<gAdditionalGlobalStats.numStats;i++) {
92 		if ((gAdditionalGlobalStats.stats[i].source == source) && (gAdditionalGlobalStats.stats[i].name == name)) {
93 			foundit = 1;
94 			break;
95 		}
96 	}
97 	if (!foundit) {
98 		gAdditionalGlobalStats.stats[gAdditionalGlobalStats.numStats].source = source;
99 		gAdditionalGlobalStats.stats[gAdditionalGlobalStats.numStats].name = name;
100 		gAdditionalGlobalStats.numStats++;
101 	}
102 	g_mainDialog->UpdateStatsLists();
103 }
104 
ClearTitleAdditionalGlobalStats(CString source,CString name)105 void ClearTitleAdditionalGlobalStats(CString source, CString name) {
106 	int foundit = 0;
107 	int i,j;
108 	for (i=0;i<gAdditionalGlobalStats.numStats;i++) {
109 		gAdditionalGlobalStats.stats[i].titleFlag = 0;
110 	}
111 	for (i=0;i<numMainStats;i++) {
112 		for (j=0;j<gStats[i].numStats;j++) {
113 			if ((gStats[i].source == source) && (gStats[i].stats[j].name == name)) {
114 				gStats[i].stats[j].titleFlag = 0;
115 			}
116 		}
117 	}
118 	g_mainDialog->UpdateStatsLists();
119 }
AddToTitleAdditionalGlobalStats(CString source,CString name)120 void AddToTitleAdditionalGlobalStats(CString source, CString name) {
121 	int foundit = 0;
122 	int i,j;
123 	for (i=0;i<gAdditionalGlobalStats.numStats;i++) {
124 		if ((gAdditionalGlobalStats.stats[i].source == source) && (gAdditionalGlobalStats.stats[i].name == name)) {
125 			ClearTitleAdditionalGlobalStats(source, name);
126 			gAdditionalGlobalStats.stats[i].titleFlag = 1;
127 			strcpy(gTitleSource, source);
128 			strcpy(gTitleName, name);
129 			foundit = 1;
130 			break;
131 		}
132 	}
133 	if (!foundit) {
134 		for (i=0;i<numMainStats;i++) {
135 			for (j=0;j<gStats[i].numStats;j++) {
136 				if ((gStats[i].source == source) && (gStats[i].stats[j].name == name)) {
137 					ClearTitleAdditionalGlobalStats(source, name);
138 					gStats[i].stats[j].titleFlag = 1;
139 					strcpy(gTitleSource, source);
140 					strcpy(gTitleName, name);
141 					foundit = 1;
142 					break;
143 				}
144 			}
145 		}
146 	}
147 	g_mainDialog->UpdateStatsLists();
148 }
149 
RemoveFromAdditionalGlobalStats(CString source,CString name)150 void RemoveFromAdditionalGlobalStats(CString source, CString name) {
151 	int foundit = 0;
152 	for (int i=0;i<gAdditionalGlobalStats.numStats;i++) {
153 		if ((gAdditionalGlobalStats.stats[i].source == source) && (gAdditionalGlobalStats.stats[i].name == name)) {
154 			for (int j=i+1;j < gAdditionalGlobalStats.numStats;j++) {
155 				gAdditionalGlobalStats.stats[j-1].name = gAdditionalGlobalStats.stats[j].name;
156 				gAdditionalGlobalStats.stats[j-1].value = gAdditionalGlobalStats.stats[j].value;
157 				gAdditionalGlobalStats.stats[j-1].source = gAdditionalGlobalStats.stats[j].source;
158 			}
159 			gAdditionalGlobalStats.numStats--;
160 			break;
161 		}
162 	}
163 	g_mainDialog->UpdateStatsLists();
164 }
165 /////////////////////////////////////////////////////////////////////////////
166 // CAboutDlg dialog used for App About
167 
168 class CAboutDlg : public CDialog
169 {
170 public:
171 	CAboutDlg();
172 
173 // Dialog Data
174 	//{{AFX_DATA(CAboutDlg)
175 	enum { IDD = IDD_ABOUTBOX };
176 	//}}AFX_DATA
177 
178 	// ClassWizard generated virtual function overrides
179 	//{{AFX_VIRTUAL(CAboutDlg)
180 	protected:
181 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
182 	//}}AFX_VIRTUAL
183 
184 // Implementation
185 protected:
186 	//{{AFX_MSG(CAboutDlg)
187 	//}}AFX_MSG
188 	DECLARE_MESSAGE_MAP()
189 };
190 
CAboutDlg()191 CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
192 {
193 	//{{AFX_DATA_INIT(CAboutDlg)
194 	//}}AFX_DATA_INIT
195 }
196 
DoDataExchange(CDataExchange * pDX)197 void CAboutDlg::DoDataExchange(CDataExchange* pDX)
198 {
199 	CDialog::DoDataExchange(pDX);
200 	//{{AFX_DATA_MAP(CAboutDlg)
201 	//}}AFX_DATA_MAP
202 }
203 
BEGIN_MESSAGE_MAP(CAboutDlg,CDialog)204 BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
205 	//{{AFX_MSG_MAP(CAboutDlg)
206 		// No message handlers
207 	//}}AFX_MSG_MAP
208 END_MESSAGE_MAP()
209 
210 
211 /////////////////////////////////////////////////////////////////////////////
212 // CIcecast2winDlg dialog
213 
214 CIcecast2winDlg::CIcecast2winDlg(CWnd* pParent /*=NULL*/)
215 	: CDialog(CIcecast2winDlg::IDD, pParent)
216 {
217 	//{{AFX_DATA_INIT(CIcecast2winDlg)
218 	m_AccessEdit = _T("");
219 	m_ErrorEdit = _T("");
220 	m_ConfigEdit = _T("");
221 	m_ServerStatus = _T("");
222 	m_SourcesConnected = _T("");
223 	m_NumClients = _T("");
224 	m_StatsEdit = _T("");
225 	m_Autostart = FALSE;
226 	//}}AFX_DATA_INIT
227 	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
228 	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
229 	m_pTray = NULL;
230 }
231 
DoDataExchange(CDataExchange * pDX)232 void CIcecast2winDlg::DoDataExchange(CDataExchange* pDX)
233 {
234 	CDialog::DoDataExchange(pDX);
235 	//{{AFX_DATA_MAP(CIcecast2winDlg)
236 	DDX_Control(pDX, IDC_STATIC_SS, m_SS);
237 	DDX_Control(pDX, IDC_SERVERSTATUS, m_ServerStatusBitmap);
238 	DDX_Control(pDX, IDC_START, m_StartButton);
239 	DDX_Control(pDX, IDC_MAINTAB, m_MainTab);
240 	DDX_Check(pDX, IDC_AUTOSTART, m_Autostart);
241 	//}}AFX_DATA_MAP
242 }
243 
BEGIN_MESSAGE_MAP(CIcecast2winDlg,CDialog)244 BEGIN_MESSAGE_MAP(CIcecast2winDlg, CDialog)
245 	//{{AFX_MSG_MAP(CIcecast2winDlg)
246 	ON_WM_SYSCOMMAND()
247 	ON_WM_PAINT()
248 	ON_WM_QUERYDRAGICON()
249 	ON_NOTIFY(TCN_SELCHANGE, IDC_MAINTAB, OnSelchangeMaintab)
250 	ON_COMMAND(ID_FILE_EXIT, OnFileExit)
251 	ON_WM_TIMER()
252 	ON_COMMAND(ID_FILE_STARTSERVER, OnFileStartserver)
253 	ON_COMMAND(ID_FILE_STOPSERVER, OnFileStopserver)
254 	ON_BN_CLICKED(IDC_START, OnStart)
255 	ON_WM_CLOSE()
256 	ON_WM_SIZE()
257 	ON_BN_CLICKED(IDC_HIDESYSTRAY, OnHidesystray)
258 	ON_COMMAND(ID_BLANK_RESTORE, OnBlankRestore)
259 	ON_MESSAGE(WM_TRAY_NOTIFY, OnTrayNotify)
260 	ON_WM_DESTROY()
261 	ON_COMMAND(ID_FILE_EDITCONFIGURATION, OnFileEditconfiguration)
262 	ON_COMMAND(ID_ABOUT_HELP, OnAboutHelp)
263 	ON_COMMAND(ID_ABOUT_CREDITS, OnAboutCredits)
264 	//}}AFX_MSG_MAP
265 END_MESSAGE_MAP()
266 
267 /////////////////////////////////////////////////////////////////////////////
268 // CIcecast2winDlg message handlers
269 
270 #include "colors.h"
271 
272 
273 BOOL CIcecast2winDlg::OnInitDialog()
274 {
275 	CDialog::OnInitDialog();
276 
277 	// Add "About..." menu item to system menu.
278 
279 	// IDM_ABOUTBOX must be in the system command range.
280 	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
281 	ASSERT(IDM_ABOUTBOX < 0xF000);
282 
283 	CMenu* pSysMenu = GetSystemMenu(FALSE);
284 	if (pSysMenu != NULL)
285 	{
286 		CString strAboutMenu;
287 		strAboutMenu.LoadString(IDS_ABOUTBOX);
288 		if (!strAboutMenu.IsEmpty())
289 		{
290 			pSysMenu->AppendMenu(MF_SEPARATOR);
291 			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
292 		}
293 	}
294 
295 	g_mainDialog = this;
296 
297 	// Set the icon for this dialog.  The framework does this automatically
298 	//  when the application's main window is not a dialog
299 	SetIcon(m_hIcon, TRUE);			// Set big icon
300 	SetIcon(m_hIcon, FALSE);		// Set small icon
301 
302 	// TODO: Add extra initialization here
303 	config_read();
304 
305 	statsTab.m_colSource0Width = m_colSource0Width;
306 	statsTab.m_colStats0Width = m_colStats0Width;
307 	statsTab.m_colStats1Width = m_colStats1Width;
308 	statusTab.m_colStats0Width = m_colGStats0Width;
309 	statusTab.m_colStats1Width = m_colGStats1Width;
310 	statusTab.m_colStats2Width = m_colGStats2Width;
311 
312 	statsTab.Create(IDD_STATSDIALOG, this);
313 	statusTab.Create(IDD_SSTATUS, this);
314 
315 	int nPageID = 0;
316 	m_MainTab.AddSSLPage (_T("Server Status"), nPageID, (CTabPageSSL *)&statusTab);
317 	nPageID++;
318 	m_MainTab.AddSSLPage (_T("Source Level Stats"), nPageID, (CTabPageSSL *)&statsTab);
319 	nPageID++;
320 
321 
322 	labelFont.CreateFont(24,0, 0, 0, FW_BOLD, 0, 0, 0, 0, OUT_TT_PRECIS, 0, PROOF_QUALITY, 0, "Arial");
323 
324 	runningBitmap.LoadBitmap(IDB_BITMAP6);
325 	stoppedBitmap.LoadBitmap(IDB_BITMAP5);
326 
327 	UpdateData(FALSE);
328 
329 	LoadConfig();
330 
331 //	AddAnchor(IDC_MAINTAB, TOP_LEFT, BOTTOM_RIGHT);
332 //	AddAnchor(IDC_STATICBLACK, TOP_LEFT, TOP_RIGHT);
333 
334 //	EnableSaveRestore("icecast2win", "positions");
335 
336 	m_pTray = NULL;
337 
338 	char	version[255] = "";
339 	sprintf(version, "Icecast2 Version %s", ICECAST_VERSION);
340 	SetWindowText(version);
341 
342 	if (m_Autostart) {
343 		OnStart();
344 	}
345 	return TRUE;  // return TRUE  unless you set the focus to a control
346 }
347 
OnSysCommand(UINT nID,LPARAM lParam)348 void CIcecast2winDlg::OnSysCommand(UINT nID, LPARAM lParam)
349 {
350 	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
351 	{
352 		CAboutDlg dlgAbout;
353 		dlgAbout.DoModal();
354 	}
355 	else
356 	{
357 		CDialog::OnSysCommand(nID, lParam);
358 	}
359 }
360 
361 // If you add a minimize button to your dialog, you will need the code below
362 //  to draw the icon.  For MFC applications using the document/view model,
363 //  this is automatically done for you by the framework.
364 
OnPaint()365 void CIcecast2winDlg::OnPaint()
366 {
367 	if (IsIconic())
368 	{
369 		CPaintDC dc(this); // device context for painting
370 
371 		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
372 
373 		// Center icon in client rectangle
374 		int cxIcon = GetSystemMetrics(SM_CXICON);
375 		int cyIcon = GetSystemMetrics(SM_CYICON);
376 		CRect rect;
377 		GetClientRect(&rect);
378 		int x = (rect.Width() - cxIcon + 1) / 2;
379 		int y = (rect.Height() - cyIcon + 1) / 2;
380 
381 		// Draw the icon
382 		dc.DrawIcon(x, y, m_hIcon);
383 	}
384 	else
385 	{
386 		CDialog::OnPaint();
387 	}
388 }
389 
390 
391 // The system calls this to obtain the cursor to display while the user drags
392 //  the minimized window.
OnQueryDragIcon()393 HCURSOR CIcecast2winDlg::OnQueryDragIcon()
394 {
395 	return (HCURSOR) m_hIcon;
396 }
397 
OnSelchangeMaintab(NMHDR * pNMHDR,LRESULT * pResult)398 void CIcecast2winDlg::OnSelchangeMaintab(NMHDR* pNMHDR, LRESULT* pResult)
399 {
400 	// TODO: Add your control notification handler code here
401 
402 	*pResult = 0;
403 }
404 
LoadConfig()405 void CIcecast2winDlg::LoadConfig()
406 {
407 	FILE	*filep;
408 	char	buffer[2046] = "";
409 	CIcecast2winApp	*myApp = (CIcecast2winApp *)AfxGetApp();
410 
411 	configTab.m_Config = "";
412 	filep = fopen(myApp->m_configFile, "r");
413 	if (filep) {
414 		fclose(filep);
415 	}
416 	else {
417 		MessageBox("Unable to load config file (" + CString(myApp->m_configFile) + ") unable to start", NULL, MB_OK);
418 	}
419 
420 }
421 
422 
OnFileExit()423 void CIcecast2winDlg::OnFileExit()
424 {
425 	// TODO: Add your command handler code here
426 	DestroyWindow();
427 }
428 
429 
430 
getTag(char * pbuf,char * ptag,char * dest)431 void CIcecast2winDlg::getTag(char *pbuf, char *ptag, char *dest)
432 {
433 	char	openTag[256] = "";
434 	char	closeTag[256] = "";
435 
436 	sprintf(openTag, "<%s>", ptag);
437 	sprintf(closeTag, "</%s>", ptag);
438 
439 	char *p1;
440 	p1 = strstr(pbuf, openTag);
441 	if (p1) {
442 		p1 = p1 + strlen(openTag);
443 		char *p2;
444 		p2 = strstr(p1, closeTag);
445 		if (p2) {
446 			strncpy(dest, p1, p2-p1);
447 		}
448 	}
449 }
450 
451 
EnableControl(UINT control)452 void CIcecast2winDlg::EnableControl(UINT control)
453 {
454 	CWnd	*pWnd;
455 	pWnd = GetDlgItem(control);
456 	::ShowWindow(pWnd->GetSafeHwnd(), SW_SHOW);
457 }
458 
DisableControl(UINT control)459 void CIcecast2winDlg::DisableControl(UINT control)
460 {
461 	CWnd	*pWnd;
462 	pWnd = GetDlgItem(control);
463 	::ShowWindow(pWnd->GetSafeHwnd(), SW_HIDE);
464 }
465 
466 
AddUpdateStatistic(int sourceIndex,char * name,char * value)467 void AddUpdateStatistic(int sourceIndex, char *name, char *value)
468 {
469 	for (int j=0;j<gStats[sourceIndex].numStats;j++) {
470 		if (gStats[sourceIndex].stats[j].name == name) {
471 			gStats[sourceIndex].stats[j].value = value;
472 			return;
473 		}
474 	}
475 	int numStats = gStats[sourceIndex].numStats;
476 	if (numStats >= MAXSTATSPERSOURCE)
477 		return;
478 	/* If we get here, we haven't found the stat, so add it */
479 	gStats[sourceIndex].stats[numStats].name = name;
480 	gStats[sourceIndex].stats[numStats].value = value;
481 	gStats[sourceIndex].numStats++;
482 
483 }
GetSourceIndex(char * sourceName)484 int GetSourceIndex(char *sourceName)
485 {
486 	if (sourceName == NULL) {
487 		return 0;
488 	}
489 	for (int i=1;i<numMainStats+1;i++) {
490 		if (!strcmp(gStats[i].source, sourceName)) {
491 			return i;
492 		}
493 	}
494 	if (numMainStats >= MAXSOURCES)
495 		return 0;
496 	/* This means we haven't seen the source, so lets add it */
497 	numMainStats++;
498 	gStats[numMainStats].source = sourceName;
499 	gStats[numMainStats].populated = 1;
500 	gStats[numMainStats].numStats = 0;
501 	return numMainStats;
502 
503 }
UpdateSourceData(xmlDocPtr doc,xmlNodePtr cur,char * sourceName)504 void UpdateSourceData(xmlDocPtr doc, xmlNodePtr cur, char *sourceName) {
505 	xmlNodePtr children;
506 	char	*ls_xmlContentPtr = NULL;
507 	int sourceIndex = GetSourceIndex(sourceName);
508 	int listenerInd = 0;
509 
510 	children = cur->xmlChildrenNode;
511 	while (children != NULL) {
512 		if (!strcmp((char *)children->name, "listeners")) {
513 			listenerInd = 1;
514 		}
515 		ls_xmlContentPtr = (char *)xmlNodeListGetString(doc, children->xmlChildrenNode, 1);
516 		AddUpdateStatistic(sourceIndex, (char *)children->name, ls_xmlContentPtr);
517 		xmlFree(ls_xmlContentPtr);
518 		children = children->next;
519 	}
520 	if (!listenerInd) {
521 		/* If no listeners, then the source has been disconnected */
522 		gStats[sourceIndex].populated = 0;
523 		gStats[sourceIndex].numStats = 0;
524 		g_mainDialog->statsTab.m_SourceListCtrl.DeleteAllItems();
525 		g_mainDialog->statsTab.m_StatsListCtrl.DeleteAllItems();
526 	}
527 }
528 
529 bool g_collectingStats = false;
530 
StartStats(void * dummy)531 void StartStats(void *dummy)
532 {
533 	while (global.running != ICE_RUNNING) {
534 		Sleep(500);
535 	}
536 	while (global.running == ICE_RUNNING) {
537 		if (global.running == ICE_RUNNING) {
538 			for (int j=0;j<MAXSOURCES;j++) {
539 				gStats[j].numStats = 0;
540 			}
541 			numMainStats = 0;
542 
543 			xmlDocPtr doc;
544 
545 			doc = stats_get_xml(STATS_PUBLIC, NULL);
546 			xmlNodePtr cur;
547 		    cur = xmlDocGetRootElement(doc);
548 
549 		    if (cur == NULL) {
550 				MessageBox(NULL, "empty XML document", "Error", MB_OK);
551 				xmlFreeDoc(doc);
552 				break;
553 			}
554 
555 			cur = cur->xmlChildrenNode;
556 			char* ls_xmlContentPtr2 = NULL;
557 
558 		    while (cur != NULL) {
559 				if ((!xmlStrcmp(cur->name, (const xmlChar *)"source"))) {
560 					ls_xmlContentPtr2 = (char *)xmlGetProp(cur, (unsigned char *)"mount");
561 					UpdateSourceData(doc, cur, ls_xmlContentPtr2);
562 				}
563 				else {
564 					/* A Global stat */
565 					ls_xmlContentPtr2 = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
566 					AddUpdateStatistic(0, (char *)cur->name, ls_xmlContentPtr2);
567 				}
568 				if (ls_xmlContentPtr2) {
569 					xmlFree(ls_xmlContentPtr2);
570 				}
571 
572 				cur = cur->next;
573 			}
574 			xmlFreeDoc(doc);
575 			g_mainDialog->UpdateStatsLists();
576 			Sleep(5000);
577 		}
578 		if (global.running != ICE_RUNNING) {
579 			numMainStats = 0;
580 			g_mainDialog->statusTab.m_GlobalStatList.DeleteAllItems();
581 			g_mainDialog->statsTab.m_SourceListCtrl.DeleteAllItems();
582 			g_mainDialog->statsTab.m_StatsListCtrl.DeleteAllItems();
583 			_endthread();
584 		}
585 	}
586 	_endthread();
587 }
OnTimer(UINT nIDEvent)588 void CIcecast2winDlg::OnTimer(UINT nIDEvent)
589 {
590 	// TODO: Add your message handler code here and/or call default
591 	if (nIDEvent == 0) {
592 		if (global.running == ICE_RUNNING) {
593 			char	buffer[255] = "";
594 			CString	tmp;
595 			// Get info from stats...
596 			m_ServerStatusBitmap.SetBitmap(HBITMAP(runningBitmap));
597 			sprintf(buffer, "%d", global.sources);
598 			tmp = buffer;
599 			if (tmp != statusTab.m_Sources) {
600 				statusTab.m_Sources = tmp;
601 				statusTab.UpdateData(FALSE);
602 			}
603 			sprintf(buffer, "%d", global.clients);
604 			tmp = buffer;
605 			if (tmp != statusTab.m_Clients) {
606 				statusTab.m_Clients = tmp;
607 				statusTab.UpdateData(FALSE);
608 			}
609 
610 			m_StartButton.GetWindowText(tmp);
611 
612 			if (tmp == "Start Server") {
613 				m_StartButton.SetWindowText("Stop Server");
614 				m_StartButton.SetState(0);
615 			}
616 			time_t	currentTime;
617 			time(&currentTime);
618 			time_t  runningTime = currentTime - serverStart;
619 
620 			CTimeSpan runningFor(runningTime);
621 
622 			char	timespan[1024] = "";
623 			sprintf(timespan, "%d Days, %d Hours, %d Minutes, %d Seconds", runningFor.GetDays(), runningFor.GetHours(), runningFor.GetMinutes(), runningFor.GetSeconds());
624 			statusTab.m_RunningFor = timespan;
625 			statusTab.UpdateData(FALSE);
626 
627 			SetTimer(0, 500, NULL);
628 		}
629 		else {
630 			statusTab.m_Sources = "0";
631 			statusTab.m_Clients = "0";
632 			m_ServerStatusBitmap.SetBitmap(HBITMAP(stoppedBitmap));
633 			m_StartButton.SetWindowText("Start Server");
634 			m_StartButton.SetState(0);
635 			UpdateData(FALSE);
636 			statusTab.m_RunningFor = "Not running";
637 			statusTab.UpdateData(FALSE);
638 		}
639 	}
640 
641 	CDialog::OnTimer(nIDEvent);
642 }
643 
644 char	g_configFile[1024] = "";
645 char	g_progName[255] = "icecast2";
646 
StartServer(void * configfile)647 void StartServer(void *configfile)
648 {
649 	int		argc = 3;
650 	char*	argv[3];
651 
652 	strcpy(g_configFile, (char *)configfile);
653 
654 	argv[0] = g_progName;
655 	argv[1] = "-c";
656 	argv[2] = g_configFile;
657 	time(&(g_mainDialog->serverStart));
658 
659 	int ret = main(argc, (char **)argv);
660 	if (ret) {
661 		MessageBox(NULL, "Unable to start server", NULL, MB_OK);
662 	}
663 	global.running = ICE_HALTING;
664 	_endthread();
665 
666 
667 }
OnFileStartserver()668 void CIcecast2winDlg::OnFileStartserver()
669 {
670 	// TODO: Add your command handler code here
671 	CIcecast2winApp	*myApp = (CIcecast2winApp *)AfxGetApp();
672 
673 	if (gConfigurationSave == "") {
674 		gConfigurationSave = m_ConfigEdit;
675 	}
676 
677 	if (global.running == ICE_RUNNING) {
678 		MessageBox("Server already running", "Error", MB_OK);
679 	}
680 	else {
681 		m_ConfigEditCtrl.SetReadOnly(TRUE);
682 		LoadConfig();
683 		SetTimer(0, 500, NULL);
684 		_beginthread(StartServer, 0, (void *)(LPCSTR)myApp->m_configFile);
685 		_beginthread(StartStats, 0, (void *)NULL);
686 	}
687 }
688 
OnFileStopserver()689 void CIcecast2winDlg::OnFileStopserver()
690 {
691 	// TODO: Add your command handler code here
692 	;
693 }
694 
695 bool infocus = false;
696 
StopServer()697 void CIcecast2winDlg::StopServer()
698 {
699 	KillTimer(0);
700 	global.running = ICE_HALTING;
701 	m_StartButton.SetWindowText("Start Server");
702 	m_StartButton.SetState(0);
703 	m_ServerStatusBitmap.SetBitmap(HBITMAP(stoppedBitmap));
704 	statusTab.m_RunningFor = "Not running";
705 	statusTab.UpdateData(FALSE);
706 
707 
708 
709 }
710 
711 
OnStart()712 void CIcecast2winDlg::OnStart()
713 {
714 	CIcecast2winApp	*myApp = (CIcecast2winApp *)AfxGetApp();
715 
716 	// TODO: Add your control notification handler code here
717 
718 	if (global.running == ICE_RUNNING) {
719 		StopServer();
720 	}
721 	else {
722 		SetTimer(0, 500, NULL);
723 		_beginthread(StartServer, 0, (void *)(LPCSTR)myApp->m_configFile);
724 		_beginthread(StartStats, 0, (void *)NULL);
725 	}
726 
727 }
728 
UpdateStatsLists()729 void CIcecast2winDlg::UpdateStatsLists()
730 {
731 	char	item[1024] = "";
732 	int l = 0;
733 
734 	// Global Stats are index of 0
735 	for (int k=0;k < gStats[0].numStats;k++) {
736 		int inthere = 0;
737 		for (l=0;l < statusTab.m_GlobalStatList.GetItemCount();l++) {
738 
739 			statusTab.m_GlobalStatList.GetItemText(l, 1, item, sizeof(item));
740 			if (!strcmp(gStats[0].stats[k].name, item)) {
741 				inthere = 1;
742 				break;
743 			}
744 		}
745 		if (!inthere) {
746 			LVITEM	lvi;
747 
748 			lvi.mask =  LVIF_IMAGE | LVIF_TEXT;
749 			lvi.iItem = statsTab.m_SourceListCtrl.GetItemCount();
750 			lvi.iSubItem = 0;
751 			//lvi.pszText = (LPTSTR)(LPCTSTR)gStats[0].source;
752 			lvi.pszText = "Global Stat";
753 			statusTab.m_GlobalStatList.InsertItem(&lvi);
754 			lvi.iSubItem = 1;
755 			lvi.pszText = (LPTSTR)(LPCTSTR)gStats[0].stats[k].name;
756 			statusTab.m_GlobalStatList.SetItem(&lvi);
757 			lvi.iSubItem = 2;
758 			lvi.pszText = (LPTSTR)(LPCTSTR)gStats[0].stats[k].value;
759 			statusTab.m_GlobalStatList.SetItem(&lvi);
760 			if ((!strcmp(gTitleSource, gStats[0].source)) &&
761 				(!strcmp(gTitleName, gStats[0].stats[k].name))) {
762 				gStats[0].stats[k].titleFlag = 1;
763 			}
764 
765 		}
766 		else {
767 			LVITEM	lvi;
768 
769 			lvi.mask =  LVIF_IMAGE | LVIF_TEXT;
770 			lvi.iItem = l;
771 			lvi.iSubItem = 2;
772 			lvi.pszText = (LPTSTR)(LPCTSTR)gStats[0].stats[k].value;
773 			statusTab.m_GlobalStatList.SetItem(&lvi);
774 		}
775 		if (gStats[0].stats[k].titleFlag) {
776 			CString	windowTitle = CString("Global Stat") + " - " + gStats[0].stats[k].name + " - " + gStats[0].stats[k].value;
777 			SetWindowText(windowTitle);
778 			if (m_pTray) {
779 				m_pTray->SetTIP((LPSTR)(LPCSTR)windowTitle);
780 			}
781 		}
782 	}
783 
784 	for (int i=1;i<numMainStats+1;i++) {
785 		int inthere = 0;
786 		int k = 0;
787 		if (gStats[i].populated) {
788 			for (l=0;l < gAdditionalGlobalStats.numStats;l++) {
789 				for (int m=0;m < gStats[i].numStats;m++) {
790 					if ((gAdditionalGlobalStats.stats[l].source == gStats[i].source) &&
791 						(gAdditionalGlobalStats.stats[l].name == gStats[i].stats[m].name)) {
792 						gAdditionalGlobalStats.stats[l].value = gStats[i].stats[m].value;
793 						break;
794 					}
795 				}
796 			}
797 			if (strcmp(gStats[i].source, "Global Stat")) {
798 				// If Not Global STat
799 				for (k=0;k < statsTab.m_SourceListCtrl.GetItemCount();k++) {
800 
801 					statsTab.m_SourceListCtrl.GetItemText(k, 0, item, sizeof(item));
802 					if (!strcmp(gStats[i].source, item)) {
803 						inthere = 1;
804 						break;
805 					}
806 				}
807 				if (!inthere) {
808 					if (gStats[i].source != "") {
809 						LVITEM	lvi;
810 
811 						lvi.mask =  LVIF_IMAGE | LVIF_TEXT;
812 						lvi.iItem = statsTab.m_SourceListCtrl.GetItemCount();
813 						lvi.iSubItem = 0;
814 						lvi.pszText = (LPTSTR)(LPCTSTR)gStats[i].source;
815 						statsTab.m_SourceListCtrl.InsertItem(&lvi);
816 					}
817 				}
818 				int nItemSelected = statsTab.m_SourceListCtrl.GetSelectionMark();
819 				if (nItemSelected != -1) {
820 					memset(item, '\000', sizeof(item));
821 					statsTab.m_SourceListCtrl.GetItemText(nItemSelected, 0, item, sizeof(item));
822 					if (!strcmp(gStats[i].source, item)) {
823 						for (int l=0;l<gStats[i].numStats;l++) {
824 							int inthere2 = 0;
825 							char	item2[1024] = "";
826 							for (int m=0;m < statsTab.m_StatsListCtrl.GetItemCount();m++) {
827 								statsTab.m_StatsListCtrl.GetItemText(m, 0, item2, sizeof(item2));
828 								if (!strcmp(gStats[i].stats[l].name, item2)) {
829 									LVITEM	lvi;
830 
831 									lvi.mask =  LVIF_TEXT;
832 									lvi.iItem = m;
833 									lvi.iSubItem = 1;
834 									lvi.pszText = (LPTSTR)(LPCTSTR)gStats[i].stats[l].value;
835 									statsTab.m_StatsListCtrl.SetItem(&lvi);
836 									inthere2 = 1;
837 									break;
838 								}
839 							}
840 							if (!inthere2) {
841 								LVITEM	lvi;
842 
843 								lvi.mask =  LVIF_TEXT;
844 								lvi.iItem = statsTab.m_StatsListCtrl.GetItemCount();
845 								lvi.iSubItem = 0;
846 								lvi.pszText = (LPTSTR)(LPCTSTR)gStats[i].stats[l].name;
847 								statsTab.m_StatsListCtrl.InsertItem(&lvi);
848 								lvi.iSubItem = 1;
849 								lvi.pszText = (LPTSTR)(LPCTSTR)gStats[i].stats[l].value;
850 								statsTab.m_StatsListCtrl.SetItem(&lvi);
851 							}
852 						}
853 					}
854 				}
855 				for (l=0;l < gAdditionalGlobalStats.numStats;l++) {
856 					int inthere2 = 0;
857 					char	item2[1024] = "";
858 					char	item3[1024] = "";
859 					CString	itemSource;
860 					CString itemName;
861 					for (int m=0;m < statusTab.m_GlobalStatList.GetItemCount();m++) {
862 						statusTab.m_GlobalStatList.GetItemText(m, 0, item2, sizeof(item2));
863 						statusTab.m_GlobalStatList.GetItemText(m, 1, item3, sizeof(item3));
864 						itemSource = item2;
865 						itemName = item3;
866 						if ((gAdditionalGlobalStats.stats[l].source == itemSource) &&
867 							(gAdditionalGlobalStats.stats[l].name == itemName)) {
868 							LVITEM	lvi;
869 
870 							lvi.mask =  LVIF_TEXT;
871 							lvi.iItem = m;
872 							lvi.iSubItem = 2;
873 							lvi.pszText = (LPTSTR)(LPCTSTR)gAdditionalGlobalStats.stats[l].value;
874 							statusTab.m_GlobalStatList.SetItem(&lvi);
875 							inthere2 = 1;
876 							break;
877 						}
878 					}
879 					if (!inthere2) {
880 						LVITEM	lvi;
881 
882 
883 						lvi.mask =  LVIF_TEXT;
884 						lvi.iItem = statusTab.m_GlobalStatList.GetItemCount();
885 						lvi.iSubItem = 0;
886 						lvi.pszText = (LPTSTR)(LPCTSTR)gAdditionalGlobalStats.stats[l].source;
887 						statusTab.m_GlobalStatList.InsertItem(&lvi);
888 						lvi.iSubItem = 1;
889 						lvi.pszText = (LPTSTR)(LPCTSTR)gAdditionalGlobalStats.stats[l].name;
890 						statusTab.m_GlobalStatList.SetItem(&lvi);
891 						lvi.iSubItem = 2;
892 						lvi.pszText = (LPTSTR)(LPCTSTR)gAdditionalGlobalStats.stats[l].value;
893 						statusTab.m_GlobalStatList.SetItem(&lvi);
894 						if ((!strcmp(gTitleSource, gAdditionalGlobalStats.stats[l].source)) &&
895 							(!strcmp(gTitleName, gAdditionalGlobalStats.stats[l].name))) {
896 							gAdditionalGlobalStats.stats[l].titleFlag = 1;
897 						}
898 
899 
900 					}
901 
902 					if (gAdditionalGlobalStats.stats[l].titleFlag) {
903 						CString	windowTitle = gAdditionalGlobalStats.stats[l].source + " - " + gAdditionalGlobalStats.stats[l].name + " - " + gAdditionalGlobalStats.stats[l].value;
904 						SetWindowText(windowTitle);
905 						if (m_pTray) {
906 							m_pTray->SetTIP((LPSTR)(LPCSTR)windowTitle);
907 						}
908 					}
909 				}
910 			}
911 			else {
912 			}
913 		}
914 	}
915 }
916 
917 char	gAppName[255] = "icecast2";
918 char	gConfigFile[255] = "icecast2.ini";
919 
config_write()920 void CIcecast2winDlg::config_write()
921 {
922 	char	buf[255] = "";
923 	char	buf2[1024] = "";
924 
925 	UpdateData(TRUE);
926 
927 	m_colSource0Width = statsTab.m_SourceListCtrl.GetColumnWidth(0);
928 	m_colStats0Width = statsTab.m_StatsListCtrl.GetColumnWidth(0);
929 	m_colStats1Width = statsTab.m_StatsListCtrl.GetColumnWidth(1);
930 	m_colGStats0Width = statusTab.m_GlobalStatList.GetColumnWidth(0);
931 	m_colGStats1Width = statusTab.m_GlobalStatList.GetColumnWidth(1);
932 	m_colGStats2Width = statusTab.m_GlobalStatList.GetColumnWidth(2);
933 
934 
935 	sprintf(buf, "%d", m_colSource0Width);
936 	WritePrivateProfileString(gAppName, "col0SourceWidth", buf, gConfigFile);
937 	sprintf(buf, "%d", m_colStats0Width);
938 	WritePrivateProfileString(gAppName, "col0StatsWidth", buf, gConfigFile);
939 	sprintf(buf, "%d", m_colStats1Width);
940 	WritePrivateProfileString(gAppName, "col1StatsWidth", buf, gConfigFile);
941 	sprintf(buf, "%d", m_colGStats0Width);
942 	WritePrivateProfileString(gAppName, "col0GStatsWidth", buf, gConfigFile);
943 	sprintf(buf, "%d", m_colGStats1Width);
944 	WritePrivateProfileString(gAppName, "col1GStatsWidth", buf, gConfigFile);
945 	sprintf(buf, "%d", m_colGStats2Width);
946 	WritePrivateProfileString(gAppName, "col2GStatsWidth", buf, gConfigFile);
947 
948 	if (m_Autostart) {
949 		WritePrivateProfileString(gAppName, "AutoStart", "1", gConfigFile);
950 	}
951 	else {
952 		WritePrivateProfileString(gAppName, "AutoStart", "0", gConfigFile);
953 	}
954 
955 	sprintf(buf, "%d", gAdditionalGlobalStats.numStats);
956 	WritePrivateProfileString(gAppName, "numAdditionalStats", buf, gConfigFile);
957 
958 	for (int i=0;i<gAdditionalGlobalStats.numStats;i++) {
959 		memset(buf, '\000', sizeof(buf));
960 		sprintf(buf2, "AdditionalStatsSource%d", i);
961 		WritePrivateProfileString(gAppName, buf2, gAdditionalGlobalStats.stats[i].source, gConfigFile);
962 
963 		memset(buf, '\000', sizeof(buf));
964 		sprintf(buf2, "AdditionalStatsName%d", i);
965 		WritePrivateProfileString(gAppName, buf2, gAdditionalGlobalStats.stats[i].name, gConfigFile);
966 
967 		if (gAdditionalGlobalStats.stats[i].titleFlag) {
968 			sprintf(buf2, "%s|%s", gAdditionalGlobalStats.stats[i].source, gAdditionalGlobalStats.stats[i].name);
969 			WritePrivateProfileString(gAppName, "TitleName", buf2, gConfigFile);
970 		}
971 	}
972 	for (i=0;i<numMainStats;i++) {
973 		for (int k=0;k < gStats[i].numStats;k++) {
974 			if (gStats[i].stats[k].titleFlag) {
975 				sprintf(buf2, "%s|%s", gStats[i].source, gStats[i].stats[k].name);
976 				WritePrivateProfileString(gAppName, "TitleName", buf2, gConfigFile);
977 			}
978 		}
979 	}
980 
981 }
982 
config_read()983 void CIcecast2winDlg::config_read()
984 {
985 	char	buf2[1024] = "";
986 	char	buf[1024] = "";
987 	CString	tempString;
988 
989 	m_colSource0Width = GetPrivateProfileInt(gAppName, "col0SourceWidth", 163, gConfigFile);
990 	m_colStats0Width = GetPrivateProfileInt(gAppName, "col0StatsWidth", 100, gConfigFile);
991 	m_colStats1Width = GetPrivateProfileInt(gAppName, "col1StatsWidth", 150, gConfigFile);
992 	m_colGStats0Width = GetPrivateProfileInt(gAppName, "col0GStatsWidth", 150, gConfigFile);
993 	m_colGStats1Width = GetPrivateProfileInt(gAppName, "col1GStatsWidth", 150, gConfigFile);
994 	m_colGStats2Width = GetPrivateProfileInt(gAppName, "col2GStatsWidth", 150, gConfigFile);
995 
996 	GetPrivateProfileString(gAppName, "AutoStart", "0", buf, sizeof(buf), gConfigFile);
997 	if (!strcmp(buf, "1")) {
998 		m_Autostart = true;
999 	}
1000 	else{
1001 		m_Autostart = false;
1002 	}
1003 	int numAdditionalGlobalStats = GetPrivateProfileInt(gAppName, "numAdditionalStats", 0, gConfigFile);
1004 	for (int i=0;i<numAdditionalGlobalStats;i++) {
1005 		memset(buf, '\000', sizeof(buf));
1006 		sprintf(buf2, "AdditionalStatsSource%d", i);
1007 		GetPrivateProfileString(gAppName, buf2, "", buf, sizeof(buf), gConfigFile);
1008 		gAdditionalGlobalStats.stats[i].source = buf;
1009 
1010 		memset(buf, '\000', sizeof(buf));
1011 		sprintf(buf2, "AdditionalStatsName%d", i);
1012 		GetPrivateProfileString(gAppName, buf2, "", buf, sizeof(buf), gConfigFile);
1013 		gAdditionalGlobalStats.stats[i].name = buf;
1014 		gAdditionalGlobalStats.numStats++;
1015 	}
1016 	GetPrivateProfileString(gAppName, "TitleName", "", buf, sizeof(buf), gConfigFile);
1017 
1018 	if (strlen(buf) > 0) {
1019 		char *p1 = strchr(buf, '|');
1020 		if (p1) {
1021 			char tmpSource[1024] = "";
1022 			char tmpName[1024] = "";
1023 			memset(tmpSource, '\000', sizeof(tmpSource));
1024 			memset(tmpName, '\000', sizeof(tmpName));
1025 
1026 
1027 			strncpy(tmpSource, buf, p1-buf);
1028 			p1++;
1029 			strcpy(tmpName, p1);
1030 
1031 
1032 			strcpy(gTitleSource, tmpSource);
1033 			strcpy(gTitleName, tmpName);
1034 		}
1035 	}
1036 
1037 }
1038 
OnClose()1039 void CIcecast2winDlg::OnClose()
1040 {
1041 	// TODO: Add your message handler code here and/or call default
1042 	config_write();
1043 	CDialog::OnClose();
1044 }
1045 
OnSize(UINT nType,int cx,int cy)1046 void CIcecast2winDlg::OnSize(UINT nType, int cx, int cy)
1047 {
1048 	CDialog::OnSize(nType, cx, cy);
1049 
1050 	int border1 = 0;
1051 	int border2 = 78;
1052 	// TODO: Add your message handler code here
1053 	if (m_MainTab.m_hWnd) {
1054 		CRect rect;
1055 		GetClientRect (&rect);
1056 		int x = rect.Width()-border1;
1057 		int y = rect.Width()-border2;
1058 
1059 		statusTab.SetWindowPos(NULL, 4, 22, cx, cy, SWP_NOZORDER);
1060 		statsTab.SetWindowPos(NULL, 4, 22, cx, cy, SWP_NOZORDER);
1061 		statusTab.m_GlobalStatList.SetWindowPos(NULL, 14, 55, cx-40, cy-180, SWP_NOZORDER);
1062 		statsTab.m_StatsListCtrl.SetWindowPos(NULL, 213, 55, cx-243, cy-180, SWP_NOZORDER);
1063 		statsTab.m_SourceListCtrl.SetWindowPos(NULL, 14, 55, 166, cy-180, SWP_NOZORDER);
1064 //			CListCtrl	m_StatsListCtrl;
1065 //	CListCtrl	m_SourceListCtrl;
1066 		m_MainTab.SetWindowPos(NULL, 0, 80, cx, cy, SWP_NOZORDER);
1067 
1068 		//m_MainTab.ResizeDialog(0, rect.Width()-border1, rect.Height()-border2);
1069 		//m_MainTab.ResizeDialog(1, rect.Width()-border1, rect.Height()-border2);
1070 	}
1071 
1072 }
1073 
1074 
OnTrayNotify(WPARAM wParam,LPARAM lParam)1075 LONG CIcecast2winDlg::OnTrayNotify ( WPARAM wParam, LPARAM lParam )
1076 {
1077 	switch (lParam) {
1078 	case WM_RBUTTONDOWN:
1079 			{
1080 			CMenu menu ;
1081 			// Load and Verify Menu
1082 			VERIFY(menu.LoadMenu(IDR_TRAY));
1083 			CMenu* pPopup = menu.GetSubMenu (0) ;
1084 			ASSERT(pPopup != NULL);
1085 
1086 			// Get the cursor position
1087 			POINT pt ;
1088 			GetCursorPos (&pt) ;
1089 
1090 			// Fix Microsofts' BUG!!!!
1091 			SetForegroundWindow();
1092 
1093 			///////////////////////////////////
1094 			// Display The Menu
1095 			pPopup->TrackPopupMenu(TPM_LEFTALIGN |
1096 			TPM_RIGHTBUTTON,pt.x, pt.y, AfxGetMainWnd());
1097 			break ;
1098 			}
1099 	case WM_LBUTTONDBLCLK:
1100 	//////////////////////////////////
1101 	// Unhide our Window
1102 		if (m_bHidden) {
1103 			ShowWindow (SW_RESTORE);
1104 		}
1105 	//OnUnHide() ;
1106 		break ;
1107 	}
1108 
1109 	return (0) ;
1110 }
1111 
OnHidesystray()1112 void CIcecast2winDlg::OnHidesystray()
1113 {
1114 	// TODO: Add your control notification handler code here
1115 	OnHide();
1116 	theApp.HideApplication();
1117 }
OnHide()1118 void CIcecast2winDlg::OnHide()
1119 {
1120 	// TODO: Add your control notification handler code here
1121 	if (m_pTray == NULL) {
1122 		m_pTray = new CTrayNot (this,WM_TRAY_NOTIFY, NULL,theApp.m_pIconList);
1123 	}
1124 	m_pTray->SetState(0);
1125 	m_bHidden = TRUE;
1126 
1127 }
1128 
OnBlankRestore()1129 void CIcecast2winDlg::OnBlankRestore()
1130 {
1131 	// TODO: Add your command handler code here
1132 		if (m_bHidden) {
1133 			ShowWindow (SW_RESTORE);
1134 		}
1135 
1136 }
1137 
OnDestroy()1138 void CIcecast2winDlg::OnDestroy()
1139 {
1140 	CDialog::OnDestroy();
1141 
1142 	if (m_pTray) {
1143 		delete m_pTray ;
1144 		m_pTray = NULL ;
1145 	}
1146 	// TODO: Add your message handler code here
1147 
1148 }
1149 
OnFileEditconfiguration()1150 void CIcecast2winDlg::OnFileEditconfiguration()
1151 {
1152 	// TODO: Add your command handler code here
1153 
1154     STARTUPINFO si;
1155     PROCESS_INFORMATION pi;
1156 
1157     ZeroMemory( &si, sizeof(si) );
1158     si.cb = sizeof(si);
1159     ZeroMemory( &pi, sizeof(pi) );
1160 
1161 
1162 	int ok = 1;
1163 	if (global.running == ICE_RUNNING) {
1164 		MessageBox("I'm sorry, but you cannot edit the configuration file while the server is running", NULL, MB_OK);
1165 	}
1166 	else {
1167 		// Start the child process.
1168 		if( !CreateProcess( NULL, // No module name (use command line).
1169 			"notepad icecast.xml", // Command line.
1170 			NULL,             // Process handle not inheritable.
1171 			NULL,             // Thread handle not inheritable.
1172 			FALSE,            // Set handle inheritance to FALSE.
1173 			0,                // No creation flags.
1174 			NULL,             // Use parent's environment block.
1175 			NULL,             // Use parent's starting directory.
1176 			&si,              // Pointer to STARTUPINFO structure.
1177 			&pi )             // Pointer to PROCESS_INFORMATION structure.
1178 		)
1179 		{
1180 		   ok = 0;
1181 		}
1182 
1183 		// Wait until child process exits.
1184 		WaitForSingleObject( pi.hProcess, INFINITE );
1185 
1186 		// Close process and thread handles.
1187 		CloseHandle( pi.hProcess );
1188 		CloseHandle( pi.hThread );
1189 	}
1190 
1191 }
1192 
OnAboutHelp()1193 void CIcecast2winDlg::OnAboutHelp()
1194 {
1195 	// TODO: Add your command handler code here
1196 	ShellExecute(NULL, "open", "doc\\icecast2.chm", NULL, NULL, SW_SHOWNORMAL);
1197 }
1198 
OnAboutCredits()1199 void CIcecast2winDlg::OnAboutCredits()
1200 {
1201 	// TODO: Add your command handler code here
1202 	CAboutDlg	about;
1203 	about.DoModal();
1204 }
1205 
OnCancel()1206 void CIcecast2winDlg::OnCancel()
1207 {
1208 }
1209 
1210