#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <descrip.h>
#include <time.h>
#include <jpidef.h>
#ifdef __GNUC__
#define UAI$_OWNER 12
#else
#include <uaidef.h>
#endif
#include <lnmdef.h>
#ifdef __GNUC__
#define PSL$C_USER 3
#else
#include <psldef.h>
#endif
#include <ssdef.h>
#include <lib$routines.h>
#include "base_includes.h"
#include "server.h"
#include "server_i.h"
#include "on.h"
#include "inp.h"
#include "system.h"
#include "qio.h"
#include "sock.h"

extern server_ptr server_list, gsrv;

void startup(server_ptr srv, char *pass)
{
  char username[MAXLEN], hostname[MAXLEN];
  char accountname[MAXLEN], *sname;

  (void)get_username(username, FALSE);
  username[8] = 0;
  if (!get_logical("IRCNAME", accountname, FALSE))
    (void)get_username(accountname, TRUE);
  if (pass && *pass) new_send(srv, "PASS %s\n", pass);
  if (!tcp_gethostname(hostname)) strcpy(hostname, "unknown");
  sname = get_server_name(srv);
  new_send(srv, "USER %s %s %s :%s\n", username, hostname,
           sname?sname:"unknown", accountname);
  new_send(srv, "NICK %s\n", get_server_nick(srv));
}

void my_sig(unsigned num, char *string)
{
  char ms[256];
  struct dsc$descriptor_s ms_d;
  unsigned status;
  unsigned short len = 0;

  ms_d.dsc$w_length = sizeof(ms);
  ms_d.dsc$b_dtype = DSC$K_DTYPE_T;
  ms_d.dsc$b_class = DSC$K_CLASS_S;
  ms_d.dsc$a_pointer = ms;
  status = sys$getmsg(num, &len, &ms_d, 0, 0);
  if (!(status&1))
    say("Could not get strerror %d", status);
  if ((len >= 0) && (len < sizeof(ms))) {
    ms[(int)len] = 0;
    yell("(%d)%s: %s", num, string, ms);
  }
}

void noast(int *old)
{
  *old = sys$setast(0);
}

void oldast(int *old)
{
  if (*old == SS$_WASSET) sys$setast(1);
}

static void lowcase(char *str)
{
  for (; *str; str++) *str = tolower(*str);
}

#define fill_descrip(__x, __y, __z) __x.dsc$b_dtype = DSC$K_DTYPE_T; \
         		            __x.dsc$b_class = DSC$K_CLASS_S; \
                                    __x.dsc$a_pointer = __y; \
                                    __x.dsc$w_length = __z;

/* Assumes that sizeof(translation) >= sizeof(buffer) */
int get_logical(char *name, char *translation, int system)
{
  struct itemlistcell il[2];
  char buffer[255];
  int status, len=0;
  struct dsc$descriptor_s name_d, table_d;
  char table[255];
  int flag1 = LNM$M_CASE_BLIND, flag2 = PSL$C_USER;

  memset(il, 0, sizeof(il));
  il[0].buffer_length = sizeof(buffer)-1;
  il[0].item_code = LNM$_STRING;
  il[0].buffer_addr = (unsigned)buffer;
  il[0].return_addr = (unsigned)(&len);
  if (system) (void)strcpy(table, "LNM$SYSTEM");
  else (void)strcpy(table, "LNM$FILE_DEV");
  fill_descrip(name_d, name, strlen(name));
  fill_descrip(table_d, table, strlen(table));
  status = sys$trnlnm(&flag1, &table_d, &name_d, &flag2, il);
  if (!ODD(status)) return FALSE;
  if (len<=0) return FALSE;
  if (len >= sizeof(buffer)) len = sizeof(buffer)-1;
  buffer[len] = 0;
  (void)strcpy(translation, buffer);
  return TRUE;
}

static void get_name(char *user, char *name, int size)
{
  struct dsc$descriptor_s user_d;
  char dummy[100];
  unsigned len = 0, loop, start = 0;
  int status;
  struct itemlistcell list[2];

  memset(list, 0, sizeof(list));
  fill_descrip(user_d, user, strlen(user));
  list[0].buffer_length = sizeof(dummy);
  list[0].item_code = UAI$_OWNER;
  list[0].buffer_addr = (unsigned)dummy;
  list[0].return_addr = (unsigned)(&len);

  status = sys$getuai(0, 0, &user_d, (unsigned long *)list, 0, 0, 0);
  if (!ODD(status)) {
    my_sig(status, "sys$getuai");
    strcpy(name, "error");
  } else {
/* Why ? */
    while ((start < sizeof(dummy)) && !isalpha(dummy[start]) && (start<len))
      start++;
    if (len) {
      while ((len > start) && isspace(dummy[len-1]) || !isalpha(dummy[len-1]))
        len--;
      dummy[len] = 0;
    }
    if ((len - start) > 0) {
      strncpy(name, &dummy[start], len - start);
      name[len-start] = 0;
    } else *name = 0;
  }
}

