/*
 * Copyright 1988, 1989, 1990, 1991 Massachusetts Institute of Technology
 */
#include"structs.h"

/* parm 1 is output number */
/* parm 2 is the client user's uid */
/* parm 3 is the auth_type to use */
/* parm 4 is whether to send additional capabilities with the type */
DoOpenServer(msgsock,hostcommand, j)
     int msgsock, j;
     Galatea_packet *hostcommand;
{
  int i, vols_for_client = 0, reject_client = 0, vol_type;
  int cur_ext;

  clients[j].rev = revision;
  clients[j].uid = hostcommand->parm[2];

  if (hostcommand->parm[1] > MAXSERVEROUTS) reject_client = 1;
  else clients[j].output = hostcommand->parm[1];
  for ( i = 0; i < num_volumes; i++)
    if (volumes[i].output == hostcommand->parm[1]) vols_for_client++;
  if (sendint(msgsock,vols_for_client) == -1) return(-1);

  for (i = 0 ; i< num_volumes; i++)
    if (volumes[i].output == hostcommand->parm[1]) {
      if (sendint(msgsock,i) == -1) return(-1);
      vol_type = volumes[i].type;
      if (hostcommand->parm[4] == 1) {
	if (volumes[i].recordable) vol_type |= RECORDABLE;
      }
      if (sendint(msgsock,vol_type) == -1) return(-1);
      if (sendstring(msgsock,volumes[i].volume) == -1) return(-1);
/*      if (DEBUG) printf("Volume %d, %s\n",i, volumes[i].volume);*/
    }
  if (sendint(msgsock, VIDEO_CHAN | LEFT_CHAN | RIGHT_CHAN) == -1) return(-1);

  if (sendint(msgsock, extnumexts()) == -1) return(-1);
  for (cur_ext = 0; cur_ext < extnumexts(); cur_ext++)
    if (sendstring(msgsock, extname(cur_ext)) == -1) return (-1);

  if (sendint(msgsock, MAX_LOCK_TIME) == -1) return(-1);
  if (reject_client) {
    if (sendint(msgsock, BAD_OUTPUT) == -1) return(-1);  /* ex1 */
  }
  else
    if (sendint(msgsock, 0) == -1) return(-1);  /* ex1 */
  if (sendint(msgsock, 0) == -1) return(-1);  /* ex2 */
  if (sendint(msgsock, 0) == -1) return(-1);  /* ex3 */

  if (sendint(msgsock, SERVER_REVISION) == -1) return(-1);  /* ex4 */

  if (sendint(msgsock, G_MINEXT) == -1) return(-1);  /* ex5 */
  if (sendint(msgsock, 0) == -1) return(-1);  /* ex6 */
  if (sendint(msgsock, 0) == -1) return(-1);  /* ex7 */
  if (sendint(msgsock, 0) == -1) return(-1);  /* ex8 */
/*  if (DEBUG) printf ("Returning from OpenServer\n");*/
  if (reject_client) {
    if (DEBUG) printf("Rejecting client %d\n", j);
    close_client(j);
  }
  return(-2);
}

/* parm 1 is srcnum,
   parm 2 is channel
   parm 3 is sync */
/* returns BAD_VOLUME  */
DoSwitch(msgsock,hostcommand,i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  Output cur_output;
  int whichdevice;
  whichdevice = hostcommand->parm[1];

  if (clients[i].rev != revision) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (whichdevice >= num_volumes) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  sync_mode = hostcommand->parm[3];
  GSetState(0,0, sync_mode);
  cur_output = volumeoutput(whichdevice, i);

  if (doswitchtree(cur_output,hostcommand->parm[2],clients[i].output)==-1){
    sync_mode = SYNC_MODE;
    GSetState(0,0, sync_mode);
    if (!hostcommand->parm[3]) return(sendint(msgsock,COULDNT_ROUTE));
    return(-2);
  }    
  if (hostcommand->parm[2] & LEFT_CHAN) cur_volume_l = hostcommand->parm[1];
  if (hostcommand->parm[2] & RIGHT_CHAN) cur_volume_r = hostcommand->parm[1];
  if (hostcommand->parm[2] & VIDEO_CHAN) cur_volume_v = hostcommand->parm[1];

  sync_mode = SYNC_MODE;
  GSetState(0,0, sync_mode);

  if (!hostcommand->parm[3]) return(sendint(msgsock,NO_ERROR));
  return(-2);
}

Output volumeoutput(whichvol, cli)
     int whichvol, cli;
{
  RPD_ptr rpd;
  INPUT_ptr inputter;
  
  if (volumes[whichvol].type == RPD_DEV) {
    rpd = 
      players[volumes[whichvol].resource[volumes[whichvol].cur_resource]];
    return(rpd->output_chans[rpd->outputnum[clients[cli].output]]);
  }
  else {
    inputter = 
      inputs[volumes[whichvol].resource[volumes[whichvol].cur_resource]];
    return(inputter->output_chans[inputter->outputnum[clients[cli].output]]);
  }
}

int doswitchtree(oneoutput,mask,output)
     Output oneoutput;
     int mask, output;
{

  SWTR_ptr switcher;
  Output cur_output;
  int new_serv_out, swtch = 0;

/* I want this routine to be fast, so assume the switchers are all
   correct.  build_volumes should make sure tables are right. */

  cur_output = oneoutput;
  while (cur_output.switcher != 0) {
    switcher = switchers[realswitcher[cur_output.switcher]];
    new_serv_out = switcher->outputnum[output];
    if (new_serv_out == -1) return -1;
    if (DEBUG) 
      printf("Attempting to set SWTR-%d, output %d, mask %d to input %d\n",
	     cur_output.switcher, new_serv_out, mask, cur_output.channel);
    if ((*switcher->set_chan_src)(switcher, mask, cur_output.channel,
				  new_serv_out) < 0) {
      swtch = -1;
      bsdsyslog(LOG_NOTICE,"Switch failed: %s on %s\n",
		switcher->devname, switcher->port);
    }
    cur_output = switcher->output_chans[new_serv_out];
  }
  return swtch;
}

