#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.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_news_util.h"
#include "manhat-lib/shared_clipboard_util.h" 
#include "manhat-lib/shared_potato_util.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_copy_file.h"
#include "manhat-lib/shared_server_string.h"
#include "manhat-lib/shared_hotpot_exam_util.h"

static void
read_parameters (char *course, char *key, char *sender,
		 char *info_fname, int *grp, int *read,
		 long *offset, char *from, char *team, int *inbox, char *student, int *no_frame)
{

  char astring[25];

  cs_get_required_parameter ("crs", course, MAX_FILENAME);	/* shared_cgi_util.c */
  cs_get_required_parameter ("id", key, MAX_KEY);

  cs_get_required_parameter ("read", astring, 5);	/* expecting 0 or 1 */
  *read = atoi (astring);

  cs_get_required_parameter ("sender", sender, MAX_USERNAME);
  cs_get_required_parameter ("from", from, MAX_FROM);
  cs_set_value("from", from);
  cs_get_required_parameter ("grp", astring, 5);
  *grp = atoi (astring);

  /* the MAIL group may be sending zero, or one other parameters which indicate
   ** whether the person is reading the INBOX, INBOX ATTIC, OUTBOX, or OUTBOX ATTIC
   ** just check for presence or absence of the next two fields
   */

  if (*grp == MAIL)
  {
   cs_get_optional_parameter("inbox", astring, 10);
   *inbox = strlen(astring);
  }
  cs_get_required_parameter ("inf", info_fname, MAX_FILENAME);

  cs_get_required_parameter ("loc", astring, 15);
  *offset = atol (astring);

   cs_get_optional_parameter("team", astring, 5);
   if(strlen(astring))
      *team = astring[0];
   else
      *team =0;
   cs_get_optional_parameter("student", student, MAX_USERNAME);
    
   cs_get_optional_parameter("noframe", astring, 5);
   if(strlen(astring))
	*no_frame = 1;
}




static void
mark_as_read (long offset, int grp, CONFIG_STRUCT *conf, SESSION *user)
{
  FILE *fp;
  int fd;
  char inbox_path[MAX_PATH + 1];	/* full path to inbox.dat */
  CENTRAL_INBOX_RECORD inbox;

  snprintf (inbox_path, MAX_PATH + 1, "%s%s", central_discussion_path, INBOX_FNAME);
  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, "");
  release_lock(fd);     /* shared_lock.c */
  fclose(fp);
  mark_msg_as_read(&inbox, conf, user);   /*shared_news_util.c */
}



