#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <dirent.h>

#include <ctype.h>  /* for isdigit(), etc. */

#include <unistd.h>
              
#include "../global.h"
#include "../custom.h"

#include "shared_util.h"
#include "shared_lock.h"
#include "shared_authenticate.h"
#include "shared_file_util.h"

#include "shared_super_util.h"  /* for type definitions */
#include "shared_strtrm.h"
#include "shared_server_string.h"
#include "shared_cs_util.h"



void list_server_commands(ADMIN_CONFIG_STRUCT *conf);
void list_course_commands(ADMIN_CONFIG_STRUCT *conf);
void list_people_commands(ADMIN_CONFIG_STRUCT *conf);

void
read_param (char *key)
{
   cs_get_required_parameter ("id", key, MAX_KEY);
}

static
int admin_config_value(char *name)
{
	 char tmp[20];

	 cs_get_optional_parameter(name, tmp, 19);
	 if(strlen(tmp))
	       return (atoi(tmp));
	 else 
	   return 0;
}

void
get_cgi_admin_config_values(ADMIN_CONFIG_STRUCT *conf)
{

   cs_get_optional_parameter("page_title", conf->page_title, MAX_ADMIN_PAGE_TITLE);
   strtrm(conf->page_title);

   conf->is_super_user     = 0;

   conf->create_new_course = admin_config_value("create_new_course");
   conf->delete_courses    = admin_config_value("delete_courses");
   conf->config_courses    = admin_config_value("config_courses");
   conf->change_course_access    = admin_config_value("change_courses");
   conf->archive_courses    = admin_config_value("archive_courses");
   conf->course_disk_usage    = admin_config_value("course_disk_usage");
   conf->purge_postoffice_message    = admin_config_value("purge_postoffice_message");
   conf->admin_surveys     = admin_config_value("admin_survey");

   conf->add_admin         = admin_config_value("add_admin");
   conf->del_admin         = admin_config_value("del_admin");
  conf->grant_admin       = admin_config_value("grant_admin");

  conf->search_profiles   = admin_config_value("search_profile");
   conf->whos_on           = admin_config_value("whos_on");
  conf->statistics        = admin_config_value("statistics");

   conf->disk_space        = admin_config_value("disk_space");

  conf->chat_server       = admin_config_value("chat_server");

  conf->lock_server       = admin_config_value("lock_server");

  conf->clean_up          = admin_config_value("clean_up");

}


void
check_str(char *str,  const char * msg)
{
    char *ptr;
    
    for(ptr = str; (*ptr); ptr++)
    {
       if(!(*ptr == '_') && !isdigit(*ptr) && !isalpha(*ptr))
	       cs_critical_error(msg, "");
    }
}













	






void
write_to_index(const char *username, const char *realname)
{
	FILE *fp;
	char fname[MAX_PATH +1];
	
	snprintf(fname, MAX_PATH +1, "../%s/%s/%s", USERS_DIR, ADMIN_DIR,  USER_INDEX_FNAME);
        fp = fopen(fname, "a+");
	if(!fp)
	  cs_critical_error( ERR_FOPEN_WRITE_FAILED, "");
	get_exclusive_lock(fileno(fp), 1);
	fprintf(fp, "%s:%s\n", username, realname);
	release_lock(fileno(fp));
	fclose(fp);
}










void
get_admin_user_passwd(const char *username, char *passwd)
{
	FILE *fp;
	char fname[MAX_PATH +1];

	snprintf(fname, MAX_PATH +1, "../%s/%s/%c/%s/%s",
			USERS_DIR, ADMIN_DIR, sub_dir_name(username), username, PASSWD_FNAME);
	fp = fopen(fname, "r");
	if(!fp)
	  cs_critical_error(ERR_FOPEN_READ_FAILED, "");
	if(!fgets(passwd, MAX_ENCRYPTED_PASSWORD + 1, fp) )
	{
	  fclose(fp);
	  cs_critical_error(ERR_FREAD_FAILED, "");
	}
	strtrm(passwd);   /* shared_strtrm.c */
	fclose(fp);
}







