/*
   Kermit's attribute packets services
*/

#include "ufk.h"
#include <stat.h>
#include <time.h>
#include <timeb.h>

#define leap(y) (!(y & 3))    /* Return TRUE if it's a leap year */

unsigned int perms,
             operms;
int owner;
struct tm timbuf;
char opsys[3];


init_attributes()
{
   file_size = 0;                       /* for % display, remains 0 if none */
   perms = 0xffff;                      /* 'world' permissions */
   operms = 0xffff;                     /* permissions in our syntax */
   timbuf.tm_yday = -1;                 /* no date given yet */
}

snd_attributes()
{
   struct stat buf;
   struct tm *localtime();
   struct tm *tpt;
   int locfp;
   char *p,
        hlpstr[16];

   locfp = open(filnam,0);
   fstat(locfp,&buf);                     /* filnam is already verified */
   p = sndpkt;

/* setup system of origin. Define UniFLEX to be number 'UF' */

   addstr('.',&p,"UF");

/* setup file size in blocks */

   sprintf(hlpstr,"%d",(int)((buf.st_size + 1024l) / 1024l));/* Rounded in K */
   addstr('!',&p,hlpstr);

/* setup file size in bytes */

   sprintf(hlpstr,"%ld",buf.st_size);
   addstr('1',&p,hlpstr);

/* setup creation date */

   tpt = localtime(&buf.st_mtime);
   sprintf(hlpstr,"%02.2d%02.2d%02.2d %02.2d:%02.2d:%02.2d",
           tpt->tm_year, tpt->tm_mon + 1, tpt->tm_mday,
           tpt->tm_hour, tpt->tm_min, tpt->tm_secs);
   addstr('#',&p,hlpstr);

/* setup file protection with respect to the world */

   *p++ = '-';
   *p++ = tochar(1);
   *p++ = tochar((buf.st_mode & S_IPRM) >> 3);

/* setup file protection in our syntax */

   *p++ = ',';
   *p++ = tochar(2);
   *p++ = tochar((buf.st_mode & S_IPRM) & 0x0f);
   *p++ = tochar((buf.st_mode & S_IPRM) >> 4);

/* setup file owner */

   sprintf(hlpstr,"%d",buf.st_uid);
   addstr('$',&p,hlpstr);

/* set file type */

   *p++ = '"';
   *p++ = tochar(1);
   if (binfil = seltype(locfp))
      *p++ = 'B';                               /* Binary file */
   else
      *p++ = 'A';                               /* Ascii file */

   *p = '\0';
   size = p - sndpkt;                           /* Final packet size */
   close (locfp);
}

rcv_attributes()
{
   int len,
       filesize;
   long dsize;
   char *p,
        *q,
        *r,
        *pos,
        hlpstr[10],
        type,
        *index(),
        *rindex();

   p = recpkt;
   while (p < recpkt + size)
   {
      type = *p++;
      if ((len = unchar(*p++)) != 0)
      {
         switch(type)
         {
            case '.':                   /* operating system origin */
                  strncpy(opsys,p,len);
                  opsys[len] = '\0';
                  break;

            case '!':                   /* Filesize in K bytes */
                  strncpy(hlpstr,p,len);
                  hlpstr[len] = '\0';
                  sscanf(hlpstr,"%d",&filesize);
                  pos = rindex(rec_filnam,'/');
                  if (pos == NULL)
                     strcpy(hlpstr,".");
                  else
                  {
                     strncpy(hlpstr,rec_filnam,pos - rec_filnam);
                     hlpstr[pos-rec_filnam] = '\0';
                  }
                  dsize = get_free(hlpstr);    /* Get number of free blocks */
                  if ((dsize == -1l) ||
                      (dsize < (long)filesize))
                     return(ERROR);            /* File too big to fit */
                  break;

            case '1':                          /* Number of bytes in file */
                  strncpy(hlpstr,p,len);
                  hlpstr[len] = '\0';
                  sscanf(hlpstr,"%ld",&file_size);
                  break;

             case '"':                         /* File type */
                  type = *p;
                  if (type == 'A')
                     binfil = FALSE;           /* Ascii */
                  else if (type == 'B')
                     binfil = TRUE;            /* Binary */
                  break;

            case '-':                          /* File permissions */
                  perms = unchar(*p) & 7;
                  break;

            case ',':                     /* File permissions in our syntax */
                  operms = unchar(p[0]);
                  if (len > 1)
                     operms |= (unchar(p[1]) << 4);
                  break;

            case '$':                          /* File owner */
                  strncpy(hlpstr,p,len);
                  hlpstr[len] = '\0';
                  sscanf(hlpstr,"%d",&owner);
                  break;

            case '#':                          /* File date */
                  q = p;                /* Check if date and time specified */
                  if (len > 8)
                  {                     /* both date and time */
                     r = index(p,' ');
                     if ((r - p) == 8)
                        q = &p[2];      /* skip first two digits of date */
                  }
                  else if (len == 8)    /* only date specified */
                     q = &p[2];

                  timbuf.tm_hour = 0;   /* Zero out optional items */
                  timbuf.tm_min = 0;
                  timbuf.tm_secs = 0;
                  sscanf(q,"%2d%2d%2d %d:%d:%d",
                            &timbuf.tm_year,
                            &timbuf.tm_mon,
                            &timbuf.tm_mday,
                            &timbuf.tm_hour,
                            &timbuf.tm_min,
                            &timbuf.tm_secs);
                  timbuf.tm_mon--;             /* Adjust month */
                  timbuf.tm_yday = 0;          /* Flag date given */
                  break;

            default:
                  break;
         }
      }
      p += len;
   }
   return NULL;
}