static void
read_inf_file (int grp, const char *sender, const char *info_fname,
	       char *dirname, char *html_index, CONFIG_STRUCT *conf)
{
  char infopath[MAX_PATH + 1];
  NEWS_INFO info;
  INFO post_info;
  ATTACHMENT attach;
  FILE *fp;
  int fd;

  snprintf (infopath, MAX_PATH + 1, "%speople/%s/%s/%s", conf->course_path,
	    sender, discussion_fname, info_fname);

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

  fd = fileno(fp);  
  get_shared_lock(fd,1);  /*shared_lock.c */
  
  /** the data structure for the POST office is different
  *** from that of other groups
  **/
  if(grp == MAIL)
   {
    if (fread (&post_info, sizeof (INFO), 1, fp) != 1)
       cs_critical_error (ERR_FREAD_FAILED, "");
   }
  else
   {  
    if (fread (&info, sizeof (NEWS_INFO), 1, fp) != 1)
       cs_critical_error (ERR_FREAD_FAILED, "");
   }
    
  if (fread (&attach, sizeof (ATTACHMENT), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");

  release_lock(fd);    /* shared_lock.c */
  fclose (fp);
  strncpy (dirname, attach.unique_fname, MAX_FILENAME + 1);
  strncpy (html_index, attach.orig_fname, MAX_FILENAME + 1);
}




static void
read_clipboard_inf_file (char *clipboard_path, char *dirname, char *html_index,
                         SESSION *user)
{
  char infopath[MAX_PATH + 1];
  CLIPBOARD_INFO info;
  ATTACHMENT attach;
  FILE *fp;
  
  snprintf (clipboard_path, MAX_PATH + 1, "%s%s/", CLIPBOARD_PATH, user->id);

  snprintf (infopath, MAX_PATH + 1, "%s%s/%s", CLIPBOARD_PATH, user->id,
  							CLIPBOARD_INF_FNAME);

  fp = fopen (infopath, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, ""); 
  if (fread (&info, sizeof (CLIPBOARD_INFO), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");
  if (fread (&attach, sizeof (ATTACHMENT), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");

  fclose (fp);
  strncpy (dirname, attach.unique_fname, MAX_FILENAME + 1);
  strncpy (html_index, attach.orig_fname, MAX_FILENAME + 1);
}







static int
create_potato_symlink(const char *sender, const char *dirname,
			const char *html_index,  char *symlink_fname,
			const char *info_fname, const char *course,
			const char *key, CONFIG_STRUCT *conf, SESSION *user)
{
  char source_base[MAX_PATH + 1];
  char dest_base[MAX_PATH + 1];

  char html_path[MAX_PATH + 1]; 
  char new_html_path[MAX_PATH + 1];
  char temp_path[MAX_PATH + 1];
  
  char oldname[MAX_PATH + 1];
  char newname[MAX_PATH + 1];
  
  FILE *fp;

  struct stat buf;
  char *buffer;
 
   /* the source_base is the teacher's selftest directory */
   snprintf (source_base, MAX_PATH + 1, "%speople/%s/%s/", 
   			conf->course_path,
                        sender, discussion_fname);

   /* the dest_base is THIS person's selftest directory */
   snprintf (dest_base, MAX_PATH + 1, "%speople/%s/%s/", 
   			conf->course_path,
                        user->username, discussion_fname);

 
   /* path to original HTML file stored in the teacher's selftest directory */
   snprintf (html_path, MAX_PATH + 1, "%s%s/%s", source_base,
                                               dirname, html_index);

   /* path to temporary file we'll write now in this user's directory */
   snprintf (temp_path, MAX_PATH + 1, "%s%s", 
                        dest_base, HOTPOT_TMP_FNAME);


  /* how large is the html file ? */			
  if (stat (html_path, &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 (html_path, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");

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


 /* now open the temporary file for writing */
 fp = fopen (temp_path, "w");
 if(!fp)
      cs_critical_error (ERR_FOPEN_WRITE_FAILED , "");
 
 /* this function will write the modified html file, if the original
 ** file meets the CGI enabled hot potato criteria
 */
 if(!process_cgi_enabled_potato(buffer,buf.st_size, course, key, 
           sender, info_fname, html_index, "AttachedWebsite",
           ALIAS, fp))     /* ALIAS is #defined in custom.h */
  {
    fclose(fp);
    unlink(temp_path);
    free(buffer);
    return 0;
 }              
      
 /* still here? then the html file was a CGI-enabled hot potato quiz
 ** and the modified html file has been written to the temporary file 
 **/     
 fclose(fp);
 free(buffer);

 kill_hotpotato_directory(user->username, conf);  /* shared_potato_util.c */
 copy_dir(source_base, dest_base,                   /* shared_copy_file.c */
 			dirname, HOTPOT_TMP_DIRNAME);

 snprintf(new_html_path,MAX_PATH + 1, "%s%s/%s", dest_base, 
 			HOTPOT_TMP_DIRNAME, html_index);
 copy_file(temp_path,new_html_path);  /* shared_copy_file.c */
 unlink(temp_path);
  
   /* oldname must be expressed relative to the images/links directory 
     ** thus, the leading ../
    */
   snprintf (oldname, MAX_PATH + 1, "../%s%s", dest_base, HOTPOT_TMP_DIRNAME);
   get_symlink_fname(course, symlink_fname, user);     /* shared_util.c */

   /* note next that the path for 'newname' is relative  to the bin directory */
   snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname);

   remove_stale_symlinks (user->username, course, conf->access);

   if (symlink (oldname, newname))
      cs_critical_error (ERR_SYMLINK_FAILED, "");
    
 return 1;
}







static void
create_symlink (const char *crs, const char *sender, const char *key,
		const char *info_fname, char *html_index,
		char *symlink_fname, int grp, CONFIG_STRUCT *conf, SESSION *user)
{
  char dirname[MAX_FILENAME + 1];
  char oldname[MAX_PATH + 1];
  char newname[MAX_PATH + 1];
  int done = 0;
  
  read_inf_file (grp, sender, info_fname, dirname, html_index, conf);
  
  /* Next is to protect against students trying to use this
  ** program to view the source XML for a Hot Potatoes exam.
  ** If this is a hot potatoes exam, and the user is not a teacher,
  ** print an obscure error message and exit
  **/
  if( (strstr(dirname, HOTPOT_EXAM_DIR_PREFIX) == dirname)  /* test for hot pot exam */
     && (user->group != FACULTY))
          cs_critical_error(ERR_GENERAL_ERROR, "");
     
     
  
  
  if (grp == SELFTEST)
     done = create_potato_symlink(sender,dirname,html_index,symlink_fname,
 		     info_fname, crs, key, conf, user);
  else if(grp == ASSIGNMENTS)
  {
    create_hotpot_exam_symlink(conf->course_path, sender, dirname,
		                             user, crs, symlink_fname, conf->access); /*shared_hotpot_exam_util.c */

    done = 1;
  }

  if(!done)   /* do ordinary symlink */
  {  
    /* oldname must be expressed relative to the images/links directory 
     ** thus, the leading ../
    */
   snprintf (oldname, MAX_PATH + 1, "../%s%s", discussion_path, dirname);
   get_symlink_fname(crs, symlink_fname, user);

   /* note next that the path for 'newname' is relative  to the bin directory */
   snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname);

   remove_stale_symlinks (user->username, crs, conf->access);

   if (symlink (oldname, newname))
      cs_critical_error (ERR_SYMLINK_FAILED, "");
  }
}



static void
create_clipboard_symlink (const char *crs, const char *sender, 
				const char *key, const char *info_fname, 
			char *html_index, char *symlink_fname, int grp, SESSION *user, int access)
{
  char clipboard_path[MAX_PATH + 1];
  char dirname[MAX_FILENAME + 1];
  char oldname[MAX_PATH + 1];
  char newname[MAX_PATH + 1];
  
  read_clipboard_inf_file (clipboard_path, dirname, html_index, user);
  
    /* oldname must be expressed relative to the images/links directory 
     ** thus, the leading ../
    */
   snprintf (oldname, MAX_PATH + 1, "../%s%s", clipboard_path, dirname);
   get_symlink_fname( crs, symlink_fname, user);

   /* note next that the path for 'newname' is relative  to the bin directory */
   snprintf (newname, MAX_PATH + 1, "../images/links/%s", symlink_fname);

   remove_stale_symlinks (user->username, crs, access);

   if (symlink (oldname, newname))
      cs_critical_error (ERR_SYMLINK_FAILED, "");
}



void
send_frameset (const char *symlink_fname, const char *html_index,
	       const char *course, const char *key, long offset, int grp,
	       const char *from, char team, int inbox, const char *student, int no_frame)
{
  char server_string[MAX_PATH + 1];
  char url[MAX_PATH + 1];
   
   get_server_string(server_string, MAX_PATH + 1);   /* shared_server_string.c */
   cs_set_value("server_name", server_string);

  if (team)
    snprintf
      (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d&amp;from=%s&amp;team=%c%s",
       "web_page_back", course, key, offset, grp, from, team, no_frame == 1 ? "&amp;noframe=1":"");
  else if (grp == MAIL)
    snprintf
      (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d&amp;from=%s%s",
       "web_page_back", course, key, offset, grp, from,  inbox ? "&inbox=yes" : "");
  else if(strlen(student))
    snprintf
      (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d&amp;student=%s&amp;from=%s%s",
       "web_page_back", course, key, offset, grp, student, from, no_frame==1 ? "&amp;noframe=1":"");

  else
       snprintf
      (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d&amp;from=%s%s",
       "web_page_back", course, key, offset, grp, from, no_frame==1?"&amp;noframe=1":"");
  cs_set_value("top_url", url);
  
  
  /** bottom_url is the content.  Need to check for special case.  If the "html_index" is set 
  *** to the value ZIP_LECTERN_START_FNAME, this is a Lectern II RealAudio lecture.  The bottom 
  *** frame must point to the CGI program "lectern_handler" to deliver this content
  ***/
  
  if(!strcmp(html_index,ZIP_LECTERN_START_FNAME))
    snprintf(url, MAX_PATH + 1, "%s?link=%s", "lectern_handler", symlink_fname);
  else
      snprintf(url, MAX_PATH +1, "%s%slinks/%s/%s", server_string, IMAGE_PATH, symlink_fname, html_index);
      
  cs_set_value("bottom_url", url);
  
}



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 sender=? command line */
  char info_fname[MAX_FILENAME + 1];	/* from inf=? command line */
  int grp;			/* from grp=? command line */
  int read;			/* from read=? command line */
  long offset;			/* from loc=? command line */
  char from[MAX_FROM];		/* from from=? command line .. this is different than usual because
			        ** this time 'from' indicates where the caller is from, not where
				** the caller is...
				*/

  char team;			/* optional parameter sent here when faculty is reading a msg
				   *  in the team_teach module
				 */
  char student[MAX_USERNAME + 1];  /* optional parameter sent when person is reading a msg via assign_read */

  int inbox = 0, no_frame=0;		/* this might appear on cmd line if grp == MAIL  * */

  char html_index[MAX_FILENAME + 1];	/*name of html file to start */
  char symlink_fname[MAX_FILENAME + 1];
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */

  cs_cgi_init();
  read_parameters (course, key, sender, info_fname, &grp, &read, &offset,
		   from, &team, &inbox,  student, &no_frame);

  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);	/* shared_util.c */
  set_discussion_names (conf.course_path, sender, grp);	  /* shared_news_util.c */


  if(grp == CLIPBOARD)
    create_clipboard_symlink (course, sender, key, info_fname,
    				html_index, symlink_fname, grp, &user, conf.access);
  else
    create_symlink (course, sender, key, info_fname, html_index, symlink_fname,
		  grp, &conf, &user);
  if ((grp != CLIPBOARD) && (grp != MAIL) && !read)
    mark_as_read (offset, grp, &conf, &user);

  cs_set_int_value("grp", grp);
  cs_set_course_info(&conf);
  send_frameset (symlink_fname, html_index, course, key, offset, grp, from,
		 team, inbox,student, no_frame);
  cs_cgi_display("web_page_start", 1);
  cs_cgi_destroy();
  return 0;
}

