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

#include "../global.h"

#include "shared_news_util.h"  /* for read_red_file() */
#include "shared_lock.h"
#include "shared_cs_util.h"   /* for cs_critical_error(), etc */

static void
read_update_post_infofile (READ_STRUCT * read_info, int *allread,
                           const char *course_path, const char *username)
{
  FILE *fp;
  INFO info;
  ATTACHMENT attachment;
  int i;
  char info_fname[MAX_PATH + 1];
  long offset;
  PERSON person;
  int found = 0;
  int finished = 0;


  snprintf (info_fname, MAX_PATH + 1, "%s%s/%s/%s/%s", course_path, PEOPLE_DIR,
	                                         username, MAIL_DIR, read_info->info_fname);
  fp = fopen (info_fname, "r+");
  if (!fp)
    cs_critical_error (ERR_ERROR_OPENING_INFO, "");
    
  get_exclusive_lock(fileno(fp),1);   /* shared_lock.c */  
  if (fread (&info, sizeof (INFO), 1, fp) != 1)
         cs_critical_error (ERR_ERROR_READING_INFO, "");

/** adjust for attached web page **/
  if (info.no_attachments == -1)
    info.no_attachments = 1;
  for (i = 1; i <= info.no_attachments; i++)
    fread (&attachment, sizeof (ATTACHMENT), 1, fp);

  *allread = 1;
  offset = ftell (fp);
  while ((fread (&person, sizeof (PERSON), 1, fp) == 1) && !finished)
    {
      if (!strcmp (person.username, read_info->reader_username))
	{
	  person.time_read = read_info->time_read;
	  fseek (fp, offset, SEEK_SET);
	  fwrite (&person, sizeof (PERSON), 1, fp);
	  found = 1;
	  finished = !*allread;
	}
      else if (!person.time_read)
	{
	  *allread = 0;
	  finished = found;
	}
      offset = ftell (fp);
    }
  release_lock(fileno(fp));   /* shared_lock.c */  
  fclose (fp);
}




static void
mark_outbox_allread (const char *outbox_fname, READ_STRUCT * read_info)
{
  FILE *fp;
  long offset;
  int done = 0;
  OUTBOX_RECORD outbox;

  fp = fopen (outbox_fname, "r+");
  if (!fp)
    cs_critical_error (ERR_ERROR_OPENING_OUTBOX, "");

  get_exclusive_lock(fileno(fp), 1);  /* shared_lock.c */
  offset = ftell (fp);
  while (!done && (fread (&outbox, sizeof (OUTBOX_RECORD), 1, fp) == 1))
    {
      if (!strcmp (outbox.info_fname, read_info->info_fname))
	{
	  done = 1;
	  outbox.unread = 0;
	  fseek (fp, offset, SEEK_SET);
	  fwrite (&outbox, sizeof (OUTBOX_RECORD), 1, fp);
	}
      offset = ftell (fp);
    }
  release_lock(fileno(fp));   /* shared_lock.h */  
  fclose (fp);
}



static void
process_red_file (const char *red_fname, const char *outbox_fname,
                  CONFIG_STRUCT *conf, SESSION *user)
{
  READ_STRUCT read_info;
  int allread;

  read_red_file (red_fname, &read_info);	/* shared_news_util.c */
  read_update_post_infofile (&read_info, &allread, conf->course_path, user->username);
  if (allread)
      mark_outbox_allread (outbox_fname, &read_info);
}




void
update_post_outbox (CONFIG_STRUCT *conf, SESSION *user)
{
  DIR *dir_p;

  struct dirent *dir_entry_p;
  char *ptr;
  char mail_dir[MAX_PATH + 1];
  char red_fname[MAX_PATH + 1], del_fname[MAX_PATH + 1];
  char outbox_fname[MAX_PATH + 1];

  snprintf (mail_dir, MAX_PATH + 1, "%s%s/%s/%s", conf->course_path, PEOPLE_DIR,
	    							user->username, MAIL_DIR);
  snprintf (outbox_fname, MAX_PATH + 1, "%s/%s", mail_dir, OUTBOX_FNAME);
  dir_p = opendir (mail_dir);
  if (!dir_p)
    cs_critical_error (ERR_CANT_OPEN_NEWS_DIR, "");

/**** do *.red files ***/
  while (NULL != (dir_entry_p = readdir (dir_p)))
    {
      ptr = strstr (dir_entry_p->d_name, ".red");
      if (ptr && *(ptr + 4) == '\0')	/* i.e. if file ends in .red */
	{
	  snprintf (red_fname, MAX_PATH + 1, "%s/%s", mail_dir,
		    dir_entry_p->d_name);
	  process_red_file (red_fname, outbox_fname, conf, user);
	  unlink (red_fname);

	}
      else
	{
	  ptr = strstr (dir_entry_p->d_name, ".del");
	  if (ptr && *(ptr + 4) == '\0')	/* i.e. if file ends in .del */
	    {
	      snprintf (del_fname, MAX_PATH + 1, "%s/%s", mail_dir,
			dir_entry_p->d_name);
/* don't process the del file, just delete it - transition to version that doesn't use *.del files	 
	 
	commented out -->     process_del_file (del_fname, outbox_fname, conf, user);
*/	 
	      unlink (del_fname);
	    }
	}
    }
  closedir (dir_p);
}




