#include <stdio.h>
#include <stdlib.h>   /* for free() */
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <unistd.h>

#include <sys/types.h>		/* for exec(), wait() et. al */
#include <sys/wait.h>



#include "global.h"


	
#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_news_util.h"



static void
read_parameters (char *course, char *key, char *sender,
		 char *dir, int *grp)
{

  char intstring[20];



  cs_get_required_parameter ("crs", course, MAX_FILENAME);	/* shared_cgi_util.c */
  cs_get_required_parameter ("id", key, MAX_KEY);
  cs_get_required_parameter ("sender", sender, MAX_USERNAME);
  cs_get_required_parameter ("dir", dir, MAX_FILENAME);
  cs_get_required_parameter ("grp", intstring, 5);
  *grp = atoi (intstring);


}



static void
deliver_file (char *mime_type, char *source_file, char *dest_file)
{
#define CHUNKSIZE 8192  

  FILE *fp;

  struct stat buf;
  int bytes_read;
  int bytes_left;
  char buffer[CHUNKSIZE];

  if (stat (source_file, &buf))
    cs_critical_error (ERR_STAT_FAILED, "");

  fp = fopen (source_file, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");


  printf ("Content-type:%s\n", mime_type);
  printf ("Content-disposition: filename=\"%s\"\n", dest_file);
  printf ("Content-length: %ld\n\n", (long) buf.st_size);


  bytes_left = buf.st_size;
  bytes_read = CHUNKSIZE;
  while (bytes_left)
    {
      if (bytes_left < CHUNKSIZE)
	bytes_read = bytes_left;
      if (fread (buffer, bytes_read, 1, fp) != 1)
	cs_critical_error (ERR_FREAD_FAILED, "");
      bytes_left -= bytes_read;
      if (fwrite (buffer, bytes_read, 1, stdout) != 1)
	cs_critical_error (ERR_FWRITE_FAILED, "");
    }
  fclose (fp);

#undef CHUNKSIZE
}


static void
check_zip_status (int error)
{

  switch (error)
    {
      /* this is my error code if exec() failed */
    case 88: cs_critical_error (ERR_CANT_START_ZIP, ""); break;

      /* remaining errors reported by unzip */
    case 0:    break;			/* everything went OK */
    case 2:    cs_critical_error (ERR_ZIP_ERROR_CODE_2, ""); break;
    case 3:    cs_critical_error (ERR_ZIP_ERROR_CODE_3, ""); break;
    case 4:    cs_critical_error (ERR_ZIP_ERROR_CODE_4, ""); break;    
    case 5:    cs_critical_error (ERR_ZIP_ERROR_CODE_5, ""); break;    
    case 6:    cs_critical_error (ERR_ZIP_ERROR_CODE_6, ""); break;    
    case 7:    cs_critical_error (ERR_ZIP_ERROR_CODE_7, ""); break;    
    case 8:    cs_critical_error (ERR_ZIP_ERROR_CODE_8, ""); break;    
    case 9:    cs_critical_error (ERR_ZIP_ERROR_CODE_9, ""); break;
    case 10:   cs_critical_error (ERR_ZIP_ERROR_CODE_10, ""); break;    
    case 11:   cs_critical_error (ERR_ZIP_ERROR_CODE_11, ""); break;
    case 12:   cs_critical_error (ERR_ZIP_ERROR_CODE_12, ""); break;
    case 13:   cs_critical_error (ERR_ZIP_ERROR_CODE_13, ""); break;
    case 14:   cs_critical_error (ERR_ZIP_ERROR_CODE_14, ""); break;    
    case 15:   cs_critical_error (ERR_ZIP_ERROR_CODE_15, ""); break;
    case 16:   cs_critical_error (ERR_ZIP_ERROR_CODE_16, ""); break;
    case 18:   cs_critical_error (ERR_ZIP_ERROR_CODE_18, ""); break;
    default:   cs_critical_error (ERR_ZIP_ERROR_UNDOCUMENTED, ""); break;

    }
}




static void
do_zip (const char *zipfile, const char *zip_program)
{

  pid_t pid, status;


  if ((pid = fork ()) < 0)
    cs_critical_error (ERR_CANT_START_NEW_PROCESS, "");

  if (pid == 0)
    {				/* child process */
      execl (zip_program, "zip",  "-r",  "-q", zipfile, ".", (char *) 0);
      exit (88);		/* this is returned if above execl() fails */
    }
 /*** parent process */
  while (wait (&status) != pid);

  check_zip_status (WEXITSTATUS (status));	/* report on status */

}







static void
send_zipped_website(const char *course, const char *key,
			const char *sender, const char *dir,
			int grp, CONFIG_STRUCT *conf, SESSION *user)
{			
 char website_path[MAX_PATH + 1];
 char zipfile[MAX_PATH + 1];
 char zipfile_fullname[MAX_PATH + 1];
 char current_dir[MAX_PATH + 1];
 char zip_program_fullname[MAX_PATH + 1];
 char modified_course[MAX_PATH + 1];
 
 course_slash_to_dot(course, modified_course);    /* shared_util.c */
  
 /* get full path to 'bin' directory */
 if(!getcwd(current_dir,MAX_PATH))
   cs_critical_error(ERR_GETCWD_FAILED,"");

 if(grp == CLIPBOARD)
   snprintf(website_path, MAX_PATH + 1,"%s%s/%s",
              CLIPBOARD_PATH, user->id, dir);
 else
  {             
   set_discussion_names (conf->course_path, sender, grp);	/* shared_news_util.c */
   snprintf (website_path, MAX_PATH + 1, "%s/%s", discussion_path, dir);	/* discussion_path global in shared_news_util.c */
  }
  
 /* put the zipfile in the distribution's 'tmp' directory */
 snprintf(zipfile, MAX_PATH + 1, "%s/../tmp/%s_%s", 
 			current_dir,sender,modified_course);
 snprintf(zipfile_fullname, MAX_PATH + 1, "%s.zip",zipfile); 			
 
 snprintf(zip_program_fullname,MAX_PATH + 1,
                    "%s/%s",current_dir,ZIP_PATH);
 
 
 if (chdir (website_path))
    cs_critical_error (ERR_CHDIR_FAILED, "");
  
  
  unlink(zipfile_fullname);
  do_zip(zipfile_fullname,zip_program_fullname);
  deliver_file("application/zip", zipfile_fullname, ZIPPED_WEBSITE_FNAME);
  unlink(zipfile_fullname);
}  
  


int
main (void)
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  char sender[MAX_USERNAME + 1];	/* from user=? command line */
  char dir[MAX_FILENAME + 1];	   /* from dir=? cmd line */
  int grp;			/* from optional grp=? cmd line */
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */


  cs_cgi_init();
  read_parameters (course, key, sender, dir, &grp);

  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);	/* shared_util.c */

  if (user.group != FACULTY)
    cs_critical_error (ERR_REQUEST_DENIED, "");

  send_zipped_website(course,key,sender,dir,grp, &conf, &user);
  cs_cgi_destroy();
  return 0;

}

