/*
  areas_file routines for gtic
*/

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

#include "config.h"

list_t *areas;

struct flag_tab area_flag_tab[]={
{AREA_READONLY,         "readonly"},
{AREA_PASSTHRU,         "passthru"},
{AREA_NOANNOUNCE,       "noannounce"},
{AREA_PRIVATE_ANNOUNCE, "private_announce"},
{AREA_NO_DESC,		"no_desc"},
{AREA_NO_REPLACES,		"no_replaces"},
{0,                     NULL}
};

void read_areagroups_config(void)
{
  FILE *fp; int linecnt=0,i; area_t *atmp;
  char buff[BUFSIZE],groupmask[SMALLBUFSIZE],dest[SMALLBUFSIZE],*p,*curgroup;
  if(areagroups_config==NULL) return;
  ass(areas!=NULL);
  fp=fopen(areagroups_config,"r");
  if(fp==NULL)
  {
    e_printf("unable to open areagroups_config %s: ",areagroups_config);
    perror("");
    abort2();
  }
  while(1)
  {
    p=fgets(buff,sizeof(buff)-1,fp); linecnt++;
    if(p==NULL) break;
    if(buff[0]==0 || buff[0]=='#') continue;
    delcrlf(p);
    p=strtok(buff,":");
    if(!p)
    {
      e_printf("%s(%d): invalid token #1",areagroups_config,linecnt);
      abort2();
    }
    strcpy(groupmask,p);
    p=strtok(NULL,":");
    if(!p)
    {
      e_printf("%s(%d): invalid token #2",areagroups_config,linecnt);
      abort2();
    }
    strcpy(dest,p);
    p=strtok(NULL,":");
/*    if(!p)
    {
      e_printf("%s(%d): invalid token #3",areagroups_config,linecnt);
      abort2();
    }*/
    for(i=0;i<list_head_max(areas);i++)
    {
      atmp=list_get_entry(areas,i);
      ass(atmp!=NULL);
      
      if(atmp->group==NULL)
        curgroup="*";
      else
        curgroup=atmp->group;

      if(wildmat_icase(curgroup,groupmask))
      {
        if(!strcasecmp(dest,"options"))
	{
	  if(atmp->group_options==FALSE)
	  {
	    if(p)
	      atmp->flags|=parse_list_with_flag_tab(areagroups_config,linecnt,p,
	  	       (struct flag_tab *)&area_flag_tab,", \t");
            atmp->group_options=TRUE;
	  }
	}
	/* TODO: another dest's support */
      }
    }
  }
  fclose(fp);
}

void readareas(void)
{
  FILE *fp; char buff1[BUFSIZE];
  area_t *cur=NULL; char *p,*pp; int first=1; user_t *tmp;
  int linecnt=0;
  fp=fopen(areas_file,"r");
  if(fp==NULL)
  {
    e_printf("unable to open areas_file %s: ",areas_file);
    perror("");
    abort2();
  }
  areas=list_init();
  while(1)
  {
    p=fgets(buff1,sizeof(buff1)-1,fp); linecnt++;
    if(p) delcrlf(p);
    /* C has left-to-right order */
    if(!p || (!strncasecmp(buff1,"area",4) && strchr(DELIM,buff1[4])))
    {
      if(!p && !cur) break;
      if(!first)
      {
        if(!cur->path)
	{
	  e_printf("%s(%d?): path for area %s not defined",
	    areas_file,linecnt,cur->name?cur->name:"?not defined too?");
	  abort2();
	}
        if(!cur->name)
	{
	  e_printf("%s(%d?): name for area with path %s not defined",
	    areas_file,linecnt,cur->path?cur->path:"?not defined too?");
	  abort2();
	}
	if(!cur->users)
	{
	  e_printf("%s(%d?): users for area %s with path %s not defined"
	  	,areas_file,linecnt,cur->name?cur->name:"?not defined?",
		cur->path?cur->path:"?not defined?");
	  abort2();
	}
/*printf("DEBUG: readareas - name=%s, path=%s, desc=%s, newfiles=%s, &aka=%p,"
"*users=%p, flags=%04X\n",cur->name,cur->path,cur->desc,cur->newfile,
cur->aka,cur->users,cur->flags);
*/
	list_add(areas,cur->name,cur);
        if(!p) break;
      }
      else
        first=0;
    }
    if(buff1[0]==0 || buff1[0]=='#') continue;
    else if(!strncasecmp(buff1,"area",4) && strchr(DELIM,buff1[4]))
    {
      cur=xmalloc(sizeof(area_t));

      /* default values */
      cur->desc=NULL;
      cur->aka=NULL;
      cur->newfile=NULL;
      cur->group=NULL;
      cur->mode=-1;
      cur->flags=0;
      cur->real_flags=0;
      cur->group_options=FALSE;

      /* this keyword must be specifed */
      cur->path=NULL;
      cur->name=NULL;
      cur->users=NULL;
      
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Area string",areas_file,linecnt);
        abort2();
      }
      cur->name=xstrcpy(p);
    }
    else if(!strncasecmp(buff1,"description",11) && strchr(DELIM,buff1[11]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Description string",areas_file,linecnt);
        abort2();
      }
      cur->desc=xstrcpy(p);
    }
    else if(!strncasecmp(buff1,"path",4) && strchr(DELIM,buff1[4]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Path string",areas_file,linecnt);
        abort2();
      }
      cur->path=xstrcpy(p);
    }
    else if(!strncasecmp(buff1,"group",5) && strchr(DELIM,buff1[5]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Group string",areas_file,linecnt);
        abort2();
      }
      cur->group=xstrcpy(p);
    }
    else if(!strncasecmp(buff1,"mode",4) && strchr(DELIM,buff1[4]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Mode string",areas_file,linecnt);
        abort2();
      }
      sscanf(p,"%o",&(cur->mode));
    }
    else if(!strncasecmp(buff1,"aka",3) && strchr(DELIM,buff1[3]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty AKA string",areas_file,linecnt);
        abort2();
      }
      cur->aka=(node_t*)xmalloc(sizeof(node_t));
			if(ftntonode(cur->aka,p,NULL))
			{
				e_printf("%s(%d): \"%s\" is not a FTN addr",areas_file,linecnt,p);
				abort2();
			}
    }
    else if(!strncasecmp(buff1,"links",5) && strchr(DELIM,buff1[5]))
    {
      p=strschr(buff1,DELIM);
/*      if(!p)
      {
        e_printf("%s(%d): empty Links string",areas_file,linecnt);
        abort2();
      }*/
      if(p==NULL)
      {
        cur->users=list_init();
	continue;
      }
      p=strtok(p,", \t");
      if(p)
        cur->users=list_init();
      while(p)
      {
        pp=p[0]=='!'?p+1:p;
	tmp=list_find_entry(users,pp);
	if(!tmp)
	{
	  e_printf("%s(%d): %s - unknown node",areas_file,linecnt,pp);
	  abort2();
	}
/*printf("DEBUG: (areas.c) tmp->passwd=%s, flags=%d\n",tmp->passwd,tmp->flags);
*/
	list_add(cur->users,p,tmp);
        p=strtok(NULL,", \t");
      }
    }
    else if(!strncasecmp(buff1,"options",7) && strchr(DELIM,buff1[7]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Options string",areas_file,linecnt);
        abort2();
      }
      cur->flags=parse_list_with_flag_tab(areas_file,linecnt,p,
      	(struct flag_tab *)&area_flag_tab,", \t");
      cur->real_flags=cur->flags;
    }
    else if(!strncasecmp(buff1,"newfile",7) && strchr(DELIM,buff1[7]))
    {
      p=strschr(buff1,DELIM);
      if(!p)
      {
        e_printf("%s(%d): empty Newfile string",areas_file,linecnt);
        abort2();
      }
      cur->newfile=xstrcpy(p);
    }
    else
    {
      e_printf("%s(%d): %s - invalid keyword - ignored",
        areas_file,linecnt,buff1);
    }
  }
  read_areagroups_config();
}

