/*
 ===========================================================================
 =                                                                         =
 =  (C) Copyright 1991 The Trustees of Indiana University                  =
 =                                                                         =
 =  Permission to use, copy, modify, and distribute this program for       =
 =  non-commercial use and without fee is hereby granted, provided that    =
 =  this copyright and permission notice appear on all copies and          =
 =  supporting documentation, the name of Indiana University not be used   =
 =  in advertising or publicity pertaining to distribution of the program  =
 =  without specific prior permission, and notice be given in supporting   =
 =  documentation that copying and distribution is by permission of        =
 =  Indiana University.                                                    =
 =                                                                         =
 =  Indiana University makes no representations about the suitability of   =
 =  this software for any purpose. It is provided "as is" without express  =
 =  or implied warranty.                                                   =
 =                                                                         =
 ===========================================================================
 =                                                                         =
 = File:                                                                   =
 =   IUPOP3_UTILITY.C                                                      =
 =                                                                         =
 = Synopsis:                                                               =
 =   This file contains miscellaneous functions that support the           =
 =   VMS IUPOP3 server.                                                    =
 =                                                                         =
 = Authors:                                                                =
 =   Jacob Levanon & Larry Hughes                                          =
 =   Indiana University                                                    =
 =   University Computing Services, Network Applications                   =
 =                                                                         =
 = Credits:                                                                =
 =   This software is based on the Post Office Protocol version 3,         =
 =   as implemented by the University of California at Berkeley.           =
 =                                                                         =
 ===========================================================================
*/

/* ====================================================================== */
/* Includes */
/* ====================================================================== */
#include <stdio.h>
#include <ctype.h>
#ifdef MULTINET
#include <types.h>
#include <time.h>
#else /* WINS || UCX */
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <string.h>
#include <varargs.h>
#include "iupop3_general.h"
#include "iupop3_global.h"
#include "iupop3_vms.h"

/* ====================================================================== */
/* Prototypes */
/* ====================================================================== */
void	bcopy();
void    get_date();
void    get_time();
int     isnumeric();
void    make_argv();
int     pop_build_info();
void    pop_log();
char    *pop_msg();
int     strncasecmp();
int     str_index();
void    system_log();

#ifdef PATCH_FROM_LINE
int     patch_from_line();
#endif

/* ====================================================================== */
/* Bcopy */
/* ====================================================================== */
#ifndef WINS
void bcopy(source, destination, length)
char *source;
char *destination;
int  length;
{
  register char *pointer;
 
  pointer = malloc(length);
  memcpy(pointer, source, length);
  memcpy(destination, pointer, length);
  free(pointer);
}
#endif /* WINS */

/* ====================================================================== */
/* Get Date */
/* ====================================================================== */
void get_date(date_str)
char *date_str;
{
  time_t calendar_time;
  struct tm *local_time;

  calendar_time = time(0);
  local_time = localtime(&calendar_time);
  ++local_time->tm_mon;
  sprintf(date_str,"19%02d-%02d-%02d",
          local_time->tm_year,local_time->tm_mon,local_time->tm_mday);
}

/* ====================================================================== */
/* Get Time */
/* ====================================================================== */
void get_time(time_str)
char *time_str;
{
  time_t calendar_time;
  struct tm *local_time;

  calendar_time = time(0);
  local_time = localtime(&calendar_time);
  sprintf(time_str,"%02d:%02d:%02d",
          local_time->tm_hour,local_time->tm_min,local_time->tm_sec);
}

/* ====================================================================== */
/* Is Numeric */
/* ====================================================================== */
int is_numeric(instring)
char *instring;
{
  int numeric = TRUE;

  while (*instring && numeric)
    numeric = isdigit(*instring++);
  return(numeric);
}

/* ======================================================================= */
/* Make Argv */
/* ======================================================================= */
void make_argv(string,argc,argv,delimiters)
char *string;
int  *argc;
char *argv[];
char *delimiters;
{
#define isdelimiter(a,b) (strchr(b,a) != NULL)
  register char *cpointer;
  register char **argpointer = argv;

  *argc = 0;
  cpointer = string;
  while (*cpointer)
  {
    while (*cpointer && isdelimiter(*cpointer,delimiters)) cpointer++;
    if (*cpointer == '\0') break;
    if (*cpointer == '\"')
    {
      cpointer++;
      *argpointer++ = cpointer;
      (*argc)++;
      while (*cpointer && (*cpointer != '\"')) cpointer++;
    }
    else
    {
      *argpointer++ = cpointer;
      (*argc)++;
      while (*cpointer && !isdelimiter(*cpointer,delimiters)) cpointer++;
    }
    if (*cpointer == '\0') break;
    *(cpointer++) = '\0';
  }
  *(argpointer++) = 0;
}

