/* --- CLIENTCONNECTION.CPP ---
/  
/ Written by Phil Himsworth, 2001-2002.
/
/*/

#include <windows.h>
#include "types.h"
#include "wamessage.h"
#include "main.h"
#include "op_winamp.h"
#include "html.h"
#include "plugin.h"
#include "resource.h"


extern char mp3root[MAX_PATH], logfiledir[MAX_PATH];
extern int dl_wa_files, dl_other_files, frames, title_refresh;
extern char szAppVer[];
extern char pagetitle[255];

extern winampGeneralPurposePlugin plugin;

bool loglocked = false;

char realm_server[]   = "Wawi Server Control";
char realm_control[]  = "Wawi Playback Control";
char realm_clear[]    = "Wawi Playlist Clear Control";
char realm_playlist[] = "Wawi Playlist Control";
char realm_download[] = "Wawi Downloads";
char realm_browse[]   = "Wawi Music Collection";

CControl Control;

// --------------------------------------------------------------------------------
// Thread called for each connection
DWORD WINAPI ClientConnection(LPVOID socket_param)		// new thread for a new client.
{

	
	bool matched = false;
	connection conn;									// structure to hold request details
	ZeroMemory(&conn,sizeof(conn));
	conn.http.auth = AUTH_ANON;
	wsprintf(conn.http.user,"anon");
	conn.log = true;
	conn.state = ST_NONE;
	conn.http.responsecode = 200;
	
	conn.socket = (SOCKET)socket_param;				// convert param into socket


	int rhost_len = sizeof(conn.remote_host);
	getpeername(conn.socket,(sockaddr*)&conn.remote_host,&rhost_len);

	if (!GetRequest(&conn))
	{
		//MessageBox(NULL,conn.http.file,"400",MB_TOPMOST | MB_OK);
		conn.http.responsecode = 400;
		Send400(&conn);
		shutdown(conn.socket,0);
		closesocket(conn.socket);
		MakeLogEntry(&conn);
		return true;
	}



// ------------- Images ------------------
	// Of the form /img?image=n where 'n' is the id of the image, eg. IDR_DIRECTORY.
	if (StrComp(conn.http.page,"/img"))
	{
		//MessageBox(NULL,conn.http.file,"File",MB_OK | MB_TOPMOST);
		//MessageBox(NULL,conn.http.page,"Page",MB_OK | MB_TOPMOST);
		conn.log = false;
		conn.state = Control.Image(&conn,IMG_GIF);
	}

// ------------- Favicon.ico!!!-----------
	// Sent the same as a img resource but with a different header
	if (StrComp(conn.http.page,"/favicon.ico"))
	{
		//conn.log = false;
		wsprintf(conn.http.file,"/img?%d",IDR_ICO_WINAMP);
		conn.state = Control.Image(&conn,IMG_ICO);
	}


// ------------ Top -----------------
	if (StrComp(conn.http.page,"/top"))
	{
		conn.log = false;
		conn.state = Control.TopFrame(&conn);
	}
		

// ------------- Small Title ------------
// No page formatting at all; just the song info.

	if (StrComp(conn.http.page,"/smalltitle"))
		conn.state = Control.SmallTitle(&conn);


// -------------- Title ----------------
	if (StrComp(conn.http.page,"/title"))
	{
		conn.log = false;
		conn.state = Control.Title(&conn);
	}
		
	
// ---------- Shutdown Computer -------------
	if (StrComp(conn.http.page,"/shutdown"))
	{
		if (!(conn.http.auth & AUTH_SERVER))
			conn.state = SendBasic401(&conn,realm_server);
		else
			conn.state = Control.Shutdown(&conn);

	}



// ---------- Clear Playlist -----
	if (StrComp(conn.http.page,"/clear"))
	{
		if (!(conn.http.auth & AUTH_CLEAR))
			conn.state = SendBasic401(&conn,realm_playlist);
		else
			conn.state = Control.Clear(&conn);
	}


// ---------- Sort playlist ----------
	if (StrComp(conn.http.page,"/sort"))
	{
		if (!(conn.http.auth & AUTH_PLAYLIST))
			conn.state = SendBasic401(&conn,realm_playlist);
		else
			conn.state = Control.Sort(&conn);
	}




// ------------ Browse -----------
	if (StrComp(conn.http.page,"/browse"))
	{
		if (!(conn.http.auth & AUTH_BROWSE))
			conn.state = SendBasic401(&conn,realm_browse);
		else
		{
			char mp3path[MAX_PATH];
			if (GetArgValue(&conn,"path",(char*)&mp3path,MAX_PATH) == false)
				wsprintf(mp3path,"%%5c");
			ReplaceSlashes(mp3path);
			conn.state = Browse(&conn, mp3path);
			if (frames == 1)
				LinkBar(&conn);
		}
	}

// ------------ Download ---------
	if (StrComp(conn.http.page,"/dl"))
		if (!(conn.http.auth & AUTH_DOWNLOAD))
			conn.state = SendBasic401(&conn,realm_download);
		else
			conn.state = Control.Download(&conn);



// ------------ Load -------------
	if (StrComp(conn.http.page,"/ld"))			// ld = load
	{
		if (!(conn.http.auth & AUTH_PLAYLIST))
			conn.state = SendBasic401(&conn,realm_playlist);
		else
			conn.state = Control.Load(&conn);
	}

// ------------ List -------------
	if (StrComp(conn.http.page,"/list"))
		conn.state = Control.List(&conn);

	
// ------------ Next -------------
	if (StrComp(conn.http.page,"/next"))							// Next track
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Next(&conn);
	}


