/* OpenWebSpider
*
 *  Authors:     Stefano Alimonti AND Stefano Fantin
 *  Version:     0.7
 *  E-Mails:     shen139 [at] openwebspider (dot) org AND stefanofantinguz@yahoo.it
*
*
* This file is part of OpenWebSpider
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*/


#ifndef __SERVR
#define __SERVR

#ifdef WIN32
unsigned __stdcall 
#else
void* 
#endif
StartOWSServer(LPVOID port)
{
	int ret;
	char *logConnection;
	struct sHandleConnection* struct_connection;
	SOCKADDR_IN owsServer_client_addr;
	unsigned int sin_size;
	
	sin_size=sizeof(SOCKADDR_IN);
	
	memset(listAccess,0,sizeof(listAccess));
	
	ret = ListenToPort((int)port, &OWS_Server_fd);
	
	switch(ret)
	{
	case -1:
		printf("\r\n\r\nOpenWebSpider Server: socket() error\r\n\r\n");
		ERROR_LOG("socket() error")
			iQuit = 1;
		break;
	case -2:
		printf("\r\n\r\nOpenWebSpider Server: bind() error\r\n\r\n");
		ERROR_LOG("bind() error")
			iQuit = 1;
		break;
	case -3:
		printf("\r\n\r\nOpenWebSpider Server: listen() error\r\n\r\n");
		ERROR_LOG("listen() error")
			iQuit = 1;
		break;
	case 1:
		/* wait for a connection */
		while(1)
		{
			if(iQuit==1)
				break;
			
			OWS_Server_fd_conn=accept(OWS_Server_fd, (struct sockaddr *)&owsServer_client_addr, &sin_size);
			
#ifdef WIN32
			if (OWS_Server_fd_conn==INVALID_SOCKET)
#else
				if (OWS_Server_fd_conn<0)
#endif
					continue;
				
				if(iQuit==1)
					break;
				
				logConnection = malloc(100);
				sprintf(logConnection,"[%s] Connection enstablished",inet_ntoa(owsServer_client_addr.sin_addr));
				OWS_LOG(logConnection);
				FREE(logConnection);
				
				//memory is freed in the function HandleConnection()
				struct_connection = malloc(sizeof(struct sHandleConnection));
				
				struct_connection->sock = OWS_Server_fd_conn;
				memcpy(&struct_connection->client,&owsServer_client_addr, sizeof(SOCKADDR_IN));
				CreateHandleConnectionThread(struct_connection);
		}
		
		closesocket(OWS_Server_fd);
		
		ExitThread(0);
		break;
	}
	
	closesocket(OWS_Server_fd);
	ExitThread(0);
	/* *** */
	return 0;
}

#ifdef WIN32
unsigned __stdcall 
#else
void* 
#endif
HandleConnection(void* connection)
{
	SOCKET sock = ((struct sHandleConnection*)connection)->sock;
	char bufIn[10000];
	char commandLine[MAXCOMMANDSIZE];
	int x;
	char *logConnection;
	unsigned long lIpAddr;
	unsigned int LoginOK;
	
    memcpy(&lIpAddr,&(((struct sHandleConnection*)connection)->client).sin_addr, sizeof(unsigned long));
	
	while(1)
	{
		if(iQuit==1)
			break;
		
		if(RecvPackets(&sock,bufIn, sizeof(bufIn))>3)
		{
			for(x=0;x<MAXCOMMANDSIZE;x++)
			{
				if(bufIn[x]=='\r' || bufIn[x]=='\n'|| bufIn[x]=='\0')
					break;
				commandLine[x] = bufIn[x];
			}
		}
		else
			break;
		
		commandLine[x] = 0;
		
		strtrim(commandLine,commandLine);
		
		logConnection = malloc(1000);
		snprintf(logConnection,999,"[%s] Requested: --%s-- ",inet_ntoa( (((struct sHandleConnection*)connection)->client).sin_addr), commandLine);
		OWS_LOG(logConnection);
		FREE(logConnection);
		
		/* is login needed? */
		LoginOK = 0;
		if(OWS_SERVER_PASSWORD[0]!=0)   //yes
		{
			int c;
			
			for(c=0;c<OWSSERVERMAXLOGINS;c++)
			{
				if(listAccess[c].LoginOKIP == lIpAddr)
					LoginOK = 1;
			}
		}
		else        //no
			LoginOK = 1;
		
		if( HandleRequest(sock,commandLine,LoginOK, lIpAddr) == 0 )
		{
			owsServer_HTML_Header(sock, LoginOK);
			__SERVR_COMMANDERR;
			owsServer_HTML_Footer(sock);
			
			logConnection = malloc(1000);
			snprintf(logConnection,999,"[%s] Error: --%s--",inet_ntoa( (((struct sHandleConnection*)connection)->client).sin_addr) , commandLine);
			OWS_LOG(logConnection);
			FREE(logConnection);
		}
		
		break;
	}
	
	FREE(connection);
	
	closesocket(sock);
	
	ExitThread(0);
	return 0;
}