/* This routine will return an array of outnums which can be used to describe
   an RPD's output capability.  It will also fill in the info for any
   switchers that have not been filled out. */
newfindoutputnums(oneoutput, num_outputs, realoutputs)
     Output oneoutput;
     int *num_outputs;
     int **realoutputs;
{
  int i, j;
  int num_newoutputs, whichswitch, *newoutputs;

/* Case 1: The inputted output is really a server final output */
  if (oneoutput.switcher == 0) {  /* really trivial case */
    *num_outputs = 1;
    *realoutputs = (int *)malloc(1 * sizeof(int));
    if (*realoutputs == NULL) {
      *num_outputs = 0;
      return(0);
    }
    *realoutputs[0] = oneoutput.channel;
    return(0);
  }
  whichswitch = realswitcher[oneoutput.switcher];
  if (whichswitch == -1) {
    *num_outputs = 0;
    return(0);
  }
/* Case 2: The switcher to which the inputted output is pointing is already
   computed.  We just need to return all of the outputs that the
   switcher can lead to */
  if (switchers[whichswitch]->computed == 0) {  /* fairly simple case */
    *num_outputs = 0;
    for (i = 0; i < MAXSERVEROUTS; i++)
      if (switchers[whichswitch]->outputnum[i] != -1) (*num_outputs)++;
    *realoutputs = (int *)malloc(*num_outputs * sizeof(int));
    if (*realoutputs == NULL) {
      *num_outputs = 0;
      return(0);
    }
    j = 0;
    for (i = 0; i < MAXSERVEROUTS; i++)
      if (switchers[whichswitch]->outputnum[i] != -1) 
	(*realoutputs)[j++] = i;
    return(0);
  }
/* Case 3: We are actually working on figuring out this switch already
   so we don't want to get into an infinite loop */
  if (switchers[whichswitch]->computed == -2) {
    *num_outputs = 0;
    return(0);
  }
/* Case 4: This switch hasn't been figured out yet, so we must recurse
   down to the next switches, then figure this one output */
  switchers[whichswitch]->computed = -2; /* eliminate infinite loops */
  for ( i = 1; i < switchers[whichswitch]->outputs + 1; i++ ) {
    if (switchers[whichswitch]->output_chans[i].switcher == -1) continue;
    newoutputs = NULL;
    newfindoutputnums(switchers[whichswitch]->output_chans[i], 
		      &num_newoutputs, &newoutputs);
    for (j = 0; j < num_newoutputs; j++)
      switchers[whichswitch]->outputnum[newoutputs[j]] = i;
    if (newoutputs) free(newoutputs);
  }
  *num_outputs = 0;
  for (i = 0; i < MAXSERVEROUTS; i++)
    if (switchers[whichswitch]->outputnum[i] != -1) (*num_outputs)++;
  *realoutputs = (int *)malloc(*num_outputs * sizeof(int));
  if (*realoutputs == NULL) {
    *num_outputs = 0;
    return(0);
  }
  j = 0;
  for (i = 0; i < MAXSERVEROUTS; i++)
    if (switchers[whichswitch]->outputnum[i] != -1) 
      (*realoutputs)[j++] = i;
  switchers[whichswitch]->computed = 0;  /* mark this switch as computed */
  return(0);
}
/* parm 1 is volume
   parm 2 is frame
   parm 3 is mask
   parm 4 is sync */
/* returns {actual current frame | BAD_VOLUME | FUNC_NOT_SUPPORTED | 
 COULDNT_SEARCH}*/
DoSearch(msgsock,hostcommand,i)
     int msgsock,i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  Output cur_output;
  int retframe, resource, mask;

  if (clients[i].rev != revision) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }

  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  resource = findclosetresource(hostcommand->parm[1], 
				hostcommand->parm[2]);
  if (resource == -1) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  volumes[hostcommand->parm[1]].cur_resource = resource;

  rpd = players[volumes[hostcommand->parm[1]].resource[resource]];

  if (rpd == NULL) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  (*rpd->search)(rpd,hostcommand->parm[2],1);

  mask = hostcommand->parm[3];

  if (hostcommand->parm[1] == cur_volume_l) {
    mask |= LEFT_CHAN;
  }
  if (hostcommand->parm[1] == cur_volume_r) {
    mask |= RIGHT_CHAN;
  }
  if (hostcommand->parm[1] == cur_volume_v) {
    mask |=  VIDEO_CHAN;
  }

  cur_output = volumeoutput(hostcommand->parm[1], i);

  if (mask) {
    if (doswitchtree(cur_output, mask, clients[i].output) == -1) {
      if (!hostcommand->parm[4]) return(sendint(msgsock,COULDNT_ROUTE));
      return(-2);
    }
  }    

  retframe = (*rpd->getframe)(rpd);

  if (!hostcommand->parm[4]) return(sendint(msgsock,retframe));
  return(-2);
}


findclosetresource(volume,goal)
     int volume, goal;
{
  int cur_close, cur_res, next_close, i;
  RPD_ptr rpd;

  if (volumes[volume].type != RPD_DEV || !volumes[volume].num_resources) 
    return(-1);
  
  rpd = players[volumes[volume].resource[0]];
  if (rpd == NULL) return(-1);

  cur_close = (*rpd->getframe)(rpd);
  
  cur_res = 0;

  for ( i = 1; i < volumes[volume].num_resources; i++) {
    rpd = players[volumes[volume].resource[i]];
    next_close = (*rpd->getframe)(rpd);
    if (abs(goal-next_close) < abs(goal-cur_close) && (
      next_close > 0 && next_close < VOLUME_LIST_OLD)) {
      cur_close = next_close;
      cur_res = i;
    }
  }
  return(cur_res);
}