// ------------ Prev -------------
	if (StrComp(conn.http.page,"/prev"))							// Previous track
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Prev(&conn);
	}

	
// ------------ Play -------------
	if (StrComp(conn.http.page,"/play"))	
				// Play (or play?xxxx)
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Play(&conn);
	}

// ------------ Stop -------------
	if (StrComp(conn.http.page,"/stop"))
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Stop(&conn);
	}

// ----------- Stop slowly -----------

	if (StrComp(conn.http.page,"/stopslow"))
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.StopSlow(&conn);
	}


// ------------ Pause ------------
	if (StrComp(conn.http.page,"/pause"))
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Pause(&conn);
	}

// ------------ Volume -----------
	if (StrComp(conn.http.page,"/vol"))
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Volume(&conn);
	}
		
// ----------- Random / Repeat --------------
	if (StrComp(conn.http.page,"/playmode"))
	{
		if (!(conn.http.auth & AUTH_CONTROL))
			conn.state = SendBasic401(&conn,realm_control);
		else
			conn.state = Control.Playmode(&conn);
	}

// ------------- Login/out---------------
	if (StrComp(conn.http.page,"/login"))
		conn.state = SendBasic401(&conn,"Winamp Web Interface");

// ------------ About ----------------

	if (StrComp(conn.http.page,"/about"))
	{
		conn.state = Control.About(&conn);
	}


// ---------- Delete playlist entry ----
	if (StrComp(conn.http.page,"/delete"))
	{
		if (!(conn.http.auth & AUTH_CLEAR))
			conn.state = SendBasic401(&conn,realm_clear);
		else
			conn.state = Control.Delete(&conn);
	}


// ---------- Stylesheet -------------
	if (StrComp(conn.http.page,"/wawi.css"))
	{
		conn.log = false;
		conn.state = Control.UserStyle(&conn);
	}

// ------------ Main page ----------------
	if (StrComp(conn.http.page,"/main"))
	{
		conn.state = Control.Main(&conn);
	}


// ------------ PDA Page ----------------
	if (StrComp(conn.http.page,"/pda"))
	{
		conn.state = Control.pda(&conn);
	}

// ------------ Admin ------------------
	if (StrComp(conn.http.page,"/admin"))
	{
		if (!(conn.http.auth & AUTH_SERVER))
			conn.state = SendBasic401(&conn,realm_server);
		else
			conn.state = Control.WebAdmin(&conn);
	}

	if (StrComp(conn.http.page,"/apply"))
	{
		if (!(conn.http.auth & AUTH_SERVER))
			conn.state = SendBasic401(&conn,realm_server);
		else
			conn.state = Control.ApplyAdmin(&conn);
	}


