/* client program to perform local file operations */
/******************************************************************************
  This code is derived from work originally done within IMM 3.0
  Written by Winston Dang <wkd@hawaii.edu>

  * Copyright (c) University of Hawaii 1993. All rights reserved.
  *  
  * License is granted to copy, to use, and to make and to use derivative
  * works for research, educational, government or evaluation purposes, provided
  * that the University of Hawaii is acknowledged in all documentation pertaining
  * to any such copy or derivative work. University of Hawaii grants no other 
  * licenses expressed or imrplied. The University of Hawaii trade name should 
  * not be used in any advertising without its written  permission.
  *  
  * UNIVERSITY OF HAWAII MAKES NO REPRESENTATIONS CONCERNING EITHER THE
  * MERCHANTABILITY OF THIS SOFTWARE OR THE SUITABILITY OF THIS SOFTWARE
  * FOR ANY PARTICULAR PURPOSE.  The software is provided "as is" without
  * express or implied warranty of any kind.
  *  
  * These notices must be retained in any copies of any part of this software.
  ******************************************************************************/
/******************************************************************************
 * This code release was developed and written by 
 * Joe Macker and Winston Dang,
 * 1996, 1997
 ******************************************************************************/
 
#include "protocol.h"
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>

/* External references (that really should be in a /usr/include file) */
extern char *optarg;
extern int optind, opterr;
extern int useimageloader;
extern struct hosttype *hosts_tail;
#ifndef __NetBSD__
extern char *sys_errlist[];
#endif
extern int fullscrflag;
extern int xvflag;
extern int debug;
extern int checkpath();
extern int archfilenum;

struct listnode {
    char *name;
    struct listnode *next;
};
struct listnode ListFile[MAXFILES];
struct listnode *ListPtr;

/* External references to sockets */
extern int xmitsock;
extern int sock;
extern int serverid;

extern struct nodetype nodelist[MAXFILES];
extern struct stattype statnum;

char *immdirectory;		/* directory name to store files */
char *displ;			/* display to put image up on */
#define DEFAULT_IMAGE_DIRECTORY "/tmp"

/**********************************************************/
/* file initializations */                                          
int xlinit(int numfiles, char *displaywin)
{
    int i;
     /* check for IMMDIR environ var */
     immdirectory = getenv("IMM_IMAGE_DIR");
     if (immdirectory == NULL) {
	 immdirectory = DEFAULT_IMAGE_DIRECTORY;
     }
     if (debug) fprintf(logfp,"directory used: %s\n",immdirectory);

    /* build circular link list to hold file names */
    for (i=0; i < (MAXFILES - 1); i++) {
	ListFile[i].name = NULL;
	ListFile[i].next = &ListFile[i+1];
    }
    ListFile[MAXFILES - 1].name = NULL;
    ListFile[MAXFILES - 1].next = &ListFile[0];
    ListPtr = &ListFile[0];

    
         /* copy displaywin to displ var */
    displ = (char *)malloc( strlen(displaywin) + 1);
    strcpy(displ,displaywin);

    /* test to see what image loader we are using */
     if (useimageloader != NULL) {
	 if (checkpath(useimageloader)) return;
     }
     xvflag = checkpath("xv");
     if (xvflag) return;

     if (checkpath("xloadimage") ) return;            
     fatal("IMM Could not find xv or xloadimage\n");
 }

/**********************************************************/   
/* subroutine to open and close files returning handle to stdio */
int xlopen(redo, nodeptr)
int redo;
struct nodetype *nodeptr;
{
    static unsigned int filecounter = 0;
    switch (redo) {
    case 1:
	close(nodeptr->ofp);
	return;
    default:
 	sprintf(nodeptr->tmpfile,"%s/.in%d.imm",
		     immdirectory, filecounter++);
	nodeptr->ofp = creat(nodeptr->tmpfile,0640);
	if (nodeptr->ofp != -1) 
	    return(nodeptr->ofp);
	printf("Unable to Open %s\n",nodeptr->tmpfile);
	exit(0);
    }
}

/**********************************************************/
/* change the user name */
int chghostname(mynewhostname)
char *mynewhostname;
{
    if (mynewhostname == NULL) 
	statnum.name_user[0] = NULL;
    else
	strncpy(statnum.name_user,mynewhostname,(MAXUSERNAME -1));
}

