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

#include "global.h"
#include "manhat-lib/shared_cs_util.h"
#include "manhat-lib/shared_util.h"
#include "manhat-lib/shared_roster_xml_parser.h"
#include "manhat-lib/shared_survey_string.h"
#include "manhat-lib/shared_authenticate.h"
#include "manhat-lib/shared_central_user.h"
#include "manhat-lib/shared_file_util.h"
#include "manhat-lib/shared_server_string.h"
#include "manhat-lib/shared_encrypt.h"
#include "manhat-lib/shared_user_index.h"
#include "manhat-lib/shared_super_util.h"
#include "manhat-lib/shared_strtrm.h"
#include "manhat-lib/shared_new_course_lock.h"
#include "manhat-lib/shared_add_util.h"
#include "manhat-lib/shared_authenticate.h"
#include "manhat-lib/shared_lock.h"
#include "manhat-lib/shared_person_list.h"
#include "manhat-lib/shared_system_data.h"



/*
** This data structure keeps track of the data items for each course created.
*/

typedef struct directory_name_node
   {
     char name[MAX_COURSE_NO + 1];             /* the original internal name of the course, as stored in the XML file */
     char dir_id[MAX_COURSE_ID + 1];           /* the new internal name of the course, as modified by the user */
     char subdir[MAX_COURSE_SUBDIR + 1];      /* the new internal subdirectory for the course */
     COURSE_TYPE course_type;                 /* Standalone, Normal or Template */
     struct directory_name_node *next;
   } DIRECTORY_NAME_NODE;



typedef enum user_state{NEW,           /* this is a new user */
                        NEW_1, 
                        EXISTS,        /* this is an existing user */
                        ERROR_UID,     /* couldn't derive a username */
                        ERROR_NAME     /* name in xml file didn't match existing name */
                        }USER_STATE;
                        
typedef enum user_add_state{FINISH,    		/* user was successfully added */
                            FAILED,    		/* error occurred while creating user */
                            USEREXISTS 		/* user was already in the course */
                            }USER_ADD_STATE;
                            

typedef enum user_central_state{C_ERROR, 	/* an error occurred while adding user to central database */
                                SUCCESS,  	/* user was successfully added to central database */
                                UN_CHANGE 	/* user was already in database, no changes required */
                                }USER_CENTRAL_STATE;

typedef struct user 
{
    char first[MAX_NAME + 1];
    char last[MAX_NAME + 1];
    char id[MAX_ID + 1];
    char username[MAX_USERNAME + 1];
    char password[MAX_PASSWORD + 1];
    GROUP_TYPE group;
    USER_STATE is_new;
    USER_ADD_STATE add_state;
    USER_CENTRAL_STATE central_state;
}USER;

typedef struct user_node
{
     USER user;
     struct user_node *next;
}USER_NODE;

typedef enum course_state{UPDATE,      		/* course already existed, this is an update */
                          C_NEW,       		/* this is a completely new course */
                          DIR_ERR,     		/* couldn't create course directory */
                          MSG_ERR,     		/* couldn't create chat message file */
                          CONFIG_ERR,  		/* couldn't write config.dat */
                          COURSE_ERR,   	/* general error? */
                          TYPE_CONFLICT  	/* course type conflict */
                          }  COURSE_STATE;
                          
/* adding teacher to a course */                          
typedef enum t_pass_state{OPEN_ERR,   		/* error appending to password file */ 
                          T_SUCCESS   		/* all teachers added successfully */
                          }T_PASS_STATE;



typedef struct master_course_list
  {
    char course_subdir[MAX_COURSE_SUBDIR + 1];
    char course_dir[MAX_COURSE_ID + 1];
    char course_path[MAX_PATH + 1];
    char course_no[MAX_COURSE_NO + 1];
    char course_title[MAX_COURSE_TITLE + 1];
    char course_semester[MAX_SEMESTER + 1];
    char instructor_title[MAX_INSTRUCTOR + 1];
  
    COURSE_TYPE course_type;
    COURSE_STATE exists; 
    T_PASS_STATE t_state; 
  
    USER_NODE *head;       /* list of teachers only */
    USER_NODE *add_head;   /* complete list of people who have been added to the course */
    USER_NODE *add_current;
  
    struct master_course_list *next;
  }  CREATED_COURSE_NODE;



typedef struct course_group
{
     char course_subdir[MAX_COURSE_SUBDIR + 1];
     char course_dir[MAX_COURSE_NO + 1];
     COURSE_TYPE course_type;
     GROUP_TYPE group;
     struct course_group *next;
}COURSE_GROUP;

typedef struct user_group_info
{
    USER user;
    COURSE_GROUP *head;
    COURSE_GROUP *current;
    struct user_group_info *next;
}USER_GROUP_INFO;

typedef struct user_group_info_list
{
    USER_GROUP_INFO *head;
    USER_GROUP_INFO *current;
}USER_GROUP_INFO_LIST;




/** Copies string 'source' into 'dest' without buffer overflow,
*** and ensures the result is null terminated.
***
*** len is the size (in chars) of dest.
**/

static void safe_strncpy(char *dest, char *source, int len)
{
 strncpy(dest, source, len);
 *(dest + len - 1) = '\0';
}

 


USER_NODE *
find_all_teachers(XML_COURSE_INFO *info)
{
   USER_NODE *head =0, *ptr, *current=0;
  
   for(info->user_current = info->user_head;
	     info->user_current; info->user_current=info->user_current->next)
   {
       if(info->user_current->data.group == FACULTY)
       {
	   ptr = (USER_NODE*)malloc(sizeof(USER_NODE));
           if(!ptr)
              cs_critical_error(ERR_MALLOC_FAILED, "in find_all_teachers()");
	   ptr->next = 0;
	   safe_strncpy(ptr->user.first, 
		   info->user_current->data.realname, MAX_NAME + 1);
	   safe_strncpy(ptr->user.last,
		   info->user_current->data.lastname, MAX_NAME + 1);
	   safe_strncpy(ptr->user.id,
		   info->user_current->data.id, MAX_ID + 1);
	   safe_strncpy(ptr->user.username,
		   info->user_current->data.username, MAX_USERNAME + 1);
	   ptr->user.group = FACULTY;
	   ptr->user.central_state = UN_CHANGE;  /* assume this to start */
	   if(!head)
	      head = ptr;
	   else
	      current->next = ptr;
	   current = ptr;
       }
   }
   return head;
}
        

