#include "shared_xml_course_create_util.h"


static 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, "");
	   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;
}
        

static 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, "");
	   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;
}

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


static 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));
	       ptr->current = ptr->head;
	       ptr->head->next =0;
	       strncpy(ptr->head->course_subdir, info->subdir, MAX_COURSE_SUBDIR +1);
	       //strncpy(ptr->head->course_dir, info->dir_id, MAX_COURSE_NO +1);
	       strncpy(ptr->head->course_dir, info->real_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;
	        strncpy(find->current->course_subdir, info->subdir, MAX_COURSE_NO +1);
	        //strncpy(find->current->course_dir, info->dir_id, MAX_COURSE_NO +1);
	        strncpy(find->current->course_dir, info->real_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;

     get_lang_string(&hdf);

     for(list->current=list->head; list->current; list->current = list->current->next)
     {
       /* if NOT Standalone course */
       if(list->current->course_type != STANDALONE && list->current->course_type != -1)
       {
	  teacher_head = find_all_teachers(list->current);
	  if(!teacher_head)
	  {
	    snprintf(error, 300, "%s %s", 
	      			list->current->course_code, list->current->title);
	    cs_critical_error(ERR_COURSE_X_Y_HAS_NO_TEACHER, error);
	  }
	 ptr = (CREATED_COURSE_NODE *)malloc(sizeof(CREATED_COURSE_NODE));
         if(!ptr)
            cs_critical_error(ERR_MALLOC_FAILED, "build_temp");
            
         strncpy(ptr->course_subdir, list->current->subdir, MAX_COURSE_SUBDIR + 1);   
         strncpy(ptr->course_dir, list->current->real_dir_id, MAX_COURSE_ID +1);
         strncpy(ptr->org_id, 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);
         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)
             strncpy(ptr->course_semester, hdf_get_value(hdf, "course_create_temp", ""), 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;
      }
     }
     hdf_destroy(&hdf);
     return head;
}





static 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(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 */
      }
}




static 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->real_dir_id, MAX_COURSE_ID +1);
         strncpy(ptr->org_id, 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);
         strncpy(ptr->instructor_title, list->current->instructor_title, MAX_INSTRUCTOR +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;
}







    
 void
set_course_table(CREATED_COURSE_NODE *head, const char *prefix)
{
#define MAX_TMP_NAME 50
       	
   CREATED_COURSE_NODE *ptr;
   USER_NODE *t_node;
   int course_count =0;
   int people_count, i =0;
   char name[MAX_TMP_NAME];

   for(ptr = head; ptr; ptr = ptr->next)
   {
	  snprintf(name, MAX_TMP_NAME, "%s.%d.type", prefix, i);
	  cs_set_int_value(name, ptr->course_type);
    
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_subdir", prefix , i);
	  cs_set_value(name, ptr->course_subdir);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_dir", prefix , i);
	  cs_set_value(name, ptr->course_dir);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_no", prefix , i);
	  cs_set_value(name, ptr->course_no);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_title", prefix , i);
	  cs_set_value(name, ptr->course_title);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_semester", prefix , i);
	  cs_set_value(name, ptr->course_semester);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.exists", prefix , i);
	  cs_set_int_value(name, ptr->exists);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.t_state", prefix , i);
	  cs_set_int_value(name, ptr->t_state);
      
          course_count++;
          people_count =0; 
      
      for(t_node = ptr->add_head; t_node; t_node = t_node->next)
      {
	if(strcmp(t_node->user.password, "drop") != 0)
	{
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.is_new", prefix , i, people_count);
	  cs_set_int_value(name, t_node->user.is_new);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.first", prefix , i, people_count);
	  cs_set_value(name, t_node->user.first);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.last", prefix , i, people_count);
	  cs_set_value(name, t_node->user.last);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.id", prefix , i, people_count);
	  cs_set_value(name, t_node->user.id);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.username", prefix , i, people_count);
	  cs_set_value(name, t_node->user.username);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.group", prefix , i, people_count);
	  cs_set_int_value(name, t_node->user.group);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.add_state", prefix , i, people_count);
	  cs_set_int_value(name, t_node->user.add_state);
	  if(ptr->course_type != STANDALONE) 
	  {
	     snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.central_state", prefix , i, people_count);
	     cs_set_int_value(name, t_node->user.central_state);
	  }
        people_count++ ; 
       }
      }
     snprintf(name, MAX_TMP_NAME, "%s.%d.total_users", prefix , i);
     cs_set_int_value(name, people_count); 
     i++;
   }
   if(!strcmp(prefix, "ctr"))   
    cs_set_int_value("ctr_total", course_count); 
   else
    cs_set_int_value("std_total", course_count); 
#undef MAX_TMP_NAME 
} 
    


