/* Internet rdate client
 * Author: Brian Teravskis, WD0EFL
 * Date: 03/30/92
 *
 * Based on RFC868 Time Protocol
 *
 * Added local hour offset - Doug Crompton 10/28/92
 * and subcommand menu for possible future commands
 */
#include "global.h"
#ifdef RDATE
#include "commands.h"
#include "mbuf.h"
#include "socket.h"
#include "netuser.h"
#ifndef MSDOS
#ifndef NO_SETTOD
#include <sys/time.h>
#endif
#include "session.h"
#endif

#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: rdate.c,v 1.18 1997/07/31 00:44:20 root Exp $";
#endif

#ifdef __GNUC__
#define DIFFTIME 2208988800LU
#else
#define DIFFTIME 2208988800
#endif
#define RDATETIMEOUT 30

static void rdate_timeout (void *);
static int rdate_offset = 0;

static int dordateserver (int argc, char *argv[], void *p);
static int dordateoff (int argc, char *argv[], void *p);


static struct cmds rdatecmds[] =
{
	{ "server",	dordateserver,	512,	2, "rdate server <address>"},
	{ "offset",	dordateoff,	0,	0, NULLCHAR},
	{ NULLCHAR,	0,		0,	0, NULLCHAR}
};


int
dordate (argc, argv, p)
int argc;
char *argv[];
void *p;
{
	return subcmd (rdatecmds, argc, argv, p);
}


static int
dordateserver (argc, argv, p)
int argc OPTIONAL;
char *argv[];
void *p OPTIONAL;
{
struct sockaddr_in sock;
int s, i_state;
struct mbuf *bp;
struct timer *t;
time_t rtime, raw_time, ltime;
#if !defined(MSDOS) && !defined(NO_SETTOD)
struct timeval tv;
#endif

	if ((sock.sin_addr.s_addr = resolve (argv[1])) == 0) {
		log (-1, "RDATE:Host %s unknown\n", argv[1]);
		return 1;
	}
	sock.sin_family = AF_INET;
	sock.sin_port = IPPORT_TIME;

	/* Open connection to time server */
	if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
		log (-1, "RDATE:Can't create socket");
		return 1;
	}
	(void) sockmode (s, SOCK_BINARY);

	/* Set timeout timer */
	t = (struct timer *) callocw (1, sizeof (struct timer));

	t->func = rdate_timeout;
	t->arg = (void *) &s;
	set_timer (t, RDATETIMEOUT * 1000L);
	start_timer (t);

	/* Connect to time server */
	if (connect (s, (char *) &sock, sizeof (sock)) == -1) {
		/* Connect failed */
		stop_timer (t);
		free (t);
		log (s, "RDATE: Connect failed");
		(void) shutdown (s, 2);
		close_s (s);
		return 1;
	}
	/* Successful connect, stop timout timer */
	stop_timer (t);
	free (t);
	/* Get time info sent by server */
	if (recv_mbuf (s, &bp, 0, NULLCHAR, (int *) 0) > 0) {
		(void) time (&ltime);
		rtime = (time_t) pull32 (&bp);
		/* Convert 1900 start date to 1970 start date */
		rtime -= (time_t) DIFFTIME;
		raw_time = rtime;
		rtime += (rdate_offset * 3600L);
		/* Set the system time */
		i_state = disable ();
#ifndef MSDOS
#ifdef NO_SETTOD
		(void) stime (&rtime);
#else
		tv.tv_sec = rtime;
		tv.tv_usec = 0;
		(void) settimeofday (&tv, NULL);
#endif
#endif
		restore (i_state);
		log (s, "RDATE:Clock set to %s from %s (delta %ld)\n", ctime (&rtime), argv[1], (rtime - ltime));
		tcmdprintf ("\nTime received from %s - %s", argv[1], ctime (&raw_time));
		tcmdprintf ("System time set to %s (delta %ld)\n", ctime (&rtime), (rtime - ltime));
		free_q (&bp);
	}
	close_s (s);
	return 0;
}				/* dordate */


/*
 * Close socket after timeout on connect
 */
static void
rdate_timeout (arg)
void *arg;
{
int *s;

	s = (int *) arg;
	close_s (*s);
}				/* rdate_timeout */


/* Set time offset */
static int
dordateoff (argc, argv, p)
int argc;
char *argv[];
void *p OPTIONAL;
{
	if (argc < 2) {
		tprintf ("Usage: 'rdate offset <+-hours>' - Current Offset %d Hours\n", rdate_offset);
		return 0;
	}
	rdate_offset = atoi (argv[1]);
	return 0;
}

#endif /* RDATE */
