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(¤tTime);
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