static DIRECTORY_NAME_NODE *
build_directory_name_list( int course_count, int *standalone)
{
    int i;
    char name[MAX_FILENAME + 1];
    char tmp[20 + 1], *str =0;
    DIRECTORY_NAME_NODE *head = 0, *ptr, *current = 0;

   for(i=1; i <= course_count; i++)
    { 
      snprintf(name, MAX_FILENAME + 1, "Query.c%d_orig_id", i);
      str = hdf_get_value(global_cgi->hdf, name, 0);
      if(str)
      {  
        /* allocate new node */
        ptr = (DIRECTORY_NAME_NODE *)malloc(sizeof(DIRECTORY_NAME_NODE));
        if(!ptr)
           cs_critical_error(ERR_MALLOC_FAILED, "");
        ptr->next = 0;

     
        /* store original internal name as it appears in the
        ** XML file
        */
        snprintf(name, MAX_FILENAME + 1, "c%d_orig_id", i);
        cs_get_required_parameter(name, ptr->name, MAX_COURSE_NO);   /* shared_cgi_util.c */
      
        /* store new internal name, as modified by user */
        snprintf(name, MAX_FILENAME + 1, "c%d_new_id", i);
        cs_get_required_parameter(name, ptr->dir_id, MAX_COURSE_ID); /* shared_cgi_util.c */


        /* store new subdirectory name, as modified by user */
        snprintf(name, MAX_FILENAME + 1, "c%d_subdir_or", i);
        cs_get_required_parameter(name, ptr->subdir, MAX_COURSE_SUBDIR);   /* shared_cgi_util.c */
        snprintf(name, MAX_FILENAME + 1, "c%d_subdir", i);
        cs_get_required_parameter(name, ptr->modified_subdir, MAX_COURSE_SUBDIR);   /* shared_cgi_util.c */
     
     
        /* store course type "Standalone", "Normal" or "Template" */
        snprintf(name, MAX_FILENAME + 1, "c%d_type", i);
        cs_get_required_parameter(name,tmp,20);
        ptr->course_type = !strcmp(tmp,"Standalone")? STANDALONE: (!strcmp(tmp, "Template"))? TEMPLATE: CENTRAL;
     
     
        /* *standalone gets set if one or more courses is "Standalone" */
        if(ptr->course_type == STANDALONE)
          *standalone = 1;
        
       if(!head)
          head = ptr;
       else
         current->next = ptr;
       current = ptr;
      }
    }   
     
  return head;
}    






    
DIRECTORY_NAME_NODE *
get_parameters(char *key, int *standalone, char *roster_path)
{
    DIRECTORY_NAME_NODE *head;
    char tmp[20 + 1];
    int course_count;
    
    cs_get_required_parameter ("id", key, MAX_KEY);    /* shared_cs_util.c */
    
    cs_get_required_parameter ("count", tmp, 20);
    course_count = atoi(tmp);

    cs_get_required_parameter ("roster_path", roster_path, MAX_PATH);
    
    head = build_directory_name_list( course_count, standalone);
    if(!head)
	cs_critical_error(ERR_PARAM_MISSING, "course parameters");

    return head;
}



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



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






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

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, "");
      
      }     
     
     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)
{
   char msg[200];
   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))
    {
       snprintf(msg,200, xml_file_path);
       cs_critical_error(ERR_FILE_X_NOT_FOUND, msg);
    }

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

   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, "");
   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 