/* A Post Office message is marked as read in two places:
**   1 the reader's inbox
**   2 the *.inf file located in the sender's directory
** Additionally, if while doing #2, we find that the message has
** been read by all of the recipients, we need to do:
**   3 Mark the sender's outbox record as completely read.
**
** This function does #2 and #3 above.  This used to be accomplished
** by a *.red file to the sender.  When the sender entered their outbox,
** they would perform the same task on their own files.
*/


void
mark_sender_files_read (INBOX_RECORD * inbox, CONFIG_STRUCT *conf, SESSION *user)
{
  READ_STRUCT red;
  int allread;
  char outbox_fname[MAX_PATH + 1];  /* path to the outbox.dat file of the person who sent the msg */


  strncpy (red.info_fname, inbox->newfile_info.info_fname, MAX_FILENAME + 1);
  strncpy (red.reader_username, user->username, MAX_USERNAME + 1);
  red.time_read = inbox->time_read;
  
  read_update_post_infofile(&red, &allread, conf->course_path, inbox->newfile_info.sender); /* shared_post_outbox.c */

  if (allread)
  {
   snprintf (outbox_fname, MAX_PATH + 1, "%s%s/%s/%s/%s", conf->course_path, PEOPLE_DIR,
	    							inbox->newfile_info.sender, MAIL_DIR, OUTBOX_FNAME);
   mark_outbox_allread (outbox_fname, &red);  /* shared_post_outbox.c */
  } 
  
}


static int
multiple_recipients (SESSION *user, PERSON_NODE *pers_head)
{
  PERSON_NODE *pptr;

  for (pptr = pers_head; pptr; pptr = pptr->next)
    if (((pptr->data.how_received == CC) || (pptr->data.how_received == TO))
	&& strcmp (user->username, pptr->data.username))
      return 1;

  return 0;
}



static
void  set_msg_value(int index, char *name, char *value)
{
#define MAX_TMP_NAME 50
char the_name[MAX_TMP_NAME + 1];

 if(index < 0)
   snprintf(the_name, MAX_TMP_NAME + 1, "msg.%s", name);
 else
   snprintf(the_name, MAX_TMP_NAME + 1, "msg.%d.%s", index, name);
  
 cs_set_value(the_name, value);

#undef MAX_TMP_NAME
}






void
set_outbox_msg_header_data (OUTBOX_RECORD * outbox,
		           char *course,  char *key,
                          int website_attached, long offset,
                          CONFIG_STRUCT *conf, SESSION *user, 
                            ATTACHMENT_NODE *attach_head,
                           PERSON_NODE *pers_head, int index)
{
#define MAX_TMP_NAME 40
  ATTACHMENT_NODE *aptr;
  PERSON_NODE *pptr;
  char timestring[MAX_TIMESTRING + 1];
  int i;
  char extension[MAX_FILENAME + 1];
  char name[MAX_TMP_NAME];
  char url[MAX_PATH * 2];
  char *escaped_subject = (char *) 0;  

  /* time the user running this program first opened this message
  ** Since this is the outbox, that's the same as the time this user
  ** sent the message
 */
  strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT,
	    localtime (&outbox->time_sent));
  set_msg_value(index, "time_read", timestring);

  /* did the user mark this message as 'sleepy' or 'hidden' ? */
  set_msg_value(index,"is_user_hidden", outbox->is_sleepy? "1": "0");

  /* username of person who wrote the message */
  set_msg_value(index, "sender", user->username);

  /* real name of person who wrote the message */
  set_msg_value(index, "sender_realname", user->realname);


  /* set a 'has_multiple_recipients' value 
  ** For inbox msgs, this is used to decide whether
  ** or not to include a 'group reply' button.
  ** But this is the outbox... hmm. maybe it'll be of
  ** some use to someone someday.
  **/
  
  if(multiple_recipients(user, pers_head))
    set_msg_value(index, "has_multiple_recipients",  "1");



