/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */
/* video_conf.c: video configuration table utilities */
#define NEED_MODELS
#include "models.h"
#include "structs.h"

static VCONF_DEVTABLE vtbl;

#define VCONF_NDEFS	NUM_MODELS

static char 	err_msg[128];
static char	filename[128];
char *fread_config_line();

int  vconf_get_table( file, vdtp )
     char *		file;
     VCONF_DEVTABLE *vdtp;	
{
  FILE *	fp;
  char	line[256];
  int	lnum = 0;
  int	nitems = 0;
  char	ttype[32];
  char	tbaud[16];
  char	tparity[32];
  int	res;
  int	i, j;
  int     highswitch = 0, swtr, cur_forward = 0, intable = 0;
  
  if( vdtp == NULL )
    return conf_err("given an empty table\n",VCONF_NO_TABLE_ERR);
  if( (fp=fopen(file,"r"))==NULL ) {
    bsdsyslog(LOG_NOTICE,"Configuration file (%s) not found.", file);
    return -1;
  }
  
  strcpy( filename, file );
  
  if (num_forwards != 0) {
    if (remote_servers) free(remote_servers);
    if (servs) free(servs);
  }
  num_forwards = 0;

  read_mount_file();
  while( !feof(fp) )
    {
      if (fread_config_line(line, 255, fp) == NULL)
	break;;
      lnum++;
      if( line[strlen(line)]=='\n' )
	line[strlen(line)] = '\0';
      
      if( line[0] == '#' || isspace(line[0]) || line[0] == '\0')
	continue;  /* skip comments, lines starting with space */
      res = sscanf( line, "%s %s %s %s %s %s %s\n",
		   ttype,
		   vtbl.dev[nitems].name,
		   vtbl.dev[nitems].model,
		   vtbl.dev[nitems].tty,
		   tbaud,
		   tparity,
		   vtbl.dev[nitems].channel );
      
      if( res==EOF )
	continue;
      
      if( res != LINE_ITEMS )
	{
	  sprintf(err_msg,"converted %d items, not %d: line %d\n",
		  res,LINE_ITEMS,lnum);
	  return conf_err( err_msg, VCONF_FILE_FMT_ERR );
	}
      
      if( !strcmp( ttype, "SWTR" ) ) {
	vtbl.dev[nitems].type = SWTR_DEV;
	sscanf(vtbl.dev[nitems].name,"SWTR-%d", &swtr);
	if (swtr > highswitch) highswitch = swtr;
      }
      else if( !strcmp( ttype, "RPD" ) )
	vtbl.dev[nitems].type = RPD_DEV;
      else if( !strcmp( ttype, "INPUT" ) )
	vtbl.dev[nitems].type = INPUT_DEV;
#ifdef OBSOLETE
      else if( !strcmp( ttype, "OUTPUT" ) )
	vtbl.dev[nitems].type = OUTPUT_DEV;
#endif /* OBSOLETE */
#ifdef DBM
      else if( !strcmp( ttype, "DATA" ))
	vtbl.dev[nitems].type = DATA_DEV;
#endif /* DBM */
      else if( !strcmp( ttype, "OPTION" ) ) {
	if (DEBUG) printf("Setting %s = %s\n",vtbl.dev[nitems].name,
			  vtbl.dev[nitems].model);
#ifdef NEWCODE
#ifdef BSD43
	setenv(vtbl.dev[nitems].name, vtbl.dev[nitems].model, 1);
#else /* BSD43 */
	scratch_buf = (char *)malloc((strlen(vtbl.dev[nitems].name) +
				     strlen(vtbl.dev[nitems].model) +
				     2) * sizeof(char));
	sprintf(scratch_buf, "%s=%s", vtbl.dev[nitems].name,
		vtbl.dev[nitems].model);
	putenv(scratch_buf);
#endif /* BSD43 */
#endif /* NEWCODE */
	continue;
      }
      else if( !strcmp( ttype, "FORW" ) ) {
	vtbl.dev[nitems].type = NETWORK_DEV;
	num_forwards++;
      }
      else if ( !strcmp(ttype, "IGN"))
	vtbl.dev[nitems].type = IGN_DEV;
      else
	{
	  bsdsyslog(LOG_NOTICE,"unknown device type: %s, line %d\n",ttype,
		    lnum);
	  continue;
	}
      if (vtbl.dev[nitems].type == RPD_DEV || 
	  vtbl.dev[nitems].type == IGN_DEV) {
	intable = 0;
	for (i = 0; i < mtbl.nmounts; i++) {
	  if (!strcmp(vtbl.dev[nitems].name,mtbl.mount_info[i].dev_name)) {
	    strcpy(vtbl.dev[nitems].name,mtbl.mount_info[i].disc_name);
	    if (mtbl.mount_info[i].mountable)
	      vtbl.dev[nitems].type = RPD_DEV;
	    else vtbl.dev[nitems].type = IGN_DEV;
	    mtbl.mount_info[i].realvol = 1;
	    intable = 1;
	  }
	}
	if (!intable) {
	  strcpy(mtbl.mount_info[mtbl.nmounts].dev_name,
		 vtbl.dev[nitems].name);
	  strcpy(mtbl.mount_info[mtbl.nmounts].disc_name,
		 vtbl.dev[nitems].name);
	  if (vtbl.dev[nitems].type == RPD_DEV)
	    mtbl.mount_info[mtbl.nmounts].mountable = 1;
	  else mtbl.mount_info[mtbl.nmounts].mountable = 0;
	  mtbl.mount_info[mtbl.nmounts].realvol = 1;
	  mtbl.nmounts++;
	}
      }
      if (vtbl.dev[nitems].type == RPD_DEV || 
	  vtbl.dev[nitems].type == SWTR_DEV)
	{
	  vtbl.dev[nitems].baud = atoi( tbaud );
#ifndef SYSV
	  if( !strcmp( tparity, "none" ) )
	    vtbl.dev[nitems].parity = 0;
	  else if( !strcmp( tparity, "odd" ) )
	    vtbl.dev[nitems].parity = ODDP;
	  else if( !strcmp( tparity, "even" ) )
	    vtbl.dev[nitems].parity = EVENP;
	  else if( !strcmp( tparity, "any" ) )
	    vtbl.dev[nitems].parity = ANYP;
#else
	  if( !strcmp( tparity, "none" ) )
	    vtbl.dev[nitems].parity = 0;
	  else if( !strcmp( tparity, "odd" ) )
	    vtbl.dev[nitems].parity = PARENB | PARODD;
	  else if( !strcmp( tparity, "even" ) )
	    vtbl.dev[nitems].parity = PARENB;
	  else if( !strcmp( tparity, "any" ) )
	    vtbl.dev[nitems].parity = 0;
#endif /* SYSV */
	  else
	    {
	      bsdsyslog(LOG_NOTICE, "unknown parity type: %s, line %d", 
			tparity, lnum);
	      return VCONF_FILE_FMT_ERR;
	    }
	  
	}
      else {  /* INPUT_DEV */
	vtbl.dev[nitems].parity = 
	  vtbl.dev[nitems].baud = 0;
      }
      nitems++;
    }
  fclose(fp);
  compact_mount_table();  
  if( nitems == 0 )
    conf_err( "must be at least one valid item",
	     VCONF_FILE_FMT_ERR );
  vtbl.ndevs = nitems;
  
  /** here we now need to open other servers and rebuild volume table **/

  remote_servers = (Forward *)malloc(num_forwards*sizeof(Forward));
  servs = (Server **)malloc(num_forwards*sizeof(Server *));
  if (!remote_servers) num_forwards = 0;
  vdtp->ndevs = 0;
  for ( i = 0; i<nitems; i++) {
    if (vtbl.dev[i].type != NETWORK_DEV) { /* a local device */
      bcopy( &vtbl.dev[i], &vdtp->dev[vdtp->ndevs], 
	    sizeof(VCONF_ENTRY) );
      vdtp->ndevs++;
    }
    else { /* a network device */
      if (servs) {
	if (DEBUG) printf("Attempting to open %s, output %d\n",
			  vtbl.dev[i].name,atoi(vtbl.dev[i].tty));
	servs[cur_forward] = GOpenServer(vtbl.dev[i].name,
					 atoi(vtbl.dev[i].tty));
	if (remote_servers) {
	  strcpy(remote_servers[cur_forward].name,vtbl.dev[i].name);
	  if (servs[cur_forward] == NULL) {
	    remote_servers[cur_forward].fd = -1;
	    cur_forward++;
	    continue;
	  }
	  else remote_servers[cur_forward].fd = GConnection(servs);
	}
	GRequestNotification(servs[cur_forward], Notify);
	
	for ( j = 0; j < GNumberVolumes(servs[cur_forward]); j++) {
	  vdtp->dev[vdtp->ndevs].server = servs[cur_forward];
	  sprintf(vdtp->dev[vdtp->ndevs].channel,"%d-%d",
		  highswitch+1,GVolumeIndex(servs[cur_forward],j));
	  vdtp->dev[vdtp->ndevs].parity = vtbl.dev[i].parity;
	  strcpy(vdtp->dev[vdtp->ndevs].name,
		 GVolumeName(servs[cur_forward],j));
	  
	  if (GVolumeType(servs[cur_forward], j)  == RPD_DEV) {
	    if (GVolumeCapabilities(servs[cur_forward], j) & RECORDABLE)
	      strcpy(vdtp->dev[vdtp->ndevs].model,"NETRPD_RECORD");
	    else
	      strcpy(vdtp->dev[vdtp->ndevs].model,"NETRPD");
	    vdtp->dev[vdtp->ndevs].type = RPD_DEV;
	  }
	  else {
	    strcpy(vdtp->dev[vdtp->ndevs].model,"INPUTDEV");
	    vdtp->dev[vdtp->ndevs].type = INPUT_DEV;
	  }
	  strcpy(vdtp->dev[vdtp->ndevs].tty,vtbl.dev[i].name);
	  vdtp->ndevs++;
	}
	vdtp->dev[vdtp->ndevs].type = SWTR_DEV;
	strcpy(vdtp->dev[vdtp->ndevs].model,"NETSWTR");
	vdtp->dev[vdtp->ndevs].server = servs[cur_forward];
	sprintf(vdtp->dev[vdtp->ndevs].name,"SWTR-%d",++highswitch);
	strcpy(vdtp->dev[vdtp->ndevs].channel,vtbl.dev[i].channel);
	strcpy(vdtp->dev[vdtp->ndevs].tty,vtbl.dev[i].name);
	vdtp->ndevs++;
	cur_forward++;
      }
      else 
	bsdsyslog(LOG_NOTICE,"vconf_get_table: unable to malloc for servers");
    }
  }
  return VCONF_AOK;	
}