**/
void
update_xml_info_list(XML_COURSE_INFO_LIST *list, DIRECTORY_NAME_NODE *modified_head)
{
    DIRECTORY_NAME_NODE *modified_ptr = 0;
    char dir[MAX_COURSE_ID + 1];
//    char error_msg[200];

    if(list->head && modified_head)
    {
       for(list->current=list->head; list->current; list->current=list->current->next)
       {
            /* find this course name in the user-supplied list */
            for(modified_ptr = modified_head; modified_ptr; modified_ptr=modified_ptr->next)    
               if(!strcmp(modified_ptr->name, list->current->dir_id) && !strcmp(list->current->subdir , modified_ptr->subdir))
                   break;
	    if(modified_ptr)
	    {
               /* if a course is a Template, must force first char to be an uppercase 'T' */
	       if( (modified_ptr->course_type == TEMPLATE) && *(modified_ptr->dir_id) !='T')
	         {
                  
                  /* if course name is already at it's maximum length, strip one char from end */ 
                  if(strlen(modified_ptr->dir_id) == MAX_COURSE_ID)
                       *(modified_ptr->dir_id + MAX_COURSE_ID - 1) = '\0';
		  snprintf(dir, MAX_COURSE_ID + 1, "%s%s","T", modified_ptr->dir_id);
	          strncpy(modified_ptr->dir_id, dir, MAX_COURSE_ID + 1);
	         }
	       list->current->course_type = modified_ptr->course_type;
               //strncpy(list->current->dir_id, modified_ptr->dir_id, MAX_COURSE_ID + 1);
               strncpy(list->current->real_dir_id, modified_ptr->dir_id, MAX_COURSE_ID + 1);
               *(list->current->real_dir_id + MAX_COURSE_ID) = '\0';
               strncpy(list->current->subdir, modified_ptr->modified_subdir, MAX_COURSE_SUBDIR + 1);
               *(list->current->subdir + MAX_COURSE_SUBDIR) = '\0';
	    }
           else
            {
	       list->current->course_type = -1;
              //snprintf(error_msg, 200,  list->current->dir_id);
              //cs_critical_error(ERR_DATA_FOR_X_NOT_FOUND, error_msg);
            }   
       }  /* for each course found in the XML file */
    }
    else
      cs_critical_error(ERR_NO_DATA_FOUND, ""); 
} 

 
 
 void
free_teacher_node(USER_NODE *t_head)
{
     USER_NODE *ptr;
     while(t_head)
     {
	 ptr = t_head->next;
	 free(t_head);
	 t_head = ptr;
     }
}
 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;
    }
}   
void free_course_group(COURSE_GROUP *head)
{
	COURSE_GROUP *ptr;
	while(head)
	{
           ptr = head->next;
	   free(head);
	   head = ptr;
	}
}
 void
free_user_group_info_list(USER_GROUP_INFO_LIST *list)
{
   USER_GROUP_INFO *ptr;
    while(list->head)
    {
	ptr = list->head->next;
	if(list->head->head)
           free_course_group(list->head->head);
        free(list->head);
        list->head = ptr;
    }
    free(list);
}    



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




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




static int write_org_info(CREATED_COURSE_NODE *course)
{
   char org_id_file[MAX_PATH +1];
   FILE *fp;
   snprintf(org_id_file, MAX_PATH +1, "%s/%s", course->course_path, "org_id.txt");
   fp = fopen(org_id_file, "w");
   if(!fp)
      return 1;
   fprintf(fp, "%s\n", course->org_id);
   fclose(fp);
   return 0; 
}



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




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



static 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, "");
      
       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;

}
          

	  


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



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




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




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, int *star)
{
 P_NODE *p_ptr;
 
 for(p_ptr = person_head; p_ptr; p_ptr=p_ptr->next)
 {
   if(!strcmp(username,p_ptr->data.username))
   {
      if( *(p_ptr->data.realname) == '*' || *(p_ptr->data.realname) == '+')
	      *star = 1;
      return 1;
   }
 }
 return 0;
}

static USER_NODE *initialize_usernode(P_NODE *one)
{
      USER_NODE *ptr;
      ptr = (USER_NODE *) malloc(sizeof(USER_NODE));
      if(!ptr)
	   cs_critical_error(ERR_MALLOC_FAILED, "initialize_usernode");
      strncpy(ptr->user.first, one->data.realname, MAX_NAME +1);
      strncpy(ptr->user.last, one->data.lastname, MAX_NAME +1);
      strncpy(ptr->user.username, one->data.username, MAX_USERNAME +1);
      strncpy(ptr->user.id, one->data.id, MAX_ID +1);
      memset(ptr->user.password, 0, MAX_PASSWORD +1);
      strncpy(ptr->user.password, "drop",  MAX_PASSWORD +1);
      ptr->user.group = one->data.group;
      ptr->next =0;
      return ptr;
}