void writeareas(void)
{
  int i,j; char new_path[PATH_MAX];
  FILE *fp; struct stat stat_buff;
  area_t *a;
  int stat_fail=FALSE;

  ass(areas!=NULL);

  /* get uid,gid,mode for old areas_file */
  if(stat(areas_file,&stat_buff))
  {
    l_printf("Warning: unable to stat %s",areas_file);
    stat_fail=TRUE;
  }

  /* make a backup copy of areas_file */
  strcpy(new_path,areas_file);
    strcat(new_path,".bak");
  if(rename(areas_file,new_path))
    l_printf("Warning: unable to move %s to %s",areas_file,new_path);

  /* try to create new areas_file, restore backup if fail */
  fp=fopen(areas_file,"w");
  if(fp==NULL)
  {
    e_printf("unable to create areas_file %s, trying to restore backup",
        areas_file);
    if(rename(new_path,areas_file))
      e_printf("unable to restore areas file (%s to %s)",new_path,areas_file);
    return;
  }

  /* restore permissions and uid/gid */
  fchmod(fileno(fp),stat_fail?0600:stat_buff.st_mode);
  if(stat_fail==FALSE)
    fchown(fileno(fp),stat_buff.st_uid,stat_buff.st_gid);

  /* write areas list */
  for(i=0;i<list_head_max(areas);i++)
  {
    a=list_get_entry(areas,i);
    ass(a!=NULL);

    ass(a->name!=NULL);
    ass(a->path!=NULL);
    ass(a->users!=NULL);

    fprintf(fp,"Area %s\n",a->name);

    if(a->desc)
      fprintf(fp,"Description %s\n",a->desc);

    fprintf(fp,"Path %s\n",a->path);

    if(a->aka)
      fprintf(fp,"AKA %s\n",nodetoftn(NULL,a->aka));

    fprintf(fp,"Links");
    for(j=0;j<list_head_max(a->users);j++)
    {
      fprintf(fp," %s",(char *)list_get_key(a->users,j));
    }
    fprintf(fp,"\n");

    if(a->group)
      fprintf(fp,"Group %s\n",a->group);

    if(a->real_flags)
    {
      fprintf(fp,"Options ");
      write_flag_tab_to_FILE(fp,a->real_flags,(struct flag_tab*)&area_flag_tab);
      fprintf(fp,"\n");
    }

    if(a->mode!=-1)
      fprintf(fp,"Mode %o\n",a->mode);

    if(a->newfile)
      fprintf(fp,"Newfile %s\n",a->newfile);

    fprintf(fp,"\n");
  }
  ass(fclose(fp)==0);
}


syntax highlighted by Code2HTML, v. 0.9.1