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

#include "global.h"
#include "custom.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_update_user_info.h"
#include "manhat-lib/shared_delete.h"




/* The administrator is given a chance to alter the following data items found in the XML
** file before the course is created.
**
** The name of the directory where the course is stored (the 'internal course name')
** The name of the subdirectory (under the standard 'courses' directory) where the course will
** be stored.
** 
** This data structure keeps track of these 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];
  
    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;





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, "find_all_teachers()");
	   ptr->next = 0;
	   strncpy(ptr->user.first, 
		   info->user_current->data.realname, MAX_NAME + 1);
	   strncpy(ptr->user.last,
		   info->user_current->data.lastname, MAX_NAME + 1);
	   strncpy(ptr->user.id,
		   info->user_current->data.id, MAX_ID +1);
	   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, "find_all_uses_in_standalone()");
	   ptr->next =0;
	   strncpy(ptr->user.first, 
		   info->user_current->data.realname, MAX_NAME +1);
	   strncpy(ptr->user.last,
		   info->user_current->data.lastname, MAX_NAME +1);
	   strncpy(ptr->user.id,
		   info->user_current->data.id, MAX_ID +1);
	   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));
	       strncpy(ptr->user.first, 
	         info->user_current->data.realname,MAX_NAME +1);
	       strncpy(ptr->user.last, 
	         info->user_current->data.lastname,MAX_NAME +1);
	       strncpy(ptr->user.id, 
	         info->user_current->data.id,MAX_ID +1);
	       if(strlen(info->user_current->data.username)>0)
	         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));
	       /* There is a bug here if the subdir name is longer than MAX_COURSE_NO.
	       The malloc above is uninitialized.  So when the sub_dir name is longer than 
	       the above constant, the string is not null terminated.  The next line assures that
	       the above structure is intialized to 0,  so the string will be null terminated.
    		DFP 6/21/2005*/
    	   memset(ptr->head, '\0', sizeof(COURSE_GROUP));

	       ptr->current = ptr->head;
	       ptr->head->next =0;
	       strncpy(ptr->head->course_subdir, info->subdir, MAX_COURSE_NO +1);
	       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));
	       /* There is a bug here if the subdir name is longer than MAX_COURSE_NO.
	       The malloc above is uninitialized.  So when the sub_dir name is longer than 
	       the above constant, the string is not null terminated.  The next line assures that
	       the above structure is intialized to 0,  so the string will be null terminated.
    		DFP 6/21/2005*/
    	   memset(find->current->next, '\0', sizeof(COURSE_GROUP));
	        find->current = find->current->next;
	        strncpy(find->current->course_subdir, info->subdir, MAX_COURSE_NO +1);
	        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;
     /*char error[300];*/
     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->course_code);*/
	  }
	 ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE));
         if(!ptr)
            cs_critical_error(ERR_MALLOC_FAILED, "build_normal_template_course_list()");
            
         strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR + 1);   
         strncpy(ptr->course_dir, list->current->dir_id, MAX_COURSE_ID +1);
         strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO +1);
         strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE +1);
         ptr->course_type = list->current->course_type;
         /*DFP 6/27/2005.  Set state */
         ptr->t_state = T_SUCCESS;
         if(ptr->course_type == TEMPLATE) {
            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);
        }
         /* change semester to a standard value for course templates */
	 if(list->current->course_type == TEMPLATE)
             strncpy(ptr->course_semester, "Course Template", MAX_SEMESTER + 1);
	 else
             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;

}



