/*	Timed execution routine. Starts a timer and executes a sequence
 *	of commands when expired.
 *
 *	Added by IW0CNB - Feb 1992
 *  'at mm' format added by WG7J - 920805
 */

/****************************************************************************
*	$Id: at.c 1.2 93/07/16 11:42:14 ROOT_DOS Exp $
*	15 Jul 93	1.2		GT	Fix warnings.									*
****************************************************************************/

#include <time.h>
#include <dos.h>
#include <ext.h>
#include "global.h"
#include "timer.h"
#include "cmdparse.h"
#include "socket.h"

#if	defined (time)
#undef	time								/* remove macro					*/
#endif

void 				atcmd(char *command);
unsigned long 	dostounix(struct date *dt, struct time *tm);


/* List of events; We keep note of all timer processes generated by the 
 * at command.
 */
struct at_list {
	struct at_list *next;	/* Linked-list pointer */
	struct timer *at_timer;
};

#define	NULLATLIST	(struct at_list *)0

static struct at_list *Head_loe = NULLATLIST;	/* Head of List Of Events */

int doat(
	int argc,
	char *argv[],
	void *p )
{
	char *cp;
	struct date *exp_date;
	struct time *exp_time;
	struct timer *t;
  	time_t nowtime;
	unsigned long time1;
   struct tm tm;
   extern struct timer *Timers;
	struct at_list *loe;	/* List of events */
    char *Errmsg = "Usage:\nat yymmddhhmm <cmd>\nat hhmm <cmd>\nat mm <cmd>\nat now+hhmm <cmd>\n";

	if (argc < 2) {							/* Print list of pending at commands */
		tputs("List of events:\n");
		for (t = Timers; t != NULLTIMER; t = t->next)	{
			if (t->func == (void (*)())atcmd)	{
				time(&nowtime);
				nowtime = (time_t)(read_timer(t) / 1000L + (unsigned long)nowtime);
				cp = ctime(&nowtime);
				rip(cp);
				tprintf("At: %s - Command: %s\n",cp,t->arg);
		   }
		}
		return 0;
	}

	if (argc < 3)	{
		tputs(Errmsg);
		return 0;
	}

	exp_date = (struct date *)mallocw(sizeof(struct date));
	exp_time = (struct time *)mallocw(sizeof(struct time));

	cp=mallocw(5);

	switch (strlen(argv[1])) {
	case 10:											/* Full date and time given 		*/
		cp[0] = argv[1][0];
		cp[1] = argv[1][1];
		cp[2] = '\0';
	
		exp_date->da_year = 1900 + atoi(cp);
		if(exp_date->da_year > 1999) goto error;

		cp[0] = argv[1][2];
		cp[1] = argv[1][3];
		cp[2] = '\0';

		exp_date->da_mon = (char)atoi(cp);
		if(exp_date->da_mon > 12) goto error;

		cp[0] = argv[1][4];
		cp[1] = argv[1][5];
		cp[2] = '\0';

		exp_date->da_day = (char)atoi(cp);
		if(exp_date->da_day > 31) goto error;

		cp[0] = argv[1][6];
		cp[1] = argv[1][7];
		cp[2] = '\0';

		exp_time->ti_hour = (char)atoi(cp);
		if(exp_time->ti_hour > 23) goto error;

		cp[0] = argv[1][8];
		cp[1] = argv[1][9];
		cp[2] = '\0';

		exp_time->ti_min = (char)atoi(cp);
		if(exp_time->ti_min > 59) goto error;

		exp_time->ti_sec = 0;
		exp_time->ti_hund = 0;

		time(&nowtime);
		time1 = (unsigned long)dostounix(exp_date,exp_time);
		if(time1 < (unsigned long)nowtime) goto error;

		break;

	case 4:  							/* Only time given, so apply current date */
		getdate(exp_date);
		cp[0] = argv[1][0];
		cp[1] = argv[1][1];
		cp[2] = '\0';

		exp_time->ti_hour = (char)atoi(cp);
		if(exp_time->ti_hour > 23) goto error;

		cp[0] = argv[1][2];
		cp[1] = argv[1][3];
		cp[2] = '\0';

		exp_time->ti_min = (char)atoi(cp);
		if(exp_time->ti_min > 59) goto error;

		exp_time->ti_sec = 0;
		exp_time->ti_hund = 0;

		time(&nowtime);
		time1 = (unsigned long)dostounix(exp_date,exp_time);
		if(time1 < (unsigned long)nowtime){	/* Requested time has passed */
			time1 += 86400L;		/* So book him for tomorrow */
		}
		break;


	case 2:  /* Only minutes given, so apply current time & date - WG7J */
		tm.tm_min = (char)atoi(argv[1]);
		if(tm.tm_min > 59) goto error;

      /* get today's date */

		getdate(exp_date);
		tm.tm_year = exp_date->da_year - 1900;
		tm.tm_mday = exp_date->da_day;
		tm.tm_mon  = exp_date->da_mon - 1;

		/* get current time */

		gettime(exp_time);
		tm.tm_hour = exp_time->ti_hour;

		/* if we're already past the minute, do it next hour ! */

		if (exp_time->ti_min > tm.tm_min)
			tm.tm_hour++;

		/* now adjust this for day boundaries, etc. */

		tm.tm_sec = 0;
		tm.tm_isdst = 0;
		time1 = mktime(&tm);
		time(&nowtime);
		break;

	case 8:	/* now+hhmm given */
		strncpy(cp,argv[1],4);
		cp[4]='\0';

		if (strcmp(cp,"now+") != 0)
			goto error;

		cp[0] = argv[1][4];
		cp[1] = argv[1][5];
		cp[2] = '\0';

		time1 = (unsigned long)atoi(cp)*3600L; 

		cp[0] = argv[1][6];
		cp[1] = argv[1][7];
		cp[2] = '\0';

		time1 += (unsigned long)atoi(cp)*60L;
		time(&nowtime);
		time1 += (unsigned long)nowtime;
		break;

	default:
	error:
		tprintf(Errmsg);
		free(exp_date);
		free(exp_time);
		free(cp);

		return 0;

	} /* switch */

	free(cp);
	free(exp_time);
	free(exp_date);

	t = (struct timer *)mallocw(sizeof(struct timer));

	set_timer(t,(time1 - (unsigned long)nowtime) * 1000L);
	t->state = TIMER_RUN;
	t->func  = (void (*)())atcmd;
	t->arg   = (char *)mallocw(strlen(argv[2])+2);
	strcpy(t->arg,argv[2]);
	start_timer(t);

	/* Add the new timer to the head of List Of Events */

	loe = (struct at_list *)mallocw(sizeof(struct at_list));
	loe->at_timer = t;
	loe->next = Head_loe;
	Head_loe = loe;

	return 0;
}