USER_NODE *
find_all_users_in_standalone(XML_COURSE_INFO *info)
{
   USER_NODE *head =0, *ptr, *current=0;
  
   for(info->user_current = info->user_head;
	     info->user_current; info->user_current=info->user_current->next)
   {
	   ptr = (USER_NODE*)malloc(sizeof(USER_NODE));
           if(!ptr)
               cs_critical_error(ERR_MALLOC_FAILED, "in find_all_users_in_standalone");
	   ptr->next =0;
	   safe_strncpy(ptr->user.first, 
		   info->user_current->data.realname, MAX_NAME + 1);
	   safe_strncpy(ptr->user.last,
		   info->user_current->data.lastname, MAX_NAME + 1);
	   safe_strncpy(ptr->user.id,
		   info->user_current->data.id, MAX_ID + 1);
	   safe_strncpy(ptr->user.username,
		   info->user_current->data.username, MAX_USERNAME + 1);
	   ptr->user.group = info->user_current->data.group;
	   ptr->user.central_state = UN_CHANGE;
	   if(!head)
	      head = ptr;
	   else
	      current->next = ptr;
	   current = ptr;
   }
   return head;
}

USER_GROUP_INFO *
find_exist_users(USER_GROUP_INFO_LIST *list, P_NODE* info)
{
    USER_GROUP_INFO *ptr;

    for(ptr=list->head;
	   ptr; ptr = ptr->next)
    {
          if(strcmp(ptr->user.id, info->data.id) ==0)
		  return ptr;
    }
    return 0;
}
    


USER_GROUP_INFO_LIST *
process_one_course(USER_GROUP_INFO_LIST *list, XML_COURSE_INFO *info)
{
     USER_GROUP_INFO *ptr, *find;
     /* for each user in the course */
     for(info->user_current=info->user_head;
	   info->user_current; info->user_current=info->user_current->next)
     {
	 if(info->user_current->data.group != FACULTY)
	 {
             find =  find_exist_users(list, info->user_current);
	     if(!find)
	     {
	       ptr = (USER_GROUP_INFO*)malloc(sizeof(USER_GROUP_INFO));
	       safe_strncpy(ptr->user.first, 
	         info->user_current->data.realname,MAX_NAME + 1);
	       safe_strncpy(ptr->user.last, 
	         info->user_current->data.lastname,MAX_NAME + 1);
	       safe_strncpy(ptr->user.id, 
	         info->user_current->data.id,MAX_ID + 1);
	       if(strlen(info->user_current->data.username)>0)
	         safe_strncpy(ptr->user.username, 
	                    info->user_current->data.username,MAX_USERNAME + 1);
	       else
		 ptr->user.username[0]='\0';
	       ptr->user.is_new =NEW;
	       ptr->user.central_state =UN_CHANGE;
	       ptr->user.group=info->user_current->data.group;
	       ptr->next =0;
	       
	       /** add a new course for this user */
	       ptr->head = (COURSE_GROUP*)malloc(sizeof(COURSE_GROUP));
	       ptr->current = ptr->head;
	       ptr->head->next =0;
	       safe_strncpy(ptr->head->course_subdir, info->subdir, MAX_COURSE_NO + 1);
	       safe_strncpy(ptr->head->course_dir, info->dir_id, MAX_COURSE_NO + 1);
	       ptr->head->course_type =  info->course_type;
	       ptr->head->group=info->user_current->data.group;
	       if(!list->head)
		  list->head = ptr;
	       else
		  list->current->next = ptr;
	       list->current = ptr;
	       
	     }
	     else  /* user was already listed */
	     {

	        find->user.central_state =UN_CHANGE;
	
		find->current->next=(COURSE_GROUP*)malloc(sizeof(COURSE_GROUP));
	        find->current = find->current->next;
	        safe_strncpy(find->current->course_subdir, info->subdir, MAX_COURSE_NO + 1);
	        safe_strncpy(find->current->course_dir, info->dir_id, MAX_COURSE_NO + 1);
	        find->current->course_type = info->course_type;
	        find->current->group = info->user_current->data.group;
	        find->current->next =0;
	     }
	 }
     }
       
    return list;
} 



USER_GROUP_INFO_LIST *
build_user_list(XML_COURSE_INFO_LIST *list)
{
   USER_GROUP_INFO_LIST *head;

   /* start with an empty user list */
   head = (USER_GROUP_INFO_LIST *)malloc(sizeof(USER_GROUP_INFO_LIST));
   if(!head)
      cs_critical_error(ERR_MALLOC_FAILED, "build_user_list()");
   head->head =0;
   head->current =0;

  /* for each course */
   for(list->current=list->head;
	list->current; list->current = list->current->next)
   {
    if(list->current->course_type != STANDALONE)
       head = process_one_course(head, list->current);
   }
   return head;
}





/* start list with normal and template courses
** and only teacher info 
*/

CREATED_COURSE_NODE*
build_normal_template_course_list(XML_COURSE_INFO_LIST *list)
{
     USER_NODE  *teacher_head;
     CREATED_COURSE_NODE *head = 0, *ptr, *current = 0;

     for(list->current=list->head; list->current; list->current = list->current->next)
     {
       /* if NOT Standalone course */
       if(list->current->course_type != STANDALONE)
       {
	  teacher_head = find_all_teachers(list->current);
	  if(!teacher_head)
	  {
	    cs_critical_error(ERR_COURSE_X_Y_HAS_NO_TEACHER, list->current->title);
	  }
	 ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE));
         if(!ptr)
            cs_critical_error(ERR_MALLOC_FAILED, "build_normal_template_course_list()");
            
         safe_strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR + 1);   
         safe_strncpy(ptr->course_dir, list->current->dir_id, MAX_COURSE_ID + 1);
         safe_strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO + 1);
         safe_strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE + 1);
         safe_strncpy(ptr->instructor_title, list->current->instructor_title, MAX_INSTRUCTOR + 1);
         ptr->course_type = list->current->course_type;
         
         /* change semester to a standard value for course templates */
	 if(list->current->course_type == TEMPLATE)
             safe_strncpy(ptr->course_semester, "Course Temlate", MAX_SEMESTER + 1);
	 else
             safe_strncpy(ptr->course_semester,  list->current->semester,   MAX_SEMESTER + 1);
             
	 ptr->next = 0;
         ptr->head = teacher_head;
         ptr->add_head = 0;
	 ptr->add_current = 0;
         
	 if(!head)
	    head = ptr;
	 else
	    current-> next = ptr;
	 current = ptr;
      }
     }
     return head;
}





