/****************************************************************************
 * This module is all original code 
 * by Rob Nation 
 * Copyright 1993, Robert Nation
 *     You may use this code for any purpose, as long as the original
 *     copyright remains in the source code and all documentation
 ****************************************************************************/
#include <FVWMconfig.h>

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>

#include "fvwm.h"
#include "menus.h"
#include "misc.h"
#include "parse.h"
#include "screen.h"
#include "module.h"

char *fvwm_file = NULL;

struct moduleInfoList
{
  char *data;
  struct moduleInfoList *next;
};

struct moduleInfoList *modlistroot = NULL;

int numfilesread = 0;

static int last_read_failed=0;

#ifdef FVWMRC /* FVWMRC should be .fvwm95rc or .fvwmrc */
static char *read_system_rc_cmd="Read system"FVWMRC;
#else
static char *read_system_rc_cmd="Read system.fvwm95rc";
#endif

void AddToModList(char *tline);

extern void StartupStuff(void);

/*
 * func to do actual read/piperead work
 */
static void ReadSubFunc(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
                        unsigned long context, char *action,int* Module,
                        int piperead)
{
  char *filename= NULL,*Home, *home_file, *ofilename = NULL;
  char *rest,*tline,line[1000];
  int HomeLen;
  FILE *fd;
  int thisfileno;
  extern Bool Restarting;
  extern XEvent Event;

  thisfileno = numfilesread;
  numfilesread++;

/*  fvwm_msg(INFO,piperead?"PipeRead":"Read","action == '%s'",action); */

  rest = GetNextToken(action,&ofilename);
  if(ofilename == NULL)
  {
    fvwm_msg(ERR,piperead?"PipeRead":"Read","missing parameter");
    last_read_failed = 1;
    return;
  }

  filename = ofilename;
/*  fvwm_msg(INFO,piperead?"PipeRead":"Read","trying '%s'",filename); */

  if (piperead)
    fd = popen(filename,"r");
  else
    fd = fopen(filename,"r");

  if (!piperead)
    {
    if((fd == NULL)&&(ofilename[0] != '/'))
      {
      /* find the home directory to look in */
      Home = getenv("HOME");
      if (Home == NULL)
	Home = "./";
      HomeLen = strlen(Home);
      home_file = safemalloc(HomeLen + strlen(ofilename)+3);
      strcpy(home_file,Home);
      strcat(home_file,"/");
      strcat(home_file,ofilename);
      filename = home_file;
      fd = fopen(filename,"r");      
      }
    if((fd == NULL)&&(ofilename[0] != '/'))
      {
      if((filename != NULL)&&(filename!= ofilename))
	free(filename);
      /* find the home directory to look in */
      Home = FVWMDIR;
      HomeLen = strlen(Home);
      home_file = safemalloc(HomeLen + strlen(ofilename)+3);
      strcpy(home_file,Home);
      strcat(home_file,"/");
      strcat(home_file,ofilename);
      filename = home_file;
      fd = fopen(filename,"r");      
      }
    }

  if(fd == NULL)
    {
      fvwm_msg(ERR,
               piperead?"PipeRead":"Read",
               piperead?"command '%s' not run":"file '%s' not found in $HOME or "FVWMDIR,
               ofilename);
      if((ofilename != filename)&&(filename != NULL))
	{
	  free(filename);
	  filename = NULL;
	}
      if(ofilename != NULL)
	{
	  free(ofilename);
	  ofilename = NULL;
	}
      last_read_failed = 1;
      return;
    }
  if((ofilename != NULL)&&(filename!= ofilename))
     free(ofilename);
  fcntl(fileno(fd), F_SETFD, 1);
  if(fvwm_file != NULL)
    free(fvwm_file);
  fvwm_file = filename;

  tline = fgets(line,(sizeof line)-1,fd);
  while(tline != (char *)0)
    {
      int l;
      while(tline && (l=strlen(line))<sizeof(line) &&
           line[l-1]=='\n' && line[l-2]=='\\')
       {
         tline = fgets(line+l-2,sizeof(line)-l,fd);
       }
      tline=line;
      while(isspace(*tline))tline++;
      /* should these next checks be moved into ExecuteFunction? */
      if((strlen(&tline[0])>1)&&(tline[0]!='#')&&(tline[0]!='*'))
	ExecuteFunction(tline,tmp_win,eventp,context,*Module);
      if(tline[0] == '*')
	AddToModList(tline);
      tline = fgets(line,(sizeof line)-1,fd);
    }

  if (piperead)
    pclose(fd);
  else
    fclose(fd);

  last_read_failed = 0;
}

