/* -------------------------------------------------------------------- */
/* SMS Client, send messages to mobile phones and pagers		*/
/*									*/
/* snppd.c								*/
/*									*/
/*  Copyright (C) 1997,1998,1999 Angelo Masci				*/
/*									*/
/*  This library is free software; you can redistribute it and/or	*/
/*  modify it under the terms of the GNU Library General Public		*/
/*  License as published by the Free Software Foundation; either	*/
/*  version 2 of the License, or (at your option) any later version.	*/
/*									*/
/*  This library 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	*/
/*  Library General Public License for more details.			*/
/*									*/
/*  You should have received a copy of the GNU Library General Public	*/
/*  License along with this library; if not, write to the Free		*/
/*  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.	*/
/*									*/
/*  You can contact the author at this e-mail address:			*/
/*									*/
/*  angelo@styx.demon.co.uk						*/
/*									*/
/* --------------------------------------------------------------------
   $Id$
   -------------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

#if defined(LINUX)
#include <getopt.h>
#endif

#include "lock/lock.h"
#include "server.h"
#include "logfile/logfile.h"
#include "common/common.h"
#include "version.h"

/* -------------------------------------------------------------------- */

#if !defined(MSNPPDLOGFILE)
#error "MSNPPDLOGFILE undefined"
#else
#define LOGFILE         MSNPPDLOGFILE
#endif

#if !defined(MSNPPDLOGLEVEL)
#error "MSNPPDLOGLEVEL undefined" 
#else
#define LOGLEVEL	MSNPPDLOGLEVEL
#endif

#if !defined(MVERSION)
#error "MVERSION undefined"
#else
#define VERSION MVERSION
#endif

/* -------------------------------------------------------------------- */

#define SNPP_PORT	444		/* Standard port number 	*/
					/* assigned for snpp traffic	*/



#define SNPPD_SPOOLDIR	"/var/spool/sms"
#define SNPPD_LOCKDIR	"locks"
#define SNPPD_LOCKFILE   SNPPD_SPOOLDIR SNPPD_LOCKDIR "/snppd.pid"

/* -------------------------------------------------------------------- */

#define ERROR_STATE	-2
#define EXIT_STATE	-1
#define LOGIN_STATE	0
#define PAGE_STATE 	1
#define MESSAGE_STATE	2
#define SEND_STATE	3
#define HELP_STATE	4

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void gateway(int new_fd)
{
	char	buf[MAX_STRING_LEN],
		host_name[512],
		ip_address[512];

	int 	state;


	if (get_client_information(new_fd, host_name, ip_address) == 0)
	{	lprintf(LOG_STANDARD, "Connection from %s [%s]\n", host_name, ip_address);
	}


	hprintf(new_fd, "220 SNPP Gateway Ready\n");

	state = LOGIN_STATE;
	while ((state != EXIT_STATE) &&
	       (state != ERROR_STATE) &&
	       (hgets(buf, MAX_STRING_LEN, new_fd) != NULL))
	{
		if (strncasecmp(buf, "PAGE", 4) == 0)
		{
			if (state == LOGIN_STATE)
			{
				hprintf(new_fd, "250 Pager ID Accepted\n");
				state = PAGE_STATE;
			}
			else
			{	state = ERROR_STATE;
			}
		}
		else
		if (strncasecmp(buf, "MESS", 4) == 0)
		{
			if (state == PAGE_STATE)
			{
				hprintf(new_fd, "250 Message OK\n");
				state = MESSAGE_STATE;
			}
			else
			{	state = ERROR_STATE;
			}
		}
		else
		if (strncasecmp(buf, "SEND", 4) == 0)
		{	
			if (state == MESSAGE_STATE)
			{
				hprintf(new_fd, "250 Message Sent Successfully\n");
				state = SEND_STATE;
			}
			else
			{	state = ERROR_STATE;
			}
		}
		else
		if (strncasecmp(buf, "QUIT", 4) == 0)
		{
			hprintf(new_fd, "221 OK, Goodbye\n");
			state = EXIT_STATE;
		}
		else
		if (strncasecmp(buf, "RESE", 4) == 0)
		{
			hprintf(new_fd, "250 RESET OK\n");
			state = LOGIN_STATE;
		}
		else
		if (strncasecmp(buf, "HELP", 4) == 0)
		{
			hprintf(new_fd, "214 PAGE <Pager ID>\n");
			hprintf(new_fd, "214 MESS <Alpha or Numeric Message>\n");
			hprintf(new_fd, "214 SEND\n");
			hprintf(new_fd, "214 QUIT\n");
			hprintf(new_fd, "250 End of Help Information\n");

			state = LOGIN_STATE;
		}
		else
		{	state = ERROR_STATE;
		}

		if (state == ERROR_STATE)
		{	hprintf(new_fd, "421 Error Connection Terminated\n");
		}
	}			
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void usage(char *file)
{
	lprintf(LOG_STANDARD, "Usage: %s [-l loglevel] [-p port]\n", file);
	lprintf(LOG_STANDARD, "       %s -v\n", file);
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
void release_lock(void)
{	resource_unlock(SNPPD_LOCKFILE);
}

/* -------------------------------------------------------------------- */
/* -------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
	int 	c,
		port;
	char	*ptr;

struct 	sockaddr 
		sa_client;


	/* ---------------------------- */

	set_logfile(LOGFILE);
	set_loglevel(LOGLEVEL);
	set_consolelog(TRUE);

	/* ---------------------------- */

	port = SNPP_PORT;

	while ((c = getopt (argc, argv, "p:l:v")) != -1)
        {
                switch (c)
                {
                        case 'p':  
				port = (int)strtol(optarg, &ptr, 10);
                                break;

                        case 'l':  
				set_loglevel((int)strtol(optarg, &ptr, 10));
				if (ptr == optarg)
				{
					lprintf(LOG_ERROR, "Option l requires an argument\n");
	     	                        usage(argv[0]);
                	                exit(-1);
				}
                                
                                break;
                        case 'v':
				lprintf(LOG_STANDARD, "%s %s\n", argv[0], VERSION);
                                exit(0);


                        case '?':
                                lprintf(LOG_ERROR, "Unknown option `-%c'\n", optopt);
                                usage(argv[0]);
                                exit(-1);

                        default:
                                abort ();
                }
        }

	if ((argc - optind) != 0)
	{	usage(argv[0]);
		exit(-1);
	}

	/* ---------------------------- */

	c = sizeof(sa_client);
	if (getpeername(fileno(stdin), &sa_client, &c) < 0)
	{
		/* getpeername() fails if fd isn't a 	*/
		/* socket. If this is the case we can 	*/
		/* assume that we aren't running	*/
		/* from inetd and should startup and	*/
		/* as and run as a daemon ourselves.	*/

		lprintf(LOG_STANDARD, "Starting SNPPD Standalone Server deamon...\n");

		if (server_main(port, gateway, SNPPD_LOCKFILE) == -1)
		{	lprintf(LOG_STANDARD, "Failed to start SNPPD Standalone Server deamon\n");
			exit(-1);
		}
	}
	else
	{	set_consolelog(FALSE);
		lprintf(LOG_STANDARD, "Starting SNPPD Server as an INETD service\n");
		gateway(fileno(stdin));
	}

	return 0;
}