int HandleRequest(SOCKET sock, char* command, unsigned int login_status, unsigned long IpAddr)
{
	char* bufOut;
	time_t long_time;
	struct tm *newtime;
	char key[MAXCONFKEYSIZE];
	char argument[MAXARGUMENTSIZE];
	char* tmpP;
	unsigned int KeyNArgAreOK;
	
    //printf("\n_%s_\n",command);
	
    if(strnicmp(command,"get ",4)==0)
        command = command + 4;
    else
        return 0;
	
	time( &long_time ); 
	newtime=localtime(&long_time);
	
	key[0]=argument[0]=0;
	
	KeyNArgAreOK = 0;	/*false*/
	
    ReplaceChr(command,'?',' ');
	
	tmpP=strchr( strtrim(command, command) ,' ');
	
	if( tmpP && tmpP-command<MAXKEYWORDSIZE && tmpP-command>0 )
	{
		memset(key,0,MAXCONFKEYSIZE);
		
		strncpy(key,command,MIN(tmpP-command,MAXKEYWORDSIZE) );
		
		strtrim(key,key);
		
		if( strlen(key)>0 && command+strlen(command) - tmpP - 1 < MAXARGUMENTSIZE )
		{
			strcpy(argument, tmpP +1);
			strtrim(argument,argument);
			
			ReplaceChr(argument,'\r',0);
			ReplaceChr(argument,'\n',0);
			
			if(strlen(argument)>0)
				KeyNArgAreOK = 1;	/* OK */
		}
	}
	else
		if(strlen(command) > MAXKEYWORDSIZE-1)	/* a single command can't be longer than MAXKEYWORDSIZE-1 */
			return 0;
		else
		{
			strcpy(key,command);
			KeyNArgAreOK = 1;	/* OK */
		}
		
		if(KeyNArgAreOK == 0)
			return 0;
		
		/* check the session */
		CheckSession(IpAddr);
		
		/* ******************************************************************************** */
		
		if( stricmp(key,"/login")==0 || login_status==0)
		{
			if(argument[0]==0 || strnicmp(argument,"http/1.",7)==0 )
			{
				owsServer_HTML_Header(sock, login_status);
				
				bufOut = malloc(10000);
				strcpy(bufOut,"<div align='center'><form name='login_form' method='get' action='login'> \r\n");
				strcat(bufOut,"  <input type='text' name='password' size='40' maxlength='50'><br> \r\n");
				strcat(bufOut,"  <input type='submit' name='submit' value='Login'> \r\n");
				strcat(bufOut,"</form> </div>\r\n");
				SEND(sock, bufOut);
				
				FREE(bufOut);
				
				owsServer_HTML_Footer(sock);
				
				return 1;
			}
			
			if(argument[0]!=0 && strnicmp(argument,"http/1.",7)!=0)
			{
				char *password;
				
				ReplaceChr(argument,'&','\0');
				
				password = malloc(strlen(argument) + 1);
				
				ReplaceStr(argument,password,"password="," ");

				strtrim(password,password);

				ReplaceChr(password,' ','\0');
				
				if( strcmp(OWS_SERVER_PASSWORD, password ) == 0 )
				{
					int c;
					
					login_status = 1;
					
					owsServer_HTML_Header(sock, login_status);
					
					SEND(sock,"\r\n<div align='center'>Login OK</div>\r\n");
					
					for(c=0;c<OWSSERVERMAXLOGINS;c++)
					{
						if(listAccess[c].LoginOKIP == 0)
						{
							listAccess[c].LoginOKIP = IpAddr;
							listAccess[c].LastAccessMS = GetTickCount();
							
							break;
						}
					}
				}
				else
				{
					owsServer_HTML_Header(sock, login_status);
					
					SEND(sock,"\r\n<div align='center'>Login Failed</div>\r\n");
				}
				
				FREE(password);
				
				owsServer_HTML_Footer(sock);
			}
			
			return 1;
		}
		
		/* login needed */
		if(login_status == 0)   // ?|?
			return 0;
		
		/* ********************************** */
		
		/* index - main request */
		if( strcmp(key,"/")==0 || stricmp(key,"/help")==0 )
		{
			/* handle home/Help page*/
			owsServer_HTML_Header(sock, login_status);
			
			bufOut = malloc(10000);
			strcpy(bufOut,"<pre>[--HELP--]\r\n");
			strcat(bufOut,"help             : this help :-)\r\n");
			strcat(bufOut,"login [password] : login to the server \r\n");
			strcat(bufOut,"                   (required if the server is password protected) \r\n");
			strcat(bufOut,"exit             : close this connection and quit the spider\r\n");
			strcat(bufOut,"pause            : Pause mode: ON\r\n");
			strcat(bufOut,"play             : Pause mode: OFF\r\n");
			strcat(bufOut,"stats            : print some brief statistics\r\n");
			strcat(bufOut,"search [query]   : search in the current index \r\n");
			strcat(bufOut,"                   (output in XML)\r\n</pre>");
			bufOut[10000-1]=0;
			
			SEND(sock, bufOut);
			
			FREE(bufOut);
			
			owsServer_HTML_Footer(sock);
			return 1;
		}
		
		if( strcmp(key,"/logout")==0 )
		{
			int c;
			
			for(c=0;c<OWSSERVERMAXLOGINS;c++)
			{
				if(listAccess[c].LoginOKIP == IpAddr)
				{
					listAccess[c].LoginOKIP = 0;
					listAccess[c].LastAccessMS = 0;
				}
				login_status = 0;
			}
			owsServer_HTML_Header(sock, login_status);
			
			SEND(sock,"\r\n<div align='center'>Logged out!</div>\r\n");
			
			owsServer_HTML_Footer(sock);
			return 1;
		}
		
		if( stricmp(key,"/pause")==0 )
		{
			iStop = 1;
			owsServer_HTML_Header(sock, login_status);
			
			SEND(sock,"\r\n<div align='center'>Pause Mode: ON</div>\r\n");
			
			owsServer_HTML_Footer(sock);
			return 1;
		}
		
		if( stricmp(key,"/play")==0 )
		{
			iStop = 0;
			
			owsServer_HTML_Header(sock, login_status);
			SEND(sock,"\r\n<div align='center'>Pause Mode: OFF</div>\r\n");
			owsServer_HTML_Footer(sock);
			return 1;
		}
		
		if( stricmp(key,"/exit")==0 )
		{
			owsServer_HTML_Header(sock, login_status);
			
			SEND(sock,"\r\n<div align='center'>Bye bye</div>\r\n");
			
			owsServer_HTML_Footer(sock);
			
			iQuit = 1;
			return 1;
		}
		
		if( stricmp(key,"/switch")==0)
		{
			owsServer_HTML_Header(sock, login_status);
			
			/* are we already switching? */
			if(iDoNextHost == 1)
			{
				char* genURL;
				
				/* if nextHost is NOT NULL we are switching to a user-defined host*/
				if(nextHost)
				{
					genURL = malloc( MAXURLSIZE + 1);
					
					GenerateURL(*nextHost,genURL);
					
					bufOut = malloc(100 + MAXURLSIZE );
					
					sprintf(bufOut, "\r\n<div align='center'>Switching to %s ...</div>\r\n", genURL);
					
					SEND(sock, bufOut);
					
					FREE(bufOut);
					
					FREE(genURL);
				}
				/* we are switching to the next host in the DB*/
				else
					SEND(sock,"\r\n<div align='center'>Switching to the next host...</div>\r\n");
				
				owsServer_HTML_Footer(sock);
				
				return 1;
			}
			
			/* we aren't switching */
			if(argument[0]==0 || strnicmp(argument,"http/1.",7)==0 )
			{
				bufOut = malloc(10000);
				strcpy(bufOut,"<div align='center'><form name='switch_form' method='get'> \r\n");
				strcat(bufOut,"  http://<input type='text' name='URL' size='50' maxlength='50'><br> \r\n");
				strcat(bufOut,"  <input type='submit' name='submit' value='Crawl'> \r\n");
				strcat(bufOut,"</form></div> \r\n");
				strcat(bufOut,"<br><div align='center'><a href='/next'>Switch to the next URL in the DB</a></div> \r\n");
				SEND(sock, bufOut);
				
				FREE(bufOut);
				
				owsServer_HTML_Footer(sock);
				
				return 1;
			}
			
			if(argument[0]!=0 && strnicmp(argument,"http/1.",7)!=0)
			{
				char *URL;
				char *httpURL;
				
				ReplaceChr(argument,'&','\0');
				
				URL = malloc( strlen(argument) + 10);
				
				ReplaceStr(argument,URL,"URL="," ");
				
				/* control of length of URL */
				if( strlen(URL) >= MAXURLSIZE)
				{
					SEND(sock,"\r\n<div align='center'>Wrong URL</div>\r\n");
					FREE(URL);
					owsServer_HTML_Footer(sock);
					
					return 1;
				}
				
				httpURL = malloc( MAXURLSIZE + 10);
				
				strcpy(httpURL, "http://");
				strcat(httpURL, URL);
				
				FREE(URL);
				
				/* nextHost is freed in ReturnFirstUrl() */
				nextHost = malloc(sizeof(struct sHost));
				
				if(ParseUrl(httpURL, nextHost, NULL)==-1)
				{
					FREE(nextHost);
					nextHost = NULL;
					
					SEND(sock,"\r\n<div align='center'>Wrong URL</div>\r\n");
				}
				else
				{
					char* genURL;
					
					iDoNextHost = 1;
					
					genURL = malloc( MAXURLSIZE + 10);
					
					
					GenerateURL(*nextHost,genURL);
					
					bufOut = malloc( 100 + MAXURLSIZE );
					
					sprintf(bufOut, "\r\n<div align='center'>Switching to %s ...</div>\r\n", genURL);
					
					SEND(sock, bufOut);
					
					FREE(bufOut);
					
					FREE(genURL);
				}
				
				
				FREE(httpURL);
			}
			owsServer_HTML_Footer(sock);
			
			return 1;
	}
	
    if( stricmp(key,"/next")==0 )
	{
		iDoNextHost = 1;
        owsServer_HTML_Header(sock, login_status);
		SEND(sock,"\r\n<div align='center'>Switching to the next host...</div>\r\n");
        owsServer_HTML_Footer(sock);
		return 1;
	}
	
    if( stricmp(key,"/search")==0)
	{
        if(argument[0]==0 || strnicmp(argument,"http/1.",7)==0 )
        {
            owsServer_HTML_Header(sock, login_status);
			
			bufOut = malloc(10000);
			strcpy(bufOut,"<div align='center'><form name='search_form' method='get'> \r\n");
            strcat(bufOut,"  <input type='text' name='query' size='40' maxlength='50'><br> \r\n");
            strcat(bufOut,"  <input type='hidden' name='n' value='0'> \r\n");
            strcat(bufOut,"  <input type='submit' name='submit' value='Search'> \r\n");
            strcat(bufOut,"</form></div> \r\n");
			SEND(sock, bufOut);
			
			FREE(bufOut);
			
            owsServer_HTML_Footer(sock);
			
            return 1;
        }
		
		if(argument[0]!=0 && strnicmp(argument,"http/1.",7)!=0)
		{
			char *query;
            
            ReplaceChr(argument,'&','\0');
			
            query = malloc( strlen(argument) + 1);
			
            ReplaceStr(argument,query,"query="," ");

            strtrim(query,query);

			/* control of the length of query */
			if(strlen(query)<MAXUSERQUERYSIZE)
				IndexedSearchXML2Sock(&gMysqlDB2,query, sock);
			
            FREE(query);
		}
		
        
		return 1;
	}
	
	if( stricmp(key,"/stats")==0 )
	{
        owsServer_HTML_Header(sock, login_status);
		
		bufOut = malloc(10000);
        
		snprintf(bufOut,10000-1,"<pre>Status: %s\r\n  - Host:\t\t%s\r\n  - Pages:\t\t%i\r\n  - Downloaded:\t\t%i Kb\r\n  - Scan time: %is (%s - %i:%i:%i)</pre>\r\n\r\n",(iStop==1)?"PAUSED":"OK",IndexingHost.Host,nPagesViewed,(int)bytesDownloaded/1024,(int)((GetTickCount()-startTimeMS)/1000),startTime,newtime->tm_hour ,newtime->tm_min ,newtime->tm_sec);
		bufOut[10000-1]=0;
		
		SEND(sock, bufOut);
		FREE(bufOut);
		
        owsServer_HTML_Footer(sock);
		
		return 1;
	}
	
	return 0;
}

