#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
       

#include "global.h"

#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_translate_url.h"
#include "manhat-lib/shared_file_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_fold_file.h"
#include "manhat-lib/shared_strtrm.h"
#include "manhat-lib/shared_system_data.h"

typedef struct data
 {
     char *url;
     char *msg;
 }DATA;



void
free_data(DATA *data)
{
    if(data)
    {
       if(data->url)
	   free(data->url);
       if(data->msg)
	   free(data->msg);
       free(data);
    }
}


DATA *
read_parameters (char *course, char *key, char *fromprog, int *hide, char *subject, int *width, int *topic, int *reply_to)
{
   char tmp[20];
   DATA *msg_data;
   char *string;


   cs_get_required_parameter ("crs", course, MAX_PATH);
   cs_get_required_parameter ("id", key, MAX_KEY);
   cs_get_required_parameter ("from", fromprog, MAX_PATH);
   cs_get_required_parameter ("subject", subject, MAX_SUBJECT);
   cs_get_required_parameter ("width", tmp, 19);
   *width = atoi(tmp);


   cs_get_required_parameter ("topic", tmp, 19);
   *topic = atoi(tmp);
   
   cs_get_required_parameter ("reply_to", tmp, 19);
   *reply_to = atoi(tmp);

   cs_get_optional_parameter ("hide", tmp, 19);
   if(strlen(tmp)>0)
      *hide = 1;
   else
      *hide =0;
   msg_data = (DATA*)malloc(sizeof(DATA));
   if(!msg_data)
      cs_critical_error(ERR_MALLOC_FAILED, "");

   string = hdf_get_value(global_cgi->hdf, "Query.tp4", 0);
   strtrm(string);    /* shared_strtrm.c */
   if(!string || !strlen(string))
      cs_critical_error(ERR_PARAM_MISSING, "tp4");
   msg_data->url = (char*)malloc(sizeof(char)*(strlen(string)+1));  
   if(!msg_data->url)
      cs_critical_error(ERR_MALLOC_FAILED, "");

   strncpy(msg_data->url, string, strlen(string) +1);

   string = hdf_get_value(global_cgi->hdf, "Query.msg", 0);
   if(string)
   {
     msg_data->msg = (char*)malloc(sizeof(char)*(strlen(string)+1));  
     if(!msg_data->msg)
        cs_critical_error(ERR_MALLOC_FAILED, "");
     strncpy(msg_data->msg, string, strlen(string) +1);
   }
   else
     msg_data->msg = 0;
   return msg_data;
}


static void
write_link_file (DATA *msg_data, const char *unique_fname, int width)
{
  FILE  *outfp;
  char filepath[MAX_PATH + 1];
  int len;

  snprintf (filepath, MAX_PATH + 1, "%s/%s", discussion_path, unique_fname);
  
  outfp = fopen (filepath, "w");
  if (!outfp)
    cs_critical_error (ERR_FOPEN_WRITE_FAILED, "");

  fprintf (outfp, "%s\n", msg_data->url);
  len = strlen(msg_data->msg);
  if(len < width || system_data_int("USE_TEXTAREA_HARD_WRAP"))
      fprintf (outfp, "%s\n", msg_data->msg);
  else 
    write_folded(outfp, msg_data->msg, width); /* shared_fold_file.c */
  fclose (outfp);
}




/* note that this creates the file */
void
get_unique_fname(char *unique_fname, const char *base_dir, const char *filetype, time_t *time_sent)
{
 int fd;
 
 fd = get_unique_fd(base_dir, filetype, unique_fname, time_sent);
 close(fd);
} 



static void
process_message_file (DATA *msg_data,  char *msg_fname, time_t * time_sent, int width)
{
    get_unique_fname (msg_fname, discussion_path, "msg", time_sent);
    write_link_file (msg_data, msg_fname, width);
}