static int find_person_in_current_roster(CREATED_COURSE_NODE *course, P_NODE *person)
{
      
     if(*(person->data.realname) == '*' || *(person->data.realname) == '+')
	  return 1;
     
     
     for(course->add_current = course->add_head;
		  course->add_current; course->add_current = course->add_current->next)
     {
	 if(strcmp(course->add_current->user.id, person->data.id) == 0)
		 return 1;

     }
     return 0;
}

static CREATED_COURSE_NODE * 
check_all_passwd_data_in_xml( P_NODE *person_head, CREATED_COURSE_NODE *course_ptr)
{
    P_NODE *ptr;
    USER_NODE *user, *start;

    int found = 0;
    for(ptr = person_head; ptr; ptr = ptr->next)
    {
        found = find_person_in_current_roster(course_ptr, ptr);
        if(!found)
	{
              user = initialize_usernode(ptr);
	      start = course_ptr->add_head;
              while(start->next)
	      {
		 start = start->next;
	      }
	     start->next = user; 
	}	
    }
    return course_ptr;
}
       
static void course_has_add_drop(CREATED_COURSE_NODE *ptr, int *drop, int *add)
{
      for(ptr->add_current = ptr->add_head; ptr->add_current; ptr->add_current = ptr->add_current->next)
      {
	   if(strcmp(ptr->add_current->user.password, "add") == 0)
		*add = 1;
	   if(strcmp(ptr->add_current->user.password, "drop") == 0)
		*drop = 1;
                 
      }
}

static void  write_to_add_list(CREATED_COURSE_NODE *course)
{
      FILE *fp;
      char path[MAX_PATH +1];
      char *time_string;

      snprintf(path, MAX_PATH +1, "%s/%s", course->course_path, ADD_LIST_FNAME);
      fp = fopen(path, "a+");
      if(!fp)
	    return;
      time_string = get_time_string(); 
      for(course->add_current = course->add_head; course->add_current; course->add_current = course->add_current->next)
      {
	   if(strcmp(course->add_current->user.password, "add") == 0)
		  fprintf(fp, "<tr><td>%s</td><td>%s</td><td>%s %s</td><td>%s</td></tr>\n", 
				  course->add_current->user.id, 
				  course->add_current->user.username, 
				  course->add_current->user.first, 
				  course->add_current->user.last, time_string);

      }
      fclose(fp);
      free(time_string);

}



static void  write_to_drop_list(CREATED_COURSE_NODE *course)
{
      FILE *fp;
      char path[MAX_PATH +1];
      char *time_string;

      snprintf(path, MAX_PATH +1, "%s/%s", course->course_path, DROP_LIST_FNAME);
      fp = fopen(path, "w");
      if(!fp)
	    return;
      time_string = get_time_string();
      fprintf(fp, "%s\n", time_string);
      free(time_string);
      for(course->add_current = course->add_head; course->add_current; course->add_current = course->add_current->next)
      {
	   if(strcmp(course->add_current->user.password, "drop") == 0 && course->add_current->user.group != FACULTY)
		  fprintf(fp, "%s:x:%s:%s:anonymous:A:%s\n", 
				  course->add_current->user.username, 
				  course->add_current->user.first, 
				  course->add_current->user.group == FACULTY ? "faculty":"student", 
				  course->add_current->user.id );

      }
      fclose(fp);
}


void write_add_drop_list(CREATED_COURSE_NODE *courses)
{
     CREATED_COURSE_NODE *ptr;
     int drop =0;
     int add =0;

     for(ptr = courses; ptr; ptr = ptr->next)
     {
	    course_has_add_drop(ptr, &drop, &add);
	    if(add)
            write_to_add_list(ptr);
        if(drop)
            write_to_drop_list(ptr);
	    drop = 0;
	    add =0;
     }
}