/* The 'how_sent' value shouldn't be needed, but we'll set values
** for this enumerated type anyway
**/      
  switch(outbox->how_sent)
  {
   case NEWMSG: set_msg_value(index, "how_sent", "NEWMSG"); break;
   case FORWARD: set_msg_value(index, "how_sent", "FORWARD"); break;   
   case REPLY: set_msg_value(index, "how_sent", "REPLY"); break;   
   case GROUP_REPLY: set_msg_value(index, "how_sent", "GROUP_REPLY"); break;   
   case 4: set_msg_value(index, "how_sent", "DELETED"); break;      /* because DELETED exists *twice* in global.h */
   default:  set_msg_value(index, "how_sent", "unknown"); break;
  }



  /********* Subject provided in both 'raw' and html escaped versions */
  set_msg_value(index, "subject", outbox->subject);
  
  escaped_subject = (char *)0;
  cs_html_escape_string(outbox->subject, &escaped_subject);   /* shared_cs_util.c */
  if(escaped_subject)
      {
        set_msg_value(index, "escaped_subject", (char *)escaped_subject);
        free(escaped_subject);
        escaped_subject = (char *) 0;
       } 
  else /* should never happen */
      set_msg_value(index, "escaped_subject", outbox->subject);

  /* time the message was sent */
  strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT,
	    localtime (&outbox->time_sent));
  set_msg_value(index, "time_sent", timestring);

  /* how many attachments are there? */
  snprintf(url, MAX_PATH * 2, "%d", outbox->attachments);
  set_msg_value(index, "attachments", url);

  /* name of the 'info' file */
  set_msg_value(index, "info_fname", outbox->info_fname);  

  /* offset value */
  snprintf(timestring, MAX_TIMESTRING, "%ld", offset);  
  set_msg_value(index, "offset", timestring);



/******** To: list ********/
  for (i = 0, pptr = pers_head; pptr; pptr = pptr->next)
    if (pptr->data.how_received == TO)
      {
	   snprintf(name, MAX_TMP_NAME, "to.%d", i);
	   set_msg_value(index, name, pptr->data.realname);
	   i++;
      }
      
  snprintf(url, MAX_PATH * 2, "%d", i);
  set_msg_value(index, "to_count", url);  /* provide a count of 'to' recipients */
            
  
   /******** CC list *********/
  for ( i = 0, pptr = pers_head; pptr; pptr = pptr->next)
    if (pptr->data.how_received == CC)
      {
        snprintf(name, MAX_TMP_NAME, "cc.%d", i);
	set_msg_value(index, name, pptr->data.realname);
	i++;
      }

  snprintf(url, MAX_PATH * 2, "%d", i);
  set_msg_value(index, "cc_count", url);  /* provide a count of 'cc' recipients */


 
  if (website_attached)
    {
      set_msg_value(index, "website_attached", "1");

      snprintf(url, MAX_PATH *2, 
	"%s?crs=%s&amp;id=%s&amp;sender=%s&amp;inf=%s&amp;grp=%d&amp;read=1&amp;loc=%ld&amp;inbox=yes&amp;from=post_read_outbox",
                 "web_page_start",
                 course,
                 key,
                 user->username,
                 outbox->info_fname,
                 MAIL,
                 offset);

       set_msg_value(index, "website_url", url);
      

    }
  else   /***** attachments ***/ 
   if (attach_head)
    {
     /* note the ext=<file_extension> parameter isn't used by the "send_file" program
     ** it's there to help offline browser programs to determine the type of file
     ** being sent
     */
      i =0;
      for (aptr = attach_head; aptr; aptr = aptr->next)
      {
        get_extension(aptr->data.orig_fname, extension);   /* shared_news_util.c */
        
        snprintf(name, MAX_TMP_NAME, "file.%d.url", i);
	snprintf
	  (url, MAX_PATH*2, "%s?crs=%s&amp;id=%s&amp;user=%s&amp;fname=%s&amp;info=%s&amp;attach=%d&amp;ext=.%s",
	   "send_file", course, key, user->username,
	   aptr->data.unique_fname, outbox->info_fname,
	   outbox->attachments, extension);
	set_msg_value(index,name, url);
	
        snprintf(name, MAX_TMP_NAME, "file.%d.orig_fname", i);
        set_msg_value(index, name, aptr->data.orig_fname);
	
	/* if this is an mp3 file, and the feature is enabled,
        ** provide url for wimpy_button mp3 player
        */
        if(!strcmp(extension,"mp3"))   /* custom.h */
	{

          cs_set_server_name();
          snprintf(url, MAX_PATH +1, "podcast_launch_framaplayer?crs=%s&id=%s&title=%s&sender=%s&fname=%s&inf=%s&grp=%d&realname=%s",
             course, key, outbox->subject, user->username, aptr->data.unique_fname,
             outbox->info_fname, MAIL, user->realname);
         snprintf(name, MAX_TMP_NAME, "file.%d.wimpy_button_url", i);
         set_msg_value(index, name, url);

        }
	i++;
      }
    }


 #undef MAX_TMP_NAME

}
