/* 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/****************************************************************************
 * 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
 ****************************************************************************/

/*
 * ********************************************************************
 *
 * code for processing module configuration commands
 *
 * Modification History
 *
 * Created 09/23/98 by Dan Espen:
 *
 * - Some  of  this Logic   used to reside  in  "read.c",  preceeded by a
 * comment about whether it belonged there.  Time tells.
 *
 * - Added  logic to  execute module config  commands by  passing to  the
 * modules that want "active command pipes".
 *
 * ********************************************************************
 */

#include "config.h"

#include <stdio.h>

#include "libs/fvwmlib.h"
#include "fvwm.h"
#include "externs.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "module_interface.h"
#include "libs/Colorset.h"
#include "libs/FScreen.h"

extern unsigned long *PipeMask;                /* in module.c */

extern int nColorsets;	/* in libs/Colorset.c */

#define MODULE_CONFIG_DELIM ':'

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

struct moduleInfoList *modlistroot = NULL;

static struct moduleInfoList *AddToModList(char *tline);
static void SendConfigToModule(
  int module, const struct moduleInfoList *entry, char *match, int match_len);


/*
 * ModuleConfig handles commands starting with "*".
 *
 * Each command is added to a list from which modules  request playback
 * thru "sendconfig".
 *
 * Some modules request that module config commands be sent to them
 * as the commands are entered.  Send to modules that want it.
 */
void  ModuleConfig(char *action) {
  int module, end;
  struct moduleInfoList *new_entry;

  end = strlen(action) - 1;
  if (action[end] == '\n')
    action[end] = '\0';
  new_entry = AddToModList(action);              /* save for config request */
  for (module = 0; module < npipes; module++) /* look at all possible pipes */
  {
    if (PipeMask[module] & M_SENDCONFIG)    /* does module want config cmds */
    {
      extern char **pipeName;
      char *name = pipeName[module];
#ifndef WITHOUT_KILLMODULE_ALIAS_SUPPORT
      extern char **pipeAlias;
      if (pipeAlias[module]) name = pipeAlias[module];
#endif
      SendConfigToModule(module, new_entry, CatString2("*", name), 0);
    }
  }
}

static struct moduleInfoList *AddToModList(char *tline)
{
  struct moduleInfoList *t, *prev, *this;
  char *rline = tline;
  char *alias_end = skipModuleAliasToken(tline + 1);

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

  while(t != NULL)
  {
    prev = t;
    t = t->next;
  }

  this = (struct moduleInfoList *)safemalloc(sizeof(struct moduleInfoList));

  this->alias_len = 0;
  if (alias_end && alias_end[0] == MODULE_CONFIG_DELIM)
  {
    /* migo (01-Sep-2000): construct an old-style config line */
    char *conf_start = alias_end + 1;
    while (isspace(*conf_start)) conf_start++;
    *alias_end = '\0';
    rline = CatString2(tline, conf_start);
    *alias_end = MODULE_CONFIG_DELIM;
    this->alias_len = alias_end - tline;
  }

  this->data = (char *)safemalloc(strlen(rline)+1);
  strcpy(this->data, rline);

  this->next = NULL;
  if(prev == NULL)
  {
    modlistroot = this;
  }
  else
    prev->next = this;

  return this;
}

/**************************************************************/
/* delete from module configuration                           */
/**************************************************************/
void CMD_DestroyModuleConfig(F_CMD_ARGS)
{
  struct moduleInfoList *current, *next, *prev;
  char *info;   /* info to be deleted - may contain wildcards */
  char *mi;
  char *alias_end;
  int alias_len = 0;

  while (isspace(*action)) action++;
  alias_end = skipModuleAliasToken(action);

  if (alias_end && alias_end[0] == MODULE_CONFIG_DELIM)
  {
    /* migo: construct an old-style config line */
    char *conf_start = alias_end + 1;
    while (isspace(*conf_start)) conf_start++;
    *alias_end = '\0';
    GetNextToken(conf_start, &conf_start);
    if (conf_start == NULL)
      return;
    info = stripcpy(CatString2(action, conf_start));
    *alias_end = MODULE_CONFIG_DELIM;
    alias_len = alias_end - action + 1;  /* +1 for a leading '*' */
    free(conf_start);
  }
  else
  {
    GetNextToken(action, &info);
    if (info == NULL)
      return;
  }

  current = modlistroot;
  prev = NULL;

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

static void send_xinerama_state(int modnum)
{
  SendName(modnum, M_CONFIG_INFO, 0, 0, 0, FScreenGetConfiguration());
  return;
}

void CMD_Send_ConfigInfo(F_CMD_ARGS)
{
  struct moduleInfoList *t;
  char *message, msg2[32];
  char *match;                          /* matching criteria for module cmds */
  int match_len = 0;                    /* get length once for efficiency */
  int n;
  char *ImagePath = GetImagePath();

  GetNextToken(action, &match);
  if (match) {
    match_len = strlen(match);
  }

  /* send desktop geometry */
  sprintf(msg2,"DesktopSize %d %d\n", Scr.VxMax / Scr.MyDisplayWidth + 1,
	  Scr.VyMax / Scr.MyDisplayHeight + 1);
  SendName(*Module,M_CONFIG_INFO,0,0,0,msg2);

  /* send ImagePath and ColorLimit first */
  if (ImagePath && strlen(ImagePath))
  {
    message=safemalloc(strlen(ImagePath)+12);
    sprintf(message,"ImagePath %s\n",ImagePath);
    SendName(*Module,M_CONFIG_INFO,0,0,0,message);
    free(message);
  }
#ifdef XPM
  {
    sprintf(msg2,"ColorLimit %d\n",Scr.ColorLimit);
    SendName(*Module,M_CONFIG_INFO,0,0,0,msg2);
  }
#endif
  send_xinerama_state(*Module);
  /* now dump the colorsets (0 first as others copy it) */
  for (n = 0; n < nColorsets; n++)
    SendName(*Module, M_CONFIG_INFO, 0, 0, 0, DumpColorset(n, &Colorset[n]));

  /* Dominik Vogt (8-Nov-1998): Scr.ClickTime patch to set ClickTime to
   * 'not at all' during InitFunction and RestartFunction. */
  sprintf(msg2,"ClickTime %d\n", (Scr.ClickTime < 0) ?
	  -Scr.ClickTime : Scr.ClickTime);
  SendName(*Module,M_CONFIG_INFO,0,0,0,msg2);
  sprintf(msg2,"MoveThreshold %d\n", Scr.MoveThreshold);
  SendName(*Module,M_CONFIG_INFO,0,0,0,msg2);

  for (t = modlistroot; t != NULL; t = t->next)
  {
    SendConfigToModule(*Module, t, match, match_len);
  }
  SendPacket(*Module,M_END_CONFIG_INFO,0,0,0,0,0,0,0,0);
  free(match);
}

static void SendConfigToModule(
  int module, const struct moduleInfoList *entry, char *match, int match_len)
{
  if (match)
  {
    if (match_len == 0)
      match_len = strlen(match);
    if (entry->alias_len > 0 && entry->alias_len != match_len)
      return;
    /* migo: this should be strncmp not strncasecmp probably. */
    if (strncasecmp(entry->data, match, match_len) != 0)
      return;
  }
  SendName(module, M_CONFIG_INFO, 0, 0, 0, entry->data);
}


syntax highlighted by Code2HTML, v. 0.9.1