COURSE_GROUP * 
initalize_course_group(CREATED_COURSE_NODE *course)
{
      COURSE_GROUP *ptr; 
      
      ptr = (COURSE_GROUP *)malloc(sizeof(COURSE_GROUP));
      if(!ptr)
	   cs_critical_error(ERR_MALLOC_FAILED, "initialize_course_group");
      strncpy(ptr->course_subdir, course->course_subdir, MAX_COURSE_SUBDIR +1);
      strncpy(ptr->course_dir, course->course_dir, MAX_COURSE_ID +1);
      ptr->next = 0;
      return ptr;
}
    
COURSE_GROUP * 
is_this_course_in_check_list(COURSE_GROUP *check_head, CREATED_COURSE_NODE *course_ptr, int *found) 
{
   COURSE_GROUP *ptr;
   int is_in = 0;

   if(!check_head) 
   {
      check_head = initalize_course_group(course_ptr);
      *found = 0;
   }
   else
   {
      for(ptr = check_head; ptr; ptr = ptr->next)
      {
	  if(strcmp(ptr->course_subdir, course_ptr->course_subdir) == 0 &&
	       strcmp(ptr->course_dir, course_ptr->course_dir) == 0)
	  {
	       is_in = 1;
	       *found = 1;
	       break;
	  } 

      }
      if(!is_in)
      {
          *found = 0;
	  ptr = check_head->next;
	  while(ptr)
	  {
	      ptr = ptr->next;
	  }
	  ptr = initalize_course_group(course_ptr);
      }

   }
   return check_head; 
}

int  mark_star(FILE *fp, const char *username)
{
    int found = 0;
	char line[200];
	long offset = 0;
	char qmark = '?';
	char *ptr;
    
	fseek(fp, 0, SEEK_SET);
	while( !found && fgets(line, 199, fp))
	{
	    if(*line != '?')
		{
		   ptr = strchr(line, ':');
		   if(!ptr)
		      return 0;
		   *ptr = '\0';
           if(!strcmp (line, username))
		   {
		       fseek (fp, offset, SEEK_SET);
			   if(fwrite (&qmark, sizeof(char), 1, fp) != 1)
			        return 0;
			   found =1;
		   }
		}
		offset = ftell(fp);
	}
	return 1;
}


CREATED_COURSE_NODE *
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;
    COURSE_GROUP *check_head = 0; 
    int found = 0;
    char course_name[MAX_PATH];
    int is_in_passwd = -1;
    int student_count = 0;
    int star = 0; 
    
    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");
        fp = fopen(file_path, "r+");
	if(!fp)
         {
	   course_ptr->t_state = OPEN_ERR; 
           break;
         }
        get_exclusive_lock(fileno(fp), 0);    /* shared_lock.c */   

        student_count = 0;
	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.add_state == USEREXISTS) 
                   is_in_passwd = listed_in_password(course_ptr->add_current->user.username,person_head, &star);
           if(is_in_passwd && star && course_ptr->add_current->user.group != FACULTY) 
		   {
		      mark_star(fp, course_ptr->add_current->user.username);
		      fseek(fp, 0, SEEK_END);
	          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);
		      star = 0;
			  is_in_passwd = 0;
		   }
		  
	      else if( (course_ptr->add_current->user.group != FACULTY) &&
                    ( (course_ptr->add_current->user.add_state == FINISH) ||
                       ((course_ptr->add_current->user.add_state == USEREXISTS) &&
                        !is_in_passwd) ) )
	      {
		         fseek(fp, 0, SEEK_END);
	             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 == CENTRAL)
		   {

                     if((course_ptr->add_current->user.add_state == USEREXISTS) &&
                        !is_in_passwd)
		     {
                         snprintf(course_name, MAX_PATH , "%s/%s", course_ptr->course_subdir, course_ptr->course_dir);
      	                 if(!add_course(course_ptr->add_current->user.username,course_name))   
	                   course_ptr->add_current->user.central_state = C_ERROR;
		     }
                             

		     strncpy(course_ptr->add_current->user.password, "add", MAX_PASSWORD +1);
                   }
	          else 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 */
	          }
	      }
	     if(course_ptr->add_current->user.group == STUDENT)
		 student_count++;    
	}
        release_lock(fileno(fp));    /* shared_lock.c */
        fclose(fp);
        if(course_ptr->course_type == CENTRAL && student_count > 0 ) 
	{
	      check_head = is_this_course_in_check_list(check_head, course_ptr, &found); 
              if(!found)
	          course_ptr = check_all_passwd_data_in_xml(person_head, course_ptr);

	}
     free_option_person_list(person_head);    /* shared_person_list.c */
    }
   }   /* for... */
    free_course_group(check_head);
    return courses;
}


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

    
     