// -------------- Users -----------------
	if (StrComp(conn.http.page,"/user"))
	{
		if (!(conn.http.auth & AUTH_SERVER))
			conn.state = SendBasic401(&conn,realm_server);
		else
			conn.state = Control.User(&conn);
	}

// ------ Set user permissions ------------
	if (StrComp(conn.http.page,"/setuser"))
	{
		if (!(conn.http.auth & AUTH_SERVER))
			conn.state = SendBasic401(&conn,realm_server);
		else
			conn.state = Control.SetUser(&conn);
	}

// ------ Save playlist ------------
	if (StrComp(conn.http.page,"/save"))
	{
		if (!(conn.http.auth & AUTH_PLAYLIST))
			conn.state = SendBasic401(&conn,realm_playlist);
		else
			conn.state = Control.SavePlaylist(&conn);
	}


// ------ Page redirect - page?page=(main|list|browse)
	if (StrComp(conn.http.page,"/page"))
	{
		char page[10];
		GetArgValue(&conn,"page",page,10);

		if (!(StrComp(page,"main") || StrComp(page,"list") || StrComp(page,"browse")))
			wsprintf(page,"main");

		prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /");
		prints(&conn,page);
		prints(&conn,"\nConnection: close\nContent-type: text/html\n\n");
		prints(&conn,"<html>\n<head>\n<title>Winamp Web Interface</title>\n</head>\n");
		prints(&conn,"<body>\n<p><a href=\"/");
		prints(&conn,page);
		prints(&conn,"\">Winamp Web Interface</a></p>\n</body>\n</html>\n\n");

		conn.state = ST_CLOSE;
	}





	if (StrComp(conn.http.page,"/winamp"))
	{
		OpenHTTPHeader(&conn,"text/html",0,NULL);
		if (conn.http.reqID == RID_HEAD)
			conn.state = ST_CLOSE;
		else
		{
			char reqpage[10];
			GetArgValue(&conn,"page",reqpage,10);

			if (!(StrComp(reqpage,"main") || StrComp(reqpage,"list") || StrComp(reqpage,"browse")))
				wsprintf(reqpage,"main");
			
			OpenHtmlHeader(&conn);
			Style(&conn);
			CloseHeader(&conn);
			if (frames == 3)
			{
				prints(&conn,"<frameset border=\"0\" frameborder=\"0\" rows=\"35,1*,27\">\n<frame name=\"top\" src=\"/top\" noresize marginheight=\"0\" marginwidth=\"0\">\n<frame name=\"main\" src=\"/page?page=");
				prints(&conn,reqpage);
				prints(&conn,"\" noresize>\n<frame name=\"bottom\" src=\"title\" noresize marginheight=\"1\" marginwidth=\"5\">\n");
				prints(&conn,"<noframes><p><b>Frames are required for this site!<b></p><p>If no-frames operation is required, check the <b>No Frames Mode</b> box in the Options screen.</p>\n");
				prints(&conn,"</frameset>\n");
			}
			else
			{
				prints(&conn,"<frameset border=\"0\" frameborder=\"0\" rows=\"35,1*\">\n<frame name=\"top\" src=\"/top\" noresize marginheight=\"0\" marginwidth=\"0\">\n<frame name=\"main\" src=\"/page?page=");
				prints(&conn,reqpage);
				prints(&conn,"\" noresize>\n");
				prints(&conn,"<noframes><p><b>Frames are required for this site!<b></p><p>If no-frames operation is required, check the <b>No Frames Mode</b> box in the Options screen.</p>\n");
				prints(&conn,"</frameset>\n");
			}

			conn.state = ST_CLOSEBODY;
		}
	}

	if (conn.state == ST_NONE)		// something else, including '/'
	{								// 302 to /winamp?page=frames
		if (frames == 1)
		{
			prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /page?page=main\nConnection: close\nContent-type: text/html\n\n");
			prints(&conn,"<html>\n<head>\n<title>Winamp Web Interface</title>\n</head>\n");
			prints(&conn,"<body>\n<p><a href=\"/page?page=main\">Winamp Web Interface</a></p>\n</body>\n</html>\n\n");
		}
		else
		{
			prints(&conn,"HTTP/1.0 302 Temporarily Moved\nLocation: /winamp?page=main\nConnection: close\nContent-type: text/html\n\n");
			prints(&conn,"<html>\n<head>\n<title>Winamp Web Interface</title>\n</head>\n");
			prints(&conn,"<body>\n<p><a href=\"/winamp?page=main\">Winamp Web Interface</a></p>\n</body>\n</html>\n\n");
		}
		//conn.log = false;
		conn.state = ST_CLOSE;
	}

	if (conn.state == ST_CLOSEBODY)
		CloseBody(&conn);											// end html


	flush(&conn);
	closesocket(conn.socket);									// close connection

	if (conn.log)
		MakeLogEntry(&conn);


	return true;
};