static void
process_standalone_username(USER_NODE *one, USER_NODE *all)
{
    char username[MAX_USERNAME +1];
    int try;

    one->user.is_new = NEW;     /* assume this to start */
    
    if(!strlen(one->user.username))   /* if username wasn't supplied in XML file */
     {
       derive_username (one->user.first, one->user.last,
	       one->user.id, username, MAX_USERNAME+1);
       for(try = 1;
	     (try <= MAX_USERNAME_TRIES) && (find_this_username(all, username));
	                   try++)
         {
	   derive_another_username(one->user.first, one->user.last, one->user.id, 
			   username, MAX_USERNAME + 1, try);
         }
      if(try > MAX_USERNAME_TRIES)
	     one->user.is_new = ERROR_UID;
     }
    else                                 /* username was supplied in XML file */
     {
         strncpy(username, one->user.username, MAX_USERNAME + 1);
         *(username + MAX_USERNAME) = '\0';
         if(find_this_username(all, username))
              one->user.is_new = ERROR_UID;
     }    
    
    
    if(one->user.is_new != ERROR_UID) 
      {
            one->user.is_new = NEW;
	    strncpy(one->user.username, username, MAX_USERNAME + 1);
	    derive_password (one->user.username, one->user.first,one->user.last,
			one->user.id, one->user.password, MAX_PASSWORD +1); /* shared_authenticate.c */
      }
}




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






void
update_standalone_username(CREATED_COURSE_NODE *sta_list)
{
    CREATED_COURSE_NODE *ptr;
    USER_NODE *t_node, *t_ptr;
    
    for(ptr = sta_list; ptr; ptr = ptr->next)
    {
      for(t_node = ptr->add_head; t_node; t_node = t_node->next)
      {
         process_standalone_username(t_node, ptr->add_head);
	 if(t_node->user.group == FACULTY)
	 {
           t_ptr =find_teacher_in_course_head(ptr->head, t_node->user.id);
	   if(t_ptr)
	   {
	      strncpy(t_ptr->user.username, t_node->user.username, MAX_USERNAME +1);
	      strncpy(t_ptr->user.password, t_node->user.password, MAX_PASSWORD +1);
	      t_ptr->user.is_new = t_node->user.is_new;
	   }
	 } 
      }
    }
}

       
       
       
/* 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));
         strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR +1);
         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);
         strncpy(ptr->course_no, list->current->course_code, MAX_COURSE_NO +1);
         strncpy(ptr->course_title, list->current->title, MAX_COURSE_TITLE +1);
         ptr->course_type = list->current->course_type;
         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()
{
   printf("<html><head><title>%s</title></head>%s\n", "Course List", "<body>");
}



    
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)?
                                "Delete Successful": (t_node->user.add_state == USEREXISTS)?
                                "Existing User": "Delete 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 */

}



void
free_directory_name_list(DIRECTORY_NAME_NODE *head)
{
    DIRECTORY_NAME_NODE *ptr;
    
    while(head)
    {
	ptr = head->next;
        free(head);
        head = ptr;
    }
}    



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) ||
                  (list->current->course_type == STANDALONE))
      {
      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, "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);   /*shared_roster_xml_parser.c */
   
   free(buf);
   return list;
}









/** adds correct internal name and course type to 
*** the master course list 
**/
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_invalid(username)        /* shared_authenticate.c */
	          || 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 */
          {
           strncpy(username, ptr->username, MAX_USERNAME + 1);
           *(username + MAX_USERNAME) = '\0';
           strtrm(username);   /* shared_strtrm.c */
           if(username_invalid(username)    /* shared_authenticate.c */
                 || username_exist(index_list, username))
              ptr->is_new = ERROR_UID;
          }
       
         if(ptr->is_new != ERROR_UID)
            {
               ptr->is_new = NEW;
	       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 */
      {

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


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

    conf->login_expire = 0;                        
    conf -> key_expire = 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->future6 = 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;
}



static int
create_inboxes_directory (const char *crs )
{
  char path[MAX_PATH + 1];

   snprintf (path, MAX_PATH + 1, "%s/%s", crs, INBOXES_DIR);
   if(mkdir (path, 0777))
         return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s",  crs, INBOXES_DIR ,ANONYMOUS_DIR);
   if(mkdir (path, 0777))
        return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s",  crs, INBOXES_DIR, ASSIGNMENTS_DIR);
   if(mkdir (path, 0777))
          return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, DISCUSSION_DIR);
   if(mkdir (path, 0777))
       return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, TEAM_DIR);
   if(mkdir (path, 0777))
        return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s",  crs, INBOXES_DIR, INET_DIR);
   if(mkdir (path, 0777))
      return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, LOUNGE_DIR);
   if(mkdir (path, 0777))
       return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s",  crs, INBOXES_DIR, MAIL_DIR);
   if(mkdir (path, 0777))
       return 0;

    snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, HANDOUTS_DIR);
    if(mkdir (path, 0777))
        return 0;

     snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, TEAM_TEACH_DIR);
   if(mkdir (path, 0777))
        return 0;

    snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, GRADES_DIR);
     if(mkdir (path, 0777))
        return 0;

    snprintf (path, MAX_PATH + 1, "%s/%s/%s", crs, INBOXES_DIR, SELFTEST_DIR);
   if(mkdir (path, 0777))
      return 0;

   snprintf (path, MAX_PATH + 1, "%s/%s/%s",  crs, INBOXES_DIR, LECTURES_DIR);
  if(mkdir (path, 0777))
	 return 0;


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




