#include <stdio.h>
#include <sys/stat.h>		/* for stat() */
#include <string.h>
#include <ctype.h>
#include <time.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_news_util.h"
#include "manhat-lib/shared_potato_util.h"   /* for calculate_elapsed_time() */
#include "manhat-lib/shared_authenticate.h"   /* for username_cmp() */
#include "manhat-lib/shared_person_list.h"   /* for build_option_person_list() */
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_podcast_util.h"  



typedef struct news_person_node
{
  NEWS_PERSON data;
  struct news_person_node *next;
}
NEWS_PERSON_NODE;

ATTACHMENT_NODE *attachment_head = 0;	/* linked list of file info */
NEWS_PERSON_NODE *person_head = 0; /* linked list of recipients */

typedef struct history_node 
 {
   HOTPOTATO_INFO_STRUCT data;
   struct history_node *next;
 } HISTORY_NODE;
 
HISTORY_NODE *history_head = 0;  /* linked list of selftest history info */    



char inbox_path[MAX_PATH + 1];	/* full path to inbox.dat */


#define NOTEAM '!'

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

  char tmp[MAX_FILENAME + 1];	/* for holding the long value, length should
				   be long enough, don't you think? */


  cs_get_required_parameter ("crs", course, MAX_PATH);	/* shared_cgi_util.c */
  cs_get_required_parameter ("id", key, MAX_KEY);	/* shared_cgi_util.c */
  cs_get_required_parameter ("loc", tmp, MAX_FILENAME);	/* shared_cgi_util.c */
  *offset = atol (tmp);

  cs_get_required_parameter ("grp", tmp, MAX_FILENAME);	/* shared_cgi_util.c */
  *grp = atoi (tmp);
  
  if(*grp == SELFTEST)
   {
     cs_get_optional_parameter("get", tmp, 20);
     *send_selftest_csv = *tmp? 1 : 0;
   }
  else
     *send_selftest_csv = 0;
  
}




static void
get_compare_data(USER_DATA *a, NEWS_PERSON *source)
{
     char *lastname;

     strncpy(a->username, source->username, MAX_USERNAME +1);
     strncpy(a->realname, source->realname, MAX_NAME +1);
     lastname = get_lastname(source->realname);
     strncpy(a->lastname, lastname, MAX_NAME +1);
     if(lastname)
       free(lastname);
}






static void
sort_news_person_list ()
{
  NEWS_PERSON_NODE *q, *tail, *p, *r;
  USER_DATA a, b, c;


  if (person_head != NULL)
    {
      tail = person_head;
      while (tail->next)
	{
	  q = tail->next;
          get_compare_data(&a, &(q->data));
          get_compare_data(&b, &(person_head->data));
	  if (username_cmp (&a, &b) < 0)   /* shared_authenticate.c */
	    {
	      tail->next = q->next;
	      q->next = person_head;
	      person_head = q;
	    }
	  else
	    {
	      r = person_head;
	      p = r->next;
             get_compare_data(&a, &(q->data));
             get_compare_data(&c, &(p->data));

	      while (username_cmp (&a, &c) > 0)  /* shared_authenticate.c */
		{
		  r = p;
		  p = r->next;
                  get_compare_data(&c, &(p->data));
		}
	      if (q == p)
		tail = q;
	      else
		{
		  tail->next = q->next;
		  q->next = p;
		  r->next = q;
		}
	    } 

	}
    }
}







static void
add_remaining_people(CONFIG_STRUCT *conf, int fac_only, int grp, char team)
{
int found;
P_NODE *p_head, *p_ptr;
NEWS_PERSON_NODE *person_ptr;


p_head = build_option_person_list(conf);  /* shared_person_list.c */

for(p_ptr = p_head; p_ptr; p_ptr=p_ptr->next)
 {
 
  if( (fac_only && p_ptr->data.group != FACULTY) || 
     ( (grp == TEAM_DISCUSSION ) && (p_ptr->data.team != team) ) ||
     ( (grp == TEAM_TEACH) && ((p_ptr->data.team != team) && (p_ptr->data.group != FACULTY)))
    ) 
      continue;
      
      
  for(found=0, person_ptr=person_head; person_ptr && !found; person_ptr=person_ptr->next)
        found = !strcmp(person_ptr->data.username, p_ptr->data.username);
        
        
  if(!found)
   {
     if (!person_head)
	{
	  person_head =
	    (NEWS_PERSON_NODE *) malloc (sizeof (NEWS_PERSON_NODE));
	  if (!person_head)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  person_ptr = person_head;
	}
      else
	{
	  for(person_ptr = person_head; person_ptr->next; person_ptr=person_ptr->next);
          person_ptr->next = (NEWS_PERSON_NODE *) malloc (sizeof (NEWS_PERSON_NODE));
	  if (!person_ptr->next)
	        cs_critical_error (ERR_MALLOC_FAILED, "");
	  person_ptr = person_ptr->next;
	}
      strncpy(person_ptr->data.username, p_ptr->data.username, MAX_USERNAME + 1);
      strncpy(person_ptr->data.realname, p_ptr->data.realname, MAX_NAME + 1);
      person_ptr->data.time_read = 0;
      person_ptr->data.user_unlocked = 0;
      person_ptr->next = 0;
    }   
  }


free_option_person_list(p_head);	 /* shared_person_list.c */
}