int
find_this_username(USER_NODE *all, const char *username)
{
     USER_NODE *ptr;
     for(ptr = all; ptr; ptr = ptr->next)
     {
	if(strlen(ptr->user.username) > 0 &&
	    strcmp(ptr->user.username, username) ==0)
	   return 1;
     }
     return 0;

}







USER_NODE *
find_teacher_in_course_head(USER_NODE *head, const char *id)
{
     USER_NODE *ptr;
     for(ptr = head; ptr; ptr = ptr->next)
     {
	if(strcmp(ptr->user.id, id) ==0)
	   return ptr;
     }
     return 0;
}


       
       
/* build list of standalone courses with teachers and students */
CREATED_COURSE_NODE *
standalone_course_list(XML_COURSE_INFO_LIST *list)
{
     CREATED_COURSE_NODE *head =0, *ptr, *current=0;

     for(list->current=list->head; 
        list->current; list->current = list->current->next)
     {
       if(list->current->course_type == STANDALONE)
       {
	 ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE));
         safe_strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR + 1);
         safe_strncpy(ptr->course_dir, list->current->dir_id, MAX_COURSE_ID + 1);
         snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", 
                                     COURSE_PATH, ptr->course_subdir, ptr->course_dir);
         safe_strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO + 1);
         safe_strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE + 1);
         ptr->course_type = list->current->course_type;
         safe_strncpy(ptr->course_semester, list->current->semester, MAX_SEMESTER + 1);
	 ptr->next = 0;
	 ptr->head = find_all_teachers(list->current);
         ptr->add_head =find_all_users_in_standalone(list->current);
	 ptr->add_current = ptr->add_head;
	 if(!head)
	    head = ptr;
	 else
	    current->next = ptr;
	 current = ptr;
      }
     }
     return head;
}




static void
print_heading(const char *key)
{
   printf("<html><head><title>%s</title></head>%s\n", "Course List", "<body>");
   fflush(stdout);
}



    
static void
print_course_table(CREATED_COURSE_NODE *head, const char *title)
{
    
   CREATED_COURSE_NODE *ptr;
   USER_NODE *t_node;
   int course_count =0;
   int people_count;
   char c_color[9] = "#C7C5FF";
   char t_color[9] = "#A4FFE5";
   char s_color[9] = "#F6FFCD";
   
   printf("<center><h2>%s</h2></center>\n", title);
   for(ptr = head; ptr; ptr = ptr->next)
   {
      if(ptr->course_type == CENTRAL)
         printf("<table border=3 align=center bgcolor=%s>\n", c_color);
      else if(ptr->course_type == STANDALONE)
         printf("<table border=3 align=center bgcolor=%s>\n", s_color);
      else 
         printf("<table border=3 align=center bgcolor=%s>\n", t_color);
    
      printf("<tr><td>%s</td><td> %s</td></tr>\n", "Group", ptr->course_subdir);
      printf("<tr><td>%s</td><td> %s</td></tr>\n", "Internal Course Name", ptr->course_dir);
      printf("<tr><td>%s</td><td> %s</td></tr>\n", "Course Code", ptr->course_no);
      printf("<tr><td>%s</td><td> %s</tr>\n", "Course Title", ptr->course_title);
      printf("<tr><td>%s</td><td> %s</td></tr>\n", "Semester", ptr->course_semester);
      printf("<tr><td>%s</td><td> %s</td></tr>\n", "Course Type", 
                                       ptr->course_type == STANDALONE? "Standalone":
                                       ptr->course_type == TEMPLATE? "Template": "Normal");
      
      printf("<tr><td>%s</td><td>", "Status");
      
      if(ptr->exists == C_NEW)
	   puts("New Course");
      else if(ptr->exists == UPDATE)
	   puts("Updated Course");
      else if(ptr->exists == DIR_ERR)
	   puts("Dir Error");
      else if(ptr->exists == CONFIG_ERR)
	   puts("Config Error");
      else if(ptr->exists == COURSE_ERR)
	   puts("Course Error");
      else if(ptr->exists == TYPE_CONFLICT)
	   puts("Course type conflict");
      puts("</td></tr>");
      
      
      printf("<tr><td>%s</td><td> %s</td></tr>", 
                          "Success?",
                          ptr->t_state == OPEN_ERR ? "No": "Yes"); 

     printf("</table>\n");
     printf("<br>\n");

    course_count++;
    people_count =0; 

    printf("<table border =1 align=center>\n");
    printf("<caption><i>%s</i></caption>\n", ptr->course_no); 
    printf("<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n",
                    "Full Name",
                    "ID",
                    "Username",
                    "Central Status",
                    "User Type",
                    "Course Status",
                    "Central Status"
                    ); 
      
      for(t_node = ptr->add_head; t_node; t_node = t_node->next)
      {
        people_count++ ; 
        printf("<tr bgcolor=\"%s\">\n", (t_node->user.is_new == ERROR_NAME) ||
                                        (t_node->user.is_new == ERROR_UID)? "#ff9999" : "#ffffff");
        printf(	"<td>%s %s</td>", t_node->user.first, t_node->user.last);
        printf("<td> %s</td>", t_node->user.id);
        printf("<td> %s</td>", t_node->user.username);

        printf("<td>%s</td>", ptr->course_type == STANDALONE? "N/A":(t_node->user.is_new == NEW) || (t_node->user.is_new == NEW_1) ?
                              "New User" : (t_node->user.is_new == EXISTS)?
                              "Existing User": (t_node->user.is_new == ERROR_NAME)?
                              "Name Mismatch": "Username Error");
                              

       printf("<td> %s</td>", (t_node->user.group == FACULTY) ? "faculty": "student");


  
	
       printf("<td>%s</td>", (t_node->user.add_state == FINISH)?
                                "Add Successful": (t_node->user.add_state == USEREXISTS)?
                                "Existing User": "Add Failed");


       printf("<td>%s</td>\n</tr>\n",  ptr->course_type == STANDALONE? "N/A":t_node->user.central_state == C_ERROR?
                              "Failed": t_node->user.central_state == SUCCESS?
                              "Success":
                              "Unchanged");
                                                       


      }
      
     printf("<tr><td colspan=7 align=center>%s %d</td></tr>\n", "Total Users", people_count);
     printf("</table><br>\n");
   }
   printf("<center><h2>%s %d </h2></center>\n", "Total Courses", course_count);
} 
    








void    
read_parameters( char *roster_path)
{
    cs_get_required_parameter ("roster_path", roster_path, MAX_PATH);   /* shared_cs_util.c */
}