seltype(fp)
int fp;
{
   unsigned char filechar[256];
   char *i;
   int size;

   size = read(fp,filechar,256);

   for (i = filechar; i < &filechar[size]; i++)
      if ((*i != 0x09) &&               /* tab */
          (*i != 0x0a) &&               /* linefeed */
          (*i != 0x0c) &&               /* formfeed */
          (*i != 0x0d) &&               /* carriage return */
          ((*i  > 0x7e) || (*i  < 0x20)) )
         return TRUE;                   /* it must be binary */
   return FALSE;                        /* ascii */
}

fset_attributes()
{
   long cvttime();

   struct stat buf;

   if (stat(rec_filnam,&buf))           /* Get status of current filename */
      prterr(ER_PERMS);
   else
   {
      if (perms != 0xffff)
      {                                    /* 'world' syntax */
         perms = (buf.st_mode &
                  S_IPRM &                 /* Mask for permissions */
                  ~(S_IOREAD | S_IOWRITE | S_IOEXEC)) |
                  (perms << 3);            /* set new 'other' bits */
         if (chmod(rec_filnam,perms) == ERROR)
            prterr(ER_PERMS);
      }
      if ((operms != 0xffff) &&
          (strcmp(opsys,"UF") == 0))       /* 'our' syntax */
         if (chmod(rec_filnam,operms) == ERROR)
            prterr(ER_PERMS);
   }
   if (timbuf.tm_yday != -1)
      fset_date(rec_filnam,cvttime(&timbuf));  /* Set new date */
}

addstr(type,q,string)
char type,
     **q,
     *string;
{
   int length;

   length = strlen(string);
   *(*q)++ = type;
   *(*q)++ = tochar(length);
   strcpy(*q,string);
   *q += length;
}

long cvttime(buf)
struct tm *buf;
{
   struct timeb tbuf;         /* To read the timezone */
   static char daytab[] = {   /* Number of days for each month */
      31, 28, 31, 30,
      31, 30, 31, 31,
      30, 31, 30, 31
      };
   int days_so_far,
       i,
       j;
   long int sec_sin_80;        /* Accumulated number of seconds */

   days_so_far = 0;
   for (j = 80; j < buf->tm_year; j++)/* Calc number of days for past years */
   {
      for (i = 0; i < 12; i++)
         days_so_far += daytab[i]; /* Add number of days in a year */
      if (leap(j))
         days_so_far++;            /* one more in a leap year */
   }
   for (i = 0; i < buf->tm_mon; i++)/* Calc number of days for past months */
   {
      days_so_far += daytab[i];
      if ((i == 1) && leap(buf->tm_year))
         days_so_far++;             /* Take care of 29 februari */
   }
   days_so_far += buf->tm_mday - 1;     /* Add number of days this month */
   sec_sin_80 = ((long)buf->tm_hour * 3600) +
                 (buf->tm_min * 60) +
                  buf->tm_secs;
   sec_sin_80 += days_so_far * (long) 86400;

   ftime(&tbuf);                    /* Get timezone value */
   sec_sin_80 += tbuf.timezone * 60; /* Correct for it */
   return(sec_sin_80);               /* That's it, return the time */
}