void owsServer_HTML_Header(SOCKET sock, unsigned int login_status)
{
	char* bufOut;
    bufOut = malloc(10000);
	
    strcpy(bufOut,"<html> \r\n");
    strcat(bufOut,"<head> \r\n");
    strcat(bufOut,"<title>OWS Serverv0.6</title> \r\n");
	strcat(bufOut,"<style type='text/css'> \r\n");
	strcat(bufOut,"<!-- \r\n");
	strcat(bufOut,".title { \r\n");
	strcat(bufOut,"     font-size: 24px; \r\n");
	strcat(bufOut,"	    font-family: Geneva, Arial, Helvetica, sans-serif; \r\n");
	strcat(bufOut,"} \r\n");
	strcat(bufOut,".menu { \r\n");
	strcat(bufOut,"	    font-size: 16px; \r\n");
	strcat(bufOut,"     font-family: Geneva, Arial, Helvetica, sans-serif; \r\n");
	strcat(bufOut,"} \r\n");
	strcat(bufOut,"--> \r\n");
	strcat(bufOut,"</style> \r\n");
	
    strcat(bufOut,"</head> \r\n");
    strcat(bufOut,"<table style='border:1px dashed #000000; ' cellpadding='2' cellspacing='2' width='780' align='center'> \r\n");
    strcat(bufOut,"  <tr> \r\n");
    strcat(bufOut,"    <td bgcolor='#BBFFBB' colspan='2' align='center' style='border:1px dashed #000000; '><span class='title'>OWS Server Administration Panel</span></td> \r\n");
    strcat(bufOut,"  </tr> \r\n");
    strcat(bufOut,"  <tr> \r\n");
    strcat(bufOut,"    <td  class='menu' style='border:1px dashed #000000; width:60px; ' valign='top' bgcolor='#DFFFDF' width='60'> \r\n");
	
    if(login_status == 0)
    {
        strcat(bufOut,"      <a href='login'>Login</a><br>\r\n");
    }
    else
    {
		if(iStop==1)
			strcat(bufOut,"      <a href='/play'>Play</a><br> \r\n");
		else
			strcat(bufOut,"      <a href=\"/pause\">Pause</a><br> \r\n");
		
        strcat(bufOut,"      <a href=\"/switch\">Switch</a><br> \r\n");
		
        strcat(bufOut,"      <a href=\"/stats\">Stats</a><br> \r\n");
        strcat(bufOut,"      <a href=\"/search\">Search</a><br> \r\n");
        strcat(bufOut,"      <a href=\"/help\">Help</a><br> \r\n");
		
        /* this server isn't password protected! So we don't need to logout */
        if(OWS_SERVER_PASSWORD[0]!=0)
            strcat(bufOut,"      <a href=\"/logout\">Logout</a><br> \r\n");
		
        strcat(bufOut,"      <a href=\"/exit\">Exit</a><br></td> \r\n");
    }
    strcat(bufOut,"    <td width='710' class='menu'> \r\n");
    
    SEND(sock,bufOut);
	
    FREE(bufOut);
}