findclosestunlockeddevice(volume,goal)
     int volume, goal;
{
  int cur_close, cur_res, next_close, i;
  RPD_ptr rpd;

  if (volumes[volume].type != RPD_DEV || !volumes[volume].num_resources) 
    return(-1);
  
  cur_res = -1;

  for ( i = 0; i < volumes[volume].num_resources; i++) {
    rpd = players[volumes[volume].resource[i]];
    if (rpd->avail != -1) continue;
    next_close = (*rpd->getframe)(rpd);
    if ((next_close > 0 && next_close < LOWEST_ERROR) &&
	(abs(goal-next_close) < abs(goal-cur_close) ||
	 cur_res == -1)) {
      cur_close = next_close;
      cur_res = i;
    }
  }
  return(cur_res);
}

/* parm 1 is volume,
   parm 2 is INDEX_ON or INDEX_OFF or INDEX_TOGGLE
   parm 3 is sync */
/* returns {NO_ERROR | BAD_VOLUME | BAD_ARGUMENT | FUNC_NOT_SUPPORTED} */
DoIndex(msgsock,hostcommand,j)
     int msgsock;
     Galatea_packet *hostcommand;
{
  int i;
  RPD_ptr rpd;

  if (clients[j].rev != revision) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }

  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  if (hostcommand->parm[2] != INDEX_ON && 
      hostcommand->parm[2] != INDEX_OFF &&
      hostcommand->parm[2] != INDEX_TOGGLE) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_ARGUMENT));
    return(-2);
  }

  if (hostcommand->parm[2] == INDEX_TOGGLE) {
    if (volumes[hostcommand->parm[1]].index_state == INDEX_ON)
      hostcommand->parm[2] = INDEX_OFF;
    else hostcommand->parm[2] = INDEX_ON;
  }
  volumes[hostcommand->parm[1]].index_state = hostcommand->parm[2];
  for ( i = 0 ; i < volumes[hostcommand->parm[1]].num_resources; i++) {
    rpd = players[volumes[hostcommand->parm[1]].resource[i]];
    if (rpd == NULL) continue;
    (*rpd->cmd)(rpd,hostcommand->parm[2]);
  }
  if (!hostcommand->parm[3]) return(sendint(msgsock,NO_ERROR));
  return(-2);
}

/* parm 1 is volume,
   parm 2 is a LEFT_CHAN | RIGHT_CHAN | VIDEO_CHAN | INDEX_CTRL | SQUELCH_CTRL
   parm 3 is TURN_ON or TURN_OFF
   parm 4 is sync */
/* returns {NO_ERROR | BAD_VOLUME | BAD_ARGUMENT | FUNC_NOT_SUPPORTED} */
DoConfigure(msgsock,hostcommand,j)
     int msgsock, j;
     Galatea_packet *hostcommand;
{
  int i, res = 0;
  RPD_ptr rpd;

  if (clients[j].rev != revision) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }

  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  if (hostcommand->parm[3] != TURN_ON && 
      hostcommand->parm[3] != TURN_OFF) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,BAD_ARGUMENT));
    return(-2);
  }

  for ( i = 0 ; i < volumes[hostcommand->parm[1]].num_resources; i++) {
    rpd = players[volumes[hostcommand->parm[1]].resource[i]];
    if (rpd == NULL) continue;
    if (hostcommand->parm[3] == TURN_ON) {
      if (hostcommand->parm[2] & LEFT_CHAN) res += (*rpd->cmd)(rpd,A1_ON);
      if (hostcommand->parm[2] & RIGHT_CHAN) res += (*rpd->cmd)(rpd,A2_ON);
      if (hostcommand->parm[2] & VIDEO_CHAN) res += (*rpd->cmd)(rpd,VIDEO_ON);
      if (hostcommand->parm[2] & INDEX_CTRL) res += (*rpd->cmd)(rpd,INDEX_ON);
      if (hostcommand->parm[2] & SQUELCH_CTRL)
	res += (*rpd->cmd)(rpd,SQUELCH_ON);
    }
    if (hostcommand->parm[3] == TURN_OFF) {
      if (hostcommand->parm[2] & LEFT_CHAN) res += (*rpd->cmd)(rpd,A1_OFF);
      if (hostcommand->parm[2] & RIGHT_CHAN) res += (*rpd->cmd)(rpd,A2_OFF);
      if (hostcommand->parm[2] & VIDEO_CHAN) res += (*rpd->cmd)(rpd,VIDEO_OFF);
      if (hostcommand->parm[2] & INDEX_CTRL) res += (*rpd->cmd)(rpd,INDEX_OFF);
      if (hostcommand->parm[2] & SQUELCH_CTRL) 
	res += (*rpd->cmd)(rpd,SQUELCH_OFF);
    }
  }
  if (!hostcommand->parm[4]) {
    if (res < 0) return(sendint(msgsock,COULDNT_DO_FUNC));
    if (res == 0) return(sendint(msgsock, NO_ERROR));
    if (res > 0) return (sendint(msgsock, FUNC_NOT_SUPPORTED));
  }
  return(-2);
}


/* parm 1 is volume,
   parm 2 is LOAD or UNLOAD or EJECT
   parm 3 is sync */