/* reads the inbox file and then the corresponding *.inf file, to get everything
** ready to be displayed
**/
static void
process_inbox_record (long offset, CENTRAL_INBOX_RECORD * inbox,
		      NEWS_INFO * infofile_info, int grp,
                      CONFIG_STRUCT *conf, SESSION *user)
{
  FILE *fp;
  int fd;
  char infopath[MAX_PATH + 1];
  int i;
  ATTACHMENT_NODE *aptr = 0;
  NEWS_PERSON_NODE *pptr = 0;
  NEWS_PERSON person;
  ATTACHMENT junker;
  char team;    /* if this is TEAM or TEAM/TEACH modules, we must determine what team we're working with */


  /** 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, inbox_path);

 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);


  /*** now read the info file */
  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, infopath);
  
  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, infopath);


  /* process attachments, build linked list */

  /* if a website was attached, we need to 'swallow' the attachment */
  if (infofile_info->attachments == -1)
    if (fread (&junker, sizeof (ATTACHMENT), 1, fp) != 1)
      cs_critical_error (ERR_FREAD_FAILED, infopath);

  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, infopath);
      aptr->next = 0;
    }

 /** now read and build the people list */
  while (fread (&person, sizeof (NEWS_PERSON), 1, fp) == 1)
    {
      if (!person_head)
	{
	  person_head =
	    (NEWS_PERSON_NODE *) malloc (sizeof (NEWS_PERSON_NODE));
	  if (!person_head)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  pptr = person_head;
	}
      else
	{
	  pptr->next =
	    (NEWS_PERSON_NODE *) malloc (sizeof (NEWS_PERSON_NODE));
	  if (!pptr->next)
	    cs_critical_error (ERR_MALLOC_FAILED, "");
	  pptr = pptr->next;
	}
      pptr->data = person;
      pptr->next = 0;
    }
  release_lock(fd);   /* shared_lock.c */
  fclose (fp);
  

  
 
  if(grp == ASSIGNMENTS)
   {
    if(user->group == FACULTY) 
     {
       if(inbox->info.reply_to == -1)  
        add_remaining_people(conf,0, grp,  NOTEAM);  /* teachers see full list of students for the topic */
       else
        add_remaining_people(conf,1, grp, NOTEAM); /* for other msgs, just add any missing faculty */
     }   
    else 
        add_remaining_people(conf,1, grp, NOTEAM);  /*for students, just add any missing faculty */
   }
  else       
   {
       team = ((grp == TEAM_DISCUSSION) || (grp == TEAM_TEACH))? inbox->info.sender_team : NOTEAM;
       add_remaining_people(conf,0, grp, team); /* if it's not assignments, then show full list of people */
   }
       
  sort_news_person_list ();
}



 