/*
struct HOSTENT FAR * gethostbyaddr (
  const char FAR * addr,  
  int len,                
  int type                
);
*/

// --------------------------------------------------------------------------------
// Adds entry in log
void MakeLogEntry(connection * conn)
{
	int logbuffer_len;

	SYSTEMTIME time;
	GetSystemTime(&time);
	char timestr[100];				//	"[DD/MM/YYYY HH:MM:SS]"
	wsprintf(timestr,"[%02d.%02d.%04d %02d:%02d:%02d]",time.wDay, time.wMonth, time.wYear, time.wHour, time.wMinute, time.wSecond);

	char logbuffer[2048];
	ZeroMemory(&logbuffer,sizeof(logbuffer));
	
	logbuffer_len = wsprintf(logbuffer,"%s %s %s %d %s %s\r\n",timestr, (char*)inet_ntoa(conn->remote_host.sin_addr), conn->http.user, conn->http.responsecode, conn->http.request, conn->http.file);

	// Find log file, in winamp plugin directory (same dir as gen_httpsrv.dll)
	char logfilepath[MAX_PATH], *p;
	char logfile[MAX_PATH];
	
	if (lstrlen(logfiledir) == 0)
	{
		GetModuleFileName(plugin.hDllInstance,logfilepath,sizeof(logfilepath));
		p=logfilepath+lstrlen(logfilepath);
		while (p >= logfilepath && *p != '\\') p--;
		if (++p >= logfilepath) *p = 0;
		wsprintf(logfile,"%shttpsrv.log",logfilepath);
	}
	else
	{
		lstrcpy(logfilepath,logfiledir);
		wsprintf(logfile,"%s\\httpsrv.log",logfilepath);
	}

	//lstrcat(logfile,"gen_httpsrv_log.log);

	//MessageBox(NULL,logfile,"Logfile",MB_OK| MB_TOPMOST);

	while(loglocked == true)		// wait for log file to be free
		Sleep(50);

	loglocked = true;				// lock it

	HANDLE hLog = CreateFile(	logfile,  
								GENERIC_WRITE, 
								0, 
								0, 
								OPEN_ALWAYS,
								0,
								0);

	if (hLog == NULL)
	{
		//MessageBox(NULL,"Couldn't open log file","gen_httpSrv debug", MB_OK);
		return;
	}
	
	DWORD dwSize = GetFileSize(hLog, NULL);

	//MessageBox(NULL,logfilename,"logfile size",MB_OK);
	SetFilePointer(hLog,(LONG)dwSize,NULL,FILE_BEGIN);
	
	unsigned long written;
	WriteFile(hLog,&logbuffer,logbuffer_len,&written,NULL);

	CloseHandle(hLog);

	if (dwSize >= 50000)		// rename log file to something else to start a new one
	{
		char logfilename[MAX_PATH];
		bool name_used = true;
		int letter = 1;
		while(name_used)
		{	// loop through acceptable names, find first unused one of form httpsrv_dd-dd-yyyy_n.log
			wsprintf(logfilename,"%shttpsrv_%d-%d-%d_%d.log",logfilepath,time.wDay,time.wMonth,time.wYear,letter);
			//MessageBox(NULL,logfilename,"Logfilename",MB_OK | MB_TOPMOST);
			if (GetFileAttributes(logfilename) == 0xFFFFFFFF)
			{
				name_used = false;
				MoveFile(logfile,logfilename);
			}
			else
			{
				letter++;
			}
		}
	}
		
	loglocked = false;		// release log file
}