Files
winamp-mpris/Wawi Source/main.cpp
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

300 lines
7.8 KiB
C++

/* --- MAIN.CPP ---
/
/ Written by Phil Himsworth, 2001-2002.
/
/*/
#include <windows.h>
#include <process.h>
#include <winver.h>
#include "types.h"
#include "plugin.h"
#include "resource.h"
#include "main.h"
char szAppName[] = "Winamp Web Interface";
char szAppVer[10]; // now filled in automagically on startup
char mp3root[MAX_PATH];
char playlistdir[MAX_PATH];
char filetypes[255]; // file types which will show in the browse bit.
char pagetitle[255];
char logfiledir[MAX_PATH];
extern char bchars[]; // lookup table for base64 needs to be built on startup
extern char achars[256];
// All winamp needs to know about the plugin
winampGeneralPurposePlugin plugin =
{
GPPHDR_VER,
"",
init,
config,
quit,
};
// Globals for actual server (rather than random winamp things)
LPDWORD client_thread;
SOCKET server_socket;
int con_port, hide_error, frames, title_refresh;
int show_other_files, dl_wa_files, dl_other_files;
extern HWND ConfigWnd;
// --------------------------------------------------------------------------------
// Entry point of DLL for windows; does nothing
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
// --------------------------------------------------------------------------------
// The interface which Winamp sees-
// It returns the plugin information struct
extern "C"
{
__declspec( dllexport ) winampGeneralPurposePlugin * winampGetGeneralPurposePlugin()
{
return &plugin;
}
}
// --------------------------------------------------------------------------------
// Startup. This is where interesting things start happening
int init()
{
HANDLE newthread;
DWORD newthread_id;
static char c[512];
char filename[512],*p;
GetModuleFileName(plugin.hDllInstance,filename,sizeof(filename));
// Retrieve version info
DWORD versize = GetFileVersionInfoSize(filename, NULL);
char * versiondata = new char[versize];
GetFileVersionInfo(filename, NULL, versize, versiondata);
VS_FIXEDFILEINFO * info;
UINT verlen;
VerQueryValue(versiondata,"\\",(void**)&info,&verlen);
int ver_l = (int)info->dwFileVersionLS;
int ver_h = (int)info->dwFileVersionMS;
int ver1, ver2, ver3, ver4; // version of form ver1,ver2,ver3,ver4
/*
ver1 = (ver_h & 0xFFFF0000) >> 16;
ver2 = (ver_h & 0x0000FFFF);
ver3 = (ver_l & 0xFFFF0000) >> 16;
ver4 = (ver_l & 0x0000FFFF);
*/
ver1 = HIWORD(ver_h);
ver2 = LOWORD(ver_h);
ver3 = HIWORD(ver_l);
ver4 = LOWORD(ver_l);
if (ver3 == 0)
wsprintf(szAppVer,"%u.%u", ver1, ver2);
else
wsprintf(szAppVer,"%u.%u.%u", ver1, ver2, ver3);
delete versiondata;
ZeroMemory(achars,256);
for(int i = 0; i < 64; i++) // build lookup table for FromBase64()
achars[bchars[i]] = i;
p = filename+lstrlen(filename);
while (p >= filename && *p != '\\') p--;
wsprintf((plugin.description=c),"%s Plugin v.%s (%s)",szAppName,szAppVer,p+1);
newthread = CreateThread(NULL,0,HTTPServerThread,0,0,&newthread_id);
return 0;
}
// --------------------------------------------------------------------------------
// Config dialog please
void config()
{
if (!ConfigWnd)
{
NewConfig();
ConfigWnd = NULL;
}
else
SetActiveWindow(ConfigWnd);
}
// --------------------------------------------------------------------------------
// Winamp is saying goodbye
void quit()
{
// Hmmm. Did there always used to be nothing in here? Curiouser and curiouser...
}
// --------------------------------------------------------------------------------
// Opens the server socket
bool InitServerSocket()
{
config_read();
WORD wVersionRequested = MAKEWORD(2,2);
WSADATA wsaData;
if (WSAStartup(wVersionRequested, &wsaData ) != 0 )
{
if (hide_error == 0)
MessageBox(plugin.hwndParent, "ERROR: Winsock not available", "Winamp Web Interface", MB_OK);
return false;
}
server_socket = socket(AF_INET,SOCK_STREAM,0);
if (server_socket == INVALID_SOCKET)
{
if (hide_error == 0)
MessageBox(plugin.hwndParent, "ERROR: Couldn't create socket", "Winamp Web Interface", MB_OK);
return false;
}
struct sockaddr_in server_address;
ZeroMemory(&server_address,sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_port = htons(con_port);
if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) != 0)
{
if (hide_error == 0)
MessageBox(plugin.hwndParent, "ERROR: Couldn't open port", "Winamp Web Interface", MB_OK);
return false;
}
if (listen(server_socket,5) != 0)
{
if (hide_error == 0)
MessageBox(plugin.hwndParent, "ERROR: Cannot act as server", "Winamp Web Interface", MB_OK);
return false;
}
return true; // Server socket opened successfully
}
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Server main thread entry point
DWORD WINAPI HTTPServerThread(LPVOID param)
{
// initialise winsock
if (InitServerSocket())
{
//printf("Server is listening for connections on port %d.\n",ntohs(server_address.sin_port));
struct sockaddr_in client_address;
SOCKET client_socket;
int client_address_length = sizeof(client_address);
while (true)
{
client_socket = accept(server_socket,(struct sockaddr *) &client_address, &client_address_length);
//printf("Connection request from %s:%d - ", (char*)inet_ntoa(client_address.sin_addr),ntohs(client_address.sin_port));
if (client_socket != INVALID_SOCKET)
{
DWORD connection_id;
client_thread = (DWORD*)CreateThread(NULL,0,ClientConnection,(void*)client_socket, 0, &connection_id);
}
}
closesocket(server_socket);
}
return true;
}
// --------------------------------------------------------------------------------
// *** WINAMP FUNCTIONS ***
// Returns handle to winamp window
HWND WAwnd()
{
return plugin.hwndParent;
}
// --------------------------------------------------------------------------------
// Insert a node into a list starting from 'current'
void Insert(fileinfo *newfile, fileinfo *current)
{
if (GoesBefore(newfile->name,current->name)) // newfile goes before current
{
//wsprintf(tempstring,"%s goes before %s and after %s",newfile->name,current->name, current->prev->name);
//MessageBox(NULL,tempstring,"gen_httpsrv debug goes before",MB_OK);
if (current->prev != NULL)
current->prev->next = newfile;
newfile->prev = current->prev;
newfile->next = current;
current->prev = newfile;
//wsprintf(tempstring,"Order is now %s, %s, %s",newfile->prev->name,newfile->name,newfile->next->name);
//MessageBox(NULL,tempstring,"gen_httpsrv debug goes before result",MB_OK);
}
else
{
if (current->next == NULL) // newfile is after current; current is the last node
{
//wsprintf(tempstring,"%s goes after %s and is the last record",newfile->name,current->name);
//MessageBox(NULL,tempstring,"gen_httpsrv debug after and last",MB_OK);
current->next = newfile;
newfile->prev = current;
}
else
{ // newfile is after current but before something else
Insert(newfile,current->next); // AAARGH! RECURSION! Like hell it'll work...
}
}
}
// --------------------------------------------------------------------------------
// Compare two strings, return TRUE if the first one should be before the second alphabetically
bool GoesBefore(char *file1, char *file2)
{
if (file1 == NULL || file2 == NULL)
return true;
int i=0;
while (ToLowerCase(file1[i]) == ToLowerCase(file2[i]))
{
if (file1[i] == 0)
return true;
i++;
}
if (ToLowerCase(file1[i]) > ToLowerCase(file2[i]))
return false;
else
return true;
}