/* returns {NO_ERROR | BAD_VOLUME | BAD_ARGUMENT | FUNC_NOT_SUPPORTED} */
DoLoad(msgsock,hostcommand,j)
     int msgsock;
     Galatea_packet *hostcommand;
{
  int i;
  RPD_ptr rpd;

  if (clients[j].rev != revision) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }

  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  if (hostcommand->parm[2] != LOAD && 
      hostcommand->parm[2] != UNLOAD &&
      hostcommand->parm[2] != EJECT) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_ARGUMENT));
    return(-2);
  }

  if (!islocal(j)) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,PERMISSION_DENIED));
    return(-2);
  }

  for ( i = 0 ; i < volumes[hostcommand->parm[1]].num_resources; i++) {
    rpd = players[volumes[hostcommand->parm[1]].resource[i]];
    if (rpd == NULL) continue;
    (*rpd->cmd)(rpd,hostcommand->parm[2]);
  }
  if (hostcommand->parm[2] == EJECT) need_to_rebuild_list = 1;
  if (!hostcommand->parm[3]) return(sendint(msgsock,NO_ERROR));
  return(-2);
}

int islocal(i)
     int i;
{
  return(clients[i].local);
}

/* parm 1 is volume
   parm 2 is speed
   parm 3 is mask
   parm 4 is sync */
/* returns {actual current speed | BAD_VOLUME | FUNC_NOT_SUPPORTED}*/
DoRun(msgsock,hostcommand,i)
     int msgsock,i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  Output cur_output;
  int mask, retspeed;

  if (clients[i].rev != revision) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  sync_mode = hostcommand->parm[4];
  GSetState(0,0,sync_mode);
  rpd = players[volumes[hostcommand->parm[1]].resource[volumes[hostcommand->parm[1]].cur_resource]];
  if (rpd == NULL) {
    sync_mode = SYNC_MODE;
    GSetState(0,0,sync_mode);
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  retspeed = (*rpd->varspeed)(rpd,hostcommand->parm[2]);

  mask = hostcommand->parm[3];

  if (mask) {
    cur_output = volumeoutput(hostcommand->parm[1], i);
    if (doswitchtree(cur_output, mask, clients[i].output) == -1) {
      sync_mode = SYNC_MODE;
      GSetState(0,0,sync_mode);
      if (!hostcommand->parm[4]) return(sendint(msgsock,COULDNT_ROUTE));
      return(-2);
    }
  }

/* This is to provide a little delay.  Can we take it out?????????? */
#ifdef OBSOLETE
  /*retframe = */(*rpd->getframe)(rpd);
#endif /* OBSOLETE */
  sync_mode = SYNC_MODE;
  GSetState(0,0,sync_mode);

  if (!hostcommand->parm[4]) return(sendint(msgsock,retspeed));
  return(-2);
}


/* parm 1 is volume
   parm 2 is direction
   parm 3 is mask 
   parm 4 is sync */
/* returns {actual current frame | BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoJog(msgsock,hostcommand,i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  Output cur_output;
  int retframe, mask;

  if (clients[i].rev != revision) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  rpd = players[volumes[hostcommand->parm[1]].resource[volumes[hostcommand->parm[1]].cur_resource]];
  if (rpd == NULL) {
    if (!hostcommand->parm[4]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  sync_mode = hostcommand->parm[4];
  GSetState(0,0,sync_mode);


  if ((*rpd->jog)(rpd,hostcommand->parm[2]) == -1) {
      if (!hostcommand->parm[4]) return(sendint(msgsock, COULDNT_DO_FUNC));
      else return -2;
  }

  retframe = (*rpd->getframe)(rpd);

  mask = hostcommand->parm[3];

  if (mask) {
    cur_output = volumeoutput(hostcommand->parm[1], i);
    if (doswitchtree(cur_output, mask, clients[i].output) == -1) {
      sync_mode = SYNC_MODE;
      GSetState(0,0,sync_mode);
      if (!hostcommand->parm[4]) return(sendint(msgsock,COULDNT_ROUTE));
      return(-2);
    }
  }
  sync_mode = SYNC_MODE;
  GSetState(0,0,sync_mode);
  if (retframe == -1) retframe = COULDNT_DO_FUNC;
  if (!hostcommand->parm[4]) return(sendint(msgsock,retframe));
  return(-2);
}

/* parm 1 is volume
   parm 2 is mask
   parm 3 is sync */
/* returns {actual current frame | BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoStill(msgsock,hostcommand,i)
     int msgsock,i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  Output cur_output;
  int retframe, mask;

  if (clients[i].rev != revision) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  rpd = players[volumes[hostcommand->parm[1]].resource[volumes[hostcommand->parm[1]].cur_resource]];
  if (rpd == NULL) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  sync_mode = hostcommand->parm[3];
  GSetState(0,0,sync_mode);
  (*rpd->varspeed)(rpd,STOP);

  retframe = (*rpd->getframe)(rpd);

  mask = hostcommand->parm[2];

  if (mask) {
    cur_output = volumeoutput(hostcommand->parm[1], i);
    if (doswitchtree(cur_output, mask, clients[i].output) == -1) {
      sync_mode = SYNC_MODE;
      GSetState(0,0,sync_mode);
      if (!hostcommand->parm[3]) return(sendint(msgsock,COULDNT_ROUTE));
      return(-2);
    }
  }
  sync_mode = SYNC_MODE;
  GSetState(0,0,sync_mode);

  if (!hostcommand->parm[3]) return(sendint(msgsock,retframe));
  return(-2);
}

/* parm 1 is volume
   parm 2 is sync */