static void
set_attachment_info (const char *sender, int grp, int attachments,
                       CONFIG_STRUCT *conf)
{
  #define MAX_TMP_NAME 40
  ATTACHMENT_NODE *aptr;
  char mail_dir[MAX_PATH + 1];
  char file_path[MAX_PATH + 1];
  struct stat file_stat;

  long filesize;
  char name[MAX_TMP_NAME + 1];
  char sizestring[MAX_TMP_NAME + 1];
  int i = 0;



  if (attachments == -1)
     cs_set_value("website_attached", "1");
  else if (attachment_head)
    {
      snprintf (mail_dir, MAX_PATH + 1, "%s%s/%s/%s/", 
                   conf->course_path,PEOPLE_DIR,
                             sender, discussion_fname);

      for (aptr = attachment_head, i = 0; aptr; aptr = aptr->next, i++)
	{
	  /* special case, a null 'orig_fname' signals an HTML directory */
	  if (!*(aptr->data.orig_fname))
              cs_set_int_value("web_page", 1);   /* why is this here? */
	  else
	    {

	      snprintf(name, MAX_TMP_NAME, "attach.%d.orig_filename", i);
	      cs_set_value(name, aptr->data.orig_fname);

	      snprintf (file_path, MAX_PATH + 1, "%s%s", mail_dir,
			aptr->data.unique_fname);

              if(stat(file_path, &file_stat))
                 filesize = 0;
              else
                 filesize = file_stat.st_size;   

	      snprintf(name, MAX_TMP_NAME, "attach.%d.size", i);
              snprintf(sizestring, MAX_TMP_NAME, "%ld", filesize);
	      cs_set_value(name, sizestring);
	    }
	}
    }

#undef MAX_TMP_NAME
}




static void
set_recipient_info ( char *sender, NEWS_INFO * infofile_info, int grp,
                      SESSION *user, CONFIG_STRUCT *conf)
{
 #define MAX_TMP_NAME 40
  NEWS_PERSON_NODE *pptr;
  char timestring[MAX_TIMESTRING + 1];
  char name[MAX_TMP_NAME];
  int i =0;
  char *escaped_subject = 0;



  cs_set_value("subject", infofile_info->subject);
  
  
  cs_html_escape_string(infofile_info->subject, &escaped_subject);  /* shared_cs_util.c */
  if(escaped_subject)
   {
     cs_set_value("escaped_subject", (char *)escaped_subject);
     free(escaped_subject);
   }
  else /* unlikely but being paranoid here */
       cs_set_value("escaped_subject", infofile_info->subject);
  
  cs_set_value("sender_realname", infofile_info->sender_realname);

  /*** time msg was posted **/
  if ((grp == ANONYMOUS_DISCUSSION) && HIDE_ANONYMOUS_TIMES)	/* see custom.h */
        *timestring = '\0';
  else
    strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT,
	                                  localtime (&infofile_info->time_sent));
  if(*timestring)
       cs_set_value("time_sent", timestring);

/***  attachment info ***/
    if(infofile_info->attachments || attachment_head)
       set_attachment_info(sender, grp, infofile_info->attachments, conf);


/*** BEGIN COMMENTED OUT SECTION
**** Here's the old pre-3.0 policy for controlling who can see
**** when others have read the message

  if (
      ( (user->group == FACULTY) &&
        ( (grp == ASSIGNMENTS) ||
          (grp == HANDOUTS_NOTICES) ||
          (grp == INTERNET_RESOURCES) ||
          (grp == SELFTEST) ||
          (grp == LECTURES) 
        )
      )
     ||
      ((grp != ANONYMOUS_DISCUSSION) && !strcmp (user->username, sender))
    )
    
**** END COMMENTED OUT SECTION
***/    
    
    
    
 /* Who gets to see when all others have read the message?
 ** Never show read times for ANONYMOUS DISCUSSION,
 ** otherwise show times to the teachers and the sender of the message
 ** This is a change from the previous policy starting with Manhattan 3
 */   
  if ( (grp != ANONYMOUS_DISCUSSION)   &&
       ((user->group == FACULTY) || !strcmp (user->username, sender)) )
    
    {
  
      cs_set_value("show_time_read", "1");
      
      for (pptr = person_head, i = 0; pptr; pptr = pptr->next, i++)
	{
          /* see custom.h form DOW_DATE_TIME_FORMAT */
	  if (pptr->data.time_read)
	    strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT,   
		      localtime (&pptr->data.time_read));
	  else
	    *timestring = '\0';

          snprintf(name, MAX_TMP_NAME, "recipient.%d.realname", i);
	  cs_set_value(name, pptr->data.realname);

          if(*timestring)
           {
             snprintf(name, MAX_TMP_NAME, "recipient.%d.time_read", i);
	     cs_set_value(name, timestring);
	   }  
	  
          snprintf(name, MAX_TMP_NAME, "recipient.%d.unlocked_attachments", i);
	  cs_set_int_value(name, pptr->data.user_unlocked);
	}

    }
    
   else  /* this person is not the sender or a teacher - show the time they first opened this message */
    { 
      cs_set_value("show_time_read", "0");

      for (pptr = person_head; pptr; pptr = pptr->next)
          if(!strcmp(pptr->data.username, user->username))
               break;
               
      if(pptr)
       {
	  if (pptr->data.time_read)
	    strftime (timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT,
		      localtime (&pptr->data.time_read));
	  else
	      *timestring = '\0';



	  cs_set_value("recipient.0.realname", pptr->data.realname);

          if(*timestring)
	        cs_set_value("recipient.0.time_read", timestring);

	  cs_set_int_value("recipient.0.unlocked_attachments", pptr->data.user_unlocked);
 
	}

     }    
 #undef MAX_TMP_NAME 
}