static
void check_invalid_chars(const char *string)
{
 const char *cptr;
 
    /* check for invalid characters */       
    for(cptr = string; *cptr; cptr++)
     {
      if((*cptr != '_')  && !isdigit(*cptr) && !isalpha(*cptr))
        {
         cs_critical_error(ERR_COURSE_X_HAS_INVALID_CHARS, string);
       }
     }
}   






/* assumes strings have been trimmed
** in read_parameters()
*/

static
void check_internal_course_names(XML_COURSE_INFO_LIST *list)
{
 
 for(list->current=list->head; list->current; list->current=list->current->next)
  {
   if(!strlen(list->current->dir_id) ||
      !strlen(list->current->subdir) )
       cs_critical_error(ERR_COURSE_NAMES_EMPTY, "");
       
     
    /* Central or Standalone Course subdir names can't start with a 'T' 
    */    
    if( list->current->course_type == CENTRAL)
      {
      if(*(list->current->subdir) == 'T') 
           cs_critical_error(ERR_COURSE_CANT_START_WITH_T, list->current->subdir);
      
      }     

     check_invalid_chars(list->current->dir_id);
     check_invalid_chars(list->current->subdir);
  } /* for each course ... */
}   




/* parses the xml file into a linked list of 
** course nodes
*/

XML_COURSE_INFO_LIST *
parse_xml_file(const char *xml_file_path)
{
   XML_COURSE_INFO_LIST *list;   /* shared_roster_xml_parser.h */
   FILE *fp;
   struct stat file_stat;
   char *buf;
   
   
   if(stat(xml_file_path, &file_stat))
    {
       cs_critical_error(ERR_FILE_X_NOT_FOUND, xml_file_path);
    }

   buf = (char*)malloc( (file_stat.st_size + 1) * sizeof(char));  /* allocate an additional byte for terminating NULL */
   if(!buf)
      cs_critical_error(ERR_MALLOC_FAILED, "in parse_xml_file()");
      

   fp = fopen(xml_file_path, "r");
   if(!fp)
      cs_critical_error(ERR_FOPEN_READ_FAILED, xml_file_path);
   if(fread(buf, file_stat.st_size, 1, fp) != 1)
      cs_critical_error(ERR_FREAD_FAILED, xml_file_path);
   fclose(fp);
   
   *(buf + file_stat.st_size) = '\0';  /* null terminate the buf string */
   
   list = xml_course_data_parser(buf, xml_file_path);   /*shared_roster_xml_parser.c */
   
   free(buf);
   return list;
}









/** For this (baypath) version, this function simply sets all
*** courses to type of CENTRAL.
**/

static void
update_xml_info_list(XML_COURSE_INFO_LIST *list)
{

    if(list->head)
    {
       for(list->current=list->head; list->current; list->current=list->current->next)
	       list->current->course_type = CENTRAL; 
    }
    else
      cs_critical_error(ERR_NO_DATA_FOUND, ""); 
} 

 
 
static void
free_teacher_node(USER_NODE *t_head)
{
     USER_NODE *ptr;
     while(t_head)
     {
	 ptr = t_head->next;
	 free(t_head);
	 t_head = ptr;
     }
}



static void
free_course_f_list(CREATED_COURSE_NODE *head)
{
   CREATED_COURSE_NODE *ptr;
    while(head)
    {
	ptr = head->next;
	if(head->head)
	    free_teacher_node(head->head); 
	if(head->add_head)
	    free_teacher_node(head->add_head); 
        free(head);
        head = ptr;
    }
}    



static void
free_user_group_info_list(USER_GROUP_INFO_LIST *list)
{
   USER_GROUP_INFO *ptr;
    while(list->head)
    {
	ptr = list->head->next;
        free(list->head);
        list->head = ptr;
    }
    free(list);
}    



INDEX_USER *
find_this_user_from_index(INDEX_USER_LIST *list, USER *node)
{
    INDEX_USER *ptr;

    for(ptr = list->head; ptr;ptr = ptr->next)
    {
	if(strcmp(ptr->id, node->id) ==0)
	  return ptr;
    }
    return 0;
}    




int
username_exist(INDEX_USER_LIST *index_list, const char *username)
{
  INDEX_USER *ptr;

     for(ptr = index_list->head; ptr;
		  ptr = ptr->next)
     {
	 if(strcmp(ptr->username, username) ==0)
		 return 1;
     }
     return 0;
}




INDEX_USER_LIST *
process_one_username(USER *ptr, INDEX_USER_LIST *index_list)
{
    INDEX_USER *a_user;
    char realname[MAX_NAME + 1];
    char username[MAX_USERNAME + 1];
    int try;

    ptr->is_new = NEW ;    /* assume this to start */
    
    a_user = find_this_user_from_index(index_list, ptr);
    if(!a_user)
    {
       if(!strlen(ptr->username))    /* if username wasn't supplied in XML file */
        {
         derive_username (ptr->first, ptr->last,     
	         ptr->id, username, MAX_USERNAME+ 1);  /* shared_authenticate.c */
         
         
         for(try = 1;
	     (try <= MAX_USERNAME_TRIES) && (username_exist (index_list, username ));
	                   try++)
             {
	        derive_another_username(ptr->first, ptr->last, ptr->id, 
			   username, MAX_USERNAME + 1, try);    /* shared_authenticate.c */
	       
               }
          if(try > MAX_USERNAME_TRIES)
	       ptr->is_new = ERROR_UID;     /* couldn't derive username */
        }
       else  /* a username was supplied in the XML file */
        {
         safe_strncpy(username, ptr->username, MAX_USERNAME + 1);
         *(username + MAX_USERNAME) = '\0';
         if(username_exist(index_list, username))
              ptr->is_new = ERROR_UID;
        }
       
       if(ptr->is_new != ERROR_UID)
            {
               ptr->is_new = NEW;
	       safe_strncpy(ptr->username, username, MAX_USERNAME + 1);
	       derive_password (ptr->username, ptr->first,ptr->last,ptr->id, 
                         ptr->password, MAX_PASSWORD + 1); /* shared_authenticate.c */

	       snprintf(realname, MAX_NAME+ 1, "%s %s", ptr->first,ptr->last);
               index_list = add_to_index_list(index_list,
		                      ptr->username, ptr->id, realname);   /* shared_user_index.c */
            }
     }
     
    else    /* person already has a central account */
    {

	  safe_strncpy(ptr->username, a_user->username, MAX_USERNAME + 1);
	  derive_password (ptr->username, ptr->first,ptr->last,ptr->id, ptr->password, MAX_PASSWORD + 1); /* shared_authenticate.c */
	  snprintf(realname, MAX_NAME+ 1, "%s %s", ptr->first,ptr->last);
	  if(strcmp(realname, a_user->realname) == 0)
             ptr->is_new = EXISTS;
	  else
	    {
	      /* copy correct real name into first, last fields */
	      get_first_last_names(a_user->realname, ptr->first, ptr->last);  /* shared_authenticate.c */
              ptr->is_new = ERROR_NAME;  /* user exists, but they had a different real name on Manhattan */
           }  
	
    }
   return index_list;
}
 
 
 