static void
complete_send (const char *msg_fname, SESSION *user, time_t time_sent, int hide, const char *subject, int topic, int reply_to)
{
  FILE  *inbox_fp;
  int info_fd, inbox_fd;
  struct stat buf;
  NEWS_PERSON person;
  
  char info_fname[MAX_FILENAME + 1];
  char inbox_fname[MAX_PATH + 1];
  int msg_id;
  CENTRAL_INBOX_RECORD inbox_record, new_inbox_record;
  int inbox_record_size,  news_person_size;
  
  
 /* memorize the sizes of these data structures, 
 ** so we don't have to repeatedly call sizeof()
 */
  inbox_record_size = sizeof(CENTRAL_INBOX_RECORD); 
  news_person_size = sizeof(NEWS_PERSON);
  
 /* this user has already read this message
 ** set a NEWS_PERSON record to be written
 ** to the end of the new inf file.
 */
 strncpy(person.username,user->username, MAX_USERNAME + 1);
 strncpy(person.realname, user->realname, MAX_NAME + 1);
 person.time_read = time_sent;
 person.user_unlocked = 0;


  /* set up as much of the new inbox record as we can before locking
  ** the inbox.dat file
  */  
  strncpy(new_inbox_record.info.msg_fname, msg_fname, MAX_FILENAME + 1);
  strncpy(new_inbox_record.info.sender, user->username, MAX_USERNAME + 1);
  strncpy(new_inbox_record.info.sender_realname, user->realname, MAX_NAME + 1);
  strncpy(new_inbox_record.info.receiver_username,"",MAX_USERNAME + 1);  
  strncpy(new_inbox_record.info.subject, subject, MAX_SUBJECT + 1);
  new_inbox_record.info.time_sent = time_sent;
  new_inbox_record.info.attachments = 0;
  new_inbox_record.info.sender_team = user->team;
  new_inbox_record.info.reply_to = reply_to;
  
  /* get the name of the 'inf' file to do so, we need to open
  ** (create) the file
  */
  info_fd = get_unique_fd (discussion_path,"inf", info_fname, &time_sent);
  /* don't bother to lock it, since no one knows it's there yet! */
  
  strncpy(new_inbox_record.info_fname,info_fname,MAX_FILENAME + 1);
  new_inbox_record.release_time = 0;      
  new_inbox_record.unrelease_time = 0;
  new_inbox_record.status =  hide? TEACHER_HIDDEN: NORMAL;      
  
  /* now open and lock the inbox.dat file */
  snprintf(inbox_fname,MAX_PATH + 1,"%s%s",central_discussion_path,INBOX_FNAME);
  inbox_fp = fopen(inbox_fname,"a+");
  if(!inbox_fp)                              /* couldn't open or create inbox.dat */
    cs_critical_error(ERR_FOPEN_WRITE_FAILED,inbox_fname);
  inbox_fd = fileno(inbox_fp);
  get_exclusive_lock(inbox_fd, 1);                      /* shared_lock.c */
  
  
  /* get the next available msg_id, by incrementing the msg_id of the
  ** last msg in the inbox.dat file
  */
  fstat(inbox_fd, &buf);
  if(!buf.st_size)    /* this is the first message */
     msg_id = 1;
  else
    {
     if(fseek(inbox_fp,-inbox_record_size,SEEK_END) == -1)
       cs_critical_error(ERR_FSEEK_FAILED, inbox_fname);
     if(fread( &inbox_record, inbox_record_size, 1, inbox_fp) != 1)
       cs_critical_error(ERR_FREAD_FAILED, inbox_fname);
     msg_id =  inbox_record.info.msg_id + 1;
    }
    
   new_inbox_record.info.msg_id = msg_id;
   new_inbox_record.info.topic_id =  topic == -1 ? msg_id : topic;
   if(fseek(inbox_fp,0,SEEK_END) == -1)
     cs_critical_error(ERR_FSEEK_FAILED, inbox_fname);
   if(fwrite(&new_inbox_record, inbox_record_size,1,inbox_fp) != 1)
      cs_critical_error(ERR_FWRITE_FAILED, inbox_fname);



  /* now write the info file */   
  if (write (info_fd, &new_inbox_record.info, sizeof (NEWS_INFO)) != sizeof(NEWS_INFO))
    cs_critical_error (ERR_FWRITE_FAILED, "");


   if(write (info_fd,&person, sizeof(NEWS_PERSON))!= sizeof(NEWS_PERSON))
        cs_critical_error (ERR_FWRITE_FAILED, "");
        
   close (info_fd);

   release_lock(inbox_fd);     /* shared_lock.c */
   fclose(inbox_fp);
   
   write_user_inbox_record(msg_id, time_sent);    /* shared_news_util.c */
}








static void
back_up (char *program)
{
  char temp[MAX_PATH + 1];

  translate_url_substitutes (temp, program, MAX_PATH + 1, 0);	/* shared_translate_url.c */
  printf ("Location: %s\n\n", temp);
}



int
main (void)
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  char from[MAX_PATH + 1];	/* from from=? command line */
  int hide;                     /* from hide=? command line */
  int topic;                    /* from topic=? command line */
  int reply_to;                 /* from reply_to=? command line */
  char subject[MAX_SUBJECT +1]; 
  char msg_fname[MAX_FILENAME + 1];	/* name given to the message */
  time_t time_sent;
  DATA *msg_data;
  int width;
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */
  
  cs_cgi_init();

  msg_data = read_parameters (course, key, from, &hide, subject, &width, &topic, &reply_to);
  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, TESTPILOT);	/* #included */
  if(!create_dirs_between(discussion_path))   /* shared_file_util.c */
    cs_critical_error (ERR_MKDIR_FAILED, discussion_path);
  if(!create_dirs_between(central_discussion_path))     /* shared_file_util.c */
    cs_critical_error (ERR_MKDIR_FAILED, central_discussion_path);


  time_sent = time (NULL);
  process_message_file (msg_data, msg_fname, &time_sent, width);
  complete_send(msg_fname,&user,time_sent,hide, subject, topic, reply_to);
  back_up (from);
  free_data(msg_data);
  cs_cgi_destroy();
  return 0;
}