void set_one_oper_value(const char *prefix, int num, char *value)
{
  #define MAX_TMP_NAME 40
  char name[MAX_NAME];

  snprintf(name, MAX_NAME, "%s.%d", prefix, num);
  cs_set_value(name, value);
  

  #undef MAX_TMP_NAME 
}

void 
super_conf_info_table(ADMIN_CONFIG_STRUCT *conf,  char *username,  char *realname) 
{
    char server_string[MAX_PATH +1];
    char url[MAX_PATH +1];
    int i = 0;

    cs_set_current_time();
    cs_set_server_name();
    cs_set_value("username", username); 
    cs_set_value("realname", realname); 
   
    if(conf->create_new_course)
    {
       set_one_oper_value("conf_course", i, "create_course");
       i++;
    }
    
    if(conf->delete_courses)
    {
       set_one_oper_value("conf_course", i, "delete_course");
       i++;
    }
    if(conf->config_courses)
    {
       set_one_oper_value("conf_course", i, "configure_course");
       i++;
    }

    if(conf->change_course_access)
    {
       set_one_oper_value("conf_course", i, "change_course_access");
       i++;
    }
    if(conf->archive_courses)
    {
       set_one_oper_value("conf_course", i, "archive_courses");
       i++;
    }


    if(conf->admin_surveys)
       set_one_oper_value("conf_course", i, "surveys");


    i =0; 
    if(conf->search_profiles)
    {
       set_one_oper_value("conf_people", i, "profile");
       i++;
    }
    if(conf->whos_on)
    {
       set_one_oper_value("conf_people", i, "who_is_on_manhattan");
       i++;
    }
    if(conf->statistics)
    {
       set_one_oper_value("conf_people", i, "login_logs");
       i++;
    }

    i =0; 
    if(conf->disk_space)
    {
       set_one_oper_value("conf_usageReport", i, "disk_space");
       i++;
    }
    if(conf->course_disk_usage)
    {
       set_one_oper_value("conf_usageReport", i, "course_disk_usage");
       i++;
    }

    i = 0;

    if(conf->chat_server)
    {
       set_one_oper_value("conf_server", i, "manage_chat");
       i++;
    }
    
    if(conf->lock_server)
    {
       set_one_oper_value("conf_server", i, "lock_server");
       i++;
    }
    i = 0;

    if(conf->clean_up)
    {
       set_one_oper_value("conf_cleanup", i, "clean_up");
       i++;
    }
    if(conf->purge_postoffice_message)
    {
       set_one_oper_value("conf_cleanup", i, "purge_postoffice_message");
       i++;
    }



    get_server_string(server_string, MAX_PATH +1);
    snprintf(url, MAX_PATH +1, "%s/%s/%s",server_string, SBIN_ALIAS, "super_doorstep");
     cs_set_value("url", url);
}
 



static DEL_COURSE_NODE *
get_node(char *str)
{
    DEL_COURSE_NODE *ptr;
    char *str_ptr;

    str_ptr = strchr(str, ':');
    if(!str_ptr)
       cs_critical_error(ERR_PARAM_FORMAT, "course_list");

    ptr = (DEL_COURSE_NODE *)malloc(sizeof(DEL_COURSE_NODE));
    if(!ptr)
      cs_critical_error(ERR_MALLOC_FAILED, "");
    ptr->next = 0;

    *str_ptr = '\0';
    ptr->del_id = malloc_str(str);
    *str_ptr = ':';
    str_ptr++;
    ptr->del_info = malloc_str(str_ptr);
    return ptr;
}

DEL_COURSE_NODE *
build_selected_course_list()
{
  DEL_COURSE_NODE *ptr, *head =0, *current=0;
  char *str;
  HDF *obj;


   str = hdf_get_value(global_cgi->hdf, "Query.course_list.0",  0);
   if(str)
   {
       obj = hdf_get_child(global_cgi->hdf, "Query.course_list");
       while(obj)
       {
	  str = obj->value;
          if(str)
          {
                ptr = get_node(str);
                if(!head)
                    head = ptr;
                 else
                     current->next = ptr;
                 current = ptr;
          }
	  
	  obj = obj->next;
       }

   }
   else
   {
      str = hdf_get_value(global_cgi->hdf, "Query.course_list",  0);
      if(!str)
          cs_critical_error(ERR_PARAM_MISSING, "course_list");
      head = get_node(str);
   }
       return head;
}