/* ====================================================================== */
/* POP Build_info */
/* ====================================================================== */
pop_build_info(p)
POP *p;
{
    char buffer[BUFSIZ];
    Message *mp;
    register int msg_num;
    int bytes = 0;
    int status;

    /*
    **  Initialize mail folder status variables.
    */
    p->msgs_deleted = 0;
    p->last_msg = 0;
    p->bytes_deleted = 0;

    /*
    **  Allocate memory for message information structures.
    */
    p->mptr = (Message *)calloc((unsigned)p->msg_count,sizeof(Message));
    if (p->mptr == NULL)
    {
        p->msg_count = 0;
        return (pop_msg (p,POP_FAILURE,
            "Can't build message list for '%s': Out of memory", p->user, 0));
    }

    /*
    **  Scan the NEMAIL folder in the VMS MAIL file, loading the message
    **  information list with information about each message.
    */
    mp = p->mptr;
    for (msg_num=1; msg_num <= p->msg_count; msg_num++,bytes=0, mp++)
    {
        mp->lines = mail_message_lines(p, &msg_num)+1;
        mp->number = msg_num;
        status = mail_message_bytes(p,&msg_num,&bytes);
        mp->length = bytes;
        mp->del_flag = FALSE;
        mp->retr_flag = FALSE;
    }
    return(POP_SUCCESS);
}

/* ====================================================================== */
/* POP Log */
/* ====================================================================== */
void pop_log(va_alist)
va_dcl
{
    POP           *p;
    char          *format;
    va_list       ap;
    register char *mp;
    char          message[MAXLINELEN];
    char          date_str[11];
    char          time_str[9];

    get_time(time_str);
    get_date(date_str);
    sprintf(message, "%s %s ", date_str, time_str);

    va_start(ap);
    p      = va_arg(ap, POP *);
    format = va_arg(ap, char *);
    mp     = message + strlen(message);
    sprintf(mp, "thread %d: ", p->threadnum);
    mp = message + strlen(message);
    vsprintf(mp, format, ap);
    va_end(ap);

    printf("%s\n",message);
}

/* ====================================================================== */
/* POP Message */
/* ====================================================================== */
char *pop_msg(va_alist)
va_dcl
{
    POP             *p;
    int             stat;
    char            *format;
    va_list         ap;
    register char   *mp;
    char            message[MAXLINELEN];
    int             len, flag, status;

    va_start(ap);
    p = va_arg(ap, POP *);
    stat = va_arg(ap, int);
    format = va_arg(ap, char *);

    mp = message;
    if (stat == POP_SUCCESS)
      sprintf (mp,"%s ",POP_OK);
    else
      sprintf (mp,"%s ",POP_ERR);
    mp += strlen(mp);
    if (format) vsprintf(mp, format, ap);
    va_end(ap);

    pop_log(p,"told: %s",message,0);

    strcat(message, "\r\n");
    len = strlen(message);

    status = send(p->sockfd, message, len, flag);
    if (status < 0)
    {
        pop_log(p,"pop_msg: error sending to client: %d",status,0);
        return(0);
    }
    return(stat);
}

