/*
 * Starnet Data Accounting Client
 * Open Source Version, 1.0
 *
 * February 2000 Matt Chapman and Shuying Wang
 * Comments to <matthewc@cse.unsw.edu.au>
 */

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define SDAS_HOST	"129.94.197.99"
#define SDAS_PORT	8000
#define CLIENT_VERSION	"Linux-Open-1.0"

#define LOGON		1
#define LOGOFF		2

/* Prompt for and read a line of input */
int read_line(char *buffer, int size, char *prompt, int hide_input)
{
	struct termios saved_attr, new_attr;
	char *p;

	printf("%s", prompt);

	if (hide_input)
	{
		tcgetattr(STDIN_FILENO, &saved_attr);
		new_attr = saved_attr;
		new_attr.c_lflag &= ~ECHO;
		tcsetattr(STDIN_FILENO, TCSANOW, &new_attr);
	}

	if (fgets(buffer, size, stdin) == NULL)
		return -1;

	p = strchr(buffer, '\n');
	if (p != NULL)
		*p = 0;

	if (hide_input)
	{
		printf("\n");
		tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
	}

	return 0;
}

/* Establish a TCP connection */
int connect_server(char *server)
{
	struct hostent *nslookup;
	struct sockaddr_in servaddr;
	int sock;

	if ((nslookup = gethostbyname(server)) != NULL)
	{
		memcpy(&servaddr.sin_addr, nslookup->h_addr, sizeof(servaddr.sin_addr));
	}
	else if (!(servaddr.sin_addr.s_addr = inet_addr(server)))
	{
		fprintf(stderr, "%s: unable to resolve host\n", server);
		return -1;
	}

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("socket");
		return -1;
	}
 
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SDAS_PORT);
 
	if (connect(sock, (struct sockaddr *)&servaddr, sizeof(struct sockaddr)) < 0)
	{
		perror("connect");
		close(sock);
		return -1;
	}

	return sock;
}

/* Get a string representing the local IP address of a socket */
char *get_localip(int sock)
{
	struct sockaddr_in cliaddr;
	socklen_t len = sizeof(cliaddr);

	getsockname(sock, &cliaddr, &len);
	return inet_ntoa(cliaddr.sin_addr);
}

/* Encode a string using a sliding Caesar cipher (length 7) */
void encode(char *string, int length)
{
	int i;

	for (i = 0; i < length; i++)
	{
		string[i] += i % 7;
	}
}

/* Decode a string using a sliding Caesar cipher (length 7) */
void decode(char *string, int length)
{
	int i;

	for (i = 0; i < length; i++)
	{
		string[i] -= i % 7;
	}
}

/* Program entrypoint */
int main(int argc, char *argv[])
{
	char buffer[128];
	char username[32];
	char password[32];
	int got_username = 0, got_password = 0;
	int operation = LOGON;
	char *opname = "on";
	int sock, len;
	char *p;

	/* Log off if name of executable is sdalogoff */
	p = strrchr(argv[0], '/');
	if (p == NULL)
		p = argv[0];
	else
		p++;

	if ((strcmp(p, "sdalogout") == 0) || (strcmp(p, "sdalogoff") == 0))
	{
		operation = LOGOFF;
		opname = "off";
		got_password = 1;
		strncpy(password, "x", sizeof(password));
	}

	/* Read username and password from command line if present */
	if (argc >= 2)
	{
		got_username = 1;
		strncpy(username, argv[1], sizeof(username));
	}

	if (argc >= 3)
	{
		got_password = 1;
		strncpy(password, argv[1], sizeof(password));
	}

	printf("Starnet Data Accounting Client (%s) - Logging %s\n",
	       CLIENT_VERSION, opname);

	/* Prompt for username and password if necessary */
	if (!got_username &&
	    (read_line(username, sizeof(username), "Username: ", 0) == -1))
		return 1;

	if (!got_password &&
	    (read_line(password, sizeof(password), "Password: ", 1) == -1))
		return 1;

	/* Connect to server */
	sock = connect_server(SDAS_HOST);
	if (sock == -1)
		return 1;

	/* Send request to server */
	len = snprintf(buffer, sizeof(buffer), "%d %s %s %s 0 %s ",
		       operation, username, password, get_localip(sock),
		       CLIENT_VERSION);

	encode(buffer, len);
	write(sock, buffer, len);

	/* Receive response */
	len = read(sock, buffer, sizeof(buffer)-1);
	if (len < 0)
	{
		perror("read");
		return 1;
	}

	/* Decode response */
	buffer[len] = 0;
	decode(buffer, len);
	printf("%s\n", buffer);

	close(sock);
	return 0;
}