void free_del_list(DEL_COURSE_NODE *head)
{
    DEL_COURSE_NODE *ptr;
    while(head)
    {
        ptr = head->next;
        if(head->del_id)
          free(head->del_id);
        if(head->del_info)
          free(head->del_info);
        free(head);
        head = ptr;
     }

}


/*** does conf contain actions that
**** should be placed under 'Courses'
**** on the sys admin's menu?
***/
int 
has_course_progs(ADMIN_CONFIG_STRUCT *conf)
{
 return (conf->create_new_course ||
         conf->delete_courses   ||
         conf->config_courses   ||
         conf->admin_surveys);
}         




/*** does conf contain actions that
**** should be placed under 'People'
**** on the sys admin's menu?
***/
int
has_people_progs(ADMIN_CONFIG_STRUCT *conf)
{

 return ( conf->search_profiles ||
         conf-> whos_on   ||
         conf->statistics);
    
}         



/*** does conf contain actions that
**** should be placed under 'Server'
**** on the sys admin's menu?
***/
int
has_server_progs(ADMIN_CONFIG_STRUCT *conf)
{
 return (conf->disk_space ||
         conf->chat_server ||
         conf->lock_server ||
	 conf->course_disk_usage ||
	 conf->purge_postoffice_message ||
         conf->clean_up);
}





int
read_super_configuration_file (const char *username, ADMIN_CONFIG_STRUCT * config)
{
  FILE *fp;
  int fd;
  char fullpath[MAX_PATH + 1];

  snprintf (fullpath, MAX_PATH + 1, "../%s/%s/%c/%s/%s",
	    USERS_DIR, ADMIN_DIR, sub_dir_name(username),username, CONFIG_FNAME);

  fp = fopen (fullpath, "r");
  if (!fp)
      return 0;
          
  fd = fileno(fp);
  get_shared_lock(fd, 1);    /* shared_lock.c */
  
  if (fread (config, sizeof (ADMIN_CONFIG_STRUCT), 1, fp) != 1)
   {
    release_lock(fd);
    fclose(fp);
    return 0;
   } 

  release_lock(fd);    /* shared_lock.c */
  fclose (fp);


  return 1;   /* success */
}



int
write_super_configuration_file (const char *username, ADMIN_CONFIG_STRUCT * config)
{
  FILE *fp;
  char fullpath[MAX_PATH + 1];

  snprintf (fullpath, MAX_PATH + 1, "../%s/%s/%c/%s/%s",
	    USERS_DIR, ADMIN_DIR, sub_dir_name(username),username, CONFIG_FNAME);

  fp = fopen (fullpath, "w");
  if (!fp)
      return 0;
          
  
  if (fwrite(config, sizeof (ADMIN_CONFIG_STRUCT), 1, fp) != 1)
   {
    fclose(fp);
    return 0;
   } 

  fclose (fp);
  return 1;   /* success */
}



/** is username the administrative 
*** super user?
***/
static
int is_super_user(const char *username)
{
 ADMIN_CONFIG_STRUCT conf;
 
 if(!read_super_configuration_file(username, &conf) ||  !conf.is_super_user)
     return 0;
 else
     return 1;
}         



/* does list of users have at least one admin
* that is NOT the super user ?
*/
int has_other_admins(ADMIN_USER *head)
{
 ADMIN_USER *ptr;
 
 for(ptr = head; ptr; ptr = ptr->next)
   if(!ptr->is_super_user)
       return 1;
       
 return 0;
}       





/*** builds a linked list
**** of administrative users from the ../users/admin/index.txt file
****
**** ADMIN_USER is #defined in shared_super_util.h
***/

