#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>


#include "global.h"
#include "custom.h"		/* for date FORMAT strings */


#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_post_inbox.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_news_util.h"
#include "manhat-lib/shared_translate_url.h"  /* for AMP_SUB, et. al */
#include "manhat-lib/shared_access.h"
#include "manhat-lib/shared_lock.h"

typedef struct inbox_node
{
  INBOX_RECORD data;
  struct inbox_node *next;
  struct inbox_node *prev;
  long offset;
}
INBOX_NODE;


INBOX_NODE *inbox_head = 0;
INBOX_NODE *inbox_tail = 0;

static void
read_parameters (char *course, char *key)
{
  cs_get_required_parameter ("crs", course, MAX_PATH);
  cs_get_required_parameter ("id", key, MAX_KEY);
}



static void
set_inbox_commands (char *course, char *key,int can_write, int access, const char *fromstring)
{
 char url[MAX_PATH +1];

     
 snprintf (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s", "main_menu", course, key);
 cs_set_value("main_menu_url", url); 
 
 snprintf (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s", "post_outbox", course, key);    	  
 cs_set_value("post_outbox_url", url); 
 
 if(can_write)
 {
    snprintf (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;from=%s","post_new_memo", course, key, fromstring);
    cs_set_value("new_memo_url", url);
 }

 cs_set_int_value("outbox", 0);
}





static void
build_inbox_list (CONFIG_STRUCT *conf, SESSION *user)
{
  FILE *fp;
  char inbox_path[MAX_PATH + 1];
  INBOX_RECORD msg;
  INBOX_NODE *ptr =  0;
  long offset = 0;

  snprintf (inbox_path, MAX_PATH + 1, "%s%s/%s/%s/%s", 
  				conf->course_path,PEOPLE_DIR,
	    				user->username, MAIL_DIR, INBOX_FNAME);

  fp = fopen (inbox_path, "r");
  if (fp)
    {
      get_shared_lock(fileno(fp), 1);     /* shared_lock.c */
      while (fread (&msg, sizeof (INBOX_RECORD), 1, fp) == 1)
	{
	  if (msg.newfile_info.how_sent != DELETED)
	    {
	      /* add the record to the end of the linked list */
	      if (!inbox_head)
		{
		  inbox_head = (INBOX_NODE *) malloc (sizeof (INBOX_NODE));
		  ptr = inbox_head;
		  ptr->prev = 0;
		}
	      else
		{
		  ptr->next = (INBOX_NODE *) malloc (sizeof (INBOX_NODE));
		  ptr->next->prev = ptr;
		  ptr = ptr->next;
		}
	      ptr->data = msg;
	      ptr->offset = offset;
	      ptr->next = 0;
	      inbox_tail = ptr;
	    }
	  offset = ftell (fp);
	}
      release_lock(fileno(fp));
      fclose (fp);
    }
}



static void
free_inbox_list ()
{
  INBOX_NODE *ptr;

  while (inbox_head)
    {
      ptr = inbox_head;
      inbox_head = inbox_head->next;
      free (ptr);
    }
}





void
set_inbox_msgs (char *course, char *key, NEWS_FILTER * filter,
                  CONFIG_STRUCT *conf, SESSION *user, int can_write, int allow_user_hidden)
{
  #define MAX_TMP_NAME 30
  int unread;
  char timestring[MAX_TIMESTRING + 1];
  INBOX_NODE *ptr;
  char name[MAX_TMP_NAME];
  char url[MAX_PATH +1];
  int i;
  char *escaped_subject = (char *) 0;
  int fixed_width_font;
  
  fixed_width_font = USE_FIXED_FONT(conf->misc);    /* global.h */

  cs_set_int_value("fixed_font", fixed_width_font? 1: 0);
  cs_set_int_value("allow_user_hidden", allow_user_hidden? 1 : 0);

  if (inbox_head)
    {
      for (i = 0, ptr = filter->oldest_first ? inbox_head : inbox_tail;
	              ptr; ptr = filter->oldest_first ? ptr->next : ptr->prev, i++)
	{
	 if(!allow_user_hidden || filter->show_user_hidden || !ptr->data.is_sleepy) 
	  {
	   unread = !ptr->data.time_read;
         
           if(allow_user_hidden && !unread)
            {
		if(ptr->data.is_sleepy)
		{
		  snprintf(name, MAX_TMP_NAME, "msg.%d.unhide_url", i);
		  snprintf(url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;hide=%d", 
                        "post_mark_hidden", course, key, ptr->offset,0);
		  cs_set_value(name, url);
		}
		else
		{
		 snprintf(name, MAX_TMP_NAME, "msg.%d.hide_url", i);
		 snprintf(url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;hide=%d", 
                        "post_mark_hidden", course, key, ptr->offset,1);
		 cs_set_value(name, url);
		}

            }
           
           snprintf(name, MAX_TMP_NAME, "msg.%d.is_unread", i);
    	   cs_set_int_value(name, unread? 1:0);


           snprintf(name, MAX_TMP_NAME, "msg.%d.has_attachments", i);
  	   cs_set_int_value(name, ptr->data.newfile_info.attachments? 1:0);

	   snprintf(name, MAX_TMP_NAME, "msg.%d.info_url", i);
	   snprintf
	    (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;from=%s%ccrs%c%s%cid%c%s",
	     "post_inbox_info", course, key, ptr->offset, "post_inbox", QMARK_SUB,
	     EQUAL_SUB, course, AMP_SUB, EQUAL_SUB, key);
           cs_set_value(name, url);

	   snprintf(name, MAX_TMP_NAME, "msg.%d.read_msg_url", i);
	   snprintf (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld",
		  "post_read_inbox", course, key, ptr->offset);
           if(fixed_width_font)
                strcat(url,"&fixed=1");		  
           cs_set_value(name, url);
		  
	   
	   
           /* handle subject - need to html escape it */	   
	   snprintf(name, MAX_TMP_NAME, "msg.%d.subject", i);
	   if(cgi_html_escape_strfunc(ptr->data.newfile_info.subject,&escaped_subject) == STATUS_OK)
	      cs_set_value(name, escaped_subject);
           else
              cs_set_value(name,  ptr->data.newfile_info.subject);
              
           if(escaped_subject)
             {
               free(escaped_subject);
               escaped_subject = (char *) 0;
             }     
           

	   snprintf(name, MAX_TMP_NAME, "msg.%d.sender", i);
	   cs_set_value(name,  ptr->data.newfile_info.sender_realname);	/*shared_format_line.c */
    
	   strftime (timestring, MAX_TIMESTRING, DOW_DATE_FORMAT,
		    localtime (&ptr->data.newfile_info.time_sent));
	   snprintf(name, MAX_TMP_NAME, "msg.%d.time_sent", i);
	   cs_set_value(name,  timestring);
	   
	   /* insert delete link */
           if(can_write && !unread)
	   {
	      snprintf(name, MAX_TMP_NAME, "msg.%d.delete_url", i);
              snprintf(url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;next=-1" ,
                           "post_delete", course, key, ptr->offset);
              cs_set_value(name, url);
	   }
	  }      
	}
    }				/* if inbox_head */

  #undef MAX_TMP_NAME 
}





static void
read_inbox_filter (NEWS_FILTER * filter, CONFIG_STRUCT *conf, SESSION *user)
{
  FILE *fp;
  char filter_path[MAX_PATH + 1];
  
  
  filter->oldest_first = 1;
  filter->show_user_hidden = 1;
  
  /* always show oldest first in capture mode */
  if(conf->access == ACCESS_CAPTURE)
      return;


  snprintf (filter_path, MAX_PATH + 1, "%s%s/%s/%s/%s",
	    conf->course_path, PEOPLE_DIR, user->username, MAIL_DIR, NEWS_FILTER_FNAME);
  fp = fopen (filter_path, "r");
  if (fp)
   {
     if(fread (filter, sizeof (NEWS_FILTER), 1, fp) != 1)
      {
       filter->oldest_first = 1;
       filter->show_user_hidden = 1;
      } 
     fclose (fp);
   }
}




static void
set_gather_form (char *course, char *key, CONFIG_STRUCT *conf)
{
  P_NODE *p;


  cs_set_value("gather_action", "post_inbox_gather");

  p = build_option_person_list (conf);    /* shared_person_list.c */
  set_option_userlist (p);	/* shared_person_list.c */
  free_option_person_list (p);	/* shared_person_list.c */
}





static void
set_sort_url (char *course, char *key,  int oldestfirst, const char *fromstring)
{
  char url[MAX_PATH +1];

    snprintf
      (url, MAX_PATH +1, "%s?crs=%s&amp;id=%s&amp;grp=%d&amp;cmd=%d&amp;from=%s",
       "news_filter_set", course, key, MAIL, oldestfirst? 1 : 0, fromstring);
    cs_set_value("sort_order_url", url);
}





static void
set_sleepy_urls(NEWS_FILTER *filter,const char *fromstring, const char *course, const char *key)
{
   
 INBOX_NODE *ptr;
 int hidden_count;
 char url[MAX_PATH*2 +1];
    
 /* count topics marked as 'hidden' by the user */
 for(ptr=inbox_head, hidden_count=0; ptr; ptr=ptr->next)
    if(ptr->data.is_sleepy)
              hidden_count++;   

 cs_set_int_value("hidden_count", hidden_count);
         
 if(filter->show_user_hidden)
    {
       snprintf (url, MAX_PATH *2 +1, "%s?crs=%s&amp;id=%s&amp;grp=%d&amp;cmd=%d&amp;from=%s", 
	    "news_filter_set", course, key, MAIL, HIDE_USER_HIDDEN, fromstring);
       cs_set_value("hide_sleepy_url", url);
    }   
   else
    {
      
      snprintf (url, MAX_PATH *2, "%s?crs=%s&amp;id=%s&amp;grp=%d&amp;cmd=%d&amp;from=%s",
	    			"news_filter_set", course, key, 
	    			MAIL, SHOW_USER_HIDDEN, fromstring); 
     cs_set_value("list_all_url", url);
	    
    }  

}




static void
set_inbox_data (char *course, char *key, CONFIG_STRUCT *conf, SESSION *user, int can_write)
{
  NEWS_FILTER filter;
  char fromstring[MAX_FROM + 1];
  int allow_user_hidden;

  cs_set_value("crs", course);
  cs_set_value("id", key);
  
  cs_set_course_info(conf);
  cs_set_current_time();

  cs_set_int_value("can_write", can_write? 1 : 0 );
  cs_set_int_value("capture_mode", (conf->access == ACCESS_CAPTURE)? 1: 0);
  
  allow_user_hidden = (conf->postoffice == 2);
  
  read_inbox_filter (&filter, conf, user);
  build_inbox_list (conf, user);
  snprintf(fromstring, MAX_FROM + 1, "%s%ccrs%c%s%cid%c%s",
              "post_inbox",QMARK_SUB,EQUAL_SUB,course,AMP_SUB,EQUAL_SUB,key);

  set_inbox_commands (course, key, can_write, conf->access, fromstring);
  
  /* show gather form, reverse order button and show sleepy options
  ** only if we are not
  ** capturing this course
  */
  if(conf->access != ACCESS_CAPTURE)
   {
      set_gather_form (course, key, conf);
      set_sort_url(course,key, filter.oldest_first, fromstring);
      if(allow_user_hidden)
          set_sleepy_urls(&filter, fromstring, course, key);
   }
      
  set_inbox_msgs (course, key, &filter, conf, user, can_write, allow_user_hidden);
  free_inbox_list ();
}





int
main (void)
{
  char course[MAX_PATH + 1];	/* from crs=? command line */
  char key[MAX_KEY + 1];	/* from id=? command line */
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */
  int can_write;                /* can this user add msgs to this course? */

  cs_cgi_init();  

  read_parameters (course, key);
  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);	/* shared_util.c */
  can_write = has_write_permission(&user, &conf);   /* shared_access.c */

#ifndef SUPPORT_PRE24_POST_OFFICE_MSGS
       update_post_inbox (user.username, &conf);	/* shared_post_inbox.c */
#else
  if(SUPPORT_PRE24_POST_OFFICE_MSGS)
       update_post_inbox (user.username, &conf);	/* shared_post_inbox.c */
       
#endif


  if(!conf.postoffice)
     cs_critical_error(ERR_REQUEST_DENIED, "");

  set_inbox_data (course, key, &conf, &user, can_write);

  /* NOTE: post_inbox_outbox.cs is used for both post_inbox.c and post_outbox.c */
  cs_cgi_display("post_inbox_outbox", 1);
  cs_cgi_destroy();
  return 0;
}