void owsServer_HTML_Footer(SOCKET sock)
{
	char* bufOut;
    bufOut = malloc(1000);
	
    strcpy(bufOut,"&nbsp;</td> \r\n");
    strcat(bufOut,"  </tr> \r\n");
    strcat(bufOut,"</table> \r\n");
    strcat(bufOut,"<br> \r\n");
    strcat(bufOut,"<br> \r\n");
    strcat(bufOut,"<div align='center'>Official Web Site: &nbsp;&nbsp;<a href='http://www.openwebspider.org/'>http://www.openwebspider.org/</a></div> \r\n");
    strcat(bufOut,"<br> \r\n");
    strcat(bufOut,"<br> \r\n");
    strcat(bufOut,"<body> \r\n");
    strcat(bufOut,"</body> \r\n");
    strcat(bufOut,"</html> \r\n");
    
    SEND(sock,bufOut);
	
    FREE(bufOut);
}

void CheckSession(unsigned long IpAddr)
{
	int c;
	
    for(c=0;c<OWSSERVERMAXLOGINS;c++)
    {
        /* current session */
        /* set last access */
        if(listAccess[c].LoginOKIP == IpAddr)
            listAccess[c].LastAccessMS = GetTickCount();
        else
			/* check the other sessions */
			if(listAccess[c].LoginOKIP != 0)
			{
				/* this IP last access is more then 10 minutes ago */
				if( listAccess[c].LastAccessMS  >  GetTickCount()    && 
					listAccess[c].LastAccessMS  -  GetTickCount() > (10 * 60 * 1000) )
				{
					/* logout */
					listAccess[c].LoginOKIP = 0;
					listAccess[c].LastAccessMS = 0;
				}
				
				/* LastAccessMS  <  GetTickCount (update it) [simple solution] */
				if( listAccess[c].LastAccessMS  <  GetTickCount() )
					listAccess[c].LastAccessMS = GetTickCount();
			}
    }
	
}

#endif


/*EOF*/


