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:
340
gen_httpSrv_systray/connection.cpp
Normal file
340
gen_httpSrv_systray/connection.cpp
Normal file
@@ -0,0 +1,340 @@
|
||||
#include <windows.h>
|
||||
#include <winsock.h>
|
||||
|
||||
#include "resource.h"
|
||||
#include "main.h"
|
||||
|
||||
extern char szAppName[];
|
||||
extern char username[20], password[20], title[255];
|
||||
extern char host[255];
|
||||
extern int port;
|
||||
|
||||
extern bool use_auth;
|
||||
|
||||
extern HWND hwnd;
|
||||
|
||||
|
||||
// Base64 character array
|
||||
// 0 1 2 3 4 5 6
|
||||
// 01234567890123456789012345678901234567890123456789012345678901234
|
||||
const char bchars[] = "=BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+*";
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Start winsock
|
||||
bool StartWinSock()
|
||||
{
|
||||
WORD wVersionRequested = MAKEWORD(2,2);
|
||||
WSADATA wsaData;
|
||||
|
||||
if (WSAStartup(wVersionRequested, &wsaData ) != 0 )
|
||||
{
|
||||
MessageBox(NULL, "ERROR: Winsock not available", szAppName, MB_OK);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Low level socket writing function - strings
|
||||
void prints(SOCKET socket, char * string)
|
||||
{
|
||||
int i=0;
|
||||
while (string[i] != 0)
|
||||
i++;
|
||||
|
||||
if (send(socket,string,i,0) == SOCKET_ERROR)
|
||||
{
|
||||
//MessageBox(NULL,"Socket send() error!",szAppName,MB_OK);
|
||||
}
|
||||
}
|
||||
|
||||
// Low level socket writing function - integers
|
||||
void printsi(SOCKET socket,int number)
|
||||
{
|
||||
char buffer[256];
|
||||
wsprintf(buffer,"%d",number); // Stick it in a string and call prints()
|
||||
prints(socket,(char*)&buffer);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Opens socket
|
||||
bool MakeRequest(char * host, int port, char * url, bool verbose, bool auth, bool gettitle)
|
||||
{
|
||||
//MessageBox(NULL,"Entering MakeRequest","wawitray",MB_OK | MB_TOPMOST);
|
||||
|
||||
SOCKET ssocket = socket(AF_INET,SOCK_STREAM,0);
|
||||
if (ssocket == INVALID_SOCKET)
|
||||
{
|
||||
if (verbose)
|
||||
MessageBox(NULL, "ERROR: Couldn't create socket", szAppName, MB_OK);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
struct sockaddr_in server_address;
|
||||
ZeroMemory(&server_address,sizeof(server_address));
|
||||
|
||||
server_address.sin_family = AF_INET;
|
||||
|
||||
server_address.sin_addr.s_addr = inet_addr(host);
|
||||
server_address.sin_port = htons(port);
|
||||
|
||||
if (SOCKET_ERROR == connect(ssocket,(sockaddr*)&server_address,sizeof(sockaddr_in)))
|
||||
{
|
||||
if (verbose)
|
||||
MessageBox(hwnd,"Couldn't connect to remote Winamp!\n\nCheck you have the address and port right.",szAppName,MB_OK|MB_ICONERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
char method[6];
|
||||
if (gettitle)
|
||||
wsprintf(method,"GET");
|
||||
else
|
||||
wsprintf(method,"HEAD");
|
||||
|
||||
char request[100];
|
||||
|
||||
if (auth)
|
||||
{
|
||||
char b64userpass[100], userpass[100];
|
||||
wsprintf(userpass,"%s:%s",username,password);
|
||||
ToBase64(userpass,b64userpass);
|
||||
wsprintf(request,"%s %s HTTP/1.0\nAuthorisation: Basic %s\n\n",method,url,b64userpass);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(request,"%s %s HTTP/1.0\nConnection: Close\n\n",method,url);
|
||||
}
|
||||
prints(ssocket,request);
|
||||
|
||||
int res = GetResponse(ssocket,gettitle);
|
||||
|
||||
closesocket(ssocket);
|
||||
|
||||
switch(res)
|
||||
{
|
||||
case RES_OK:
|
||||
break;
|
||||
case RES_AUTH:
|
||||
if (verbose)
|
||||
MessageBox(hwnd,"Incorrect username or password!\n\nCheck the details are right in the Config window.",szAppName,MB_OK|MB_ICONERROR | MB_TOPMOST);
|
||||
break;
|
||||
case RES_NOTFOUND:
|
||||
if (verbose)
|
||||
MessageBox(hwnd,"Received a 404 Page Not Found response, which the Winamp HTTP Server does not produce!\n\nAre you sure your host and port settings are correct?",szAppName,MB_OK | MB_ICONERROR | MB_TOPMOST);
|
||||
break;
|
||||
case RES_BADREQUEST:
|
||||
if (verbose)
|
||||
MessageBox(hwnd,"Received a 400 Bad Request message, which the Winamp HTTP Server does not produce!\n\nCheck your Host and Port settings are correct.",szAppName, MB_OK | MB_ICONERROR | MB_TOPMOST);
|
||||
case RES_UNKNOWN:
|
||||
case RES_FAIL:
|
||||
if (verbose)
|
||||
MessageBox(hwnd,"Unknown HTTP Response",szAppName,MB_OK | MB_ICONWARNING | MB_TOPMOST);
|
||||
break;
|
||||
}
|
||||
|
||||
//MessageBox(hwnd,"Leaving MakeRequest","wawitray",MB_OK | MB_TOPMOST);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int WASend(char * command)
|
||||
{
|
||||
MakeRequest(host,port,command,true,use_auth,false);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Converts a string to Base64
|
||||
void ToBase64(char * instr, char * outstr)
|
||||
{
|
||||
//MessageBox(NULL,instr,"instr",MB_OK);
|
||||
|
||||
int i=0;
|
||||
int o=0;
|
||||
int j = lstrlen(instr);
|
||||
|
||||
bool done = false;
|
||||
|
||||
while(instr[i] != 0 && done == false)
|
||||
{
|
||||
outstr[o] = bchars[(instr[i] & 0xFC) / 4];
|
||||
outstr[o+1] = bchars[((instr[i] & 0x03) * 16) + ((instr[i+1] & 0xF0) / 16)];
|
||||
if (instr[i+1] == 0)
|
||||
{
|
||||
outstr[o+2] = '=';
|
||||
outstr[o+3] = '=';
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
outstr[o+2] = bchars[((instr[i+1] & 0x0F) * 4) + ((instr[i+2] & 0xC0) /64)];
|
||||
if (instr[i+2] == 0)
|
||||
{
|
||||
outstr[o+3] = '=';
|
||||
done = true;
|
||||
}
|
||||
else
|
||||
outstr[o+3] = bchars[(instr[i+2] & 0x3F)];
|
||||
}
|
||||
|
||||
o += 4;
|
||||
i += 3;
|
||||
}
|
||||
|
||||
outstr[o] = 0;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Receives return HTTP header
|
||||
int GetResponse(SOCKET socket, bool gettitle)
|
||||
{
|
||||
char buffer[2048],http_version[20],response[5],text[100];
|
||||
int buffer_len;
|
||||
int buffer_filled = 0;
|
||||
int buffer_left;
|
||||
bool complete = false;
|
||||
|
||||
int breaks;
|
||||
if (gettitle)
|
||||
breaks = 1;
|
||||
else
|
||||
breaks = 0;
|
||||
|
||||
|
||||
while(true)
|
||||
{
|
||||
// receive data
|
||||
buffer_len = sizeof(buffer);
|
||||
buffer_left = buffer_len-buffer_filled;
|
||||
if (buffer_left <= 0)
|
||||
buffer_len = 0;
|
||||
else
|
||||
buffer_len = recv(socket,buffer + buffer_filled,buffer_len-buffer_filled,0);
|
||||
|
||||
if (buffer_len != SOCKET_ERROR && buffer_len != 0)
|
||||
{
|
||||
buffer_filled += buffer_len;
|
||||
// scan for end of header
|
||||
for (int i=0;i<=buffer_filled;i++)
|
||||
if (buffer[i]=='\n' && (buffer[i+1]=='\n' || buffer[i+2]=='\n'))
|
||||
{
|
||||
if (breaks == 0)
|
||||
{
|
||||
buffer[i+1] = 0;
|
||||
//MessageBox(NULL,buffer,"gen_httpsrv debug", MB_OK);
|
||||
char * chptr = (char*)&buffer;
|
||||
|
||||
chptr = GetAString(chptr,http_version);
|
||||
chptr = GetAString(chptr,response);
|
||||
chptr = GetAString(chptr,text);
|
||||
chptr = SkipHeader(chptr);
|
||||
|
||||
if (StrComp(response,"200"))
|
||||
{
|
||||
if (gettitle)
|
||||
GetALine(chptr,title);
|
||||
return RES_OK;
|
||||
}
|
||||
if (StrComp(response,"401"))
|
||||
return RES_AUTH;
|
||||
if (StrComp(response,"404"))
|
||||
return RES_NOTFOUND;
|
||||
if (StrComp(response,"400"))
|
||||
return RES_BADREQUEST;
|
||||
|
||||
return RES_UNKNOWN;
|
||||
}
|
||||
else
|
||||
breaks--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return RES_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Retrieves next token from buffer
|
||||
char * GetAString(char* chptr, char* text) // Old GetAString - only accepts single words
|
||||
{
|
||||
int bptr = 0;
|
||||
int tptr = 0;
|
||||
while (chptr[bptr] == ' ' || chptr[bptr] == '\n' || chptr[bptr] == '\r') // skip leading spaces and stuff
|
||||
bptr++;
|
||||
|
||||
while (chptr[bptr] != 0 && chptr[bptr] != ' ' && chptr[bptr] != '\n' && chptr[bptr] != '\r' && bptr < 255) // while current char is a letter
|
||||
{
|
||||
text[tptr] = chptr[bptr]; // add letter to text[]
|
||||
bptr++;
|
||||
tptr++;
|
||||
}
|
||||
text[tptr] = 0;
|
||||
chptr = chptr + bptr;
|
||||
return chptr; // return pointer to the end of this string
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Skips the rest of the HTTP header
|
||||
char * SkipHeader(char * chptr)
|
||||
{
|
||||
while (chptr[0] != '\n' || (chptr[1] != '\n' && chptr[2] != '\r'))
|
||||
chptr++;
|
||||
return chptr;
|
||||
}
|
||||
// --------------------------------------------------------------------------------
|
||||
// Gets a whole line
|
||||
char * GetALine(char * chptr, char * text)
|
||||
{
|
||||
int bptr = 0;
|
||||
int tptr = 0;
|
||||
while (chptr[bptr] == ' ' || chptr[bptr] == '\n' || chptr[bptr] == '\r') // skip leading spaces and stuff
|
||||
bptr++;
|
||||
|
||||
while (chptr[bptr] != 0 && chptr[bptr] != '\n' && chptr[bptr] != '\r' && bptr < 255) // while current char is a letter
|
||||
{
|
||||
text[tptr] = chptr[bptr]; // add letter to text[]
|
||||
bptr++;
|
||||
tptr++;
|
||||
}
|
||||
text[tptr] = 0;
|
||||
chptr = chptr + bptr;
|
||||
return chptr; // return pointer to the end of this string
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Strcmp() without using Clib
|
||||
bool StrComp(char * string1, char * string2)
|
||||
{
|
||||
int ptr=0;
|
||||
|
||||
while (ToLowerCase(string1[ptr]) == ToLowerCase(string2[ptr])) // while the strings are the same, keep going
|
||||
{
|
||||
if (string1[ptr] == 0) // if they're the same and 0, they're identical null terminated strings
|
||||
return true;
|
||||
ptr++;
|
||||
}
|
||||
return false; // if not the same, they're... not the same
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Convert a char to lower case
|
||||
char ToLowerCase(char c)
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z')
|
||||
c += 32;
|
||||
return c;
|
||||
}
|
||||
Reference in New Issue
Block a user