Files
ergosteur 22492dbee9 Implement XDG compliance, logging, and improved 401 error handling
- Install to ~/.local/bin/winamp-mpris
- Use ~/.local/state/winamp-mpris/bridge.log for logging
- Use $XDG_RUNTIME_DIR/winamp-mpris.pid for PID management
- Add detailed user notification for 401 Unauthorized errors
- Add install.sh for automated, standard-compliant setup
- Include Winamp Web Interface source code and installer in repository
2026-04-08 18:29:40 -04:00

454 lines
12 KiB
C++

#include <windows.h>
#include <prsht.h>
#include <mmsystem.h>
#include <commctrl.h>
#include "resource.h"
#include "main.h"
extern HINSTANCE inst;
extern HWND hwnd;
extern char host[255], username[20], password[20];
extern int port, default_action, update_delay;
extern UINT timer_id;
extern bool use_auth;
extern char szAppName[], AboutText[];
extern HWND ConfigWnd, VolumeWnd;
// --------------------------------------------------------------------------------
// Entry point for new Config window, using Property Sheets instead of a single dialog.
void NewConfig()
{
PROPSHEETPAGE psp[4];
PROPSHEETHEADER psh;
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[0].hInstance = inst;
psp[0].pszTemplate = MAKEINTRESOURCE(IDD_ABOUT);
psp[0].pszIcon = MAKEINTRESOURCE(IDI_WINAMP);
psp[0].pfnDlgProc = ConfigAboutWndProc;
psp[0].pszTitle = "About";
psp[0].lParam = 0;
psp[0].pfnCallback = NULL;
psp[1].dwSize = sizeof(PROPSHEETPAGE);
psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[1].hInstance = inst;
psp[1].pszTemplate = MAKEINTRESOURCE(IDD_SERVER);
psp[1].pszIcon = MAKEINTRESOURCE(IDI_SERVER);
psp[1].pfnDlgProc = ConfigServerWndProc;
psp[1].pszTitle = "Server";
psp[1].lParam = 0;
psp[1].pfnCallback = NULL;
psp[2].dwSize = sizeof(PROPSHEETPAGE);
psp[2].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[2].hInstance = inst;
psp[2].pszTemplate = MAKEINTRESOURCE(IDD_SYSTRAY);
psp[2].pszIcon = MAKEINTRESOURCE(GetIconID());
psp[2].pfnDlgProc = ConfigSystrayWndProc;
psp[2].pszTitle = "Tray Icon";
psp[2].lParam = 0;
psp[2].pfnCallback = NULL;
psp[3].dwSize = sizeof(PROPSHEETPAGE);
psp[3].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[3].hInstance = inst;
psp[3].pszTemplate = MAKEINTRESOURCE(IDD_AUTH);
psp[3].pszIcon = MAKEINTRESOURCE(IDI_AUTH2);
psp[3].pfnDlgProc = ConfigAuthWndProc;
psp[3].pszTitle = "Authentication";
psp[3].lParam = 0;
psp[3].pfnCallback = NULL;
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE;
psh.hwndParent = hwnd;
psh.hInstance = inst;
psh.pszIcon = NULL;
psh.pszCaption = "WawiTray Config";
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
psh.pfnCallback = NULL;
PropertySheet(&psh);
config_write();
ConfigWnd = NULL;
return;
}
// --------------------------------------------------------------------------------
// Server options window proc
BOOL CALLBACK ConfigServerWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
char TempString[10];
int port_temp;
switch(uMsg)
{
case WM_INITDIALOG:
wsprintf(TempString,"%d",port);
SetDlgItemText(hwndDlg,IDC_HOST,host);
SetDlgItemText(hwndDlg,IDC_PORT,TempString);
break;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_APPLY: port_temp = GetDlgItemInt(hwndDlg,IDC_PORT,NULL,false);
if (port_temp > 0 && port_temp < 65536)
{
port = port_temp;
GetDlgItemText(hwndDlg,IDC_HOST,host,255);
}
else
{
MessageBox(hwndDlg,"Port must be from 1 to 65535!","Winamp Web Interface",MB_OK);
SetDlgItemInt(hwndDlg,IDC_PORT,port,false);
SetWindowLong(hwndDlg,DWL_MSGRESULT,true);
return true;
}
break;
}
break;
}
return false;
}
// --------------------------------------------------------------------------------
// Systray options window proc
BOOL CALLBACK ConfigSystrayWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
char temp[5];
switch(uMsg)
{
case WM_INITDIALOG:
int def_button;
switch(default_action)
{
case WA_PREV:
def_button = IDC_DEF_PREV;
break;
case WA_PLAY:
def_button = IDC_DEF_PLAY;
break;
case WA_PAUSE:
def_button = IDC_DEF_PAUSE;
break;
case WA_STOP:
def_button = IDC_DEF_STOP;
break;
case WA_NEXT:
def_button = IDC_DEF_NEXT;
break;
}
CheckRadioButton(hwndDlg,IDC_DEF_PREV,IDC_DEF_NEXT,def_button);
wsprintf(temp,"%d",update_delay);
SetDlgItemText(hwndDlg,IDC_UPDATEDELAY,temp);
break;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_APPLY: update_delay = GetDlgItemInt(hwndDlg,IDC_UPDATEDELAY,NULL,false);
KillTimer(hwnd,timer_id);
timer_id = SetTimer(hwnd,TIMER_ID,update_delay*1000,NULL);
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED)
default_action = WA_PREV;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED)
default_action = WA_PREV;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PLAY) == BST_CHECKED)
default_action = WA_PLAY;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PAUSE) == BST_CHECKED)
default_action = WA_PAUSE;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_STOP) == BST_CHECKED)
default_action = WA_STOP;
else
default_action = WA_NEXT;
systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),szAppName);
break;
}
break;
}
return false;
}
// --------------------------------------------------------------------------------
// Authentication options window proc
BOOL CALLBACK ConfigAuthWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
int use_auth_int;
switch(uMsg)
{
case WM_INITDIALOG:
SetDlgItemText(hwndDlg,IDC_USERNAME,username);
SetDlgItemText(hwndDlg,IDC_PASSWORD,password);
if (use_auth)
CheckDlgButton(hwndDlg,IDC_AUTH,1);
else
CheckDlgButton(hwndDlg,IDC_AUTH,0);
break;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_APPLY: GetDlgItemText(hwndDlg,IDC_USERNAME,username,20);
GetDlgItemText(hwndDlg,IDC_PASSWORD,password,20);
use_auth_int = IsDlgButtonChecked(hwndDlg,IDC_AUTH);
if (use_auth_int == 0)
use_auth = false;
else
use_auth = true;
break;
}
break;
}
return false;
}
// --------------------------------------------------------------------------------
// About window proc
BOOL CALLBACK ConfigAboutWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
break;
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_APPLY: break;
}
break;
}
return false;
}
// --------------------------------------------------------------------------------
// WindowProc for Config dialog
BOOL CALLBACK ConfigWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
ConfigWnd = hwndDlg; // Keep global pointer to window so no more than one is active
char temp[100];
switch (uMsg)
{
case WM_INITDIALOG:
int def_button;
switch(default_action)
{
case WA_PREV:
def_button = IDC_DEF_PREV;
break;
case WA_PLAY:
def_button = IDC_DEF_PLAY;
break;
case WA_PAUSE:
def_button = IDC_DEF_PAUSE;
break;
case WA_STOP:
def_button = IDC_DEF_STOP;
break;
case WA_NEXT:
def_button = IDC_DEF_NEXT;
break;
}
SetDlgItemText(hwndDlg,IDC_HOST,host);
wsprintf(temp,"%d",port);
SetDlgItemText(hwndDlg,IDC_PORT,temp);
wsprintf(temp,"%d",update_delay);
SetDlgItemText(hwndDlg,IDC_UPDATEDELAY,temp);
SetDlgItemText(hwndDlg,IDC_USERNAME,username);
SetDlgItemText(hwndDlg,IDC_PASSWORD,password);
CheckRadioButton(hwndDlg,IDC_DEF_PREV,IDC_DEF_NEXT,def_button);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCANCEL: EndDialog(hwndDlg,0);
break;
case IDABOUT: MessageBox(hwnd,AboutText,szAppName,MB_OK | MB_ICONINFORMATION);
break;
case IDOK: GetDlgItemText(hwndDlg,IDC_HOST,host,255);
port = GetDlgItemInt(hwndDlg,IDC_PORT,NULL,false);
update_delay = GetDlgItemInt(hwndDlg,IDC_UPDATEDELAY,NULL,false);
KillTimer(hwnd,timer_id);
timer_id = SetTimer(hwnd,TIMER_ID,update_delay*1000,NULL);
GetDlgItemText(hwndDlg,IDC_USERNAME,username,20);
GetDlgItemText(hwndDlg,IDC_PASSWORD,password,20);
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED)
default_action = WA_PREV;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PREV) == BST_CHECKED)
default_action = WA_PREV;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PLAY) == BST_CHECKED)
default_action = WA_PLAY;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_PAUSE) == BST_CHECKED)
default_action = WA_PAUSE;
else
if (IsDlgButtonChecked(hwndDlg,IDC_DEF_STOP) == BST_CHECKED)
default_action = WA_STOP;
else
default_action = WA_NEXT;
systray_modify(hwnd,1030,LoadIcon(inst, MAKEINTRESOURCE(GetIconID())),szAppName);
config_write();
EndDialog(hwndDlg,0);
break;
}
}
return FALSE;
}
// --------------------------------------------------------------------------------
// write config
void config_write()
{
char ini_file[MAX_PATH], *p;
char string[32];
GetModuleFileName(inst,ini_file,sizeof(ini_file));
p=ini_file+lstrlen(ini_file);
while (p >= ini_file && *p != '\\') p--;
if (++p >= ini_file) *p = 0;
lstrcat(ini_file,"client.ini");
wsprintf(string,"%d",port);
WritePrivateProfileString(szAppName,"port",string,ini_file);
wsprintf(string,"%d",default_action);
WritePrivateProfileString(szAppName,"default",string,ini_file);
wsprintf(string,"%d",update_delay);
WritePrivateProfileString(szAppName,"updatedelay",string,ini_file);
if (use_auth)
WritePrivateProfileString(szAppName,"auth","1",ini_file);
else
WritePrivateProfileString(szAppName,"auth","0",ini_file);
WritePrivateProfileString(szAppName,"host",host,ini_file);
WritePrivateProfileString(szAppName,"username",username,ini_file);
WritePrivateProfileString(szAppName,"password",password,ini_file);
}
// --------------------------------------------------------------------------------
// read config (port and password)
void config_read()
{
char ini_file[MAX_PATH], *p;
GetModuleFileName(inst,ini_file,sizeof(ini_file));
p=ini_file+lstrlen(ini_file);
while (p >= ini_file && *p != '\\') p--;
if (++p >= ini_file) *p = 0;
lstrcat(ini_file,"client.ini");
GetPrivateProfileString(szAppName,"host","127.0.0.1",(char*)&host,255,ini_file);
GetPrivateProfileString(szAppName,"username","user",(char*)&username,20,ini_file);
GetPrivateProfileString(szAppName,"password","password",(char*)&password,20,ini_file);
port = GetPrivateProfileInt(szAppName,"port",80,ini_file);
default_action = GetPrivateProfileInt(szAppName,"default",WA_NEXT,ini_file);
update_delay = GetPrivateProfileInt(szAppName,"updatedelay",10,ini_file);
int use_auth_int = GetPrivateProfileInt(szAppName,"auth",0,ini_file);
if (use_auth_int == 1)
use_auth = true;
else
use_auth = false;
}
// --------------------------------------------------------------------------------
// WindowProc for Volume dialog
BOOL CALLBACK VolumeWndProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
char temp[50];
VolumeWnd = hwndDlg;
HWND SliderWnd;
POINT mousepos;
switch(uMsg)
{
case WM_INITDIALOG:
GetCursorPos(&mousepos);
SetWindowPos(hwndDlg,HWND_TOP,mousepos.x-46,mousepos.y-95,0,0,SWP_NOSIZE);
SliderWnd = GetDlgItem(hwndDlg,IDC_VOLUME);
SendMessage(SliderWnd, TBM_SETRANGE, (WPARAM) true, (LPARAM) MAKELONG(0,10));
break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDC_DONE:
EndDialog(hwndDlg,0);
break;
}
break;
case WM_VSCROLL:
DWORD dwPos;
switch(LOWORD(wParam))
{
case TB_THUMBTRACK:
case TB_LINEDOWN:
case TB_LINEUP:
case TB_PAGEDOWN:
case TB_PAGEUP:
SliderWnd = GetDlgItem(hwndDlg,IDC_VOLUME);
dwPos = SendMessage(SliderWnd, TBM_GETPOS, 0, 0);
wsprintf(temp,"/vol?volume=%d",10-dwPos);
//MessageBox(SliderWnd,temp,"Slider Position",MB_OK | MB_TOPMOST);
WASend(temp);
return 0;
break;
default:
break;
}
break;
}
return false;
}