static void
free_history_list()
{
 HISTORY_NODE *hptr;
 while(history_head)
  {
   hptr = history_head;
   history_head = history_head -> next;
   free(hptr);
  }
}  

static int
history_record_cmp(HISTORY_NODE *a, HISTORY_NODE *b)
{
 int str_compare;
 
 str_compare = strcmp(a->data.system_fname, b->data.system_fname);
 if(str_compare)
    return(str_compare);
    
 /* the system filenames are the same */
 return(a->data.time_submitted < b->data.time_submitted? -1 : 
       (a->data.time_submitted > b->data.time_submitted)? +1 : 0 );
}       


static void
sort_history_list ()
{
  HISTORY_NODE *q, *tail, *p, *r;

  if (history_head != NULL)
    {
      tail = history_head;
      while (tail->next)
	{
	  q = tail->next;
	  if (history_record_cmp (q, history_head) < 0)
	    {
	      tail->next = q->next;
	      q->next = history_head;
	      history_head = q;
	    }
	  else
	    {
	      r = history_head;
	      p = r->next;
	      while (history_record_cmp (q, p) > 0)
		{
		  r = p;
		  p = r->next;
		}
	      if (q == p)
		tail = q;
	      else
		{
		  tail->next = q->next;
		  q->next = p;
		  r->next = q;
		}
	    }
	}
    }
}







   
static void
build_history_list(const char *info_fname, const char *sender,
                         const char *quiz_taker_username, CONFIG_STRUCT *conf,
                         SESSION *user)
{
 FILE *fp;
 char history_path[MAX_PATH + 1];
 HOTPOTATO_INFO_STRUCT data;
 HISTORY_NODE *hptr = 0;

  snprintf (history_path, MAX_PATH + 1, "%speople/%s/%s/%s", conf->course_path,
	    quiz_taker_username, discussion_fname, HOTPOT_FNAME);
  fp = fopen(history_path,"r");
  if(!fp)
     return;
  while(fread(&data,sizeof(HOTPOTATO_INFO_STRUCT),1,fp) == 1)
   {
    if( (!strcmp(data.sender,sender) && !strcmp(data.info_fname,info_fname)) &&
        ((!data.hidden) || !strcmp (data.sender,user->username) ) )
     {
      if(!history_head)
        {
         history_head = (HISTORY_NODE *) malloc(sizeof(HISTORY_NODE));       	    
         if(!history_head)
           cs_critical_error(ERR_MALLOC_FAILED,"");
         hptr = history_head;  
       }  
      else
       {
        hptr->next = (HISTORY_NODE *) malloc(sizeof(HISTORY_NODE));       	    
         if(!hptr->next)
           cs_critical_error(ERR_MALLOC_FAILED,"");
        hptr = hptr->next;
       }  
      hptr->data = data;
      hptr->next = 0;
     }	    
   }                         
 fclose(fp);
 sort_history_list();
} 