/**********************************************************/   
/* create subdirectory if they don't exist */
int makesubdir(direct,is_directory)
char *direct;
int is_directory;
{
    char *token;
    char *workdir;
    char newdir[250];
    char tokensep[] = "//";	/* token seperator */
    int retval = TRUE;
    workdir = getenv("PWD");
    if (chdir(immdirectory)) {
	warn("failed to chdir to %s\n",immdirectory);
	return FALSE;
	}
    token = strtok(direct,tokensep);
    while (token != NULL) {
	strcpy(newdir,token);
	token = strtok(NULL,tokensep);
	if ((token == NULL) && (! is_directory)) break;
	if ( chdir(newdir) ) {
	    if ( mkdir(newdir,0755)) {
		warn("unable to create %s\n",direct);
		retval = FALSE;
		break;
	    }
	    chdir(newdir);
	    if (debug ) printf("create subdir %s\n",newdir);
	}
    }
    return retval;
}
/**********************************************************/   
int changename(nodeptr)
struct nodetype *nodeptr;
{
  char directory_line[250];
  char *file_name_token;
  int i;

  file_name_token = nodeptr->currfile;
  /* test if this is a directory */
  if (file_name_token[ strlen(file_name_token) - 1] == '/') {
	sprintf(directory_line,"%s/%s", immdirectory, file_name_token);
    	 if ( ! access(directory_line,F_OK)) return TRUE;
	makesubdir(file_name_token,TRUE);
	unlink(nodeptr->tmpfile);
	return TRUE;
  }

  /*rename a file - test if need to replicate directory structure */	
  if (fullscrflag < 11) {
	/* no directory replication needed - get the last name of the file */
	file_name_token = strrchr(nodeptr->currfile,'/');
	if (file_name_token != NULL) {
	    strcpy(directory_line,file_name_token);
	    strcpy(nodeptr->currfile, directory_line);
	}
	file_name_token = nodeptr->currfile;
  }

  sprintf(directory_line,"%s/%s", immdirectory, file_name_token);
	
  if (debug) printf("rename %s->%s\n",nodeptr->tmpfile,directory_line);
  if ( ! access(directory_line,F_OK)) {
	/* file exists add extension counter */
	for (i=1; i < MAXFILES; i++) {
	    sprintf(directory_line,"%s/%s.%d",
		    immdirectory, file_name_token,i);
	    if (debug) printf("duplicate %s->%s\n",nodeptr->tmpfile,directory_line);
	    if ( access(directory_line,F_OK)) break;
	}
    }
    if (rename(nodeptr->tmpfile,directory_line)) {
	if (makesubdir(file_name_token,FALSE)) {
	    if (rename(nodeptr->tmpfile,directory_line))
		fprintf(logfp, "unable to change %s to %s\n",
			nodeptr->tmpfile,directory_line);
	}
    }
    if (nodeptr->serverflags & BUF_FLG_EXECUT) {
	chmod(directory_line, S_IXUSR | S_IXGRP | S_IRUSR | S_IRGRP);
    }
    nodeptr->tmpfile[0] = NULL;
   if (fullscrflag != 11) {
	ListPtr = ListPtr->next;
	if (ListPtr->name != NULL) {
	    if (debug) fprintf(logfp,"unlink %s\n",ListPtr->name);
	    if (archfilenum != 0) unlink(ListPtr->name);
	    free(ListPtr->name);
	}
	ListPtr->name  = malloc(strlen(directory_line) + 1);
	strcpy(ListPtr->name,directory_line);
    }   
   return FALSE;
}

/**********************************************************/   
/* close file and rename it, put it in the proper subdirect */
int xlclose(nodeptr)
struct nodetype *nodeptr;
{
    char cmdline[250];
    char xvopts[200];
    int is_directory_indicator;
    
    if (nodeptr->transmitcode == TRANSMISSION_REST) return FALSE;
    nodeptr->transmitcode = TRANSMISSION_REST;
    close(nodeptr->ofp);

    statnum.lastreceived = nodeptr;
      /* file received - now do some post processing with it */
    fullscrflag = build_xvopts(xvflag, xvopts);

    is_directory_indicator = changename(nodeptr);