/* ====================================================================== */
/* Patch From Line */
/* ====================================================================== */
#ifdef PATCH_FROM_LINE
int patch_from_line(POP *p, char *from)
{
#define FROM    "From:"
#define FROMLEN 5
  int  parsing   = TRUE;
  int  in_quotes = FALSE;
  int  length;
  int  offset;
  char chr;
  char *bufptr;
  char *start;
  char *end;
  char *truestart;
  char transport[16] = "";
  char decnode[16]   = "";
  char clusternodes[] = "/prism/gold/jade/aqua/rose/amber/";

  lower(from+FROMLEN);
  bufptr = from + FROMLEN;
  while (isspace(*bufptr)) bufptr++;
  truestart = start = end = bufptr;

  for (; *bufptr && parsing; bufptr++)
  {
    chr = *bufptr;
    if (in_quotes)
    {
      switch (chr)
      {
        case '"' :   /* Foreign mailer delimiter */
        case '>' :   /* SMTP delimiter */
          end--;
          parsing = FALSE;
          continue;

        case '<' :   /* SMTP delimiter */
          start = end = bufptr+1;
          break;

        case ':' :   /* DECnet delimiter */
          start = end = bufptr+2;
          bufptr++;
          break;

        default :
          end++;
          break;

      }
    }
    else
    {
      switch (chr)
      {
        case '%' :   /* Foreign mailer delimiter */
          length = bufptr - truestart;
          memcpy(transport,truestart,length);
          *(transport+length) = '\0';
          start = end = bufptr+1;
          break;

        case '"' :   /* Foreign mailer delimiter */
          in_quotes = TRUE;
          start = end = bufptr+1;
          break;

        case ':' :   /* DECnet delimiter */
          length = bufptr - truestart;
          memcpy(decnode,truestart,length);
          *(decnode+length) = '\0';
          start = end = bufptr+2;
          bufptr++;
          break;

        case ' '  :
        case '\t' :
          end--;
          parsing = FALSE;
          continue;

        default  :
          end++;
          break;
      }
    }
  }

  if (*transport)
  {
    if ((offset = str_index(transport,":")) >= 0)
      bcopy(transport+offset+2,transport,strlen(transport)-offset-1);
  }

  if (end <= start)
  {
    pop_log(p,"parse error: %s",from,0);
    from_parse_errors++;
  }
  else
  {
    *(from + FROMLEN) = ' ';
    length = end - start + 1;
    bcopy(start,from+FROMLEN+1,length);
    *(from+FROMLEN+length+1) = '\0';

    if ((offset = str_index(from,"@")) >= 0)
    {
      if ((offset = str_index(from+offset+1,".")) < 0)
        strcat(from,".bitnet");
    }
    else if (*decnode)
    {
      if (str_index(clusternodes,decnode) >= 0)
        strcat(from,"@ucs.indiana.edu");
      else
      {
        strcat(from,"%");
        strcat(from,decnode);
        strcat(from,".decnet@iugate.ucs.indiana.edu");
      }
    }
  }
  return(POP_SUCCESS);
}
#endif /* PATCH_FROM_LINE */

/* ====================================================================== */
/* POP Send Line */
/* ====================================================================== */
pop_sendline(p,buffer)
POP  *p;
char *buffer;
{
    char *bp;
    char tmp[256];
    int  status, len, flag;

    /*
    **  Byte stuff lines that begin with the termination octet.
    */
    if (*buffer == POP_TERMINATE)
    {
      sprintf(tmp, ".%s", buffer);
      strcpy(buffer, tmp);
    }

    if (bp = strchr(buffer,NEWLINE)) *bp = 0;
    strcat(buffer, "\r\n");
    len = strlen(buffer);
    status = send(p->sockfd, buffer, len, flag);

    return(POP_SUCCESS);
}

/* ====================================================================== */
/* String Index - find string s in string t */
/* ====================================================================== */
str_index(register char s[], register char t[])
{
  register int i,k,j;

  for (i=0; s[i] != '\0'; i++)
  {
    for (j=i, k=0; t[k] != '\0' && s[j] == t[k]; j++, k++);
    if (t[k] == '\0')
      return(i);
  }
  return (-1);
}

/* ======================================================================== */
/*  Perform a case-insensitive string comparision */
/* ======================================================================== */
strncasecmp(str1,str2,len)
register char *str1;
register char *str2;
register int  len;
{
    register int i;
    char a, b;

    for (i=len-1;i>=0;i--)
    {
        a = str1[i];
        b = str2[i];
        if (isupper(a)) a = tolower(str1[i]);
        if (isupper(b)) b = tolower(str2[i]);
        if (a > b) return (1);
        if (a < b) return(-1);
    }
    return(0);
}

/* ======================================================================== */
/* System Log */
/* ======================================================================== */
void system_log(va_alist)
va_dcl
{
    char          *format;
    va_list       ap;
    register char *mp;
    char          message[MAXLINELEN];
    char          date_str[11];
    char          time_str[9];

    get_time(time_str);
    get_date(date_str);
    sprintf(message, "%s %s ", date_str, time_str);

    va_start(ap);
    format = va_arg(ap, char *);
    mp     = message + strlen(message);
    vsprintf(mp, format, ap);
    va_end(ap);

    printf("%s\n",message);
}
