/*-------------------------------------------------------------------------
 *  Listserv - Unix Mailing List manager (sub-set of FRECP's
 *             Bitnet Listserv tool.
 *
 *  Copyright (C) 1991,1992  Kimmo Suominen, Christophe Wolfhugel
 *
 *  Please read the files COPYRIGHT and AUTHORS for the extended
 *  copyrights refering to this file.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------*/

static char rcsid[] = "@(#)$Id: lp.c,v 1.11 92/12/04 09:15:55 wolf Exp $";

/*
 * $Log:	lp.c,v $
 * Revision 1.11  92/12/04  09:15:55  wolf
 * Updated some syslog defines
 * 
 * Revision 1.10  92/07/14  15:43:09  wolf
 * Authorized comments in lists; removed third field in file.
 * 
 * Revision 1.9  92/06/12  07:11:21  listserv
 * Initial 2.00 release
 * 
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/times.h>
#include "conf.h"
#include "ext.h"
#include "str.h"
#include <limits.h>
#ifdef FAKESYSLOG
# include "fakesyslog.h"
#else
# include <syslog.h>
#endif

extern char From[],To[];

struct ITEM {
  struct ITEM *next;
  char *value;
};

static struct ITEM *commentList=NULL,*commentPtr=NULL;
static struct ITEM *editorList=NULL,*editorPtr=NULL;
static struct ITEM *ownerList=NULL,*ownerPtr=NULL;
static struct ITEM *userList=NULL,*userPtr=NULL;

static char review[16],send[16],subscription[16];
static char lname[64],replyto[128],errorsto[128];

static char buf2[512];

int IsEditor(char *s)
{
   struct ITEM *p;

   for (p=editorList; p!=NULL; p=p->next) {
      if (strspacecmp(p->value,s)==0) return(1);
   } /* endfor */
   return(0);
}

int IsOwner(char *s)
{
   struct ITEM *p;

   for (p=ownerList; p!=NULL; p=p->next) {
      if (strspacecmp(p->value,s)==0) return(1);
   } /* endfor */
   return(0);
}

int IsUser(char *s)
{
   struct ITEM *p;

   for (p=userList; p!=NULL; p=p->next) {
      if (strspacecmp(p->value,s)==0) return(1);
   } /* endfor */
   return(0);
}

void RewindUserList()
{
   userPtr=userList;
}

char *GetUser(char *s)
{
   struct ITEM *p;

   if (userPtr==NULL) return(NULL);
   p=userPtr; userPtr=userPtr->next;
   if (s!=NULL) strcpy(s,p->value);
   return(p->value);
}

void RewindCommentList()
{
   commentPtr=commentList;
}

char *GetComment(char *s)
{
   struct ITEM *p;

   if (commentPtr==NULL) return(NULL);
   p=commentPtr; commentPtr=commentPtr->next;
   if (s!=NULL) strcpy(s,p->value);
   return(p->value);
}

void RewindEditorList()
{
   editorPtr=editorList;
}

char *GetEditor(char *s)
{
   struct ITEM *p;

   if (editorPtr==NULL) return(NULL);
   p=editorPtr; editorPtr=editorPtr->next;
   if (s!=NULL) strcpy(s,p->value);
   return(p->value);
}

void RewindOwnerList()
{
   ownerPtr=ownerList;
}

char *GetOwner(char *s)
{
   struct ITEM *p;

   if (ownerPtr==NULL) return(NULL);
   p=ownerPtr; ownerPtr=ownerPtr->next;
   if (s!=NULL) strcpy(s,p->value);
   return(p->value);
}


/*
 * Returns:  0 if new entry, 1 if updated.
 */