static int  update_org_id(CREATED_COURSE_NODE *course)
{
      char org_id_file[MAX_PATH +1];
      char org_id[MAX_PATH +1];
      FILE *fp;
      int found =0;

      snprintf(org_id_file, MAX_PATH +1, "%s/%s", course->course_path, "org_id.txt");
      fp = fopen(org_id_file, "a+");
      if(!fp)
	  return 1;
      while(fgets(org_id,MAX_PATH +1, fp))
      {
	  org_id[strlen(org_id) -1] = '\0';
          if(!strcmp(org_id, course->org_id))
	  {
                 found = 1;
		  break;
	  }
      } 
      if( !found)
      {
	 if(fseek(fp, 0, SEEK_END))
		 return 1;
	 fprintf(fp, "%s\n", course->org_id);
      }

      fclose(fp);
      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;        
            }
	    update_org_id(ptr);

	 }
	 else
	 {
	    ptr->exists = C_NEW;             /* new course */
	    if(create_course_dir(ptr))
	    {
             write_org_info(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);   
   printf("real_dir: %s\n", list->current->real_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("first= %s<br>\n", ptr->user.first);
     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);
        } 
   }

}



	       

void
set_course_data_record_log(CREATED_COURSE_NODE *head, const char *prefix, const char *action)
{
#define MAX_TMP_NAME 50
       	
   CREATED_COURSE_NODE *ptr;
   USER_NODE *t_node;
   int course_count =0;
   int drop_count =0;
   int people_count, i =0;
   char name[MAX_TMP_NAME];

   for(ptr = head; ptr; ptr = ptr->next)
   {
	  snprintf(name, MAX_TMP_NAME, "%s.%d.type", prefix, i);
	  cs_set_int_value(name, ptr->course_type);
    
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_subdir", prefix , i);
	  cs_set_value(name, ptr->course_subdir);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_dir", prefix , i);
	  cs_set_value(name, ptr->course_dir);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_org", prefix , i);
	  cs_set_value(name, ptr->org_id);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_no", prefix , i);
	  cs_set_value(name, ptr->course_no);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_title", prefix , i);
	  cs_set_value(name, ptr->course_title);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.course_semester", prefix , i);
	  cs_set_value(name, ptr->course_semester);
	  snprintf(name, MAX_TMP_NAME, "%s.%d.exists", prefix , i);
	  cs_set_int_value(name, ptr->exists);
      
          course_count++;
          people_count =0;
		  drop_count = 0;

      for(t_node = ptr->add_head; t_node; t_node = t_node->next)
      {
	  if(strcmp(t_node->user.password, "drop") == 0)
	      drop_count++;
	  if(strcmp(t_node->user.password, "add") == 0 || (t_node->user.group == FACULTY && strcmp(t_node->user.password, "drop") != 0) )
	  {
	     snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.first", prefix , i, people_count);
	     cs_set_value(name, t_node->user.first);
	     snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.last", prefix , i, people_count);
	    cs_set_value(name, t_node->user.last);
	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.id", prefix , i, people_count);
	    cs_set_value(name, t_node->user.id);
	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.username", prefix , i, people_count);
	    cs_set_value(name, t_node->user.username);
	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.group", prefix , i, people_count);
	    cs_set_int_value(name, t_node->user.group);

	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.is_new", prefix , i, people_count);
	    cs_set_int_value(name, t_node->user.is_new);

	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.add_state", prefix , i, people_count);
	    cs_set_int_value(name, t_node->user.add_state);

	    snprintf(name, MAX_TMP_NAME, "%s.%d.users.%d.central_state", prefix , i, people_count);
	    cs_set_int_value(name, t_node->user.central_state);

           people_count++ ; 
	  }

      }
	  if(people_count || drop_count)
	      update_roster_log(action, "", ptr->course_no, ptr->course_title, people_count, drop_count, "Success"); /* shared_wnec_roster_log.h */
     i++;
   }
   if(!strcmp(prefix, "ctr"))   
    cs_set_int_value("ctr_total", course_count); 
#undef MAX_TMP_NAME 
} 
    

