#include <stdio.h>
#include <time.h>
#include <string.h>
#include <ctype.h>		/* for tolower() */
#include <sys/types.h>
#include <unistd.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_super_util.h"
#include "manhat-lib/shared_super_menu.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_encrypt.h"
//#include "manhat-lib/shared_news_util.h"
//#include "manhat-lib/shared_post_inbox.h"


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


typedef struct outbox_node
{
  OUTBOX_RECORD data;
  struct outbox_node *next;
  struct outbox_node *prev;
  long offset;
}
OUTBOX_NODE;


OUTBOX_NODE *
build_outbox_list (const char *outbox)
{
  FILE *fp;
  OUTBOX_RECORD msg;
  OUTBOX_NODE *ptr = 0;
  OUTBOX_NODE *outbox_head = 0;
  OUTBOX_NODE *outbox_tail = 0;

  long offset = 0;

  fp = fopen (outbox, "r");
  
  
  if (fp)
    {
      while (fread (&msg, sizeof (OUTBOX_RECORD), 1, fp) == 1)
	{
	      /* add the record to the end of the linked list */
	      if (!outbox_head)
		{
		  outbox_head = (OUTBOX_NODE *) malloc (sizeof (OUTBOX_NODE));
		  if (!outbox_head)
		    cs_critical_error (ERR_MALLOC_FAILED, "");
		  ptr = outbox_head;
		  ptr->prev = 0;
		}
	      else
		{
		  ptr->next = (OUTBOX_NODE *) malloc (sizeof (OUTBOX_NODE));
		  if (!ptr->next)
		    cs_critical_error (ERR_MALLOC_FAILED, "");
		  ptr->next->prev = ptr;
		  ptr = ptr->next;
		}
	      ptr->data = msg;
	      ptr->offset = offset;
	      ptr->next = 0;
	      outbox_tail = ptr;

	  offset = ftell (fp);
       }
      fclose (fp);
    }
    return outbox_head;
}




