/*
 ===========================================================================
 =                                                                         =
 =  (C) Copyright 1991-1994 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>
#include <sys/types.h>
#include <sys/time.h>
#ifndef MULTINET
#include <iodef.h>
#endif
#include <errno.h>
#include <string.h>
#include <varargs.h>

#include <netinet/in.h>

#ifdef KERBEROS
#include <krb.h>
#include <des.h>
#endif /* KERBEROS */

#include "iupop3_general.h"
#include "iupop3_vms.h"
#include "iupop3_global.h"

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

/* ====================================================================== */
/* Bcopy */
/* ====================================================================== */
#ifdef UCX
void bcopy(source, destination, length)
char *source;
char *destination;
int  length;
{
  char buffer[256];

  memcpy(buffer, source, length);
  memcpy(destination, buffer, length);
}
#endif /* UCX */

/* ====================================================================== */
/* Get Date */
/* ====================================================================== */
void get_date(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(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);
}

/* ======================================================================= */
/* Make Argv */
/* ======================================================================= */
void make_argv(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 */
/* ====================================================================== */
int pop_build_info(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));
    }

    /*
    **  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->del_flag = FALSE;
        mp->retr_flag = FALSE;
        mp->foreign_msg = FALSE;
        mp->number = msg_num;
        status = mail_message_bytes(p,&msg_num,&bytes);
        if (vms_error(status))
          return(pop_msg(p, POP_FAILURE, "%s", vms_message(status)));
        mp->length = bytes;
        p->newmail_size += bytes;
    }

    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];
    int           log_level;

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

    if (log_level <= master_log_level)
    {
      get_time(time_str);
      get_date(date_str);
      sprintf(message, "%s %s ", date_str, time_str);
      mp = message + strlen(message);
      sprintf(mp, "thread %d: ", p->threadnum);
      mp = message + strlen(message);
      vsprintf(mp, format, ap);
      fprintf(log_file, "%s\n", message);
    }

    va_end(ap);
}

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

    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);

    netprintf(p, "%s\r\n", message);
    pop_log(LOG_DEBUG, p, "tx: %s", message);
    return(stat);
}

/* ====================================================================== */
/* Patch From Line */
/* ====================================================================== */
#ifndef IGNORE_MAIL11_HEADERS
void patch_from_line(POP *p, char *from_line)
#else
void patch_from_line(POP *p, char *from_line, int *decnet)
#endif IGNORE_MAIL11_HEADERS
{
  int  num_tokens;
  char input[256];
  char output[256];
  char *tokens[128];  /* make it huge or the stack might get corrupted */
  char *pointer;

  /* Token #1 is address, #2 (if it exists) is personal name */
  strcpy(input, from_line);
  make_argv(input, &num_tokens, tokens, " ");
  if ((num_tokens < 1) || (num_tokens > 2))
  {
    pop_log(LOG_ERROR, p, "error parsing %s", from_line);
    return;
  }

  /* Lower case the address (but not the personal name) */
  lower(tokens[0]);

  /*
   * If address is of the form:
   *
   *    FOO%"someone@somewhere"    -or-
   *    NODE::"someone@somewhere"
   *
   * Just use what is in the quotes.
   */
  if (pointer = (char *)strchr(tokens[0], '"'))
  {
    strcpy(output, pointer+1);
    pointer = output + strlen(output) - 1;
    if (*pointer == '"') *pointer = '\0';
  }

  /*
   * If address is of the form:
   *
   *   NODE::USER
   *
   * Convert it to the form user@node
   */
  else if (pointer = (char *)strstr(tokens[0], "::"))
  {
    strcpy(output, pointer+2);
    strcat(output, "@");
    *pointer = '\0';
    strcat(output, tokens[0]);
#ifdef IGNORE_MAIL11_HEADERS
    *decnet = TRUE;
#endif IGNORE_MAIL11_HEADERS
  }

  /*
   * None of the above; it's local, so append "@hostname"
   */
  else
  {
    sprintf(output, "%s@%s", tokens[0], myhostname);
  }

  /*
   * Put the address in angle brackets, and prepend personal name if it exists.
   */
  from_line[0] = '\0';
#ifdef PERSONAL_NAME
  if (tokens[1]) sprintf(from_line, "\"%s\" ", tokens[1]);
#endif PERSONAL_NAME
  if (*output == '<')
    sprintf(from_line+strlen(from_line), "%s", output);
  else
    sprintf(from_line+strlen(from_line), "<%s>", output);
}

/* ====================================================================== */
/* String Index - find string s in string t */
/* ====================================================================== */
int 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 */
/* ======================================================================== */
int strncasecmp(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];
    int           log_level;

    va_start(ap);
    log_level = va_arg(ap, int);
    format    = va_arg(ap, char *);

    if (log_level <= master_log_level)
    {
      get_time(time_str);
      get_date(date_str);
      sprintf(message, "%s %s ", date_str, time_str);
      mp = message + strlen(message);
      vsprintf(mp, format, ap);
      fprintf(log_file, "%s\n", message);
    }

    va_end(ap);
}

/* ======================================================================== */
/* Net Printf */
/* ======================================================================== */
int netprintf(va_alist)
va_dcl
{
  POP           *p;
  char          *format;
  va_list       ap;
  char          message[MAXLINELEN];

  va_start(ap);
  p      = va_arg(ap, POP *);
  format = va_arg(ap, char *);
  vsprintf(message, format, ap);
  va_end(ap);

  if (p->retrieve.blocked)
    return(0);
  else
    return(netwrite(p->sockfd, message, strlen(message)));
}
