#include #include #include #include #include #include #include #include #include "../global.h" #include "shared_course_search.h" #include "shared_util.h" #include "shared_strtrm.h" #include "shared_authenticate.h" #include "shared_cs_util.h" static int internal_name_matches(const char *target, const char *lowercased_search, int where) { char *lowercased_target; char *ptr; int match; int search_len; search_len = strlen(lowercased_search); if(!search_len) return 1; /* a blank search string matches everything */ if(search_len > (int) strlen(target)) /* search string is longer than target, can't match */ return 0; /* make a lowercased copy of the target */ lowercased_target = (char *) malloc(strlen(target) + 1); if(!lowercased_target) cs_critical_error(ERR_MALLOC_FAILED, ""); strcpy(lowercased_target, target); for(ptr = lowercased_target; *ptr; ptr++) *ptr = tolower(*ptr); if( (where == 0) || (where == 1)) /* 0 = anywhere within string , 1= at start of string */ { ptr = strstr(lowercased_target, lowercased_search); if(!ptr) match = 0; else if(where == 0) match = 1; else match = (ptr == lowercased_target); } else /* match end of string */ { ptr = strrchr(lowercased_target, '\0'); if(!ptr) /* can't happen */ match = 0; else { ptr -= search_len; match = !strcmp(lowercased_search, ptr); } } free(lowercased_target); return match; } static int config_meets_criteria(CONFIG_STRUCT *conf, int type) { switch(type) { case 0: return 1; /* standalone or centralized */ break; case 1: return conf->standalone; /*standalone only */ break; default: return !(conf->standalone); /* centralized only */ break; } } static COURSE_SEARCH_NODE * add_to_search_list(COURSE_SEARCH_NODE *result_head, CONFIG_STRUCT *conf, const char *dirname, const char *subdir) { COURSE_SEARCH_NODE *new_node; static COURSE_SEARCH_NODE *last_node = 0; new_node = (COURSE_SEARCH_NODE *) malloc(sizeof(COURSE_SEARCH_NODE)); if(!new_node) cs_critical_error(ERR_MALLOC_FAILED, ""); new_node-> conf = *conf; strncpy(new_node->subdir, subdir, MAX_COURSE_SUBDIR + 1); strncpy(new_node->dirname, dirname, MAX_FILENAME + 1); new_node ->next = (COURSE_SEARCH_NODE *) 0; if(!result_head) { result_head = new_node; last_node = result_head; } else { last_node->next = new_node; last_node = last_node -> next; } return result_head; } static COURSE_SEARCH_NODE * process_course_templates(COURSE_SEARCH_NODE *head, const char *lowercased_search, int type, int where) { DIR *template_dir_p, /* used to open the ../templates directory */ *teacher_dir_p; /* used to open a teachers directory within the ../templates directory, e.g. ../templates/Tsnarmont */ struct dirent *template_dir_entry_p, /* used to traverse the ../templates directory */ *teacher_dir_entry_p; /* used to traverse a teacher's directory within the templates directory */ char template_dir[MAX_PATH + 1]; /* relative path to the templates directory i.e. ../templates */ char teacher_dir[MAX_PATH + 1]; /* relative path to one teacher's directory e.g. ../templates/Tsnarmont */ char course_fname[MAX_PATH + 1]; CONFIG_STRUCT conf; COURSE_SEARCH_NODE *result_head = head; char *cptr; strncpy(template_dir, TEMPLATE_PATH, MAX_PATH + 1); /*remove trailing slash from template_dir */ cptr = strchr(template_dir, '\0'); if(cptr && (cptr != template_dir)) *(cptr - 1) = '\0'; template_dir_p = opendir(template_dir); if(!template_dir_p) /* the installation MUST have a ../templates dir */ cs_critical_error (ERR_OPENDIR_FAILED, ""); while (NULL != (template_dir_entry_p = readdir (template_dir_p))) { if( (*(template_dir_entry_p->d_name)) != '.') { snprintf(teacher_dir, MAX_PATH + 1, "%s/%s", template_dir, template_dir_entry_p->d_name); teacher_dir_p = opendir(teacher_dir); if(teacher_dir_p) /* let's ignore an error here */ { while (NULL != (teacher_dir_entry_p = readdir (teacher_dir_p))) { if( (*(teacher_dir_entry_p->d_name)) != '.') { if(internal_name_matches(teacher_dir_entry_p->d_name, lowercased_search, where)) { snprintf(course_fname, MAX_PATH + 1, "%s/%s", template_dir_entry_p->d_name, teacher_dir_entry_p->d_name); if(read_configuration_file_ok(course_fname, &conf) /* shared_util.c */ && config_meets_criteria(&conf,type) ) result_head = add_to_search_list(result_head, &conf, teacher_dir_entry_p->d_name, template_dir_entry_p->d_name); } } } closedir(teacher_dir_p); } } } closedir(template_dir_p); return result_head; } COURSE_SEARCH_NODE * process_one_subdir (COURSE_SEARCH_NODE *head, const char *lowercased_search, int type , int where, const char *subdir) { DIR *dir_p; struct dirent *dir_entry_p; char dir_path[MAX_PATH + 1]; char course_fname[MAX_PATH + 1]; CONFIG_STRUCT conf; COURSE_SEARCH_NODE *result_head = head; if(!strcmp(subdir, TEMPLATES_NAME)) return process_course_templates(head, lowercased_search, type, where); else { snprintf(dir_path, MAX_PATH + 1, "%s%s", COURSE_PATH, subdir); dir_p = opendir(dir_path); if(dir_p) { while (NULL != (dir_entry_p = readdir (dir_p))) { if( (*(dir_entry_p->d_name)) != '.') { if(internal_name_matches(dir_entry_p->d_name, lowercased_search, where)) { snprintf(course_fname, MAX_PATH + 1, "%s/%s", subdir, dir_entry_p->d_name); if(read_configuration_file_ok(course_fname, &conf) /* shared_util.c */ && config_meets_criteria(&conf,type) ) result_head = add_to_search_list(result_head, &conf, dir_entry_p->d_name, subdir); } } } closedir(dir_p); } /* if directory could be opened */ } /* else not TEMPLATES_NAME */ return result_head; } int course_node_cmp( COURSE_SEARCH_NODE *a, COURSE_SEARCH_NODE *b) { int comp; comp = strcmp(a->subdir, b->subdir); if(comp) return comp; else /* subdirs are the same */ return strcmp(a->dirname, b->dirname); } static COURSE_SEARCH_NODE * sort_course_search_list (COURSE_SEARCH_NODE *course_head) { COURSE_SEARCH_NODE *q, *tail, *p, *r; if (course_head != NULL) { tail = course_head; while (tail->next) { q = tail->next; if (course_node_cmp (q, course_head) < 0) { tail->next = q->next; q->next = course_head; course_head = q; } else { r = course_head; p = r->next; while (course_node_cmp (q,p) > 0) { r = p; p = r->next; } if (q == p) tail = q; else { tail->next = q->next; q->next = p; r->next = q; } } } } return course_head; } COURSE_SEARCH_NODE * build_course_search_list(COURSE_SEARCH_PARAMS *params) { SUBDIR_NODE *sub_ptr; COURSE_SEARCH_NODE *head = 0; char *lowercased_search; char *ptr; /*save a lower case version of the search string for comparisons */ lowercased_search = (char *) malloc(strlen(params->search) + 1); if(!lowercased_search) cs_critical_error(ERR_MALLOC_FAILED, ""); strcpy(lowercased_search, params->search); for(ptr=lowercased_search; *ptr; ptr++); *ptr = tolower(*ptr); for(sub_ptr = params->subdir_head; sub_ptr; sub_ptr = sub_ptr->next) head = process_one_subdir(head, lowercased_search, params->type, params->where, sub_ptr->subdir); free(lowercased_search); head = sort_course_search_list(head); return head; } void free_course_search_list(COURSE_SEARCH_NODE *head) { COURSE_SEARCH_NODE *ptr; while(head) { ptr = head; head = head->next; free(ptr); } } void write_last_search_selections(const char *username, COURSE_SEARCH_PARAMS *params) { FILE *fp; char path[MAX_PATH + 1]; SUBDIR_NODE *ptr; /* build a path to the file that holds the last search by this user ** sub_dir_name() is in shared_authenticate.c */ snprintf(path, MAX_PATH + 1, "../%s/%s/%c/%s/%s", USERS_DIR, ADMIN_DIR, sub_dir_name(username), username, LAST_SEARCH_FNAME); fp = fopen(path,"w"); if(fp) { fprintf(fp,"%s\n%d\n%d\n" , params->search, params->type, params->where); for(ptr = params->subdir_head; ptr; ptr=ptr->next) fprintf(fp,"%s\n", ptr->subdir); fclose(fp); } } void get_last_search_selections(const char *username, COURSE_SEARCH_PARAMS *last_search) { FILE *fp; char path[MAX_PATH + 1]; char line[MAX_PATH + 1]; SUBDIR_NODE *new_node, *last_node = 0; last_search->subdir_head = 0; /* build a path to the file that holds the last search by this user ** sub_dir_name() is in shared_authenticate.c */ snprintf(path, MAX_PATH + 1, "../%s/%s/%c/%s/%s", USERS_DIR, ADMIN_DIR, sub_dir_name(username), username, LAST_SEARCH_FNAME); fp = fopen(path,"r"); if(fp) { if(fgets(line, MAX_PATH, fp)) /* first line contains search string */ { strtrm(line); /* shared_strtrm.c */ strncpy(last_search->search, line, MAX_FILENAME + 1); if(fgets(line, MAX_PATH, fp)) /* second line contains type - standalone, centralized, both */ { last_search->type = atoi(line); if(fgets(line, MAX_PATH, fp)) /* second line contains 'where' - match anywhere, start or end of string? */ { last_search->where = atoi(line); while(fgets(line, MAX_PATH, fp)) /* remaining lines contain directories (internal course names) */ { strtrm(line); new_node = (SUBDIR_NODE *) malloc(sizeof(SUBDIR_NODE)); if(!new_node) cs_critical_error(ERR_MALLOC_FAILED, ""); new_node->next = (SUBDIR_NODE *) 0; strncpy(new_node->subdir, line, MAX_COURSE_SUBDIR + 1); if(!last_search->subdir_head) last_search->subdir_head = new_node; else last_node -> next = new_node; last_node = new_node; } } } } fclose(fp); } } void free_subdir_list(SUBDIR_NODE *head) { SUBDIR_NODE *ptr; while(head) { ptr = head; head = head->next; free (ptr); } } /*******/ static GROUP_INFO_LIST * sort_group_list(GROUP_INFO_LIST *head) { GROUP_INFO_LIST *q, *tail, *p, *r; if (head != NULL) { tail = head; while (tail->next) { q = tail->next; if (q->created_time > head->created_time) { tail->next = q->next; q->next = head; head = q; } else { r = head; p = r->next; while (q->created_time < p->created_time) { r = p; p = r->next; } if (q == p) tail = q; else { tail->next = q->next; q->next = p; r->next = q; } } } } return head; } /* the "short description" is the first line of the text file named ** GROUP_DESCRIPTION_FNAME stored within the course subdirectory */ void get_short_group_description(const char *subdir, char *short_description) { char full_path[MAX_PATH + 1]; FILE *fp; snprintf(full_path, MAX_PATH + 1, "%s%s/%s", *subdir == 'T'? TEMPLATE_PATH:COURSE_PATH , subdir, GROUP_DESCRIPTION_FNAME); fp=fopen(full_path, "r"); if(!fp || !fgets(short_description, MAX_SEMESTER + 1, fp)) { *short_description = '\0'; } else strtrm(short_description); if(fp) fclose(fp); } GROUP_INFO_LIST * build_group_list(const char *course_path) { DIR *dir_p, *subdir_p; GROUP_INFO_LIST *head =0, *ptr, *current=0; struct dirent *dir_entry_p; struct stat buf; char dir_path[MAX_PATH + 1]; char *cptr; char subdir[MAX_PATH +1]; /* remove trailing slash in course_path, if present */ strncpy(dir_path, course_path, MAX_PATH + 1); cptr = strchr(dir_path, '\0'); if(cptr && (cptr != dir_path) && (*(cptr - 1) == '/')) *(cptr - 1) = '\0'; dir_p = opendir(dir_path); if(!dir_p) cs_critical_error (ERR_OPENDIR_FAILED, ""); while (NULL != (dir_entry_p = readdir (dir_p))) { if( (*(dir_entry_p->d_name)) != '.') { snprintf(subdir, MAX_PATH +1, "%s/%s", dir_path, dir_entry_p->d_name); subdir_p = opendir(subdir); if(subdir_p) { stat(subdir, &buf); ptr = (GROUP_INFO_LIST*)malloc(sizeof(GROUP_INFO_LIST)); if(!ptr) cs_critical_error(ERR_MALLOC_FAILED, ""); get_short_group_description(dir_entry_p->d_name, ptr->short_description); strncpy(ptr->subdir, dir_entry_p->d_name, MAX_COURSE_SUBDIR + 1); ptr->created_time = buf.st_mtime; ptr->next =0; if(!head) head = ptr; else current->next = ptr; current = ptr; } } } closedir(dir_p); head =sort_group_list(head); return head; } void free_course_group_list(GROUP_INFO_LIST *head) { GROUP_INFO_LIST *ptr; while(head) { ptr = head->next; free(head); head = ptr; } } int in_last_search(const char *subdir, COURSE_SEARCH_PARAMS *last_search) { SUBDIR_NODE *ptr; for(ptr = last_search->subdir_head; ptr; ptr = ptr->next) if(!strcmp(subdir, ptr->subdir)) return 1; return 0; }