    switch (fullscrflag) {
    case TRUE:
      if (xvflag) {
	if (is_directory_indicator) return TRUE; 
          sprintf(cmdline,
                  "xv %s -root -disp %s -quit %s/%s",
                  xvopts,displ,immdirectory,nodeptr->currfile);
	  post_process(cmdline);
      } else {
          sprintf(cmdline,
                  "xloadimage %s  -onr -displ %s -bor %s %s/%s",
                  xvopts,displ,immdirectory,nodeptr->currfile);
	  post_process(cmdline);
      }
      break;
    case FALSE:
          if (xvflag) {
	    if (is_directory_indicator) return TRUE; 
              sprintf(cmdline,
                      "xv -rmod 0 -root -disp %s -maxp -quit %s",
                      displ,ListPtr->name);
	      post_process(cmdline);
          } else {
              sprintf(cmdline,
                      "xloadimage -onr -displ %s -bor black -full %s",
                      displ,ListPtr->name);
	      post_process(cmdline);
	  }
      break;
    case 10:
      if (is_directory_indicator) return TRUE; 
      sprintf(cmdline,
              "%s -disp %s -quit %s",
              xvopts,displ,ListPtr->name);
      post_process(cmdline);
      break;
    case 11:
      return TRUE;
  case 12:
      sprintf(cmdline,
              "%s %s",
              xvopts,ListPtr->name);
      post_process(cmdline);
      break;
    }
    if (debug) fprintf(logfp,"%s\n",cmdline); 
    return TRUE;
}
/**********************************************************/
/* signal interrupt to abort image - close up shop */
int xlredraw()
{
    char cmdline[250];
    char xvopts[40];

    if (ListPtr->name == NULL) return FALSE;
    fullscrflag = build_xvopts(xvflag, xvopts);
    switch (fullscrflag) {
    case 10:
	sprintf(cmdline,
		"%s -disp %s %s",
		xvopts,displ,ListPtr->name);
	post_process(cmdline);
	break;
    case 12:
	sprintf(cmdline,
		"%s %s",
		xvopts,ListPtr->name);
	post_process(cmdline);
	break;
	
    default:
	if (xvflag) {
	    sprintf(cmdline,
		    "xv -disp %s %s",
		    displ,ListPtr->name);
	    post_process(cmdline);
	} else {
	    sprintf(cmdline,
		    "xloadimage -displ %s %s",
		    displ,ListPtr->name);
	    post_process(cmdline);
	}
	break;
    }
    if (debug) fprintf(logfp,"%s\n",cmdline); 
    return TRUE;
}
/**********************************************************/
int post_process(char *cmdline) {
    int pid = 0;
/*    system(cmdline);
    return TRUE;
*/    
#ifdef SIGCLD	
	signal(SIGCLD,SIG_IGN);
#endif
#ifdef SIGCHLD
	signal(SIGCHLD,SIG_IGN);
#endif
    pid = fork();
    switch (pid) {
    case -1:
	fprintf(stderr, "unable to fork \n");
	exit(1);
    case 0:	/* Child process */

	checkhost(RECOV_MISS_FREE,NULL,NULL);
	fclose(stdin);
	close(xmitsock);
	close(sock);

	if (debug) fprintf( stderr,"post_process %s\n", cmdline);
	execlp("/bin/sh","/bin/sh","-c",cmdline,NULL);	

	exit(0);
    default:
	return TRUE;
    }
}    
/**********************************************************/           
/* signal interrupt to abort image - close up shop */
void abortimage()
{
    struct nodetype *nodeptr;
    struct hosttype *hostptr;
    int i;
    if (debug) printf("shutting down\n");
    fflush(stdout);
    if (fullscrflag != 11) {
	for (i=0; i < MAXFILES; i++) {
	    if (ListPtr->name != NULL) {
		if (debug) printf("unlink %s\n",ListPtr->name);
		unlink(ListPtr->name);
	    }
	    ListPtr = ListPtr->next;
	}
    }
    for (hostptr = hosts_tail; hostptr != NULL;
	hostptr = (struct hosttype *) hostptr->prev) {
	nodeptr = &hostptr->node;
	close(nodeptr->ofp);
	if (nodeptr->tmpfile[0] != NULL) unlink(nodeptr->tmpfile);
    }
    if (serverid) {
	fprintf(logfp,"kill server proc %d\n",serverid);
	kill(serverid,SIGKILL);
    }

    if (logfp)
	fclose(logfp);
    exit(0);
}

/* close all the files */ 
int closeall()
{
    int i;
    if (fullscrflag != 11) {    
	for (i=0; i < MAXFILES; i++) {
	    if (ListPtr->name != NULL) {
		unlink(ListPtr->name);
	    }
	    ListPtr = ListPtr->next;
	}
    }
    close(xmitsock);
    close(sock);
    fclose(logfp);
}