void ReadFile(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
              unsigned long context, char *action,int* Module)
{
  int this_read = numfilesread;
  ReadSubFunc(eventp,junk,tmp_win,context,action,Module,0);

  if (last_read_failed && this_read == 0)
  {
    fvwm_msg(INFO,"Read","trying to read system rc file");
    ExecuteFunction(read_system_rc_cmd,NULL,&Event,C_ROOT,-1);
  }

  if (this_read == 0)
  {
    StartupStuff();
  }
}

void PipeRead(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
              unsigned long context, char *action,int* Module)
{
  int this_read = numfilesread;
  ReadSubFunc(eventp,junk,tmp_win,context,action,Module,1);

  if (last_read_failed && this_read == 0)
  {
    fvwm_msg(INFO,"PipeRead","trying to read system rc file");
    ExecuteFunction(read_system_rc_cmd,NULL,&Event,C_ROOT,-1);
  }

  if (this_read == 0)
  {
    StartupStuff();
  }
}

void AddToModList(char *tline)
{
  struct moduleInfoList *t, *prev, *this;

  /* Find end of list */
  t = modlistroot;
  prev = NULL;

  while(t != NULL)
    {
      prev = t;
      t = t->next;
    }
  
  this = (struct moduleInfoList *)safemalloc(sizeof(struct moduleInfoList));
  this->data = (char *)safemalloc(strlen(tline)+1);
  this->next = NULL;
  strcpy(this->data, tline);  
  if(prev == NULL)
    {
      modlistroot = this;
    }
  else
    prev->next = this;

}

/* interface function for AddToModList */
void AddModConfig(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
                  unsigned long context, char *action,int* Module)
{
  AddToModList( action );
}

/**************************************************************/
/* delete from module configuration                           */
/**************************************************************/
void DestroyModConfig(XEvent *eventp,Window junk,FvwmWindow *tmp_win,
                      unsigned long context, char *action,int* Module)
{
  struct moduleInfoList *this, *that, *prev;
  char *info;   /* info to be deleted - may contain wildcards */
  char *mi;

  action = GetNextToken(action,&info); 
  if( info == NULL )
  {
    return;
  }

  this = modlistroot;
  prev = NULL;
  while(this != NULL)
  {
    GetNextToken( this->data, &mi);
    that = this->next;
    if( matchWildcards(info, mi+1) )
    {
      free(this->data);
      free(this);
      if( prev )
      {
        prev->next = that;
      }
      else
      {
        modlistroot = that;
      }
    }
    else
    {
      prev = this;
    }
    this = that;
  }
}

void SendDataToModule(XEvent *eventp,Window w,FvwmWindow *tmp_win,
	      unsigned long context, char *action, int *Module)
{
  struct moduleInfoList *t;
  char message[256];
  extern char *IconPath;
#ifdef XPM
  extern char *PixmapPath;
#endif

  sprintf(message,"IconPath %s\n",IconPath);
  SendName(*Module,M_CONFIG_INFO,0,0,0,message);
#ifdef XPM
  sprintf(message,"PixmapPath %s\n",PixmapPath);
  SendName(*Module,M_CONFIG_INFO,0,0,0,message);
#endif
  sprintf(message,"ClickTime %d\n",Scr.ClickTime);
  SendName(*Module,M_CONFIG_INFO,0,0,0,message);

  t = modlistroot;
  while(t != NULL)
    {
      SendName(*Module,M_CONFIG_INFO,0,0,0,t->data);
      t = t->next;
    }  
  SendPacket(*Module,M_END_CONFIG_INFO,0,0,0,0,0,0,0,0);
}