static void
set_history_list( char *realname)
{
#define MAX_TMP_NAME 80 
 HISTORY_NODE *hptr;
 char current_system_fname[MAX_FILENAME + 1] = "";
 char timestring[MAX_TIMESTRING + 1];
 int hours, minutes, seconds; 
 char name[MAX_TMP_NAME + 1];
 char name_prefix[MAX_TMP_NAME + 1];
 int result_count = 0;
 int test_count = -1;
 static int user_count =0;
 char time[MAX_TIMESTRING +1];


 if(history_head)
 { 
  
   snprintf(name_prefix, MAX_TMP_NAME, "selftest_user.%d.realname",user_count); 
   cs_set_value(name_prefix, realname);
       
   for(hptr = history_head; hptr; hptr = hptr -> next)
   {
    if(strcmp(hptr -> data.system_fname, current_system_fname))
     {
       test_count++;
       snprintf(name, MAX_TMP_NAME, "selftest_user.%d.exercise.%d.title", user_count, test_count); 
       cs_set_value(name, hptr->data.exercise);
       snprintf(name, MAX_TMP_NAME, "selftest_user.%d.exercise.%d.filename", user_count, test_count); 
       cs_set_value(name, hptr->data.orig_fname);
       strncpy(current_system_fname,hptr->data.system_fname,MAX_FILENAME);
       result_count =0;
     }
     snprintf(name, MAX_TMP_NAME, "selftest_user.%d.exercise.%d.result.%d.time_submitted", user_count, test_count, result_count); 
     strftime(timestring, MAX_TIMESTRING, DOW_DATE_TIME_FORMAT, 
                        localtime (&hptr->data.time_submitted));
     cs_set_value(name, timestring);                   
     /* shared_potato_util.c */                        
     calculate_elapsed_time(hptr->data.elapsed_time, &hours, &minutes, 
     					&seconds);
                             
     snprintf(time, MAX_TIMESTRING +1, " %02d:%02d:%02d",hours,minutes,seconds);
     snprintf(name, MAX_TMP_NAME, "selftest_user.%d.exercise.%d.result.%d.elapsed_time", user_count, test_count,result_count); 
     cs_set_value(name, time);
     snprintf(name, MAX_TMP_NAME, "selftest_user.%d.exercise.%d.result.%d.score", user_count, test_count, result_count); 
     cs_set_value(name ,hptr->data.score);
     result_count++;
   }
   user_count++;
 }
#undef MAX_TMP_NAME 
}    

static void
send_csv_history_list(const char *realname, const char *username, CONFIG_STRUCT *conf)
{
 HISTORY_NODE *hptr;
 char current_system_fname[MAX_FILENAME + 1] = "";
 char datestring[MAX_TIMESTRING + 1];
 char timestring[MAX_TIMESTRING + 1];
 int hours, minutes, seconds; 
 
 static int heading_sent = 0;
 
 if(history_head)
 { 
 
   if(!heading_sent)
    {
     cs_load_lang("news_info");    /* shared_cs_util.c */
     printf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"\n",
                 
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_semester_label", "Semester"),
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_course_label", "Course"),
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_realname_label", "Real Name"),
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_username_label", "Manhattan Username"),
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_subject_label", "Message Subject"),
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_quiz_filename_label", "Quiz Filename"),                 
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_date_submitted_label", "Date Submitted"),                 
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_submitted_label", "Time Submitted"),                 
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_elapsed_label", "Elapsed Time"),                                  
                 hdf_get_value (global_cgi->hdf, "lang.news_info.selftest_score_label", "Score")
                );
     heading_sent = 1;
    }
            

   for(hptr = history_head; hptr; hptr = hptr -> next)
   {
    if(strcmp(hptr -> data.system_fname, current_system_fname))
     {
       strncpy(current_system_fname,hptr->data.system_fname,MAX_FILENAME);
     }
     strftime(datestring, MAX_TIMESTRING, DATE_FORMAT, 
                        localtime (&hptr->data.time_submitted));
                        
     strftime(timestring, MAX_TIMESTRING, TIME_FORMAT, 
                        localtime (&hptr->data.time_submitted));
                        



     /* shared_potato_util.c */                        
     calculate_elapsed_time(hptr->data.elapsed_time, &hours, &minutes, 
     					&seconds);
                             
     printf("\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",%s,%s,%02d:%02d:%02d,%s\n",
                 
                 conf->semester,
                 conf->title,
                 realname,
                 username,
                 hptr->data.exercise,
                 hptr->data.orig_fname,
                 datestring,
                 timestring,
                 hours,
                 minutes,
                 seconds,
                 hptr->data.score);
   }
 }                 
}    




static void
show_one_selftest_history(const char *info_fname,
				const char *sender,
				const char *quiz_taker_username,
				char *realname, CONFIG_STRUCT *conf, SESSION *user,
				int sending_csv_file)
{

build_history_list(info_fname,sender,quiz_taker_username, conf, user);
if(sending_csv_file)
   send_csv_history_list(realname, quiz_taker_username, conf);
else
   set_history_list(realname);
free_history_list();
}				