/* returns {actual current frame | BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoGetFrame(msgsock,hostcommand,i)
     int msgsock,i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  int retframe, cc;

  if (clients[i].rev != revision) {
    cc = sendint(msgsock,VOLUME_LIST_OLD);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    cc = sendint(msgsock,BAD_VOLUME);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    cc = sendint(msgsock,FUNC_NOT_SUPPORTED);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }

  rpd = players[volumes[hostcommand->parm[1]].resource[volumes[hostcommand->parm[1]].cur_resource]];
  if (rpd == NULL) {
    cc = sendint(msgsock,FUNC_NOT_SUPPORTED);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }

  retframe = (*rpd->getframe)(rpd);
  if (retframe == -1) retframe = COULDNT_DO_FUNC;

  cc = sendint(msgsock,retframe);
  if (!hostcommand->parm[2]) return(cc);
  return(-2);
}

/* parm 1 is volume
   parm 2 is sync */
/* returns {actual current speed | BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoGetSpeed(msgsock,hostcommand,i)
     int msgsock,i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  int retspeed, cc;

  if (clients[i].rev != revision) {
    cc = sendint(msgsock,VOLUME_LIST_OLD);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    cc = sendint(msgsock,BAD_VOLUME);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    cc = sendint(msgsock,FUNC_NOT_SUPPORTED);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }

  rpd = players[volumes[hostcommand->parm[1]].resource[volumes[hostcommand->parm[1]].cur_resource]];
  if (rpd == NULL || rpd->getspeed == NULL) {
    cc = sendint(msgsock,FUNC_NOT_SUPPORTED);
    if (!hostcommand->parm[2]) return(cc);
    return(-2);
  }

  retspeed = (*rpd->getspeed)(rpd);
  if (retspeed == -1) retspeed = COULDNT_DO_FUNC;

  cc = sendint(msgsock,retspeed);
  if (!hostcommand->parm[2]) return(cc);
  return(-2);
}
/* parm 1 is volume 
   parm 2 is sync */
/* returns {NO_ERROR | BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoReset(msgsock,hostcommand, j)
     int msgsock,j;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  int i;

  if (clients[j].rev != revision) {
    if (!hostcommand->parm[2]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[2]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[2]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  for ( i = 0 ; i < volumes[hostcommand->parm[1]].num_resources; i++) {
    rpd = players[volumes[hostcommand->parm[1]].resource[i]];
    if (rpd == NULL) continue;
    sync_mode = hostcommand->parm[2];
    GSetState(0,0,sync_mode);
    (*rpd->reset)(rpd);
    sync_mode = SYNC_MODE;
    GSetState(0,0,sync_mode);
  }

  if (!hostcommand->parm[2]) return(sendint(msgsock,NO_ERROR));
  return(-2);
}


/* parm 1 is volume
   parm 2 is start frame
   parm 3 is end frame
   parm 4 is speed
   parm 5 is mask
   parm 6 is return_flag
   parm 7 is sync */
/* returns {actual current frame | actual current speed | 
   BAD_VOLUME | FUNC_NOT_SUPPORTED} */