INDEX_USER_LIST *
derive_teacher_username_password(CREATED_COURSE_NODE *course_head, INDEX_USER_LIST *index_list)
{
  CREATED_COURSE_NODE *course;
  USER_NODE *ptr;

  for(course = course_head; course; course = course->next) 
  {
    for(ptr = course->head; ptr; ptr = ptr->next)
          index_list = process_one_username(&(ptr->user), index_list);
  }
   return index_list;
}
         
         
         
         
INDEX_USER_LIST *
derive_student_username_password(USER_GROUP_INFO_LIST *user_list,
		INDEX_USER_LIST *index_list)
{
  for(user_list->current = user_list->head;
	user_list->current; user_list->current = user_list->current->next) 
  {
      index_list = process_one_username
	      (&(user_list->current->user), index_list);

  }
   return index_list;
}






int
create_course_dir(CREATED_COURSE_NODE *course)
{
 char path[MAX_PATH + 1];


 /* create subdir, if necessary */
 snprintf(path, MAX_PATH + 1, "%s%s", 
                course->course_type == TEMPLATE? TEMPLATE_PATH : COURSE_PATH,
                course->course_subdir);
 if(!file_exists(path))
  {
     if(mkdir (path, 0777))
	    return 0;
  }
  
 if(mkdir(course->course_path, 0777))
        return 0;
 return 1;
}         

                   



static void
get_config_default_value(CREATED_COURSE_NODE *course, CONFIG_STRUCT *conf)
{
    char professor[MAX_INSTRUCTOR + 1];


    safe_strncpy(conf->course_no, course->course_no, MAX_COURSE_NO+ 1);
    safe_strncpy(conf->title, course->course_title, MAX_COURSE_TITLE+ 1);
    safe_strncpy(conf->semester, course->course_semester, MAX_SEMESTER+ 1);
    if(strlen(course->instructor_title))
        snprintf(professor, MAX_INSTRUCTOR + 1, "%s",  course->instructor_title);
    else
        snprintf(professor, MAX_INSTRUCTOR + 1, "%s %s", "Prof.", course->head->user.last);
    safe_strncpy(conf->instructor, professor, MAX_INSTRUCTOR + 1);

    conf->testpilot = 0;                        
    conf -> key_expire = system_data_int("MAX_KEY_EXPIRE");          
    conf -> mail_attachments = MAX_ATTACHMENTS;    

    conf -> assignments = 0;
    conf -> syllabus = 0;
    conf -> discussion = 0;
    conf -> postoffice = 0;
    conf -> internet = 0;
    conf -> lounge = 0;
    conf -> chat = 0;
    conf -> anonymous = 0;
    conf -> team = 0;
    conf -> team_teach = 0;
    conf -> grades = 0;
    conf -> selftest = 0;
    conf -> lectures = 0;
    conf -> people  = 0;
    conf -> surveys = 0;
    
    conf->access = ACCESS_ALL;    /*Full access for teachers and students */

    conf ->standalone = (course->course_type == STANDALONE)? 1 : 0;
    conf -> template = (course->course_type == TEMPLATE)? 1 : 0;
    

    conf->misc = 0;
    conf->podcasts = 0;
    conf->calendar = 0;
    conf->theme = 0;
  

}




static
int write_config_file(const char *course, CONFIG_STRUCT *conf)
{
    FILE *fp;
    char file_path[MAX_PATH + 1];
    
    snprintf(file_path, MAX_PATH + 1, "%s/%s", course, CONFIG_FNAME);
    fp = fopen(file_path,"w");
    if(!fp)
       return 0;

    if(fwrite(conf, sizeof(CONFIG_STRUCT), 1, fp) != 1)
     {
       fclose(fp);
       return 0;
    }

   fclose(fp);
   return 1;
}






int
create_inbox_key_people(const char *course_path)
{
   char path[MAX_PATH + 1];

  snprintf (path, MAX_PATH + 1, "%s/%s",  course_path, KEY_DIR);
  if(mkdir (path, 0777))
         return 0;
  snprintf (path, MAX_PATH + 1, "%s/%s",  course_path, PEOPLE_DIR);
  if(mkdir (path, 0777))
	 return 0;
  snprintf (path, MAX_PATH + 1, "%s/%s",  course_path, INBOXES_DIR);
  if(mkdir (path, 0777))
	 return 0;
  return 1;
}




static
int write_chat_message_log(const char *course)
{
  FILE *fp;
  char log_fname[MAX_PATH + 1];

   snprintf(log_fname, MAX_PATH + 1, "%s/%s",  course,  CHAT_MSG_LOG); 
    fp = fopen (log_fname, "w");
    if(!fp)
      return 0;
   fclose(fp);
  return 1;
}
int
write_logout_html (const char *crs)
{
  FILE *fp;
  char fname[MAX_PATH + 1];

  snprintf(fname, MAX_PATH + 1, "%s/%s",  crs,  EXIT_FILE);  
  fp = fopen (fname, "w");
    if(!fp)
  return 0;

  fprintf (fp, "<center><a href=%s>%s</a></center>", system_data_str("EXIT_URL"), system_data_str("EXIT_URL"));  
   fclose (fp);
  return 1;
}



int
create_one_person_dir (const char *course_path, const char *username)
{
  char basedir [MAX_PATH + 1];

  snprintf (basedir, MAX_PATH + 1, "%s/",  course_path);
  return create_directories(basedir,username);   /* shared_add_util.c */
  
}




CREATED_COURSE_NODE *
add_user_to_course_list(CREATED_COURSE_NODE *course, USER *ptr)
{
 USER_NODE *target;
 
     target = (USER_NODE *)malloc(sizeof(USER_NODE)); 
     if(!target)
        cs_critical_error(ERR_MALLOC_FAILED, "in add_user_to_course_list()");
      
       safe_strncpy(target->user.username, ptr->username, MAX_USERNAME + 1);
       safe_strncpy(target->user.first, ptr->first, MAX_NAME + 1);
       safe_strncpy(target->user.password, ptr->password, MAX_PASSWORD + 1);
       safe_strncpy(target->user.last, ptr->last, MAX_NAME + 1);
       safe_strncpy(target->user.id, ptr->id, MAX_ID + 1);
       target->user.is_new = ptr->is_new;
       target->user.group = ptr->group;
       target->user.add_state = ptr->add_state;
       target->user.central_state = ptr->central_state;
       target->next = 0;
          
 
 
    if(!course->add_head)
    {
       course->add_head = target;
       course->add_current = course->add_head;
    }
    else
    {
       course->add_current->next = target;
       course->add_current = course->add_current->next;
    }
     
    return course;
}


