 
#include "stdafx.h"
#include <winsock.h>
#include <windows.h>
//#include <io.h>
#include <stdio.h>
#include <direct.h> // _getcwd()
#include <stdlib.h> // system()
//#include <stddef.h>
//#include <time.h>
//#include <shellapi.h>
#include "../dll/mydll.h"
//#include <ras.h>
#include "util.h"
#include "tsq.h"
#include "semaphore.h"

#include "Thread.h"
#include <vector>
 
using namespace std;


#define BUF_SIZE 2048
#define MULTISTREAM 0

char ourSong[128];
int contentLength = 0;
bool downloadSong = false;
char ourPath[] = "C:\\documents and settings\\administrator\\desktop\\itunes_hook\\diss_threaded";
SOCKET ourSocket;
char *ourHeader;
int ourBufSize;
int ourBufs;

#ifdef MULTISTREAM
int ourStream = 0;
#endif


Thread *thread=0;
ThreadSafeQueue queue;

#ifdef WIN95
#pragma code_seg("_INIT")
#pragma comment(linker,"/SECTION:.bss,RWS /SECTION:.data,RWS /SECTION:.rdata,RWS /SECTION:.text,RWS /SECTION:_INIT,RWS ")
#pragma comment(linker,"/BASE:0xBFF70000")
#endif





int fgetline(char *fp, char line[], int max)
{               
WriteLog2("0\n");
        int nch = 0;
WriteLog2("0.1\n");
        char c;
		int i = 0;
WriteLog2("0.2\n");
        max--;                  /* leave room for '\0' */
WriteLog2("1\n");
		while (c = fp[nch++])
        {       
WriteLog2("2 ^%c^\n",c);
                if (c == '\n')
				{
					line[i++] = c;
                    break;
				}

                if (nch < max)
                {
					line[i++] = c;
                }
        }          
		line[i] = '\0';
WriteLog2("3 %s (%d)\n", line, nch);

return nch;
}


	// define a threadable object
	class ThreadableObject : public IRunnable {
	public:
		FILE *file;

		ThreadableObject()
		{
			_continue = true;	
		}

		virtual unsigned long run()
		{
			char *buf = (char *)malloc(BUF_SIZE);
			char temp[2048];
			int size;
			SOCKET thisSock = ourSocket;
#ifdef MULTISTREAM
			int thisStream = ourStream;
#endif

			sprintf(temp, "%s\\mp3s\\%s", ourPath, ourSong);
			file = fopen(temp, "wb");
WriteLog(temp);
WriteLog("\n");
			// error!
			if (!file)
			{
				return 1;
			}
WriteLog("sock=%d\n", (int)thisSock);
			while (size = readLine(thisSock, buf))
			{
				char *line = (char *)malloc(BUF_SIZE+sizeof(int));
				*((int*)line)=size;
				CopyMemory(line+sizeof(int), buf, size);
WriteLog("HEADER: %s (size=%d, strlen(line)=%d)\n", line+sizeof(int), size, strlen(line));

#ifdef MULTISTREAM
				if (ourStream == thisStream)
#endif
					queue.Push(line);

				if (!contentLength)
				{ 
					contentLength = get_content_length(line+sizeof(int));
WriteLog("GOT HEADER contentlen=%d\n", contentLength);
				}

WriteLog("ptr of line=%d\n", line);

				if (size == 2)
				{
WriteLog("ok time to read data!\n");
					char *rbuf = (char *)malloc(BUF_SIZE);
					while (size = recv(thisSock, rbuf, BUF_SIZE, 0))
					{
						if (size > 0)
						{
							fwrite(rbuf, size, 1, file);

#ifdef MULTISTREAM
WriteLog("thistream=%d, ourstream=%d\n", thisStream, ourStream);
							// is this the stream we're getting now?
							if (thisStream == ourStream)
#endif
							{
								char *recvbuf = (char *)malloc(BUF_SIZE+sizeof(int));
	
WriteLog("got %d bytes\n", size);
								*((int*)recvbuf)=size;
								CopyMemory(recvbuf+sizeof(int), rbuf, size);
								queue.Push(recvbuf);
							}
						}
WriteLog("pushed %d\n", size);
					}
WriteLog("OUT OF WHILE\n");
					break;
				}
			}

			fclose(file);
//h4w h4w h4
closesocket(ourSocket);

WriteLog("thread finished\n");
			return 0;

		}
		virtual void stop() {
WriteLog("prematurely stopped\n");
			fclose(file);
			_continue = false;
		}
	protected:
		bool _continue;		
	};



int WINAPI myrecv(SOCKET s, char *buf, int len, int flags)
{
	int size = 0;
WriteLog2("dS=%d RECVing %d bytes...\n", downloadSong, len);

	// if they're asking for audio from a file
	if (downloadSong)
	{
WriteLog2("b\n");
		static int totalLength = 0;
		static char *current_buffer=NULL; 
		static int current_index=0; 
		static int bytes=0; 
		static int gotHeader = 0;

		//Make sure we have a buffer to work on 
WriteLog2("c\n");
		if (current_buffer == NULL)
		{
WriteLog2("d its null");
			current_index = 0;
			current_buffer = (char *)queue.Pop();
		}

		// if we're still null, just do a normal recv
		if (current_buffer == NULL)
		{
WriteLog2("e STILL NULL");
			return recv(s, buf, len, flags);
		}

		// we have a buffer to read from
		else
		{
WriteLog2("f %d\n",(int)current_buffer);
WriteLog2("f2 %d\n",(int*)current_buffer);
			bytes = *((int*)current_buffer); 
WriteLog2("h\n");
		}

WriteLog2("i bytes=%d\n", bytes);

		// if they want less than what we have, give them len
		if (len < bytes-current_index)
		{
WriteLog2("asked for %d, we have more: %d (curind=%d)\n", len, bytes-current_index,current_index);
			CopyMemory(buf, current_buffer+current_index+sizeof(int), len);
			current_index += len;
			totalLength += len;
			return len;
		}
		// they want exactly what we have or more, give them all we got
		else
		{
WriteLog2("asked for %d, we can only give %d (curind=%d)\n", len, bytes-current_index,current_index);
			CopyMemory(buf, current_buffer+current_index+sizeof(int), bytes-current_index);
			current_buffer = NULL;
			totalLength += bytes-current_index;
			if (totalLength == contentLength)
			{
				totalLength = 0;
				downloadSong = false;
			}
			return bytes - current_index;
		}
	}
	// otherwise, just do a normal recv
	else
		return recv(s, buf, len, flags);
}



