#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>		/* for tolower() */
#include <sys/stat.h>
#include <sys/types.h>
       
#include "global.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_lock.h"
#include "manhat-lib/shared_copy_file.h"
#include "manhat-lib/shared_file_util.h"

ATTACHMENT_NODE *attachment_head = 0;	/* linked list of file info */
char inbox_path[MAX_PATH + 1];	/* full path to inbox.dat */




static void
read_parameters (char *course, char *key, long *offset, int *grp, int *inbox)
{

  char tmp[MAX_FILENAME + 1];	/* for holding the long value * */

  cs_get_required_parameter ("crs", course, MAX_FILENAME);	/* cgihtml library */
  cs_get_required_parameter ("id", key, MAX_KEY);

  cs_get_required_parameter ("grp", tmp, MAX_FILENAME);
  *grp = atoi (tmp);

  cs_get_required_parameter ("loc", tmp, MAX_FILENAME);
  *offset = atol (tmp);

  if (*grp == MAIL)
    {
      cs_get_required_parameter ("inbox", tmp, MAX_FILENAME);
      *inbox = (*tmp == 'Y') || (*tmp == 'y');
    }
  else
     *inbox = 1;   /* doesn't really matter, but it's best to initialize this to prevent compiler warnings */  

}





/* reads the inbox file and then the corresponding *.inf file 
** to get everything ready to copy
** this function is almost the same as the one with the same name
** in news_read.c   (this version doesn't bother sending marking
** the message as read)
**/
static void
process_news_inbox_record (long offset, CENTRAL_INBOX_RECORD * inbox,
			   int grp, int *website_attached,CONFIG_STRUCT *conf)
{
  int fd;
  FILE *fp;
  char infopath[MAX_PATH + 1];
  int i;
  ATTACHMENT_NODE *aptr = 0;
  NEWS_INFO infofile_info;
  

  /** this sets global inbox_path string */
  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);

 *website_attached = 0;  /* assume this to start */
 if(inbox->info.attachments)   /* read the info file to get the attachment data */
  {
   snprintf (infopath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path,PEOPLE_DIR, inbox->info.sender,
	    discussion_fname, inbox->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 */


   if (fread (&infofile_info, sizeof (NEWS_INFO), 1, fp) != 1)
     cs_critical_error (ERR_FREAD_FAILED, "");


   /* process attachments, build linked list */
   *website_attached = (infofile_info.attachments == -1);

   /* so we go thru next for loop */
   if (*website_attached)
      infofile_info.attachments = 1;

    for (i = 1; i <= infofile_info.attachments; i++)
    {
      if (!attachment_head)
	{
	  attachment_head =
	    (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!attachment_head)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = attachment_head;
	}
      else
	{
	  aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!aptr->next)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = aptr->next;
	}

      if (fread (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1)
	cs_critical_error (ERR_FREAD_FAILED, "");
      aptr->next = 0;
    }				/* for .. */

   release_lock(fd);   /* shared_lock.c */
   fclose (fp);
  }  

}




static void
get_news_clipboard_info (CLIPBOARD_INFO * clipboard_info, int grp, int offset,
                         CONFIG_STRUCT *conf)
{

  CENTRAL_INBOX_RECORD inbox;
  int website_attached;


  process_news_inbox_record (offset, &inbox, grp, &website_attached, conf);

  clipboard_info->group = grp;
  strncpy (clipboard_info->subject, inbox.info.subject, MAX_SUBJECT + 1);
  strncpy (clipboard_info->sender_username, inbox.info.sender, MAX_USERNAME + 1);
  strncpy (clipboard_info->sender_realname, inbox.info.sender_realname, MAX_NAME + 1);
  clipboard_info->time_sent = inbox.info.time_sent;
  clipboard_info->attachments = inbox.info.attachments;
  strncpy (clipboard_info->msg_fname, inbox.info.msg_fname, MAX_FILENAME + 1);
  clipboard_info->website_attached = website_attached;

}