void get_username(char username[MAXLEN], int account)
{
  unsigned short len;
  char *ptr;
  char name[MAXLEN];
  int flags = JPI$_USERNAME, ss;
  struct dsc$descriptor_s name_d;

  fill_descrip(name_d, name, sizeof(name));

  ss = lib$getjpi(&flags, 0, 0, 0, &name_d, &len);
  if (!ODD(ss)) my_sig(ss, "get username");
  name[sizeof(name)-1] = (char)0;
  if ((len >= 0) && (len < sizeof(name))) name[len] = (char)0;
  if ((ptr = strchr(name, ' ')) != NULL)
    *ptr = (char)0;
  lowcase(name);
  if (account)
    get_name(name, username, MAXLEN);
  else
    (void)strcpy(username, name);
}

static unsigned delta_time[2], bintime[2];

char curr_time_s[30], date[30], curr_time[30];
static $DESCRIPTOR(realt_d, curr_time_s);
static $DESCRIPTOR(reald_d, date);

/* This code should be placed after the time is set in the ast */

static void check_access(void)
{
  time_t c_time;
  char inpbuff[10];
  char string_time[32]; /* this is long enough to hold any date/timestamp */
  c_time = time(NULL);
  strcpy(string_time, ctime(&c_time));
  if (!((strncasecmp(string_time, "SAT", 3)==0) ||
        (strncasecmp(string_time, "SUN", 3)==0)))
  {
    int hour;
    hour = atoi(&string_time[12]);
/* Can't run from 9-> 5 */
    if ((hour>=9) && (hour<17))
    {
/* Note: the following routine won't exit until the user hits return.
   I did this so that they could see a message before we quit them out */
      read_input(inpbuff, sizeof(inpbuff),
                 "% Program is only available during certain hours.");
/* There is no return from user_quit */
      user_quit("forced exit - system imposed time restrictions",
                0, NULL);
    }
  }
}

void real_time(void)
{
  unsigned status;
  unsigned short len;
  status = sys$gettim(bintime);
  if (!ODD(status)) my_sig(status, "real time");

  realt_d.dsc$w_length = 11;   /* time only */
  status = sys$asctim(&len, &realt_d, bintime, (unsigned long)1);
  if (!ODD(status)) my_sig(status, "acstim");
  strncpy(curr_time, curr_time_s, 5);
  curr_time[5] = '\0';

  reald_d.dsc$w_length = 12;   /* Date and time */
  status = sys$asctim(&len, &reald_d, bintime, 0);
  if (!ODD(status)) my_sig(status, "asctime2");
  date[6] = ' ';
  date[7] = 0;
  (void)strcat(date, curr_time);
  updatestatwin();
}

static unsigned long timer_efn;
char timer_wait[20];
$DESCRIPTOR(timer_d, timer_wait);
static int minute = 0;
static int idle_time = 0;
extern int last_keyhit;

static void timer_action(void)
{
  server_ptr temp;
  char s_time[6];
  int status, old, new_idle;
  old = sys$setast(0);
  real_time();
  temp = server_list;
  while (temp) {
    if (temp->connected && temp->welcomed) send_notify(temp);
    temp = temp->next;
  }
  if (minute>=4) minute = minute % 4; /* assumes 15 second intervals */
  strncpy(s_time, curr_time, 5);
  s_time[5] = 0;
  if (minute == 0) handle_on(o_timer, s_time, 0);
  new_idle = (time(NULL) - last_keyhit)/60;
  if (new_idle!=idle_time) {
    idle_time = new_idle;
    sprintf(s_time, "%d", new_idle);
    if (new_idle) handle_on(o_idle, s_time, 0);
  }
  minute++;
  status = sys$setimr(timer_efn, delta_time, timer_action, 4536, 0);
  if (old == SS$_WASSET) (void)sys$setast(1);
}

void launch_timer(void)
{
  unsigned status;

  status = lib$get_ef(&timer_efn);
  if (!ODD(status)) my_sig(status, "get_ef launch_timer");
  (void)strcpy(timer_wait, "0000 00:00:15.00");
  timer_d.dsc$w_length = strlen(timer_wait);
  status = sys$bintim(&timer_d, delta_time);
  if (!ODD(status)) my_sig(status, "bintim launch timer");
  timer_action();
}