static void
update_central_info(CREATED_COURSE_NODE *course, USER *user_ptr)
{
     char realname[MAX_NAME + 1];
     char course_name[MAX_PATH + 1];
     
     snprintf(realname, MAX_NAME + 1, "%s %s", user_ptr->first, user_ptr->last);
     snprintf(course_name, MAX_PATH + 1, "%s/%s",
                                              course->course_subdir, course->course_dir);
     /*printf("<p>%s, %s, %d</p>", realname, course_name, user_ptr->add_state); */

     if( (user_ptr->is_new == NEW) && (user_ptr->add_state == FINISH)
	 && ( (course->exists == C_NEW) || (course->exists == UPDATE)) 
         && (user_ptr->central_state != SUCCESS) )
     {
        /* create_central_letter_dir is in shared_central_user.c */
        /* sub_dir_name is in shared_authenticate.c */
	if(!create_central_letter_dir (sub_dir_name(user_ptr->username)))
	  user_ptr->central_state = C_ERROR;
        
	if(!create_central_user_dir(user_ptr->username))    /* shared_central_user.c */
	  user_ptr->central_state = C_ERROR;

        if(!write_central_id_file (realname,user_ptr->username, user_ptr->id))  /* shared_central_user.c */
	  user_ptr->central_state = C_ERROR;

	if(!write_central_password_file (user_ptr->username, user_ptr->password))  /* shared_central_user.c */
	  user_ptr->central_state = C_ERROR;

        	if(!add_course(user_ptr->username,course_name))   /* shared_central_user.c */
	  user_ptr->central_state = C_ERROR;
	else
	{
	  user_ptr->central_state = SUCCESS;
	  user_ptr->is_new = NEW_1;   /* central records already updated for this user */
	}
     }
     else if((user_ptr->is_new != ERROR_UID || user_ptr->is_new != NEW) && user_ptr->add_state == FINISH)
     {
        if(course->exists == C_NEW || course->exists == UPDATE)
        {
	   if(!add_course(user_ptr->username,course_name))   /* shared_central_user.c */
	     user_ptr->central_state = C_ERROR;
	   else
	     user_ptr->central_state = SUCCESS;
	}
     }
     else
	 user_ptr->central_state = UN_CHANGE;

}
          

	  


CREATED_COURSE_NODE *    
add_teachers(CREATED_COURSE_NODE *course)
{
  USER_NODE *ptr;
  char file_path[MAX_PATH + 1];

  if(course->exists == C_NEW)
  {
     for(ptr = course->head; ptr; ptr=ptr->next)  /* for each teacher */
     {
      if(create_one_person_dir (course->course_path, ptr->user.username))
	   ptr->user.add_state = FINISH;
      else
	   ptr->user.add_state = FAILED;
      if(course->course_type != STANDALONE)
      {
        update_central_info(course, &(ptr->user));
        course =add_user_to_course_list(course, &(ptr->user));
      }
     }
  }
  else if(course->exists == UPDATE)
  {
     for(ptr = course->head; ptr; ptr =ptr->next)
     {
       snprintf(file_path, MAX_PATH + 1, "%s/%s/%s",
                               course->course_path, PEOPLE_DIR, ptr->user.username);
      if(!file_exists(file_path))
      {
         if(create_one_person_dir (course->course_path, ptr->user.username))
	   ptr->user.add_state = FINISH;
        else
	   ptr->user.add_state = FAILED;
        if(course->course_type != STANDALONE)
          update_central_info(course, &(ptr->user));
      }
      else
	   ptr->user.add_state = USEREXISTS;
      if(course->course_type != STANDALONE)
         course =add_user_to_course_list(course, &(ptr->user));
     }
  }
  return course;
}



int
write_passwd_file(CREATED_COURSE_NODE *course, USER_NODE *head)
{
    USER_NODE *ptr;
    char file_path[MAX_PATH + 1];
    FILE *fp;

    if( (course->exists != C_NEW) &&
        (course->exists != UPDATE) )
           return 0;

    
    snprintf(file_path, MAX_PATH + 1, "%s/%s",
                                 course->course_path, PASSWORD_FNAME);
    fp = fopen(file_path, "a+");
    if(!fp)
       return -1; 

    get_exclusive_lock(fileno(fp),1);    /* shared_lock.c */
    
    for(ptr = head; ptr; ptr = ptr->next)
    {
       if( (course->course_type == STANDALONE) && ptr->user.add_state == FINISH)
       {
	  fprintf(fp, "%s:x:%s %s:%s:anonymous:Z:%s\n", 
	    ptr->user.username,  ptr->user.first, ptr->user.last,
     	                                              "faculty", ptr->user.id);
	    write_password(ptr->user.username, ptr->user.password, course->course_path);    /* shared_encrypt.c */

       }
       else if(ptr->user.add_state == FINISH && ptr->user.central_state == SUCCESS)
       {
	  fprintf(fp, "%s:x:%s %s:%s:anonymous:Z:%s\n", 
	    ptr->user.username,  ptr->user.first, ptr->user.last,
	    "faculty", ptr->user.id);
       }
    }
    release_lock(fileno(fp));   /* shared_lock.c */
    fclose(fp);

    return 1;
}




CREATED_COURSE_NODE *
find_this_course(CREATED_COURSE_NODE *course_head, const char *dir, const char *subdir)
{
    CREATED_COURSE_NODE *ptr;
    for(ptr = course_head; ptr; ptr = ptr->next)
    {
	if(!strcmp(ptr->course_dir, dir)  && !strcmp(ptr->course_subdir, subdir))
		return ptr;
    }
    return 0;
}
 
int
find_user_in_this_course(CREATED_COURSE_NODE *course, const char *username)
{
    USER_NODE *ptr;
    for(ptr = course->add_head; ptr; ptr = ptr->next)
    {
	if(!strcmp(ptr->user.username, username))
           return 1;
    }
    return 0;
}
	