static void
process_mail_inbox_record (long offset, INBOX_RECORD * inbox,
			   INFO * infofile_info, int *website_attached,
                           CONFIG_STRUCT *conf, SESSION *user)
{
  char infopath[MAX_PATH + 1];
  FILE *fp;
  ATTACHMENT_NODE *aptr = 0;
  int i;


  snprintf (inbox_path, MAX_PATH + 1, "%speople/%s/mail/%s", conf->course_path,
	    user->username, INBOX_FNAME);
  fp = fopen (inbox_path, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");
  if (fseek (fp, offset, SEEK_SET))
    cs_critical_error (ERR_FSEEK_FAILED, "");
  if (fread (inbox, sizeof (INBOX_RECORD), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");
  fclose (fp);

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

  fp = fopen (infopath, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");
    
  /* note that file locking is not necessary when working with the Post Office */  
  if (fread (infofile_info, sizeof (INFO), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");


  /* process attachments */

  *website_attached = (infofile_info->no_attachments == -1);
  if (*website_attached)
    infofile_info->no_attachments = 1;	/* since we have to pick up the dirname */

  for (i = 1; i <= infofile_info->no_attachments; i++)
    {
      if (!attachment_head)
	{
	  attachment_head =
	    (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!attachment_head)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = attachment_head;
	}
      else
	{
	  aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!aptr->next)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = aptr->next;
	}

      if (fread (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1)
	cs_critical_error (ERR_FREAD_FAILED, "");
      aptr->next = 0;
    }

  fclose (fp);
}




static void
get_mail_inbox_clipboard_info (CLIPBOARD_INFO * clipboard_info,
			       int grp, int offset, CONFIG_STRUCT *conf, SESSION *user)
{

  INBOX_RECORD inbox;
  INFO infofile_info;
  int website_attached;

  process_mail_inbox_record (offset, &inbox, &infofile_info,
			     &website_attached, conf, user);


  clipboard_info->group = grp;
  strncpy (clipboard_info->subject, inbox.newfile_info.subject,
	   MAX_SUBJECT + 1);
  strncpy (clipboard_info->sender_username, inbox.newfile_info.sender,
	   MAX_USERNAME + 1);
  strncpy (clipboard_info->sender_realname,
	   inbox.newfile_info.sender_realname, MAX_NAME + 1);
  clipboard_info->time_sent = inbox.newfile_info.time_sent;
  clipboard_info->attachments = inbox.newfile_info.attachments;
  strncpy (clipboard_info->msg_fname,
	   infofile_info.msg_fname, MAX_FILENAME + 1);
  clipboard_info->website_attached = website_attached;

}


static void
process_mail_outbox_record (long offset, OUTBOX_RECORD * outbox,
			    INFO * infofile_info, int *website_attached,
                            CONFIG_STRUCT *conf, SESSION *user)
{
  char outbox_path[MAX_PATH + 1];
  FILE *fp;
  char infopath[MAX_PATH + 1];
  ATTACHMENT_NODE *aptr = 0;
  int i;

  snprintf (outbox_path, MAX_PATH + 1, "%speople/%s/mail/%s",
	    conf->course_path, user->username, OUTBOX_FNAME);
  fp = fopen (outbox_path, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");
  if (fseek (fp, offset, SEEK_SET))
    cs_critical_error (ERR_FSEEK_FAILED, "");
  if (fread (outbox, sizeof (OUTBOX_RECORD), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");
  fclose (fp);

  snprintf (infopath, MAX_PATH + 1, "%speople/%s/mail/%s", conf->course_path,
	    user->username, outbox->info_fname);

  fp = fopen (infopath, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, "");
  /* note file locking not necessary when working with the Post Office */  
  if (fread (infofile_info, sizeof (INFO), 1, fp) != 1)
    cs_critical_error (ERR_FREAD_FAILED, "");


  /* process attachments */

  *website_attached = (infofile_info->no_attachments == -1);
  if (*website_attached)
    infofile_info->no_attachments = 1;	/* since we have to pick up the dirname in next loop */

  for (i = 1; i <= infofile_info->no_attachments; i++)
    {
      if (!attachment_head)
	{
	  attachment_head =
	    (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!attachment_head)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = attachment_head;
	}
      else
	{
	  aptr->next = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
	  if (!aptr->next)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  aptr = aptr->next;
	}

      if (fread (&aptr->data, sizeof (ATTACHMENT), 1, fp) != 1)
	cs_critical_error (ERR_FREAD_FAILED, "");
      aptr->next = 0;
    }


  fclose (fp);
}




void
get_mail_outbox_clipboard_info (CLIPBOARD_INFO * clipboard_info,
				int grp, int offset,
                                CONFIG_STRUCT *conf, SESSION *user)
{
  OUTBOX_RECORD outbox;
  INFO infofile_info;
  int website_attached;

  process_mail_outbox_record (offset, &outbox, &infofile_info,
			      &website_attached,conf, user );

  clipboard_info->group = grp;
  strncpy (clipboard_info->subject, outbox.subject, MAX_SUBJECT + 1);
  strncpy (clipboard_info->sender_username, user->username, MAX_USERNAME + 1);
  strncpy (clipboard_info->sender_realname, user->realname, MAX_NAME + 1);
  clipboard_info->time_sent = outbox.time_sent;
  clipboard_info->attachments = outbox.attachments;
  strncpy (clipboard_info->msg_fname,
	   infofile_info.msg_fname, MAX_FILENAME + 1);
  clipboard_info->website_attached = website_attached;

}



static void
get_clipboard_info (CLIPBOARD_INFO * clipboard_info,
		    int grp, long offset, int inbox,
                    CONFIG_STRUCT *conf, SESSION *user)
{

  switch (grp)
    {
    case CLASS_DISCUSSION:
    case STUDENT_LOUNGE:
    case ANONYMOUS_DISCUSSION:
    case TEAM_DISCUSSION:
    case HANDOUTS_NOTICES:
    case TEAM_TEACH:
    case SELFTEST:
    case LECTURES:
    case ASSIGNMENTS:
    case INTERNET_RESOURCES:
    case SURVEYS:
    case PODCASTS:
      get_news_clipboard_info (clipboard_info, grp, offset, conf);
      break;


    case MAIL:
      if (inbox)
	get_mail_inbox_clipboard_info (clipboard_info, grp, offset, conf, user);
      else
	get_mail_outbox_clipboard_info (clipboard_info, grp, offset, conf, user);
      break;
    default:
      cs_critical_error (ERR_UNSUPPORTED_GROUP, "");
      break;
    }
}






static void
write_msg_file (const char *destpath, const char *sender_username,
		const char *msg_fname, int grp, CONFIG_STRUCT *conf)
{
  FILE *fp, *outfp;
  char fullpath[MAX_PATH + 1];
  char fulldestpath[MAX_PATH + 1];
  int big_buffer = 200;
  char *buffer, c;
  int i;
  char *unescape_url;

  buffer = (char*)malloc ( sizeof(char) * (big_buffer +1));
  if(!buffer)
      cs_critical_error(ERR_MALLOC_FAILED, "");
      

  
  snprintf (fulldestpath, MAX_PATH + 1, "%s/%s", destpath, msg_fname);
  outfp = fopen (fulldestpath, "w");
  if (!outfp)
    cs_critical_error (ERR_FOPEN_WRITE_FAILED, fulldestpath);


  /* discussion_fname is global and should have been set in set_discussion_names() */
  snprintf (fullpath, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,
	    sender_username, discussion_fname, msg_fname);
  fp = fopen (fullpath, "r");
  if (!fp)
    cs_critical_error (ERR_FOPEN_READ_FAILED, fullpath);


/** Early versions of Manhattan 'escaped' the characters of the URL typed
*** into an INTERNET_RESOURCES module.  The current version does not.
*** (This URL is stored in the first line of the message.)  The next 'if'
*** maintains compatiblity with those earlier versions by 'unescaping' the
*** first line of the msg before writing it to the clipboard.  You can 
*** safely remove this 'if' if you don't have to deal with classrooms created
*** with 'old' Manhattans
**/


  if (grp == INTERNET_RESOURCES)
    {
	i =0;
        while((c = getc(fp)) != '\n')
	{
	   if((int)strlen(buffer) >= big_buffer)
	   {
	      buffer = realloc(buffer, big_buffer*2 +1);
	      big_buffer = big_buffer *2;
	   }
	   buffer[i] = c;
	   buffer[i+1] = '\0';
	   i++;
	} 
	  unescape_url = (char *)cgi_url_unescape (buffer);  /* Clearsilver.h  */
	  fprintf (outfp, "%s\n", unescape_url);
    }
/*** end kludge */


  while (fgets (buffer, big_buffer, fp))
    fprintf (outfp, "%s", buffer);

  fclose (outfp);
  fclose (fp);
  if(buffer)
    free(buffer);
}


static void
write_clipboard_file (const char *clipboard_dir,
		      CLIPBOARD_INFO * clipboard_info)
{
  ATTACHMENT_NODE *ptr;
  char dest_path[MAX_PATH + 1];
  FILE *fp;


  snprintf (dest_path, MAX_PATH + 1, "%s/%s", clipboard_dir,
	    CLIPBOARD_INF_FNAME);
  fp = fopen (dest_path, "w");
  if (!fp)
    cs_critical_error (ERR_FOPEN_WRITE_FAILED, "");

  if (fwrite (clipboard_info, sizeof (CLIPBOARD_INFO), 1, fp) != 1)
    cs_critical_error (ERR_FWRITE_FAILED, "");

  for (ptr = attachment_head; ptr; ptr = ptr->next)
    if (fwrite (&(ptr->data), sizeof (ATTACHMENT), 1, fp) != 1)
      cs_critical_error (ERR_RED_WRITE, "");

  fclose (fp);
}









static void
write_website (const char *clipboard_dir, const char *sender_username,
                CONFIG_STRUCT *conf)
{

  char source_base[MAX_PATH + 1], dest_base[MAX_PATH + 1];


  snprintf (source_base, MAX_PATH + 1, "%s%s/%s/%s/", conf->course_path, PEOPLE_DIR,
	    							sender_username, discussion_fname);
  snprintf (dest_base, MAX_PATH + 1, "%s/", clipboard_dir);

  copy_dir (source_base, dest_base,        /* shared_copy_file.c */
	    attachment_head->data.unique_fname,
	    attachment_head->data.unique_fname);

}




static void
write_attachments (const char *clipboard_dir,
		   int website_attached, const char *sender_username,
                   CONFIG_STRUCT *conf)
{
  char source_path[MAX_PATH + 1], dest_path[MAX_PATH + 1];
  ATTACHMENT_NODE *ptr;

  if (website_attached)
    write_website (clipboard_dir, sender_username, conf);
  else
    {
      for (ptr = attachment_head; ptr; ptr = ptr->next)
	{
	  snprintf (source_path, MAX_PATH + 1, "%speople/%s/%s/%s",
		    conf->course_path, sender_username, discussion_fname,
		    ptr->data.unique_fname);

	  snprintf (dest_path, MAX_PATH + 1, "%s/%s", clipboard_dir,
		    ptr->data.unique_fname);
	  copy_file (source_path, dest_path);  /* shared_copy_file.c */
	}
    }
}



static void
free_attachment_list ()
{
  ATTACHMENT_NODE *aptr;

  while (attachment_head)
    {
      aptr = attachment_head;
      attachment_head = attachment_head->next;
      free (aptr);
    }
}


void
write_clipboard_data (const char *path, const char *course, const char *key,
		      long offset, int grp, int inbox, CONFIG_STRUCT *conf,
                      SESSION *user)
{
  CLIPBOARD_INFO clipboard_info;


  /* this directory should NOT exist (because we killed it earlier),
     ** so we create it first
   */
  if (mkdir (path, 0777))
    cs_critical_error (ERR_MKDIR_FAILED, path);

  /* gather information about this message */
  get_clipboard_info (&clipboard_info, grp, offset, inbox, conf, user);


  write_clipboard_file (path, &clipboard_info);
  write_msg_file (path, clipboard_info.sender_username,
		  clipboard_info.msg_fname, grp, conf);



  if (clipboard_info.attachments)
    write_attachments (path, clipboard_info.website_attached,
		       clipboard_info.sender_username, conf);

  free_attachment_list ();
}




int
main (void)
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  long offset;			/* from loc=? command line */
  int grp;			/* from grp=? command line */
  int inbox;			/* from optional inbox=? command line */
  char clipboard_path[MAX_PATH + 1];	/* complete path to this user's clipboard directory */
  SESSION user;
  CONFIG_STRUCT conf;

  cs_cgi_init();

  read_parameters (course, key, &offset, &grp, &inbox);
  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, "");

  set_discussion_names (conf.course_path, user.username, grp);	/* shared_news_util.c */
  snprintf (clipboard_path, MAX_PATH + 1, "%s%s/", CLIPBOARD_PATH, user.id);
  kill_directory (clipboard_path);	/* shared_file_util.c */

  write_clipboard_data (clipboard_path, course, key, offset, grp, inbox, &conf, &user);

  cs_cgi_display("clipboard_copy", 1);
  cs_cgi_destroy();
  return (0);
}

