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
This commit is contained in:
299
Wawi Source/main.cpp
Normal file
299
Wawi Source/main.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/* --- 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user