int
create_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;
  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>", EXIT_URL, 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 */
  
}




int
no_error_mark_passwd_file (const char *username, const CONFIG_STRUCT *conf)
{
  FILE *fp;
  int fd;
  int found = 0;
  long offset = 0;
  char line[200];
  char *ptr;
  char qmark = '?';
  char passwd_fname[MAX_PATH + 1];

  snprintf (passwd_fname, MAX_PATH + 1, "%s%s", conf->course_path, PASSWD_FNAME);
  fp = fopen (passwd_fname, "r+");	/* open for reading and writing */
  
  if (!fp)
    return 0;
  fd = fileno(fp);
  get_exclusive_lock(fd, 1);                      /* shared_lock.c */

  while (!found && fgets (line, 199, fp))
    {
      if (*line != '?')		/* skip usernames that start with ? */
	{
	  ptr = strchr (line, ':');
	  if (!ptr)
	    cs_critical_error (ERR_PASSWD_PARSE_ERROR, line);
	  *ptr = '\0';
	  if (!strcmp (line, username))
	    {
	      fseek (fp, offset, SEEK_SET);
	      if (fwrite (&qmark, sizeof (char), 1, fp) != 1)
		cs_critical_error (ERR_FWRITE_FAILED, passwd_fname);
	      found = 1;
	    }

	}
      offset = ftell (fp);
    }

  release_lock(fd);
  fclose (fp);

  return found? 1: 0;
}





CREATED_COURSE_NODE *
delete_user_from_course_list(CREATED_COURSE_NODE *course, USER *ptr)
{
  int deleted;			/* was the user's directory removed? */
  char dirname[MAX_PATH + 1];
  int exists;

  CONFIG_STRUCT conf;
    
    read_configuration_file (course->course_path, &conf);			/* shared_util.c */

#ifdef DEBUGPRINT    
    printf("<p>Read configuration file. conf.standalone = %d</p>", (int) conf.standalone);
#endif
    
    if(!conf.standalone) {
#ifdef DEBUGPRINT
        printf("<p>About to call delete_course.</p>");
#endif
        snprintf(dirname, MAX_PATH+1, "%s/%s", course->course_subdir, course->course_dir);
       delete_course(ptr->username, dirname );    /* delete course in central course list file - shared_delete.c */
    }
    exists = no_error_mark_passwd_file (ptr->username, &conf);
    if (exists) {
        deleted = !user_contributed (ptr->username, &conf);  /* shared_delete.c */
        if (deleted)
         {
          snprintf (dirname, MAX_PATH + 1, "%s%s/%s",
    		conf.course_path, PEOPLE_DIR, ptr->username);
          kill_directory(dirname);   /* shared_file_util.c */
         }
    }
    return course;
}

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, "add_user_to_course_list()");
      
       strncpy(target->user.username, ptr->username, MAX_USERNAME + 1);
       strncpy(target->user.first, ptr->first, MAX_NAME +1);
       strncpy(target->user.password, ptr->password, MAX_PASSWORD + 1);
       strncpy(target->user.last, ptr->last, MAX_NAME +1);
       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);

     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)
    {
#ifdef DEBUGPRINT
        printf("<p>Looking for %s, looking at %s</p>", username, ptr->user.username);
#endif
	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];

      for(user_ptr = user_list->head; user_ptr; user_ptr = user_ptr->next)
      {
	 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
		     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;
} 

	
CREATED_COURSE_NODE *
drop_students_from_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];
#ifdef DEBUGPRINT
      printf("<p>In drop students from courses. </p>");
