#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <ctype.h>
main(argc,argv)
int argc;
char *argv[];
{
/*
	client process to connect to  the daytime service via port 13.
	The client process uses the time message received to check (and
	optionally to set) the time of the local clock.  the comparison 
	assumes that the local clock keeps time in seconds from 1/1/70 
	which is the UNIX standard, and it computes the time difference 
	by converting the received MJD to seconds since 1/1/70 and adding 
	the received hr, min and sec, also converted to seconds.  If the
	local machine keeps time in some other way, then the comparison
	method will have to change, but the rest should be okay.

	This software was developed with US Government support
	and it may not be sold, restricted or licensed.  You 
	may duplicate this program provided that this notice
	remains in all of the copies, and you may give it to
	others provided they understand and agree to this
	condition.

	This program and the time protocol it uses are under 
	development and the implementation may change without 
	notice.

	For questions or additional information, contact:

	Judah Levine
	Time and Frequency Division
	NIST/847
	325 Broadway
	Boulder, Colorado 80303
	(303) 492 7785
	jlevine@time_a.timefreq.bldrdoc.gov
*/
long int address;		/* holds ip address */
int pserv = 13;		/* daytime port number on server */
char *cp;			/* server address in . notation */
struct sockaddr_in sin;		/* socket address structure */
int s;				/* socket number */
int length;			/* size of message */
char buf[132];			/* holds message */
long int mjd0 = 40587;		/* MJD of 1/1/70 = origin of UNIX time system*/
struct timeval tvv,tgg;		/* holds local time */
long int mjd;			/* holds parsed received mjd*/
int yr,mo,dy,hr,min,sec;	/* holds parsed received time */
int dst,ls,health;		/* received flags: dst, ls and health */
long int diff;			/* time difference, local - NIST */
char cc;
int stat;
int isw();			/*parses command-line switches*/
char let;			/*command-line letter*/
long int val;			/*command line value*/
/*
	the following variables define what this program
	should do and what output should be produced.  The
	values below are the defaults which may be changed
	by characters on the command line as described below.
	The effect of each variable is as follows:

Command-Line Switch	effect
	-m0		msg  = 0	Do not produce any messages;
					only time difference is written to
					standard output.

	-m1 or -M	     = 1	Produce short messages.
	-m2		     = 2	Produce longer messages.

	-s0		set  = 0	Do not adjust local time.
	-s1 or -S	     = 1	Adjust local time if server is healthy.
	-s2	             = 2	Adjust local time even if server is 
					unhealthy.
	-s3		     = 3	Ask operator first.
*/
int msg =1;		/*default is short messages */
int set =3;		/*default is ask before setting clock */
/*
	parse command line 
*/
	while( sw(argc,argv,&let,&val) != 0) /*switch is present*/
	   {
	   switch(let)
	      {
	      case 'm':
		msg=val;
		break;
	      case 's':
		set=val;
		break;
	      case 'S':
		set=1;
		break;
	      case 'M':
		msg=1;
		break;
	      default:
		fprintf(stderr,"\nSwitch %c not recognized.",let);
		break;
	   }
	   argc--;	/*decrement argument counter */
	   argv++;	/*and increment pointer */
	}
/*
	internet address of server named time_a.timefreq.bldrdoc.gov
*/
	cp="132.163.135.130";
/*
	convert address to internal format
*/
	if( (address=inet_addr(cp) ) == -1)
	   {
	   fprintf(stderr,"\n Internet address error.");
	   exit(1);
	}
	bzero( (char *)&sin,sizeof(sin));
	sin.sin_addr.s_addr=address;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(pserv);
/*
	create the socket and then connect to the server
	note that this is a stream socket and that record
	boundaries are not preserved.
*/
	if( (s=socket(AF_INET,SOCK_STREAM,0) ) < 0)
	   {
	   fprintf(stderr,"\n Socket creation error.");
	   exit(1);
	}
	if(connect(s, (struct sockaddr *) &sin, sizeof(sin) ) < 0)
	   {
	   perror(" time server Connect failed --");
	   exit(1);
	}
	length=read(s,buf,80);
	gettimeofday(&tvv,0);	/*get time as soon as read completes*/
	if(length <= 0) 
	   {
	   fprintf(stderr,"\n No response from server.");
	   close(s);
	   exit(1);
	}
	buf[length]= '\0';   /*add terminating null */
	if(msg != 0)
	   {
	   printf("\n Time message received:");
	   printf("\n                        D  L");
	   printf("\n MJD  YY MM DD HH MM SS ST S H  Adv.");
	   printf("%s\n",buf);
	}
	close(s);
/*
	now compute difference between local time and
	received time.
*/
	sscanf(buf," %ld %2d-%2d-%2d %2d:%2d:%2d %d %d %d",
		&mjd,&yr,&mo,&dy,&hr,&min,&sec,&dst,&ls,&health);
	if(msg == 2)		/*longer messages selected */
	   {
	   if( (dst == 0)  || (dst > 51) )
	      {
	      printf("\nStandard Time now in effect.");
	      if(dst > 51) 
		printf("\nChange to Daylight Saving Time in %d days.",dst-51);
	   }
	   if( (dst <= 50) && (dst > 1) )
	      {
	      printf("\nDaylight Saving Time now in effect.");
	      if( (dst > 1)  && (dst < 50) )
		printf("\nChange to Standard Time in %d days.",dst-1);
	   }
	   if(dst == 1) printf("\nStandard time begins at 2am today.");
	   if(dst == 51)printf("\nDaylight Saving Time begins at 2am today.");
	   if(ls ==1) printf("\nLeap Second to be added at end of month.");
	   if(ls ==2) printf("\nSecond to be dropped at end of month.");
	}
/*
	convert received time to seconds since 1/1/70 and subtract
	this from the local time in the same units.
	Since no correction has been made for the network delay,
	this difference cannot be taken too seriously, although
	the delay in a local network should be no more than about
	0.05 seconds.
*/
	diff=tvv.tv_sec - 86400*(mjd-mjd0) - 3600*hr -60*min - sec;
	if(tvv.tv_usec >= 500000l) diff++;	/*round microseconds */
	if(msg == 0)		/*no messages except time diff.*/
	   printf("%ld",diff);
	else
	   printf("\nLocal Clock - NIST = %ld second(s).",diff);
	if(diff == 0)
	  {
	  if(msg != 0) printf("\n No adjustment is needed.\n");
	  exit(0);
	}
	if(set == 0) exit(0);
	if( (health != 0) && (msg != 0) )
	   printf("\n Server is not healthy, adjustment not recommended.");
	cc = 'n';	/*default is not to set */
	if(set == 3)	/*action depends on answer to query*/
	   {
	   printf("\n Do you want to adjust the local clock ? [y/n] ");
	   cc=getchar();
	}
	if( (set == 2) ||	 	     /*always set */
	    ( (set == 1) && (health == 0) ) ||   /*set if healthy*/
	    (cc == 'y') || 			/*set if response yes*/
	    (cc == 'Y') )
	   {
	   if(diff > 2100l)
	      {
	      printf("\n Adjustment limited to -2100 s.");
	      diff= 2100l;
	   }
	   if(diff < -2100l)
	      {
	      printf("\n Adjustment limited to +2100 s.");
	      diff= -2100l;
	   }
	   tvv.tv_sec= -diff;
	   tvv.tv_usec = 0;
	   stat=adjtime(&tvv,&tgg);
	   if(msg != 0)
	      {
	      if(stat == 0) printf("\n Adjustment was started.\n");
	      else perror("Adjustment failed. ");
	   }
	}
	exit(0);
}