/*
	atcmd - Function to be called on timer expiration to execute a command
*/

void atcmd(char *command)
{
	extern struct cmds far Cmds[];
	struct at_list *loe, *p;

	log(-1, "AT command: %s", command);

	/* Free up memory for expired at commands */
	
	p   = Head_loe;
	loe = Head_loe;

	while(loe != NULLATLIST) {
		if (loe->at_timer->state == TIMER_EXPIRE) {
			free(loe->at_timer);					/* Free timer 							*/
			if (loe == Head_loe) {
				Head_loe=loe->next;
				p=loe->next;
				free(loe);
				loe = p;
				p = Head_loe;
			} else {
				p->next = loe->next;
				free(loe);
				loe = p->next;
			}
		} else {										/* Not expired, go on 				*/
			if (loe != Head_loe) p=p->next;
			loe = loe->next;
		}
	}
	cmdparse(Cmds,command,NULL);				/* Go with requested command */
	free(command);
}

/*
	dostounix - convert time format
*/

unsigned long dostounix(
	struct date *dt,
	struct time *tm )
{
	char tbuf[6];

	/* setup time in UNIX unpacked format												*/
	
   tbuf[0] = (char)dt->da_year - 1970;				/* year - 1970 				*/
	tbuf[1] = (char)dt->da_mon;						/* month	 (1 to 12)			*/
	tbuf[2] = (char)dt->da_day;						/* day    (1 to 31)			*/
	tbuf[3] = (char)tm->ti_hour;						/* hour   (0 to 23)			*/
	tbuf[4] = (char)tm->ti_min;						/* minute (0 to 59)			*/
	tbuf[5] = (char)tm->ti_sec;						/* second (0 to 59)			*/

	return utpack(tbuf);									/* convert to packed form	*/
}