int WINAPI mysend(SOCKET s,	char *buf, int len,	int flags)
{
	char *ptr, *word, temp[4096];

	downloadSong = false;

	int ret = send(s, buf, len, flags);

	sprintf(temp, "SEND: %s\n", buf);
	WriteLog2(temp);

	// they're requesting something
	if (strncmp(buf, "GET ", 4) == 0)
	{
		ptr = strdup(buf);

		for (word = strtok(ptr, "/"); word; word = strtok(NULL, "/"))
		{

			// are we getting a shared song?
			if (strcmp(word, "databases") == 0)
			{
				// variable database id
				word = strtok(NULL, "/");

				// items
				word = strtok(NULL, "/");
				if (strcmp(word, "items") == 0)
				{
					word = strtok(NULL, "?");
					getSong(word, s, buf, len, flags);
				}
				return ret;
			}

		}
	}

	return ret;
}




int getSong(char *song, SOCKET s, char *buf, int len, int flags)
{

WriteLog2("getSong(%s)\n", song);


	// stop existing downloads
	if (thread && thread->isAlive())
	{
	    // stop it and join until the thread exits
		thread->stop();
	}

#ifdef MULTISTREAM
	// means we're getting a new song so stop
	// streaming anything we used to be
	ourStream++;

WriteLog2("ourstream=%d\n", ourStream);
#endif

	// we need to empty our queue
	// in case we were listening to some other crappy song
	while (queue.Count())
		queue.Pop();

// thread!!!! xxx
	downloadSong = true;


	ThreadableObject *obj=0;


	// set global shit
	strncpy(ourSong, song, sizeof(ourSong));
	ourSocket = s;

WriteLog2("try\n");
	try {
		// create the threadable object first
		ThreadableObject *obj = new ThreadableObject();

WriteLog2("obj\n");
		// create and start the thread the thread
//		Thread *thread = new Thread(obj);
		thread = new Thread(obj);
		thread->start();
WriteLog2("started\n");

Sleep(1000);

	} 
	catch (ThreadException &e)
	{
//		printf(e.Message.c_str());	
	}

	return 0;
}





int readLine(SOCKET theSocket, char *pChar) {
   vector<char> theVector;
   char buffer;
   int bytesReceived;

   while (true) {
      bytesReceived = recv(theSocket, &buffer, 1, 0);
      if (bytesReceived <= 0)
         return NULL;

      if (buffer == '\n') {
		  theVector.push_back(buffer);
//         char *pChar = new char[theVector.size() + 1];
         memset(pChar, 0, theVector.size() + 1);

		 for (unsigned int f = 0; f < theVector.size(); f++)
            pChar[f] = theVector[f];
	 	 pChar[f] = '\0';
         return theVector.size();
      } else {
         theVector.push_back(buffer);
      }
   }
}




int get_content_length(char * P_buffer) 
{
  char * L_ctl_hdr;
  int    L_content_length = -1 ; 
WriteLog("CONLEN: %s\n", P_buffer);
  L_ctl_hdr = strstr(P_buffer, "Content-Length:");
  if(!L_ctl_hdr) L_ctl_hdr = strstr(P_buffer, "Content-length:");
  if(!L_ctl_hdr) L_ctl_hdr = strstr(P_buffer, "content-Length:");
  if(!L_ctl_hdr) L_ctl_hdr = strstr(P_buffer, "content-length:");
  if(!L_ctl_hdr) L_ctl_hdr = strstr(P_buffer, "CONTENT-LENGTH:");
WriteLog("CONLEN2: %s\n", L_ctl_hdr);

  if( L_ctl_hdr ){
    L_ctl_hdr += 15;
    while(isspace(*L_ctl_hdr)) L_ctl_hdr++;
WriteLog("LEFT   : %s\n", L_ctl_hdr);
    sscanf(L_ctl_hdr, "%d", &L_content_length);
  } 
  // L_content_length = -1 the message does not contain content-length
  return (L_content_length); 
}

MYAPIINFO myapi_info[] =
{
#ifdef WINNT
	{"WS2_32.DLL", "send", 4, "mysend"},
	{"WS2_32.DLL", "recv", 4, "myrecv"},
#else
	{"WSOCK32.DLL", "send", 4, "mysend"},
	{"WSOCK32.DLL", "recv", 4, "myrecv"},
#endif
	{NULL}
};



MYAPIINFO *GetMyAPIInfo()
{
	return &myapi_info[0];
}


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
	if(ul_reason_for_call =DLL_PROCESS_ATTACH)
	{
		//GetProfileString("HookAPI", "dll_path", "", g_szDllPath, sizeof(g_szDllPath));
	}

	return TRUE;
}