int  AddItem(struct ITEM **head,char *s)
{
  struct ITEM *p,*q,*r;

  q=NULL;
  for (p= *head; p!=NULL; p=p->next) {
    if (p->value[0]=='#') { q=p; continue; }
    if (strspacecmp(s,p->value)==0) {
      p->value=(char *)realloc(p->value,strlen(s)+1);
      strcpy(p->value,s);
      return(1);
    } /* endif */
    if (strspacecmp(s,p->value)<0) {
      r=(struct ITEM *)malloc(sizeof(struct ITEM));
      r->value=(char *)malloc(strlen(s)+1);
      if (q==NULL) *head=r; else q->next=r;
      r->next=p;
      strcpy(r->value,s);
      return(0);
    } /* endif */
    q=p;
  } /* endfor */
  p=(struct ITEM *)malloc(sizeof(struct ITEM));
  p->value=(char *)malloc(strlen(s)+1);
  p->next=NULL;
  strcpy(p->value,s);
  if (q!=NULL) q->next=p; else *head=p;
  return(0);
}


/*
 * Returns 0 is OK, -1 is key not found
 */

int DelItem(struct ITEM **head,char *s)
{
  struct ITEM *p,*q;

  q=NULL;
  for (p= *head; p!=NULL; p=p->next) {
    if (strspacecmp(s,p->value)==0) {
      if (q==NULL) *head=p->next; else q->next=p->next;
      free(p->value);
      free(p);
      return(0);
    } /* endif */
    q=p;
  } /* endfor */
  return(-1);
}

int  DelUser(char *s)
{
   return(DelItem(&userList,s));
}

int  AddUser(char *s)
{
   return(AddItem(&userList,s));
}

void AddEditor(char *s)
{
   AddItem(&editorList,s);
}

void AddOwner(char *s)
{
   AddItem(&ownerList,s);
}

void DelList(struct ITEM **head)
{
  struct ITEM *p;

   while (*head!=NULL) {
      p= *head; *head=p->next;
      free(p->value);
      free(p);
   } /* endwhile */
   *head=NULL;
}

#define DELIM "# =\r\n\t"

void parseComment(char *s)
{
   char *kw;

   kw=strtok(buf2,DELIM);
   if (kw==NULL) return;
   if (strcasecmp(kw,"owner")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) AddItem(&ownerList,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"editor")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) AddItem(&editorList,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"review")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) strcpy(review,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"send")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) strcpy(send,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"subscription")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) strcpy(subscription,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"reply-to")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) strcpy(replyto,kw);
      return;
   } /* endif */
   if (strcasecmp(kw,"errors-to")==0) {
      kw=strtok(NULL,DELIM);
      if (kw!=NULL) strcpy(errorsto,kw);
      return;
   } /* endif */
}


/*
 * Returns: 0 on success, -1 is list.u file not found
 */

int  ReadUserList(char *s)
{
   FILE *f;

   strcpy(review,"all");
   strcpy(send,"all");
   strcpy(subscription,"open");
   strcpy(replyto,"list,respect");
   errorsto[0]=0;
   sprintf(lname,"%s.u",s); f=fopen(lname,"r");
   if (f==NULL) { syslog(LOG_ERR,"can't open %s",lname); return(-1); }
   while (fgets(buf2,256,f)!=NULL) {
      strtok(buf2,"\r\n"); if (buf2[0]==0) continue;
      if (buf2[0]=='#') 
         { AddItem(&commentList,buf2); parseComment(buf2); continue; }
      AddUser(buf2);
   } /* endwhile */
   fclose(f);
   return(0);
}

void WriteUserList()
{
   FILE *f;

   f=fopen("tmpfile","w");
   RewindCommentList(); RewindUserList();
   while (GetComment(buf2)!=NULL) fprintf(f,"%s\n",buf2);
   while (GetUser(buf2)!=NULL) fprintf(f,"%s\n",buf2);
   fclose(f);
   rename("tmpfile",lname);
   unlink("tmpfile");
}

void CloseUserList()
{
   DelList(&userList);
   DelList(&editorList);
   DelList(&ownerList);
   DelList(&commentList);
}

char *GetSubscription()
{
   return(subscription);
}

char *GetReview()
{
   return(review);
}

char *GetSend()
{
   return(send);
}

char *GetReplyTo()
{
   return(replyto);
}

char *GetErrorsTo()
{
   return(errorsto);
}
