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

#include "global.h"
#include "custom.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_read_infofile.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_potato_util.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_server_string.h"
#include "manhat-lib/shared_mime_type.h"


/* sender is really the offset into inbox.dat -- for anonymous groups ---
** this fcn returns the real sender username
**/

static void
get_sender_username (char *sender, CONFIG_STRUCT *conf, SESSION *user)
{
  int fd;
  long offset;
  FILE *fp;
  char inbox_path[MAX_PATH + 1];
  CENTRAL_INBOX_RECORD inbox;

  snprintf (inbox_path, MAX_PATH + 1, "%s%s/%s/%s", conf->course_path, INBOXES_DIR, ANONYMOUS_DIR, INBOX_FNAME);
  offset = atol (sender);

  fp = fopen (inbox_path, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");
    
  fd = fileno(fp);
  get_shared_lock(fd, 1);   /* shared_lock.c */
  
  if(fseek (fp, offset, SEEK_SET))
    cs_critical_error(ERR_FSEEK_FAILED,"");
  if (fread (&inbox, sizeof (CENTRAL_INBOX_RECORD), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");
  strncpy (sender, inbox.info.sender, MAX_USERNAME + 1);
  
  release_lock(fd);   /* shared_lock.c */
  fclose (fp);
}



static void
read_parameters (char *course, char *key, char *sender,
		 char *fname, char *info_fname, int *attach,
		 int *grp, int *ra_file)
{

  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 ("user", sender, MAX_USERNAME);
  cs_get_required_parameter ("fname", fname, MAX_FILENAME);
  cs_get_required_parameter ("info", info_fname, MAX_FILENAME);
  cs_get_required_parameter ("attach", intstring, 5);
  *attach = atoi (intstring);

/* grp parameter is optional */
  cs_get_optional_parameter ("grp", intstring, 5);
  if (strlen(intstring))
    *grp = atoi (intstring);
  else
    *grp = -1;			/* flag that this is not a newsgroup */

/* ra_file parameter (Used for Real Audio files) is optional */
  cs_get_optional_parameter ("ra_file", intstring, 5);
  if(strlen(intstring))
     *ra_file = 1;
  else 
     *ra_file = 0;



}




static void
verify_access_rights (SESSION *user)
{
  PERSON_NODE *ptr;

  for (ptr = person_head; ptr; ptr = ptr->next)
    if (!strcmp (user->username, ptr->data.username))
      return;
  cs_critical_error (ERR_REQUEST_DENIED, "");
}


static void
get_original_fname (char *original_fname, const char *fname)
{
  ATTACHMENT_NODE *ptr;

  for (ptr = attachment_head; ptr; ptr = ptr->next)
    if (!strcmp (ptr->data.unique_fname, fname))
      {
	strncpy (original_fname, ptr->data.orig_fname, MAX_FILENAME + 1);
	return;
      }
  cs_critical_error (ERR_UNABLE_TO_DETERMINE_FILENAME, "");
}














static void
deliver_special_selftest ( char *source_file, char *dest_file,
                            char *course, char *key, char *sender, 
                            char *info_fname, char *original_fname,
                            char *system_fname)
{

  FILE *fp;

  struct stat buf;
  char *buffer;
  
  
  if (stat (source_file, &buf))
    cs_critical_error (ERR_STAT_FAILED, "");
    
  /* allocate an extra byte for a terminating null */
  buffer = (char *) malloc( (buf.st_size + 1) * sizeof(char));
  if(!buffer)
    cs_critical_error (ERR_MALLOC_FAILED, "");
      
  fp = fopen (source_file, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, source_file);

  /* read the whole file in one gulp */
  if (fread (buffer, buf.st_size, 1, fp) != 1)
	cs_critical_error (ERR_FREAD_FAILED, "");
  fclose(fp);

  /* shared_potato_util.c */
  if (!process_cgi_enabled_potato(buffer,buf.st_size, course, key, 
           sender, info_fname, original_fname,system_fname,ALIAS,stdout))
      {  /* send the file as-is */
       printf ("Content-type:text/html\n");
       printf ("Content-disposition: filename=\"%s\"\n", dest_file);
       printf ("Content-length: %ld\n\n", (long)buf.st_size);
       
       if (fwrite (buffer, buf.st_size, 1, stdout) != 1)
     	  cs_critical_error (ERR_FWRITE_FAILED, "");
      }  	
  free(buffer);
}  




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
deliver_realaudio_meta (char *mime_type, char *course, char *key,
			const char *sender, const char *fname,
			const char *info_fname, int attach, int grp)
{
  char server_string[MAX_PATH + 1];
  char *script_name;
  
  get_server_string(server_string, MAX_PATH + 1);
  
  printf ("Content-type:%s\n\n", mime_type);
  /* work on this later */
  /* SCRIPT_NAME is defined in cgi-lib.h   */
  script_name = hdf_get_value(global_cgi->hdf, "CGI.ScriptName", "");
  printf
   ("%s%s?crs=%s&id=%s&user=%s&fname=%s&info=%s&attach=%d&grp=%d&ra_file=1",
   server_string, script_name, course, key, sender, fname, info_fname, attach, grp);
}






static void
send_file (char *sender, char *fname,
	   char *info_fname, int attach, int grp, int ra_file,
	   char *key, char *course, CONFIG_STRUCT *conf, SESSION *user)
{
  INFO infofile_info;
  char original_fname[MAX_FILENAME + 1];
  char mime_type[MAX_MIME_TYPE + 1];
  char source_path[MAX_PATH + 1];
  int is_realaudio;		/* is this a real audio file? */

  read_post_infofile (sender, info_fname, &infofile_info, conf);	/* shared_read_infofile.c */
  if (strcmp (user->username, sender))	/* if this user didn't send the file */
    verify_access_rights (user);
  get_original_fname (original_fname, fname);

  snprintf (source_path, MAX_PATH + 1, "%s%s/%s/%s/%s",
	    conf->course_path, PEOPLE_DIR, sender, MAIL_DIR, fname);

  /* shared_mime_type.c */
  get_mime_type (source_path, original_fname, mime_type,    
		 &is_realaudio);


  if (is_realaudio && !ra_file)
    deliver_realaudio_meta (mime_type, course, key, sender, fname, info_fname,
			    attach, grp);
  else  
    deliver_file (mime_type, source_path, original_fname);
}






static void
send_news_file (char *sender, char *fname,
		char *info_fname, int attach, int grp, int ra_file,
		char *key, char *course, CONFIG_STRUCT *conf)
{
  NEWS_INFO infofile_info;
  char original_fname[MAX_FILENAME + 1];
  char mime_type[MAX_MIME_TYPE + 1];
  char source_path[MAX_PATH + 1];
  int is_realaudio;


  read_news_infofile (sender, info_fname, &infofile_info, grp, conf);	/* shared_read_infofile.c */

/* we don't have to verify_access_rights because we know by definition that
** everyone has been sent the same file.  Fortunate, because of the way the
** person list is mucked up... see comment above
***
*** well... that's not quite true.  the 'small group' thing is where not everyone
*** gets the same file  oh well, we'll take our chances and skip the validation anyway
**/
/***  verify_access_rights();   ******/
  get_original_fname (original_fname, fname);
  set_discussion_names (conf->course_path, sender, grp);	/* shared_news_util.c */
  snprintf (source_path, MAX_PATH + 1, "%s/%s", discussion_path, fname);	/* discussion_path global in shared_news_util.c */

  /* shared_mime_type.c */
  get_mime_type (source_path, original_fname, mime_type, 
		 &is_realaudio);


  if (is_realaudio && !ra_file)
    deliver_realaudio_meta (mime_type, course, key, sender, fname, info_fname,
			    attach, grp);
  else if ( (grp == SELFTEST)  &&  !strcmp(mime_type,"text/html") )
    deliver_special_selftest(source_path,original_fname,course,
                               key,sender,info_fname,original_fname, fname);
  else
    deliver_file (mime_type, source_path, original_fname);
}



static void
send_clipboard_file (char *sender, char *fname,
		char *info_fname, int attach, int grp, int ra_file,
		char *key, char *course, SESSION *user)
{
  CLIPBOARD_INFO infofile_info;
  char clipboard_path[MAX_PATH + 1];
  char original_fname[MAX_FILENAME + 1];
  char mime_type[MAX_MIME_TYPE + 1];
  char source_path[MAX_PATH + 1];
  int is_realaudio;

  get_clipboard_info (&infofile_info,clipboard_path, user);

  get_original_fname (original_fname, fname);
  snprintf (source_path, MAX_PATH + 1, "%s%s", clipboard_path, fname);	

  /* shared_mime_type.c */
  get_mime_type (source_path, original_fname, mime_type, &is_realaudio);

  deliver_file (mime_type, source_path, original_fname);
}    




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 fname[MAX_FILENAME + 1];	   	/* from fname=? cmd line */
  char info_fname[MAX_FILENAME + 1];	/* from inf=? cmd line */
  int attach;				/* from attach=? cmd line */
  int grp;				/* from optional grp=? cmd line */
  int ra_file;				/* from optional ra_file=? cmd line */
  SESSION user;
  CONFIG_STRUCT conf;			/* the configuration read from config file */

  cs_cgi_init();
  read_parameters (course, key, sender, fname, info_fname,
		   &attach, &grp, &ra_file);

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

  if (grp == ANONYMOUS_DISCUSSION)		/*the 'user' param was really the offset into inbox.dat */
    get_sender_username (sender, &conf, &user);
  if (grp == -1)
    send_file (sender, fname, info_fname, attach, grp, ra_file, key, course, &conf, &user);	/* from mail system */
  else
   if (grp == CLIPBOARD)
    send_clipboard_file(sender, fname, info_fname, attach, grp, ra_file, key,
		    course, &user);
   else
   {
    send_news_file (sender, fname, info_fname, attach, grp, ra_file, key,
		    course, &conf);
   }

  free_attachment_list ();	/* shared_read_infofile.c */
  cs_cgi_destroy();
  return 0;

}

