SDeviceInfo ChangeJournalWatcher::getDeviceInfo(const std::wstring &name)
{
	q_get_dev_id->Bind(name);
	db_results res=q_get_dev_id->Read();
	q_get_dev_id->Reset();
	SDeviceInfo r;
	r.has_info=false;
	if(!res.empty())
	{
		r.has_info=true;
		r.journal_id=os_atoi64(wnarrow(res[0][L"journal_id"]));
		r.last_record=os_atoi64(wnarrow(res[0][L"last_record"]));
		r.index_done=watoi(res[0][L"index_done"])>0;
	}
	return r;
}
std::wstring ChangeJournalWatcher::getFilename(_i64 frn, _i64 rid)
{
	std::wstring path;
	_i64 curr_id=frn;
	while(true)
	{
		q_get_name->Bind(curr_id);
		q_get_name->Bind(rid);
		db_results res=q_get_name->Read();
		q_get_name->Reset();

		if(!res.empty())
		{
			_i64 pid=os_atoi64(wnarrow(res[0][L"pid"]));
			if(pid!=-1)
			{
				path=res[0][L"name"]+os_file_sep()+path;
				curr_id=pid;
			}
			else
			{
				path=res[0][L"name"]+os_file_sep()+path;
				break;
			}
		}
		else
		{
			Server->Log(L"Couldn't follow up to root. Current path: "+path, LL_ERROR);
			return L"";
		}
	}
	return path;
}
float CSettingsReader::getValue(std::wstring key, float def)
{
	std::wstring value;
	bool b=getValue(key,&value);
	if(b==false)
		return def;
	else
		return (float)atof(wnarrow(value).c_str());
}
_i64 ChangeJournalWatcher::hasEntry( _i64 rid, _i64 frn)
{
	q_get_entry->Bind(frn);
	q_get_entry->Bind(rid);
	db_results res=q_get_entry->Read();
	q_get_entry->Reset();
	if(res.empty())
		return -1;
	else
		return os_atoi64(wnarrow(res[0][L"id"]));
}
_i64 ChangeJournalWatcher::hasRoot(const std::wstring &root)
{
	q_has_root->Bind(root);
	db_results res=q_has_root->Read();
	q_has_root->Reset();
	if(res.empty())
		return -1;
	else
	{
		return os_atoi64(wnarrow(res[0][L"id"]));
	}
}
std::vector<_i64 > ChangeJournalWatcher::getChildren(_i64 frn, _i64 rid)
{
	std::vector<_i64> ret;
	q_get_children->Bind(frn);
	q_get_children->Bind(rid);
	db_results res=q_get_children->Read();
	q_get_children->Reset();
	for(size_t i=0;i<res.size();++i)
	{
		ret.push_back(os_atoi64(wnarrow(res[i][L"frn"])));
	}
	return ret;
}
SStatus Connector::getStatus(void)
{
    std::string d=getResponse("STATUS","");

    std::vector<std::string> toks;
    Tokenize(d, toks, "#");

    SStatus ret;
    ret.pause=false;
    ret.capa=0;
    if(toks.size()>0)
        ret.lastbackupdate=wxString::FromUTF8(toks[0].c_str() );
    if(toks.size()>1)
        ret.status=wxString::FromUTF8(toks[1].c_str() );
    if(toks.size()>2)
        ret.pcdone=wxString::FromUTF8(toks[2].c_str() );
    if(toks.size()>3)
    {
        if(toks[3]=="P")
            ret.pause=true;
        else if(toks[3]=="NP")
            ret.pause=false;
    }
    if(toks.size()>4)
    {
        std::map<std::wstring,std::wstring> params;
        ParseParamStr(toks[4], &params);
        std::map<std::wstring,std::wstring>::iterator it_capa=params.find(L"capa");
        if(it_capa!=params.end())
        {
            ret.capa=watoi(it_capa->second);
        }
        std::map<std::wstring,std::wstring>::iterator it_new_server=params.find(L"new_ident");
        if(it_new_server!=params.end())
        {
            ret.new_server=wnarrow(it_new_server->second);
        }
    }

    return ret;
}
bool File::Open(std::wstring pfn, int mode)
{
	fn=pfn;
	std::ios::openmode _mode;
	if( mode==MODE_READ || mode==MODE_READ_DEVICE )
		_mode=std::ios::in|std::ios::binary;
	else if( mode==MODE_WRITE || mode==MODE_TEMP )
	{
		_unlink(pfn.c_str());
		_mode=std::ios::out|std::ios::binary;
	}
	else if( mode==MODE_APPEND )
		_mode=std::ios::app|std::ios::binary;
	else if( mode==MODE_RW )
		_mode=std::ios::in|std::ios::out|std::ios::binary;

	fi.open(wnarrow(fn).c_str(), _mode);
	
	if( fi.is_open()==true )
		return true;
	else
		return false;
}
std::vector<UsnInt> ChangeJournalWatcher::getJournalData(const std::wstring &vol)
{
	q_get_journal_data->Bind(vol);
	db_results res=q_get_journal_data->Read();
	q_get_journal_data->Reset();
	std::vector<UsnInt> ret;
	for(size_t i=0;i<res.size();++i)
	{
		UsnInt rec;
		rec.Usn=os_atoi64(wnarrow(res[i][L"usn"]));
		rec.Reason=(DWORD)os_atoi64(wnarrow(res[i][L"reason"]));
		rec.Filename=res[i][L"filename"];
		rec.FileReferenceNumber=os_atoi64(wnarrow(res[i][L"frn"]));
		rec.ParentFileReferenceNumber=os_atoi64(wnarrow(res[i][L"parent_frn"]));
		rec.NextUsn=os_atoi64(wnarrow(res[i][L"next_usn"]));
		rec.attributes=(DWORD)os_atoi64(wnarrow(res[i][L"attributes"]));
		ret.push_back(rec);
	}
	return ret;
}
void CWorkerThread::ProcessRequest(CClient *client, FCGIRequest *req)
{
	if( req->keep_connection )
	{
		keep_alive=true;
	}
	else
	{
		keep_alive=false;
	}

	if( req->role != FCGIRequest::RESPONDER )
	{
		Server->Log("Role ist not Responder", LL_ERROR);
		return;
	}

	str_map GET,POST;

	str_nmap::iterator iter=req->params.find("QUERY_STRING");
	if( iter!=req->params.end() )
	{
		for(size_t i=0,size=iter->second.size();i<size;++i)
		{
			if( iter->second[i]=='+' )
				iter->second[i]=' ';
		}
		ParseParamStr(iter->second, &GET );			
		req->params.erase( iter );
	}
	
	std::string ct=req->params["CONTENT_TYPE"];
	std::string lct=ct;
	strlower(lct);
	bool postfile=false;
	POSTFILE_KEY pfkey;
	if(lct.find("multipart/form-data")==std::string::npos)
	{
		if( req->stdin_stream.size()>0 && req->stdin_stream.size()<1048576 )
		{
			for(size_t i=0,size=req->stdin_stream.size();i<size;++i)
			{
				if( req->stdin_stream[i]=='+' )
					req->stdin_stream[i]=' ';
			}
			ParseParamStr(req->stdin_stream, &POST );
		}
	}
	else
	{
		std::string boundary=getafter("boundary=",ct);
		pfkey=ParseMultipartData(req->stdin_stream, boundary);
	        req->params["POSTFILEKEY"]=nconvert(pfkey);
	        postfile=true;
	}

	str_map::iterator iter2=GET.find(L"a");

	if( iter2!=GET.end() )
	{
		int starttime=Server->getTimeMS();

		str_map::iterator iter3=GET.find(L"c");

		std::wstring context;
		if( iter3!=GET.end() )
			context=iter3->second;

		THREAD_ID tid=Server->Execute(iter2->second, context, GET, POST, req->params, req );

		if( tid==0 )
		{
			std::wstring error=L"Error: Unknown action ["+iter2->second+L"]";
			Server->Log(error, LL_WARNING);
			req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+wnarrow(error));
		}

		starttime=Server->getTimeMS()-starttime;
		Server->Log("Execution Time: "+nconvert(starttime)+" ms - time="+nconvert(Server->getTimeMS() ), LL_INFO);
	}
	else
	{
		std::string error="Error: Parameter 'action' not given.";
		req->write("Content-type: text/html; charset=UTF-8\r\n\r\n"+error);
	}
	
	if(postfile)
	{
		Server->clearPostFiles(pfkey);
	}

	req->end_request(0, FCGIRequest::REQUEST_COMPLETE);
}
bool CClientThread::ProcessPacket(CRData *data)
{
	uchar id;
	if( data->getUChar(&id)==true )
	{
		switch(id)
		{
		case ID_GET_GAMELIST:
			{	
#ifdef CHECK_IDENT
				std::string ident;
				data->getStr(&ident);
				if(!FileServ::checkIdentity(ident))
				{
					Log("Identity check failed -1", LL_DEBUG);
					return false;
				}
#endif

				hFile=0;
				std::vector<std::wstring> games=get_maps();


				Log("Sending game list", LL_DEBUG);

				EnableNagle();

				CWData data;
				data.addUChar( ID_GAMELIST );
				data.addUInt( (unsigned int)games.size() );

				stack.Send(clientpipe, data);

				for(size_t i=0;i<games.size();++i)
				{
					std::string version;
					std::wstring udir;
					version=getFile(wnarrow(map_file(games[i]+L"\\version.uri",true,&udir)));

					if( udir!=L"" )
						games[i]+=L"|"+udir;

					std::string game=Server->ConvertToUTF8(games[i]);
					

					stack.Send(clientpipe, (char*)game.c_str(), game.size() );					
					stack.Send(clientpipe, (char*)version.c_str(), version.size() );
				}
				
				Log("done.", LL_DEBUG);

				DisableNagle();
			}break;
		case ID_GET_FILE_RESUME:
		case ID_GET_FILE:
		case ID_GET_FILE_RESUME_HASH:
			{
				std::string s_filename;
				if(data->getStr(&s_filename)==false)
					break;

#ifdef CHECK_IDENT
				std::string ident;
				data->getStr(&ident);
				if(!FileServ::checkIdentity(ident))
				{
					Log("Identity check failed -2", LL_DEBUG);
					return false;
				}
#endif

				std::wstring o_filename=Server->ConvertToUnicode(s_filename);

				_i64 start_offset=0;
				bool offset_set=data->getInt64(&start_offset);

				Log("Sending file "+Server->ConvertToUTF8(o_filename), LL_DEBUG);

				std::wstring filename=map_file(o_filename);

				Log("Mapped name: "+Server->ConvertToUTF8(filename), LL_DEBUG);

				if(filename.empty())
				{
					char ch=ID_BASE_DIR_LOST;
					int rc=SendInt(&ch, 1);

					if(rc==SOCKET_ERROR)
					{
						Log("Error: Socket Error - DBG: Send BASE_DIR_LOST -1", LL_DEBUG);
						return false;
					}
					Log("Info: Base dir lost -1", LL_DEBUG);
					break;
				}

				cmd_id=id;

				if( id==ID_GET_FILE_RESUME_HASH )
				{
					hash_func.init();
				}

#ifdef _WIN32
				if(filename.size()<2 || (filename[0]!='\\' && filename[1]!='\\' ) )
				{
					filename=L"\\\\?\\"+filename;			
				}

				if(bufmgr==NULL)
				{
					bufmgr=new CBufMgr(NBUFFERS,READSIZE);
				}
#endif
				
#ifndef LINUX
#ifndef BACKUP_SEM
				hFile=CreateFileW(filename.c_str(), FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
#else
				hFile=CreateFileW(filename.c_str(), FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN, NULL);
#endif

				if(hFile == INVALID_HANDLE_VALUE)
				{
					hFile=NULL;
#ifdef CHECK_BASE_PATH
					std::wstring basePath=map_file(getuntil(L"/",o_filename)+L"/");
					if(!isDirectory(basePath))
					{
						char ch=ID_BASE_DIR_LOST;
						int rc=SendInt(&ch, 1);
						if(rc==SOCKET_ERROR)
						{
							Log("Error: Socket Error - DBG: Send BASE_DIR_LOST", LL_DEBUG);
							return false;
						}
						Log("Info: Base dir lost", LL_DEBUG);
						break;
					}
#endif
					
					char ch=ID_COULDNT_OPEN;
					int rc=SendInt(&ch, 1);
					if(rc==SOCKET_ERROR)
					{
						Log("Error: Socket Error - DBG: Send COULDNT OPEN", LL_DEBUG);
						return false;
					}
					Log("Info: Couldn't open file", LL_DEBUG);
					break;
				}

				currfilepart=0;
				sendfilepart=0;
				sent_bytes=start_offset;

				LARGE_INTEGER filesize;
				GetFileSizeEx(hFile, &filesize);

				curr_filesize=filesize.QuadPart;

				next_checkpoint=start_offset+c_checkpoint_dist;
				if(next_checkpoint>curr_filesize)
					next_checkpoint=curr_filesize;

				if( offset_set==false || id==ID_GET_FILE_RESUME || id==ID_GET_FILE_RESUME_HASH )
				{
					CWData data;
					data.addUChar(ID_FILESIZE);
					data.addUInt64(filesize.QuadPart);

					int rc=SendInt(data.getDataPtr(), data.getDataSize());
					if(rc==SOCKET_ERROR)
					{
						Log("Error: Socket Error - DBG: SendSize", LL_DEBUG);
						CloseHandle(hFile);
						hFile=NULL;
						return false;
					}
				}

				if(filesize.QuadPart==0)
				{
					CloseHandle(hFile);
					hFile=NULL;
					break;
				}

				for(_i64 i=start_offset;i<filesize.QuadPart && stopped==false;i+=READSIZE)
				{
					bool last;
					if(i+READSIZE<filesize.QuadPart)
						last=false;
					else
					{
						last=true;
						Log("Reading last file part", LL_DEBUG);
					}

					while(bufmgr->nfreeBufffer()==0 && stopped==false)
					{
						int rc;
						SleepEx(0,true);
						rc=SendData();
						if(rc==-1)
						{
							Log("Error: Send failed in file loop -1", LL_DEBUG);
							CloseThread(hFile);
						}
						else if(rc==0)
							SleepEx(1,true);
					}

					if( stopped==false )
						ReadFilePart(hFile, i, last);

					if(FileServ::isPause() )
					{
						DWORD starttime=GetTickCount();
						while(GetTickCount()-starttime<5000)
						{
							SleepEx(500,true);

							int rc=SendData();
							if(rc==-1)
							{
								Log("Error: Send failed in file pause loop -2", LL_DEBUG);
								CloseThread(hFile);
							}
						}
					}
				}

				while(bufmgr->nfreeBufffer()!=NBUFFERS && stopped==false)
				{
					SleepEx(0,true);
					int rc;
					rc=SendData();
					
					if( rc==2 && bufmgr->nfreeBufffer()!=NBUFFERS )
					{
						Log("Error: File end and not all Buffers are free!-1", LL_WARNING);
					}

					if(rc==-1)
					{
						Log("Error: Send failed in off file loop -3", LL_DEBUG);
						CloseHandle(hFile);
						hFile=NULL;
						break;
					}
					else if(rc==0)
						SleepEx(1,true);
				}

				if( stopped==false )
				{
					Log("Closed file.", LL_DEBUG);
					CloseHandle(hFile);
					hFile=NULL;
				}
#else //LINUX
				hFile=open64(Server->ConvertToUTF8(filename).c_str(), O_RDONLY|O_LARGEFILE);
				
				if(hFile == INVALID_HANDLE_VALUE)
				{
#ifdef CHECK_BASE_PATH
					std::wstring basePath=map_file(getuntil(L"/",o_filename)+L"/");
					if(!isDirectory(basePath))
					{
						char ch=ID_BASE_DIR_LOST;
						int rc=SendInt(&ch, 1);
						if(rc==SOCKET_ERROR)
						{
							Log("Error: Socket Error - DBG: Send BASE_DIR_LOST", LL_DEBUG);
							return false;
						}
						Log("Info: Base dir lost", LL_DEBUG);
						break;
					}
#endif
					hFile=0;
					char ch=ID_COULDNT_OPEN;
					int rc=SendInt(&ch, 1);
					if(rc==SOCKET_ERROR)
					{
						Log("Error: Socket Error - DBG: Send COULDNT OPEN", LL_DEBUG);
						return false;
					}
					Log("Info: Couldn't open file", LL_DEBUG);
					break;
				}
				
				currfilepart=0;
				sendfilepart=0;
				
				struct stat64 stat_buf;
				fstat64(hFile, &stat_buf);
				
				off64_t filesize=stat_buf.st_size;
				curr_filesize=filesize;
				
				if( offset_set==false || id==ID_GET_FILE_RESUME || id==ID_GET_FILE_RESUME_HASH )
				{
					CWData data;
					data.addUChar(ID_FILESIZE);
					data.addUInt64(filesize);

					int rc=SendInt(data.getDataPtr(), data.getDataSize() );	
					if(rc==SOCKET_ERROR)
					{
						Log("Error: Socket Error - DBG: SendSize", LL_DEBUG);
						CloseHandle(hFile);
						hFile=0;
						return false;
					}
				}
				
				if(filesize==0)
				{
					CloseHandle(hFile);
					hFile=0;
					break;
				}
				
				off64_t foffset=start_offset;

				unsigned int s_bsize=8192;

				if(id==ID_GET_FILE || id==ID_GET_FILE_RESUME )
				{
					s_bsize=32768;
					next_checkpoint=curr_filesize;
				}
				else
				{
					next_checkpoint=start_offset+c_checkpoint_dist;
					if(next_checkpoint>curr_filesize)
					    next_checkpoint=curr_filesize;
				}

				char *buf=new char[s_bsize];

				bool has_error=false;
				
				while( foffset < filesize )
				{
					size_t count=(std::min)((size_t)s_bsize, (size_t)(next_checkpoint-foffset));
					if( clientpipe==NULL && ( id==ID_GET_FILE || id==ID_GET_FILE_RESUME ) )
					{
						ssize_t rc=sendfile64(int_socket, hFile, &foffset, count);
						if(rc>0)
						{
							foffset+=rc;
						}
						else
						{
							Log("Error: Reading and sending from file failed", LL_DEBUG);
							CloseHandle(hFile);
							delete []buf;
							return false;
						}
					}
					else
					{
						ssize_t rc=read(hFile, buf, count);
						if(rc>0)
						{
							rc=SendInt(buf, rc);
							if(rc==SOCKET_ERROR)
							{
								Log("Error: Sending data failed");
								CloseHandle(hFile);
								delete []buf;
								return false;
							}
							else if(id==ID_GET_FILE_RESUME_HASH)
							{
								hash_func.update((unsigned char*)buf, rc);
							}
							
							foffset+=rc;
						}
						else
						{
							Log("Error: Reading from file failed", LL_DEBUG);
							CloseHandle(hFile);
							delete []buf;
							return false;
						}
						
						if(id==ID_GET_FILE_RESUME_HASH && foffset==next_checkpoint)
						{
							hash_func.finalize();
							SendInt((char*)hash_func.raw_digest_int(), 16);
							next_checkpoint+=c_checkpoint_dist;
							if(next_checkpoint>curr_filesize)
								next_checkpoint=curr_filesize;
							
							hash_func.init();
						}
					}
					if(FileServ::isPause() )
					{
						Sleep(500);
					}
				}
				
				CloseHandle(hFile);
				delete []buf;
				hFile=0;
#endif

			}break;
		case ID_GET_FILE_BLOCKDIFF:
			{
				bool b=GetFileBlockdiff(data);
				if(!b)
					return false;
			}break;
		case ID_BLOCK_REQUEST:
			{
				if(state==CS_BLOCKHASH)
				{
					Handle_ID_BLOCK_REQUEST(data);
				}
			}break;
		}
	}
	if( stopped==true )
		return false;
	else
		return true;
}