int vconf_find_model( name )	/* returns index, or -1 */
     char *name;
{
  int	i;
  
  if( !name )
    return -1;
  for( i=0; i<VCONF_NDEFS; i++ )
    if( !strcmp(name,model_tbl[i].the_name) )
      return i;
  return -1;
}

int (*vconf_find_set_func( name ))()
     char *name;
{
  int i;
  if (!name)
    return (NULL);
  for (i = 0; i<VCONF_NDEFS; i++)
    if (!strcmp(name, model_tbl[i].the_name))
      return (model_tbl[i].setfuncs);
  return(NULL);
}

print_models()
{
  int i;
  printf("Available devices are:\n");
  for (i = 0; i < VCONF_NDEFS; i++)
    if (i == NETRPD || i == NETSWTR || i == NETRPD_RECORD) continue;
    else printf("  %s\n",model_tbl[i].the_name);
  return;
}

static int conf_err( explain, retcode )
     char *	explain;
     int	retcode;
{
  if (DEBUG) printf( stderr, "VCONF err: %s: %s\n", filename,explain );
  return retcode;
}

char *fread_config_line(line, max_c, fp)
     char *line;
     int max_c;
     FILE *fp;
{
  int i = 0, temp_c;
  char *cur_point;

  cur_point = line;

  while (i < max_c) {
    temp_c = fgetc(fp);
    *cur_point = (char)temp_c;
    if (temp_c == EOF) {
      if (i == 0) return(NULL);
      else return(line);
    }
    if (*cur_point == '\n') {
      if (i < 1 || *(cur_point-1) != '\\') {
	*cur_point = '\0';
	return(line);
      }
      else {
	cur_point--;
	i--;
      }
    }
    else {
      cur_point++;
      i++;
    }
  }
  return(line);
}