#endif
      for(user_ptr = user_list->head; user_ptr; user_ptr = user_ptr->next)
      {
#ifdef DEBUGPRINT
        printf ("<p>In first for loop.</p>");
#endif
	    for(user_ptr->current = user_ptr->head;  
		user_ptr->current; user_ptr->current = user_ptr->current->next)
	    {
#ifdef DEBUGPRINT 
	     printf("<p>In second for loop.</p>");
#endif
	     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)) { /* Student  in course */
#ifdef DEBUGPRINT
		            printf("<p>User %s exists!</p>", user_ptr->user.username);
#endif
		            user_ptr->user.add_state = USEREXISTS;  /* but he may not be in the password file! */
                   course_ptr = delete_user_from_course_list(course_ptr, &(user_ptr->user));
                    user_ptr->user.add_state = FINISH;
                }
                else {
                    user_ptr->user.add_state = FAILED;
#ifdef DEBUGPRINT
                    printf("<p>Did not find user %s in course.</p>", user_ptr->user.username);
#endif
                }
                course_ptr = add_user_to_course_list(course_ptr, &(user_ptr->user));
	     }
#ifdef DEBUGPRINT
	     else {

	        printf("<p>Did not find course %s/%s.</p>", user_ptr->current->course_subdir, user_ptr->current->course_dir );
	        if(!course_ptr) {
	            printf("<p>Course ptr null.</p>");
	        }
	        else {
	            printf("<p>Course state = %d, course_type = %d</p>", course_ptr->t_state,
	             course_ptr->course_type);
	        }
	    }
#endif
	 }

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

 
       

    


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;
    
    

    for(course_ptr = courses; course_ptr; course_ptr = course_ptr->next)
    {
      /* 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->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)
      {
         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_inboxes_directory (ptr->course_path) ) 
		  ptr->exists = DIR_ERR;  //can't create inbox, key, or people dirs 
	       if(!create_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;
}



void
create_standalone_with_students(CREATED_COURSE_NODE *stand_head) 
{
      CREATED_COURSE_NODE *ptr;
      char file_path[MAX_PATH +1];

      for(ptr = stand_head; ptr; ptr = ptr->next)
      {
	  if(ptr && (ptr->t_state == T_SUCCESS))
	  {
	    for(ptr->add_current = ptr->add_head; ptr->add_current; 
			  ptr->add_current = ptr->add_current->next)
	    {
		if(ptr->add_current->user.group != FACULTY)
		{
                  snprintf(file_path, MAX_PATH +1, "%s/%s/%s", 
		    			ptr->course_path,PEOPLE_DIR, ptr->add_current->user.username);
	          if(!file_exists(file_path))
	          {
	             if(ptr->add_current->user.is_new != ERROR_UID)
		     { 
		       if(create_one_person_dir(ptr->course_path, ptr->add_current->user.username))
		        ptr->add_current->user.add_state = FINISH;
		      else
		        ptr->add_current->user.add_state = FAILED;
		    }
                  }	
                  else
		     ptr->add_current->user.add_state = USEREXISTS;
		}
		else 
		{
		   if(ptr->exists == C_NEW)
			   ptr->add_current->user.add_state = FINISH;
		   else
			   ptr->add_current->user.add_state = USEREXISTS;
		}
	    }
	  }
      }
}

 

/* 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()
{
   
   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);   /* parse xml file */

   /* incorporate any directory name changes made by the user into the xml_info_list */
   update_xml_info_list(xml_info_list);         /* add correct course type and internal name to list */
   
   
   
   /* make sure the directory names provided are reasonable */
   check_internal_course_names(xml_info_list);
   

   send_content_type(); 
   print_heading();
  
   /* 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 */
      /* DFP 6/24/2005 Don't need to do the next two steps. */
      /*
      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);
          /* DFP 6/24/2005 */
          /*This will become drop students from courses */
          /*course_head = add_students_to_courses(course_head, user_list);*/
          course_head = drop_students_from_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;
}
    



	       