static void
show_all_selftest_history(const char *info_fname, const char *sender,
                          CONFIG_STRUCT *conf, SESSION *user, int sending_csv_file)
{
 NEWS_PERSON_NODE *pptr;
 

 for (pptr = person_head; pptr; pptr = pptr->next)
  {
   if (pptr->data.time_read)
	    show_one_selftest_history (info_fname, sender,
	        pptr->data.username, pptr->data.realname, conf, user, sending_csv_file);
  }	    
}				
				




static 
void set_selftest_info(const char *info_fname,
   		       const char *sender, CONFIG_STRUCT *conf, 
   		       SESSION *user, int sending_csv_file)
{
  if( (user->group == FACULTY)) 
     show_all_selftest_history(info_fname, sender, conf, user, sending_csv_file);     		
  else
     show_one_selftest_history(info_fname,sender,user->username,user->realname, conf, 
                                             user, sending_csv_file);
}        		 







static void
display_info (char *course, char *key, long offset, int grp, CONFIG_STRUCT *conf, SESSION *user)
{
  CENTRAL_INBOX_RECORD inbox;
  NEWS_INFO infofile_info;
  char url[MAX_PATH + 1];

  cs_set_course_info(conf);
  cs_set_current_time();
  cs_set_int_value("grp", grp);

  process_inbox_record (offset, &inbox, &infofile_info, grp, conf, user);
  
  set_recipient_info (inbox.info.sender, &infofile_info, grp, user, conf);

  if(grp == SELFTEST)
   {
     if(user->group == FACULTY)
      {
       snprintf(url, MAX_PATH, "%s?crs=%s&amp;id=%s&amp;loc=%ld&amp;grp=%d&amp;get=csv", 
                                      "news_info", course, key, offset, SELFTEST);
       cs_set_value("selftest_csv_url", url);
      }

     set_selftest_info(inbox.info_fname,
     				inbox.info.sender, conf, user, 0);
   }

  if( (grp == PODCASTS) && (user->group == FACULTY) )
       set_podcast_download_log_data(inbox.info_fname, conf);       /* shared_podcast_util.c */
   				

}




static void
free_news_person_list ()
{
  NEWS_PERSON_NODE *pptr;

  while (person_head)
    {
      pptr = person_head;
      person_head = person_head->next;
      free (pptr);
    }
}


static void
free_news_attachment_list ()
{
  ATTACHMENT_NODE *pptr;

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




static void
get_csv_filename(const char *course, const char *subject, char *filename)
{
strcpy(filename,"hotpot_info.csv");
}





static void
send_selftest_data_file (char *course, char *key, long offset, int grp, 
                             CONFIG_STRUCT *conf, SESSION *user)
{
  CENTRAL_INBOX_RECORD inbox;
  NEWS_INFO infofile_info;
  char csv_filename[MAX_PATH + 1];
  
  process_inbox_record (offset, &inbox, &infofile_info, grp, conf, user);

  get_csv_filename(course, infofile_info.subject, csv_filename);

  printf ("Content-type:application/octet-stream\n");
  printf ("Content-disposition:attachment; filename=\"%s\"\n\n", csv_filename);
    
  show_all_selftest_history(inbox.info_fname, inbox.info.sender, conf, user, 1);     		  

}



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 send_selftest_csv;        /* from optional get=? cmd line - send Selftest Hot Potato
                                ** quiz records as a CSV file?
                                */
  SESSION user;
  CONFIG_STRUCT conf;		/* the configuration read from config file */

  cs_cgi_init();

  read_parameters (course, key, &offset, &grp, &send_selftest_csv);
  read_configuration_file (course, &conf);	/* shared_util.c */
  validate_key (key, &user, &conf);	/* shared_util.c */

  /** this program can't be used to view survey info 
  *** Use survey_info.c instead
  **/
  if(grp == SURVEYS)
      cs_critical_error(ERR_REQUEST_DENIED, "");
      
 /** Only send a csv file of selftest results if this is a teacher running the program
  **/
  if(send_selftest_csv && (user.group != FACULTY))
             cs_critical_error(ERR_REQUEST_DENIED, "");
      
  set_discussion_names (conf.course_path, user.username, grp);	/* shared_news_util.c */
  
  if(send_selftest_csv)
   {
     send_selftest_data_file(course,key, offset, grp, &conf, &user);
     free_news_person_list ();
     free_news_attachment_list ();
   }
  else
   {   
    display_info (course, key, offset, grp, &conf, &user);

    free_news_person_list ();
    free_news_attachment_list ();
    cs_cgi_display("news_info", 1);
   }

  cs_cgi_destroy();
  return 0;
}