DoPlaySeg(msgsock,hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  RPD_ptr rpd;
  int retframe, resource, mask, realspeed;
  Output cur_output;

  if (DEBUG) printf("Entering DoPlaySeg()\n");
  if (clients[i].rev != revision) {
    if (!hostcommand->parm[7]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  if (hostcommand->parm[1] >= num_volumes) {
    if (!hostcommand->parm[7]) return(sendint(msgsock,BAD_VOLUME));
    return(-2);
  }
  if (volumes[hostcommand->parm[1]].type != RPD_DEV) {
    if (!hostcommand->parm[7]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }
  if (hostcommand->parm[2] == CURRENT_FRAME) {
    if (DEBUG) printf("   using current resource for CURRENT_FRAME search\n"); 
    resource = volumes[hostcommand->parm[1]].cur_resource;
  }
  else {
    if (DEBUG) printf("   findclosetresource(%d, %d)\n",
		      hostcommand->parm[1], hostcommand->parm[2]);
    resource = findclosetresource(hostcommand->parm[1],hostcommand->parm[2]);
    if (resource == -1) {
      if (!hostcommand->parm[7]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
      return(-2);
    }
    volumes[hostcommand->parm[1]].cur_resource = resource;
  }
  rpd = players[volumes[hostcommand->parm[1]].resource[resource]];
  if (rpd == NULL) {
    if (!hostcommand->parm[7]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
    return(-2);
  }

  if (hostcommand->parm[2] == CURRENT_FRAME) {
    /* must get current location before calculating segment size */
    retframe = (*rpd->getframe)(rpd);
    if (DEBUG) printf("   playing from CURRENT_FRAME (%d)\n",retframe);
  }
  else
    retframe = hostcommand->parm[2];

  if (MAX_LOCK_TIME && hostcommand->parm[4] &&
      abs((hostcommand->parm[3] - retframe) / hostcommand->parm[4])
      > MAX_LOCK_TIME && hostcommand->parm[6] == RETURN_SYNC) {
    if (!hostcommand->parm[7]) return(sendint(msgsock,SEGMENT_TOO_LONG));
    return(-2);
  }

  mask = hostcommand->parm[5];

  if (hostcommand->parm[1] == cur_volume_l) {
    mask |= LEFT_CHAN;
  }
  if (hostcommand->parm[1] == cur_volume_r) {
    mask |= RIGHT_CHAN;
  }
  if (hostcommand->parm[1] == cur_volume_v) {
    mask |=  VIDEO_CHAN;
  }

  if (hostcommand->parm[2] != CURRENT_FRAME) {
    if (hostcommand->parm[7]) {
      if (DEBUG) printf("   ASYNC_MODE doesn't require (*rpd->search)()\n");
    }
    else{
      if (DEBUG) printf("   (*rpd->search)(rpd, %d, 1)\n", 
			hostcommand->parm[2]);
      retframe = (*rpd->search)(rpd, hostcommand->parm[2], 1);
      if (retframe == -1) {
	if (!hostcommand->parm[7]) return(sendint(msgsock,COULDNT_DO_FUNC));
	else return(-2);
      }
    }
    retframe = hostcommand->parm[2];
  }

  realspeed = abs(hostcommand->parm[4]);
  if (DEBUG) printf("   Current frame = %d\n", retframe);
  if (hostcommand->parm[3] < retframe)
    realspeed = 0 - realspeed;

  sync_mode = hostcommand->parm[7];
  GSetState(0,0,sync_mode);
  if (mask) {
    cur_output = volumeoutput(hostcommand->parm[1], i);
    if (doswitchtree(cur_output, mask, clients[i].output) == -1) {
      sync_mode = SYNC_MODE;
      GSetState(0,0,sync_mode);
      if (!hostcommand->parm[7]) return(sendint(msgsock,COULDNT_ROUTE));
      return(-2);
    }
  }
  if (DEBUG) printf("   (*rpd->segplay)(rpd, %d, %d, %d)\n",
		    hostcommand->parm[2], hostcommand->parm[3],
		    realspeed, hostcommand->parm[6]);
  retframe = (*rpd->segplay)(rpd,hostcommand->parm[2],hostcommand->parm[3],
			     realspeed, 
			     hostcommand->parm[6] == RETURN_SYNC ? 1: 0);
  if (retframe == -1) {
    sync_mode = SYNC_MODE;
    GSetState(0,0,sync_mode);
    if (!hostcommand->parm[7]) return(sendint(msgsock,COULDNT_DO_FUNC));
    else return(-2);
  }
  sync_mode = SYNC_MODE;
  GSetState(0,0,sync_mode);

  if (hostcommand->parm[6] == RETURN_SYNC) {
    if (DEBUG) printf("   (*rpd->getframe)()\n");
    retframe = (*rpd->getframe)(rpd);
  }
  else if (hostcommand->parm[6] == RETURN_NOW) {
    retframe = hostcommand->parm[2];
  }
  else if (hostcommand->parm[6] == RETURN_NOW_WITH_SPEED) {
    if(rpd->getspeed)
      realspeed = (*rpd->getspeed)(rpd);

  }

  switch(hostcommand->parm[6])
    {
    case RETURN_NOW_WITH_SPEED:
      if (!hostcommand->parm[7]) return(sendint(msgsock,realspeed));      
    case RETURN_NOW:
    case RETURN_SYNC:
      if (retframe == -1)
	retframe = COULDNT_DO_FUNC;
      if (!hostcommand->parm[7]) return(sendint(msgsock,retframe));
      break;
    default:
      break;
    }

  return(-2);
}

/* parm 1 is number of segments
   parm 2 is return_flag
   parm 3 is sync */
/* returns {BAD_VOLUME | FUNC_NOT_SUPPORTED | SEGMENT_TOO_LONG} */
DoPlaySequence(msgsock,hostcommand, clinum)
     int msgsock, clinum;
     Galatea_packet *hostcommand;
{
  fd_set justcheck;
  struct timeval zero_delay;
  
  int i, numsegs, totaltime = 0, resource, thistime, tm, ret, secondres;
  int prev_resource = -1;
  Output cur_output;
  RPD_ptr rpd, secondrpd;
  GSegment *segstoplay;
  GSegment nullseg;
  if (clients[clinum].rev != revision) {
    if (!hostcommand->parm[3]) return(sendint(msgsock,VOLUME_LIST_OLD));
    return(-2);
  }
  numsegs = hostcommand->parm[1];
  segstoplay = (GSegment *)malloc(numsegs * sizeof(GSegment));
  if (segstoplay == (GSegment *)NULL) {
    bsdsyslog(LOG_NOTICE, "DoPlaySequence: Unable to alloc sequence");
    for (i = 0; i < numsegs; i++) {
      if ((nullseg.volumenum = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
	free(segstoplay);
	return(-1);
      }
      if ((nullseg.start = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
	free(segstoplay);
	return(-1);
      }
      if ((nullseg.end = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
	free(segstoplay);
	return(-1);
      }
      if ((nullseg.speed = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
	free(segstoplay);
	return(-1);
      }
      if ((nullseg.mask = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
	free(segstoplay);
	return(-1);
      }
    }
    if (!hostcommand->parm[3]) return(sendint(msgsock,COULDNT_DO_FUNC));
    else return(-2);
  }
  for (i = 0; i < numsegs; i++) {
    if ((segstoplay[i].volumenum=serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
      free(segstoplay);
      return(-1);
    }
    if ((segstoplay[i].start = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
      free(segstoplay);
      return(-1);
    }
    if ((segstoplay[i].end = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
      free(segstoplay);
      return(-1);
    }
    if ((segstoplay[i].speed = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
      free(segstoplay);
      return(-1);
    }
    if ((segstoplay[i].mask = serv_acceptint(msgsock, MAX_BLOCK)) == -1) {
      free(segstoplay);
      return(-1);
    }
    if (DEBUG) printf("Received segment: num = %d, start = %d, end = %d, speed = %d, mask = %d\n",segstoplay[i].volumenum, segstoplay[i].start, segstoplay[i].end, segstoplay[i].speed, segstoplay[i].mask);
  }
  /* Error check sequence before playing */
  for (i = 0; i < numsegs; i++) {
    if (segstoplay[i].volumenum >= num_volumes || 
	volumes[segstoplay[i].volumenum].output != clients[clinum].output) {
      free(segstoplay);
      if (!hostcommand->parm[3]) return(sendint(msgsock,BAD_VOLUME));
      return(-2);
    }
    if (volumes[segstoplay[i].volumenum].type != RPD_DEV) {
      free(segstoplay);
      if (!hostcommand->parm[3]) return(sendint(msgsock,FUNC_NOT_SUPPORTED));
      return(-2);
    }
    if (segstoplay[i].speed)
      thistime = 
	abs(segstoplay[i].end - segstoplay[i].start / segstoplay[i].speed);
    else thistime = segstoplay[i].end;
    totaltime += thistime;
    if (MAX_LOCK_TIME && segstoplay[i].speed &&
	thistime > MAX_LOCK_TIME) {
      free(segstoplay);
      if (!hostcommand->parm[3]) return(sendint(msgsock,SEGMENT_TOO_LONG));
      return(-2);
    }
  }
  if (MAX_LOCK_TIME && 
      hostcommand->parm[2] == RETURN_SYNC && totaltime > MAX_LOCK_TIME) {
    free(segstoplay);
    if (!hostcommand->parm[3]) return(sendint(msgsock, SEGMENT_TOO_LONG));
    return(-2);
  }
  
  for (i = 0; i < numsegs; i++) {
    /* initialize because it used in a couple places, and -1 is an
       invalid value.  Kinda a lazy evaluation technique. */
    resource = -1;
    /* First attempt to async speed up the NEXT search */
    /* This may NOT be a good idea */
    if (i < numsegs - 1) {
      if (segstoplay[i].volumenum != segstoplay[i+1].volumenum) {
	if (DEBUG) printf("Attempting to optimize non-identical case.\n");
	resource = findclosetresource(segstoplay[i+1].volumenum,
				      segstoplay[i+1].start);
	volumes[segstoplay[i+1].volumenum].cur_resource = resource;
	rpd = players[volumes[segstoplay[i+1].volumenum].resource[resource]];
	if (DEBUG) printf("Attempting async search\n");
	sync_mode = ASYNC_MODE;
	GSetState(0,0,sync_mode);
	(*rpd->search)(rpd, segstoplay[i+1].start, 0);
	sync_mode = SYNC_MODE;
	GSetState(0,0,sync_mode);
	resource = -1;
      }
      else {  /* Consecutive segs are on same volume */
	/* See if there is more than one device available */
	if (DEBUG) printf("Attempting to optimize identical case.\n");
	if (volumes[segstoplay[i].volumenum].num_resources > 1) {
	  if (DEBUG) printf("Multiple devices available.\n");
	  resource = findclosetresource(segstoplay[i].volumenum, 
					segstoplay[i].start);
	  rpd = players[volumes[segstoplay[i].volumenum].resource[resource]];
	  rpd->avail = clinum;
	  secondres = findclosestunlockeddevice(segstoplay[i+1].volumenum,
						segstoplay[i+1].start);
	  secondrpd = 
	    players[volumes[segstoplay[i].volumenum].resource[secondres]];
	  if (DEBUG) printf("Attempting async search\n");
	  sync_mode = ASYNC_MODE;
	  GSetState(0,0,sync_mode);
	  (*secondrpd->search)(secondrpd, segstoplay[i+1].start, 0);
	  sync_mode = SYNC_MODE;
	  GSetState(0,0,sync_mode);
	  rpd->avail = -1;
	}
	else if (DEBUG) printf("Multiple devices not available.\n");
      }
    }
    /* We may have found it earlier */
    if (resource == -1)
      resource = findclosetresource(segstoplay[i].volumenum, 
				    segstoplay[i].start);
    volumes[segstoplay[i].volumenum].cur_resource = resource;
    rpd = players[volumes[segstoplay[i].volumenum].resource[resource]];
    if (DEBUG) printf("Attempting real search\n");
    if ((*rpd->search)(rpd, segstoplay[i].start, 1) == -1) {
      if (DEBUG) printf("real search failed\n");
    }
    
    /* do switching here */
    if (segstoplay[i].mask) {
      cur_output = volumeoutput(segstoplay[i].volumenum, clinum);
      if (doswitchtree(cur_output, segstoplay[i].mask, 
		       clients[clinum].output) == -1) {
	if (!hostcommand->parm[3]) return(sendint(msgsock,COULDNT_ROUTE));
	free(segstoplay);
	return(-2);
      }
    }
    if (DEBUG) printf("Switch completed\n");
    /* Send ack after first seg is set up if in RETURN_NOW mode */
    if (i == 0 && 
	hostcommand->parm[2] == RETURN_NOW && 
	!hostcommand->parm[3]) {
      if (sendint(msgsock, NO_ERROR) == -1) {
	free(segstoplay);
	return(-1);
      }
    }
    if (segstoplay[i].speed == 0) {
      if (DEBUG) printf("Sleeping for %d useconds\n",segstoplay[i].end);
      microsleep(segstoplay[i].end);
    }
    else {
      if (DEBUG) printf("Attempting to play segment\n");
      ret = (*rpd->segplay)(rpd, segstoplay[i].start, segstoplay[i].end,
			    segstoplay[i].speed, 1);
      if (DEBUG) printf("Return from segplay = %d\n", ret);
    }
    if (hostcommand->parm[2] == RETURN_NOW) {
      if (LOCKED) justcheck = lockavail;
      else justcheck = allavail;
      zero_delay.tv_sec = 0;
      zero_delay.tv_usec = 0;
      tm = select(MAXSOCKETS, &justcheck, 0, 0, &zero_delay);
      if (tm > 0) {
	if (DEBUG) printf("Breaking out of loop\n");
	break;
      }
    }
  }
  if (numsegs && segstoplay) free(segstoplay);
  if (!hostcommand->parm[3]) {
    if (hostcommand->parm[2] == RETURN_SYNC)
      return(sendint(msgsock, NO_ERROR));
    else return(0);
  }
  else return (-2);
}

/* no parms */
/*ARGSUSED*/
/* returns {NO_ERROR | VOLUME_LIST_OLD} */
DoCheckRevision(msgsock,hostcommand,i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  if (clients[i].rev != revision)
    sendint(msgsock,VOLUME_LIST_OLD);
  else sendint(msgsock,NO_ERROR);
  return(-2);
}

/* no parms */
/* return current server time since midnight, January 1, 1970 */
/*ARGSUSED*/
DoGetServerTime(msgsock, hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  struct timeval nowtime;
  int curtime;

  if (gettimeofday(&nowtime, 0) != 0) {
    bsdsyslog(LOG_INFO,"gettimeofday failed");
    curtime = -1;
    if (sendint(msgsock, curtime) == -1) return(-1);
    return(-2);
  }
  curtime = (int)(nowtime.tv_sec);
  if (sendint(msgsock,curtime) == -1) return(-1);
  return(-2);
}

/* no parms */
/* returns {NO_ERROR} */
/*ARGSUSED*/
DoLock(msgsock,hostcommand,i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  int j;

  FD_ZERO(&lockavail);
  FD_SET(msgsock,&lockavail);
  if (notice_socket > -1)
    FD_SET(notice_socket,&lockavail);
  if (!LOCKED) {
    whichlock = i;
#ifdef FORKLOCK
    if (MAX_LOCK_TIME && timer_pid > 0) kill(timer_pid,SIGUSR1);
#else
    if (MAX_LOCK_TIME) set_lock();
#endif /* FORKLOCK */
    /* Lock all connected remote server */
    for (j = 0; j < num_forwards; j++) {
      if (servs[j])
	add_lock(servs[j]);
    }
    LOCKED = 1;
  }
  sendint(msgsock,NO_ERROR);
  return(-2);
}

/* no parms */
/* returns {NO_ERROR} */
/*ARGSUSED*/
DoUnLock(msgsock,hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  clean_lock();
  sendint(msgsock,NO_ERROR);
  /* This return will return to dealwithit() which will then call
     unlock_all(), hence freeing the remote servers */
  return(-2);
}

unlock_self()
{
  bsdsyslog(LOG_NOTICE,"Timeout on client[%d] lock",whichlock);

  LOCKED = 0;
#ifdef SYSV
#ifdef FORKLOCK
  signal(SIGUSR1, unlock_self);
#else /* FORKLOCK */
  signal(SIGALRM, unlock_self);
#endif /* FORKLOCK */
#endif /* SYSV */
}

clean_lock()
{

  LOCKED = 0;
#ifdef FORKLOCK
  if (timer_pid > 0)
    kill(timer_pid,SIGUSR2);
#else
  unset_lock();
#endif /* FORKLOCK */
}

/* parm 1 is SPINDOWN or NOSPINDOWN */
/* returns {NO_ERROR | BADARGUMENT} */
DoShutOff(msgsock,hostcommand,i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  int j;

  if (hostcommand->parm[1] != SPINDOWN && hostcommand->parm[1] != NOSPINDOWN) {
    if (sendint(msgsock,BAD_ARGUMENT) == -1) return(-1);
    return(-2);
  }
    
  if (!islocal(i)) {
    if (sendint(msgsock,PERMISSION_DENIED) == -1) return(-1);
    return(-2);
  }

  sendint(msgsock,NO_ERROR);

  if (clients[i].address)
    bsdsyslog(LOG_NOTICE, "shutting down on %s ...",clients[i].address);
  else 
    bsdsyslog(LOG_NOTICE, "shutting down on unknown client ...");
  if (hostcommand->parm[1] == SPINDOWN) shutoff_server(1);
  else shutoff_server(0);
/*NOTREACHED*/
}
  
/*ARGSUSED*/
DoRequestNotification(msgsock, hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{

  int j;

  if (islocal(i) || !clients[i].address) return(-2);

  if (DEBUG) printf("Requesting host is: %s on connection %d\n",
		    clients[i].address,i);

  for ( j = 0; j < MAXSOCKETS; j++)
      if (notify_list[j] != (char *)NULL &&
	  !strcmp(clients[i].address,notify_list[j])) return(-2);

  notify_list[i] = (char *)malloc(strlen(clients[i].address)+1);
  if (notify_list[i])
    strcpy(notify_list[i],clients[i].address);
  write_host_file();
  return(-2);
}

/*ARGSUSED*/
int DoGetStatistics(msgsock, hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  struct timeval cur_time;
#ifdef OBSOLETE
  num_connections, max_connections, delayed_requests;
#endif

  if (sendint(msgsock, revision) == -1) return(-1);
  if (sendint(msgsock, num_requests) == -1) return(-1);
  if (!gettimeofday(&cur_time, NULL)) {
    if (sendint(msgsock, (int)cur_time.tv_sec - start_time) == -1)
      return(-1);
  }
  else if (sendint(msgsock, 0) == -1) return(-1);
  if (sendint(msgsock, num_collisions) == -1) return(-1);
  if (sendint(msgsock, num_connections) == -1) return(-1);
  if (sendint(msgsock, max_connections) == -1) return(-1);
  if (sendint(msgsock, delayed_requests) == -1) return(-1);
  return(-2);

}

/*ARGSUSED*/
int DoRebuild(msgsock, hostcommand, i)
     int msgsock, i;
     Galatea_packet *hostcommand;
{
  if (islocal(i)) {
    need_to_rebuild_list = 1;
    if (sendint(msgsock,NO_ERROR) == -1) return(-1);
  }
  else if (sendint(msgsock, PERMISSION_DENIED) == -1) return(-1);
  return(-2);
}

int findvolumeid(name, output)
     char *name;
     int output;
{
  int i;
  for (i = 0; i < num_volumes; i++) {
    if (strcmp(name, volumes[i].volume) == 0 && output == volumes[i].output)
      return i;
  }
  return -1;
}