CREATED_COURSE_NODE *
add_students_to_courses(CREATED_COURSE_NODE *course_head, 
		                        USER_GROUP_INFO_LIST *user_list)
{
      CREATED_COURSE_NODE *course_ptr;
      USER_GROUP_INFO *user_ptr;
      char file_path[MAX_PATH + 1];

      puts("<p>.</p>");
      fflush(stdout);
      /* For each user. */
      for(user_ptr = user_list->head; user_ptr; user_ptr = user_ptr->next)
      {
         puts(".");
         fflush(stdout);
         /* for each course the students has listed in the xml file */
	     for(user_ptr->current = user_ptr->head;  
		  user_ptr->current; user_ptr->current = user_ptr->current->next)
	    {
	        course_ptr = find_this_course(course_head, user_ptr->current->course_dir, 
                                                      user_ptr->current->course_subdir);
	        if(course_ptr &&  (course_ptr->t_state == T_SUCCESS) &&  (course_ptr->course_type != TEMPLATE))
	        {
                snprintf(file_path, MAX_PATH + 1, "%s/%s/%s", 
		            course_ptr->course_path, PEOPLE_DIR, user_ptr->user.username);
		        if(!file_exists(file_path))
		        {
		            if(user_ptr->user.is_new != ERROR_UID)
		            { 
		                if(create_one_person_dir(course_ptr->course_path, user_ptr->user.username))
		                   user_ptr->user.add_state = FINISH;
		                else
		                   user_ptr->user.add_state = FAILED;
	                    if(course_ptr->course_type != STANDALONE)
                           update_central_info(course_ptr, &(user_ptr->user));
		           }
               }	
               else
               {
                   /*printf ("<p>We think %s in course %s exists.</p>", 
                     user_ptr->user.username, user_ptr->current->course_dir); */
		           user_ptr->user.add_state = USEREXISTS;  /* but he may not be in the password file! */
		       }
		       if(!find_user_in_this_course(course_ptr, user_ptr->user.username))
                   course_ptr = add_user_to_course_list(course_ptr, &(user_ptr->user));
	      }
	   }

     }
     return course_head;
} 




static P_NODE*
build_password_list(const char *subdir, const char *dir)
{
 char course_name[MAX_PATH + 1];
 CONFIG_STRUCT conf;
 P_NODE *head = 0;
 
 snprintf(course_name, MAX_PATH + 1, "%s/%s", subdir, dir);
 if(read_configuration_file_ok(course_name,&conf))
    head=build_option_person_list(&conf);
 return head;
}




static
int listed_in_password(const char *username, P_NODE *person_head)
{
 P_NODE *p_ptr;
 
 for(p_ptr = person_head; p_ptr; p_ptr=p_ptr->next)
   if(!strcmp(username,p_ptr->data.username))
      return 1;
      
 return 0;
}

 
       

    


static void
write_students_to_password_file(CREATED_COURSE_NODE *courses)
{
    CREATED_COURSE_NODE *course_ptr;
    char file_path[MAX_PATH + 1];
    FILE *fp;
    P_NODE *person_head;
    /* DFP 9/28/2005 
    Need this string so we can add the course for students who did work in a course,
    the dropped course, back into their course_list. */
    char course_name[MAX_PATH + 1];
     

    

    for(course_ptr = courses; course_ptr; course_ptr = course_ptr->next)
    {
      /* DFP 9/28/2005 Get the name of the course */
     snprintf(course_name, MAX_PATH + 1, "%s/%s",
       course_ptr->course_subdir, course_ptr->course_dir);

      /* students are NOT added to course templates! */
      if(course_ptr->course_type != TEMPLATE)
      {
      
        person_head = build_password_list( course_ptr->course_subdir, course_ptr->course_dir);
        snprintf(file_path, MAX_PATH + 1, "%s/%s",
	                            course_ptr->course_path,PASSWORD_FNAME);
        fp = fopen(file_path, "a");
	if(!fp)
         {
	   course_ptr->t_state = OPEN_ERR; 
           break;
         }
        get_exclusive_lock(fileno(fp), 0);    /* shared_lock.c */   

	for(course_ptr->add_current = course_ptr->add_head; course_ptr->add_current; 
			course_ptr->add_current = course_ptr->add_current->next)
	{
	       if( (course_ptr->add_current->user.group != FACULTY) &&
                    ( (course_ptr->add_current->user.add_state == FINISH) ||
                       ((course_ptr->add_current->user.add_state == USEREXISTS) &&
                        !listed_in_password(course_ptr->add_current->user.username,person_head)) ) )
	      {
	          fprintf(fp, "%s:x:%s %s:%s:anonymous:A:%s\n",
		        course_ptr->add_current->user.username,  
		        course_ptr->add_current->user.first, course_ptr->add_current->user.last,
		        "student", course_ptr->add_current->user.id);
		      if (course_ptr->add_current->user.add_state == USEREXISTS) {
		        /* DFP 9/28/2005 With this type of student, the course was not
		        being added to the course list.  This should fix the problem. */
		        if(!add_course(course_ptr->add_current->user.username,course_name))   /* shared_central_user.c */
	                course_ptr->add_current->user.central_state = C_ERROR; 
		      }

	          if(course_ptr->course_type == STANDALONE)
	          { 
	             write_password(course_ptr->add_current->user.username, 
			       course_ptr->add_current->user.password, course_ptr->course_path);    /* shared_encrypt.c */
	          }
	      } 
	}
        release_lock(fileno(fp));    /* shared_lock.c */
        fclose(fp);
        free_option_person_list(person_head);    /* shared_person_list.c */
      }
    }   /* for... */
}


int
check_course_type(CREATED_COURSE_NODE *course)
{
    CONFIG_STRUCT conf;
    char file[MAX_PATH + 1];

    snprintf(file, MAX_PATH + 1, "%s/%s", course->course_subdir, course->course_dir);
    read_configuration_file (file, &conf);

    if(conf.standalone && course->course_type == STANDALONE)
	 return 1;
    else if((!conf.standalone) && course->course_type == CENTRAL)
	 return 1;
    else
	 return 0;
}

    
     