ADMIN_USER * 
build_admin_user_list()
{
#define MAX_LINE 200
    FILE *fp;
    char fname[MAX_PATH +1];
    char line[MAX_LINE +1];
    char *chr_ptr;
    ADMIN_USER *head = 0, *ptr, *current=0;
    
    snprintf(fname, MAX_PATH +1, "../%s/%s/%s",
		    USERS_DIR, ADMIN_DIR,  USER_INDEX_FNAME);

    fp = fopen(fname, "r");
    if(!fp)
 	  cs_critical_error(ERR_FOPEN_READ_FAILED, "");
    get_shared_lock(fileno(fp), 1);
    while(fgets(line, MAX_LINE, fp))
    {
        strtrm(line);	     /* shared_strtrm.c */
        ptr = (ADMIN_USER *)malloc(sizeof(ADMIN_USER));
	chr_ptr = strchr(line, ':');
	if(!chr_ptr)
	   cs_critical_error( ERR_FILE_FORMAT_ERROR, "");
	*chr_ptr = '\0';
	strncpy(ptr->username, line, MAX_USERNAME + 1);    /* copy username field */

        chr_ptr++;
        strncpy(ptr->realname, chr_ptr, MAX_NAME +1);    /* copy realname field */

        ptr->is_super_user = is_super_user(ptr->username);
	
	ptr->next = 0;
	if(!head)
	    head = ptr;
	else
	    current->next = ptr;
	current = ptr;
    }
    release_lock(fileno(fp));
    fclose(fp);

    return head;
 #undef MAX_LINE 
}





void
free_admin_user_list(ADMIN_USER *list)
{
	ADMIN_USER *ptr;
	while(list)
	{
	    ptr = list->next;
	    free(list);
	    list = ptr;
	}

}



static void
set_checkbox(const char *prefix, int num,  int selected)
{
     #define MAX_TMP_NAME 30
     char name[MAX_TMP_NAME];
     
     snprintf(name, MAX_TMP_NAME, "%s.%d.selected", prefix, num);
     if(selected)
        cs_set_int_value(name, 1);
     else
        cs_set_int_value(name, 0);
          
     #undef MAX_TMP_NAME 
}



void
list_course_commands(ADMIN_CONFIG_STRUCT *conf)
{
     int i =0;

     set_checkbox("conf_course", i, conf->create_new_course);
     i++;
     set_checkbox("conf_course", i, conf->delete_courses);
     i++;
     set_checkbox("conf_course",i, conf->config_courses);
     i++;
     set_checkbox("conf_course",i, conf->change_course_access);
     i++;
     set_checkbox("conf_course",i, conf->archive_courses);
     i++;
     set_checkbox("conf_course", i, conf->admin_surveys);
     i++;


}   




void
list_people_commands(ADMIN_CONFIG_STRUCT *conf)
{

/** note the ability to add/delete/modify administrators is NEVER
*** given to anyone but the super user
**/
   int i =0;

   set_checkbox("conf_people", i,conf->search_profiles);
   i++;
   set_checkbox("conf_people", i,  conf->whos_on);
   i++;
   set_checkbox("conf_people", i,  conf->statistics);


}


void 
list_server_commands(ADMIN_CONFIG_STRUCT *conf)
{
 
    int i =0; 
    set_checkbox("conf_server", i, conf->disk_space);
    i++;
    set_checkbox("conf_server",i, conf->course_disk_usage);
    i++;
    set_checkbox("conf_server", i, conf->chat_server);
    i++;
    set_checkbox("conf_server", i,  conf->lock_server);
    i++;
    set_checkbox("conf_server", i,  conf->clean_up);
    i++;
    set_checkbox("conf_server",i, conf->purge_postoffice_message);
}  

void
set_admin_data( ADMIN_USER *list)
{
   #define MAX_TMP_NAME 30
    ADMIN_USER *ptr;
   char name[MAX_TMP_NAME];
   int i =0;

    for(ptr = list; ptr; ptr = ptr->next)
    {

       if(!ptr->is_super_user)  /* never show the super user */
       {
          snprintf(name, MAX_TMP_NAME, "user.%d.username",i);
         cs_set_value(name, ptr->username);
         snprintf(name, MAX_TMP_NAME, "user.%d.realname",i);
         cs_set_value(name, ptr->realname);
         i++;
      }
   }
  #undef MAX_TMP_NAME
}






    
