/* OpenWebSpider
*
 *  Authors:     Stefano Alimonti AND Stefano Fantin
 *  Version:     0.8
 *  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
#include <stdint.h>

#ifdef WIN32
unsigned __stdcall 
#else
void* 
#endif


StartOWSServer(LPVOID port)
{
    int intPort = (int)(intptr_t)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(intPort, &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);
		snprintf(logConnection,999,"[%s] Requested: --%.900s-- ",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);
			snprintf(logConnection,999,"[%s] Error: --%.900s--",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 && (size_t)(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);
            if (!bufOut) {
                return 1;
            }

            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);
            if (!password) {
                owsServer_HTML_Header(sock, login_status);
                SEND(sock, "\r\n<div align='center'>Login Failed</div>\r\n");
                owsServer_HTML_Footer(sock);
                return 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);
        if (!bufOut) {
            owsServer_HTML_Footer(sock);
            return 1;
        }

        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);
                if (!genURL) {
                    owsServer_HTML_Footer(sock);
                    return 1;
                }

                GenerateURL(*nextHost, genURL);

                bufOut = malloc(100 + MAXURLSIZE);
                if (!bufOut) {
                    FREE(genURL);
                    owsServer_HTML_Footer(sock);
                    return 1;
                }

                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);
            if (!bufOut) {
                owsServer_HTML_Footer(sock);
                return 1;
            }

            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);
            if (!URL) {
                SEND(sock, "\r\n<div align='center'>Wrong URL</div>\r\n");
                owsServer_HTML_Footer(sock);
                return 1;
            }

            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);
            if (!httpURL) {
                FREE(URL);
                owsServer_HTML_Footer(sock);
                return 1;
            }

            strcpy(httpURL, "http://");
            strcat(httpURL, URL);

            FREE(URL);

            /* nextHost is freed in ReturnFirstUrl() */
            nextHost = malloc(sizeof(struct sHost));
            if (!nextHost) {
                FREE(httpURL);
                owsServer_HTML_Footer(sock);
                return 1;
            }

            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);
                if (!genURL) {
                    FREE(nextHost);
                    nextHost = NULL;
                    FREE(httpURL);
                    owsServer_HTML_Footer(sock);
                    return 1;
                }

                GenerateURL(*nextHost, genURL);

                bufOut = malloc(100 + MAXURLSIZE);
                if (!bufOut) {
                    FREE(genURL);
                    FREE(nextHost);
                    nextHost = NULL;
                    FREE(httpURL);
                    owsServer_HTML_Footer(sock);
                    return 1;
                }

                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);
            if (!bufOut) {
                owsServer_HTML_Footer(sock);
                return 1;
            }

            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);
            if (!query) {
                return 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);
        if (!bufOut) {
            owsServer_HTML_Footer(sock);
            return 1;
        }

        snprintf(
            bufOut,
            10000 - 1,
            "<pre>Status: %s\r\n  - Host:\t\t%s\r\n  - Pages:\t\t%i\r\n  - Downloaded:\t\t%llu Kb\r\n  - Scan time: %is (%s - %i:%i:%i)</pre>\r\n\r\n",
            (iStop == 1) ? "PAUSED" : "OK",
            IndexingHost.Host,
            nPagesViewed,
            (unsigned long long)(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*/