CREATED_COURSE_NODE *
create_course_with_teachers(CREATED_COURSE_NODE *course_head)
{
      CREATED_COURSE_NODE *ptr;
      CONFIG_STRUCT conf;

      for(ptr = course_head; ptr; ptr = ptr->next)
      {
         puts(".");
         fflush(stdout);
         if(ptr->course_type == TEMPLATE)
          {
            /* the first teacher's username is used as the course_subdir within the templates directory */                                        
            snprintf(ptr->course_subdir, MAX_COURSE_SUBDIR + 1, "T%s", ptr->head->user.username);
            *(ptr->course_subdir + MAX_COURSE_SUBDIR) = '\0';

            snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", 
                                                    TEMPLATE_PATH, ptr->course_subdir, ptr->course_dir);

            
           }  
         else
            snprintf(ptr->course_path, MAX_PATH + 1, "%s%s/%s", 
                                                    COURSE_PATH, ptr->course_subdir, ptr->course_dir);
            
	 if(file_exists(ptr->course_path))     /* shared_file_util.c */
	 {
	    if(ptr->course_type == TEMPLATE)
	       ptr->exists = UPDATE;         /*  Course already exists  */
	    else                             
	    {

	      if(check_course_type(ptr))
	      {
	         ptr->exists = UPDATE;         /*  Course already exists  */
	         ptr =add_teachers(ptr);
	      }
	      else
	       ptr->exists = TYPE_CONFLICT;        
            }

	 }
	 else
	 {
	    ptr->exists = C_NEW;             /* new course */
	    if(create_course_dir(ptr))
	    {
             get_config_default_value(ptr, &conf);
             if(write_config_file(ptr->course_path, &conf))
	     {
	       if(!create_inbox_key_people(ptr->course_path))
		  ptr->exists = DIR_ERR;  //can't create inbox, key, or people dirs 
	       else
	       {
		 if(conf.standalone && !write_logout_html(ptr->course_path))
		    ptr->exists = MSG_ERR;  //can't write logout html file for standalone course or chat log 
	         if( !write_chat_message_log(ptr->course_path))
		    ptr->exists = MSG_ERR;  // chat log 
	         else	
	           ptr =add_teachers(ptr);
	       }
	     }
	     else
	       ptr->exists = CONFIG_ERR; // can't write conf file 
	      
	    }
            else
             {
	      ptr->exists = COURSE_ERR; // can't create course dir 
             }
             
	    
	 }
	 
         ptr->t_state = write_passwd_file(ptr, ptr->head) == 1? T_SUCCESS : OPEN_ERR;

      }
      return course_head;
}




 

/* for debugging only */
void dump_xml_list(XML_COURSE_INFO_LIST *list)
{
 int students = 0;
 
 send_content_type();
 puts("<html><body><pre>\n");
 for(list->current = list->head; list->current; list->current=list->current->next)
  {
   printf("\n\nCourse Code: %s\n", list->current->course_code);
   printf("Title: %s\n", list->current->title);
   printf("Semester: %s\n", list->current->semester);   
   printf("subdir: %s\n", list->current->subdir);   
   printf("dir_id: %s\n", list->current->dir_id);   
   
   for(list->current->user_current = list->current->user_head, students = 0; 
                   list->current->user_current;
                      list->current->user_current = list->current->user_current->next, students++)
                      
    {
     printf("real name: %s<br>\n",  list->current->user_current->data.realname);
     printf("last name: %s<br>\n",  list->current->user_current->data.lastname);
     printf("id number: %s<br>\n", list->current->user_current->data.id);     
    } 
    
    printf("Total users: %d<br><p>\n", students);
                          
                       
   
  }
// puts("</body></html>");
// exit(1);
}     
 
 
/*** for debugging only 
***/ 
 
void dump_user_list(USER_GROUP_INFO_LIST *user_list)
{

 USER_GROUP_INFO *ptr;
 COURSE_GROUP *course_ptr;
 
  
  for(ptr=user_list->head; ptr; ptr = ptr->next)
   {
     printf("lastname= %s<br>\n", ptr->user.last);
     printf("id = %s<br>\n", ptr->user.id);
     for(course_ptr = ptr->head; course_ptr; course_ptr=course_ptr->next)
        {
         printf("subdir : %s<br>\n", course_ptr->course_subdir);
         printf("coursedir : %s<br>\n", course_ptr->course_dir);
        } 
   }

}


int main()
{
   char key[MAX_KEY + 1];
   
   XML_COURSE_INFO_LIST *xml_info_list;                                  /* shared_roster_xml_parser.h */
   CREATED_COURSE_NODE *course_head = 0 ;
   USER_GROUP_INFO_LIST *user_list = 0;
   INDEX_USER_LIST *index_list = 0;
   char roster_path[MAX_PATH + 1];   /* full (relative) path to xml file */ 
   
    cs_cgi_init();    /* shared_cs_util.c */
    
   /* build a linked list of directory names assigned to each course by the user */
    read_parameters( roster_path);
   
   /** NEXT COMMENTED OUT - no authentication is done in this version
   ***
   *** validate_super_key(key, &user);
   ***
   **/ 

   
   /* parse the xml file into a linked list */
   xml_info_list = parse_xml_file(roster_path);   

   update_xml_info_list(xml_info_list);         /* for this version, simply sets all courses to CENTRAL */
   
   
   /* make sure the directory names provided are reasonable */
   check_internal_course_names(xml_info_list);
   

   send_content_type(); 
   print_heading(key);
  
   /* only one admin can create a course at a time */
   get_new_course_lock();    /* shared_new_course_lock.c */
   
   
   /* start list with normal and template courses
   ** and only teacher info 
   */
   course_head = build_normal_template_course_list(xml_info_list);   
   
 
   if(course_head)
   {
      index_list = (INDEX_USER_LIST *)malloc(sizeof(INDEX_USER_LIST));   
      index_list->current =0;
      index_list->head = 0;
      index_list = build_index_user_list(index_list);     /* shared_user_index.c */
      index_list = derive_teacher_username_password(course_head,index_list);
      
      course_head = create_course_with_teachers(course_head);
      
      user_list = build_user_list(xml_info_list);    /* list contains all students, with their courses */
      
      
      if(user_list)
       {
        index_list=derive_student_username_password(user_list,index_list);
        course_head = add_students_to_courses(course_head, user_list);
        write_students_to_password_file(course_head);
        reindex_users("../users");     /* shared_user_index.c  */
        print_course_table(course_head, "Normal and Template Courses");
     } 
   }
   else
     printf("<center><h2>%s</h2></center>", "(No central courses)");

   free_xml_data_list(xml_info_list);
   if(index_list)
     free_index_user_list(index_list);     /* shared_user_index.c */
   if(course_head)
     free_course_f_list(course_head);
   if(user_list)
     free_user_group_info_list(user_list);
     
   free_new_course_lock();   /* shared_new_course_lock.c */  
   unlink(roster_path);

   cs_cgi_destroy();        /* shared_cs_util.c */     
   return 0;
}
    



	       