static void
free_outbox_list (OUTBOX_NODE *outbox_head)
{
  OUTBOX_NODE *ptr;

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




INBOX_NODE *
build_inbox_list (const char *inbox)
{
  FILE *fp;
  INBOX_RECORD msg;
  INBOX_NODE *ptr =  0;
  long offset = 0;
  INBOX_NODE *inbox_head = 0;
  INBOX_NODE *inbox_tail = 0;

  fp = fopen (inbox, "r");
  if (fp)
    {
      while (fread (&msg, sizeof (INBOX_RECORD), 1, fp) == 1)
	{
	     /* 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);
	}
      fclose (fp);
    }
   return inbox_head; 
}



static void
free_inbox_list (INBOX_NODE *inbox_head)
{
  INBOX_NODE *ptr;

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



DEL_COURSE_NODE *
read_parameters(char *key, char *password)
{
    DEL_COURSE_NODE *head;     /*shared_super_util.c */

    cs_get_required_parameter ("id", key, MAX_KEY);   /* shared_cs_util.c */
    cs_get_required_parameter ("password", password, MAX_PASSWORD);
    head = build_selected_course_list();               /* shared_super_util.c */
   return head;
}

int find_sender(P_NODE *p_head, char *username)
{
    P_NODE *ptr;
    int found = 0;

    for(ptr = p_head; ptr && !found; ptr = ptr->next)
    {
        if( !strcmp(username, ptr->data.username) && ptr->data.group == FACULTY)
              found = 1;
	else if( !strcmp(username, ptr->data.username))
              found = 2;
	
    }
    if(found == 2)
	 return 0;
	
   return 1;
   
}

void delete_inbox_msg(INBOX_NODE *inbox_head, P_NODE *p_head)
{
    INBOX_NODE *ptr;
    int is_from_teacher = 0;

    for(ptr = inbox_head; ptr; ptr = ptr->next)
    {
         is_from_teacher = find_sender(p_head, ptr->data.newfile_info.sender);
         if(!is_from_teacher)
	    ptr->data.newfile_info.how_sent = DELETED;	 
    }
}

void rewrite_inbox(INBOX_NODE *inbox_head, const char *inbox_path)
{
    FILE *fp;
    INBOX_NODE *ptr;


    fp = fopen(inbox_path, "w");
    if(!fp)
       cs_critical_error(ERR_UNABLE_TO_OPEN_INBOX, inbox_path);
    for(ptr = inbox_head; ptr; ptr = ptr->next)
    {
	 if(fwrite (&ptr->data, sizeof(INBOX_RECORD), 1, fp) != 1)
	     cs_critical_error (ERR_FWRITE_FAILED, inbox_path);

    }
    fclose(fp);

}


void process_inbox(const char *path_to_mail, P_NODE *p_head)
{
    INBOX_NODE *inbox_head = 0;
    char inbox_path[MAX_PATH +1];

    snprintf(inbox_path, MAX_PATH +1, "%s/%s", path_to_mail, INBOX_FNAME);
    inbox_head = build_inbox_list (inbox_path);
    delete_inbox_msg(inbox_head, p_head);
    rewrite_inbox(inbox_head, inbox_path);
    free_inbox_list (inbox_head);

}
void delete_all_files(const char *info_fname, const char *path_to_mail, 
		ATTACHMENT_NODE *attachment_head, INFO *infofile_info)
{
    char path[MAX_PATH +1];
    ATTACHMENT_NODE *ptr;

    snprintf(path, MAX_PATH +1, "%s/%s", path_to_mail, infofile_info->msg_fname);
    unlink(path);   /* delete msg file */
    unlink(info_fname);  /* delete inf file */

    /* delete all the attached files */
    for(ptr = attachment_head; ptr; ptr = ptr->next)
    {
       snprintf(path, MAX_PATH +1, "%s/%s", path_to_mail, ptr->data.unique_fname);
       if(infofile_info->no_attachments == -1 
		       && ptr == attachment_head 
		       && isdirectory(path_to_mail, ptr->data.unique_fname)  )
	 kill_directory(path);   /* shared_file_util.c */
       else
	  unlink(path);
    }

}

int  find_teacher_in_list(PERSON_NODE *person_head, P_NODE *p_head)
{
    PERSON_NODE *ptr;

    for(ptr = person_head; ptr; ptr = ptr->next)
    {
        if(find_sender(p_head, ptr->data.username))
	     return 1;

    }
    return 0;
}



int process_one_outbox_msg(const char *info_fname, P_NODE *p_head, const char *path_to_mail)
{
   FILE *fp;
   INFO infofile_info;
   ATTACHMENT_NODE *aptr = 0, *aptr_current = 0;
   PERSON_NODE *pptr = 0, *pptr_current = 0;
   int i;
   PERSON person_buffer;
   PERSON_NODE *person_head = 0;
   ATTACHMENT_NODE *attachment_head = 0;
   int is_sent_to_teacher;

   fp = fopen(info_fname, "r");
   if(fp)
   {
      if (fread (&infofile_info, sizeof (INFO), 1, fp) != 1)
	      cs_critical_error (ERR_READING_INFO, info_fname);

      for (i = 1; i <= abs(infofile_info.no_attachments); i++)
      {
	   aptr = (ATTACHMENT_NODE *) malloc (sizeof (ATTACHMENT_NODE));
           if (!aptr)
                cs_critical_error (ERR_MALLOC_FAILED, "");

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

           if (!attachment_head)
                attachment_head = aptr;
           else
	       aptr_current->next = aptr;
	   aptr_current = aptr;
      }

      while (fread (&person_buffer, sizeof (PERSON), 1, fp) == 1)
      {
	  pptr = (PERSON_NODE *) malloc (sizeof (PERSON_NODE));
	  pptr->data = person_buffer;
	  pptr->next = 0;
	  if(!person_head)
	      person_head = pptr;
	  else
	      pptr_current->next = pptr;
	  pptr_current = pptr;

      }
      is_sent_to_teacher = find_teacher_in_list(person_head,p_head);
      if(!is_sent_to_teacher)
      {
         delete_all_files(info_fname, path_to_mail, attachment_head, &infofile_info);
	 return 1;
      } 
      else
	return 0; 

   }
   else
     return 1;
}


void delete_outbox_msg(OUTBOX_NODE *outbox_head, P_NODE *p_head, const char *path_to_mail)
{
    OUTBOX_NODE *ptr;
    char info_fname[MAX_PATH +1];
    int is_deleted = 0;

    for(ptr = outbox_head; ptr; ptr = ptr->next)
    {
         snprintf(info_fname, MAX_PATH +1, "%s/%s", path_to_mail, ptr->data.info_fname);
         is_deleted = process_one_outbox_msg(info_fname, p_head, path_to_mail);
	 if(is_deleted)
	    ptr->data.how_sent = DELETED; 
    }
     
}

void rewrite_outbox(OUTBOX_NODE *outbox_head, const char *outbox_path)
{
    OUTBOX_NODE *ptr;
    FILE *fp;

    fp = fopen(outbox_path, "w");

    if(!fp)
       cs_critical_error (ERR_FWRITE_FAILED, outbox_path);

    for(ptr = outbox_head; ptr; ptr = ptr->next)
    {
	 if(fwrite (&ptr->data, sizeof(OUTBOX_RECORD), 1, fp) != 1)
	     cs_critical_error (ERR_FWRITE_FAILED, outbox_path);

    }
    fclose(fp);
}

void process_outbox(const char *path_to_mail, P_NODE *p_head)
{
    OUTBOX_NODE *outbox_head = 0;
    char outbox_path[MAX_PATH +1];

    snprintf(outbox_path, MAX_PATH +1, "%s/%s", path_to_mail, OUTBOX_FNAME);
    outbox_head = build_outbox_list (outbox_path);
    delete_outbox_msg(outbox_head, p_head, path_to_mail);
    rewrite_outbox(outbox_head, outbox_path);
    free_outbox_list (outbox_head);

}


void purge_users_postoffice(P_NODE *one_user, P_NODE *p_head, CONFIG_STRUCT *conf)	
{
    char path_to_mail[MAX_PATH +1];

    snprintf(path_to_mail, MAX_PATH +1, "%s%s/%s/%s", conf->course_path, PEOPLE_DIR, one_user->data.username, MAIL_DIR);
    process_inbox(path_to_mail, p_head);
    process_outbox(path_to_mail, p_head);
   
}

void purge_postoffice_message(P_NODE *p_head, CONFIG_STRUCT *conf)
{
    P_NODE *ptr;

    for(ptr = p_head; ptr; ptr = ptr->next)
    {
	if(ptr->data.group == STUDENT)
	    purge_users_postoffice(ptr, p_head, conf);	
    }

    
}

void  do_action(DEL_COURSE_NODE *course_head)
{
    DEL_COURSE_NODE *ptr;
    CONFIG_STRUCT conf;
    P_NODE *p_head;
    

    for(ptr = course_head; ptr; ptr = ptr->next)
    {
        read_configuration_file (ptr->del_id, &conf);          /*shared_util.c*/
        p_head = build_option_person_list (&conf);       /* shared_person_list.c */
        purge_postoffice_message(p_head, &conf);
	free_option_person_list (p_head);  /* shared_person_list.c */

    }
    
}

void  set_purged_course_info(DEL_COURSE_NODE *head)
{
    #define MAX_TMP_NAME 50
    DEL_COURSE_NODE *ptr;
    char name[MAX_TMP_NAME];
   int i =0;

    if(!head)
        cs_critical_error( ERR_NO_COURSE_MSG, "");

    for(ptr = head; ptr; ptr = ptr->next)
    {
          snprintf(name, MAX_TMP_NAME, "course_list.%d.id", i);
           cs_set_value(name, ptr->del_id);
          snprintf(name, MAX_TMP_NAME, "course_list.%d.info", i);
           cs_set_value(name, ptr->del_info);
           i++;
    }
#undef MAX_TMP_NAME

}




int
main (void)
{
  char key[MAX_KEY + 1];	/* from id=? command line */
  DEL_COURSE_NODE *course_head = 0;
  char password[MAX_PASSWORD +1];


  SESSION user;

  cs_cgi_init();
  course_head = read_parameters (key, password);
  validate_super_key (key, &user);	/* shared_util.c */

  if(!course_head)
        cs_critical_error( ERR_NO_COURSE_MSG, "");
	
  if(confirm_super_password(password, user.username))                 /* shared_encrypt.c */
  {
     set_admin_page(&user, key, 0, "super_purge_postoffice_message_form"); /* shared_super_menu.c */
     do_action(course_head);
     set_purged_course_info(course_head);
  }
  else
    cs_critical_error(ERR_USERNAME_PASSWD_INCORRECT, "");

  free_del_list(course_head); /* shared_super_util.c */
  cs_cgi_display("super_purge_postoffice", 0);
  cs_cgi_destroy();
  return 0;
}


