#include #include #include #include "../global.h" #include "shared_search_profile.h" #include "shared_util.h" #include "shared_super_util.h" #include "shared_authenticate.h" #include "shared_person_list.h" #include "shared_lock.h" #include "shared_super_list.h" #include "shared_strtrm.h" #include "shared_central_user.h" #include "shared_escape_realname.h" #include "shared_cs_util.h" void read_search_parameters(char *key, char *crs, char *group, char *oper, char *search, int *field, int *users, int *results, int *sensitive, int *where, int *sort, int *start_record, int *records_per_page) { char tmp[20]; cs_get_required_parameter("id", key, MAX_KEY); cs_get_optional_parameter("crs", crs, MAX_PATH); cs_get_optional_parameter("group", group, MAX_ID); cs_get_optional_parameter("oper", oper, 19); cs_get_optional_parameter("sensitive", tmp, 19); *sensitive = atoi(tmp); cs_get_optional_parameter("where", tmp, 19); *where = atoi(tmp); cs_get_optional_parameter ("search",search,MAX_PATH); strtrm(search); cs_get_optional_parameter("field", tmp, 19); *field = atoi(tmp); cs_get_optional_parameter("users", tmp, 19); *users = atoi(tmp); cs_get_optional_parameter("results", tmp, 19); *results = atoi(tmp); cs_get_optional_parameter("sort", tmp, 19); *sort = atoi(tmp); cs_get_optional_parameter("start", tmp, 19); *start_record = atoi(tmp); if(*start_record <= 0) *start_record = 1; /* 'step' param indicates the number of records per page ** if not supplied then ** - for FULL_RESULT searches, limit number of records on page to MAX_FULL_RECORDS_PER_PAGE ** as #defined in shared_search_profile.h ** - otherwise set to one million, which in effect means no limit */ cs_get_optional_parameter("step", tmp, 19); *records_per_page = atoi(tmp); if(*records_per_page <= 0) *records_per_page = (*results == FULL_RESULTS)? MAX_FULL_RECORDS_PER_PAGE : 1000000; } static int parse_index_line(char *line, PROFILE_NODE *test_data) { char *ptr; char *ptr2; ptr = strchr(line,':'); if(!ptr) return 0; *ptr = '\0'; strncpy(test_data->person.username, line, MAX_USERNAME + 1); *(test_data->person.username + MAX_USERNAME) = '\0'; *ptr = ':'; ptr++; ptr2 = strchr(ptr,':'); if(!ptr2) return 0; *ptr2 = '\0'; strncpy(test_data->person.id, ptr, MAX_ID + 1); *(test_data->person.id + MAX_ID) = '\0'; *ptr2 = ':'; ptr2++; strncpy(test_data->person.realname, ptr2, MAX_NAME + 1); *(test_data->person.realname + MAX_NAME) = '\0'; strtrm(test_data->person.realname); test_data -> username_match = NO_MATCH; test_data -> id_match = NO_MATCH; test_data -> realname_match = NO_MATCH; test_data -> course_head = (USER_COURSE_NODE *) 0; return 1; } /* returns 1 if 'username' has a course in the course list represented by ** 'course_head' in which he is of 'user_type' (i.e. a student or a teacher **/ static int correct_user_type(COURSE_LIST_NODE *course_head, const char *username, int user_type) { char passwd_fname[MAX_PATH + 1]; FILE *fp; COURSE_LIST_NODE *course_ptr; char line[201]; USER_DATA person; int type_found = 0; int username_found; /* this function can only find students and faculty ** should never receive other values */ if( (user_type != STUDENT_USERS) && (user_type != FACULTY_USERS)) return 0; for(course_ptr = course_head; course_ptr && !type_found; course_ptr = course_ptr->next) { snprintf(passwd_fname, MAX_PATH + 1, "%s%s/%s", *course_ptr->crs == 'T'? TEMPLATE_PATH: COURSE_PATH, course_ptr->crs, PASSWD_FNAME); fp = fopen(passwd_fname, "r"); if(fp) { get_shared_lock(fileno(fp),1); username_found = 0; while (!username_found && fgets (line, 200, fp)) { if (*line == '?') /* password lines starting with a '?' are ignored */ continue; get_passwd_line_data(line, &person); /* shared_person_list.c */ if(!strcmp(person.username, username)) { username_found = 1; type_found = user_type==STUDENT_USERS? (person.group == STUDENT) : (person.group == FACULTY); } } release_lock(fileno(fp)); /* shared_lock.c */ fclose(fp); } } /* for */ return type_found; } static int user_type_matches(const char *username, int user_type) { char course_list[MAX_PATH + 1]; FILE *fp; COURSE_LIST_NODE *course_head; int result; if(user_type == ALL_USERS) return 1; snprintf(course_list, MAX_PATH +1, "../%s/%c/%s/%s", USERS_DIR, sub_dir_name(username), username, COURSE_LIST_FNAME); fp = fopen(course_list, "r"); if(!fp) { if((user_type == STUDENT_USERS) || (user_type == CLASSLESS_USERS)) return 1; else /* if looking for teachers */ return 0; } get_shared_lock(fileno(fp), 1); /* shared_lock.c */ course_head = build_course_list(fp); /*shared_super_list.c */ release_lock(fileno(fp)); /*shared_lock.c */ fclose(fp); if(!course_head) { if((user_type == STUDENT_USERS) || (user_type == CLASSLESS_USERS)) return 1; else /* if looking for teachers */ return 0; } result = correct_user_type(course_head, username, user_type); super_free_course_list(course_head); /* shared_super_list.c */ return result; } static int string_matches(const char *needle, int sensitive, int where, const char *haystack, int *matchpoint) { char *tmp; char *ptr; int haystack_len; int match = 0; int needle_len; *matchpoint = NO_MATCH; /* work with a copy of the string to be searched */ haystack_len = strlen(haystack); tmp = (char *) malloc((haystack_len + 1) * sizeof(char)); if(!tmp) cs_critical_error(ERR_MALLOC_FAILED, ""); strncpy(tmp,haystack, haystack_len + 1); /* if this search is not case sensitive, ** convert the working copy to lowercase ** The 'needle' string should already be ** in lowercase */ if(!sensitive) { for(ptr=tmp; *ptr; ptr++) *ptr = tolower(*ptr); } /* deal with searching from the end of the ** string - this is a special case */ if(where == END_WITH) { needle_len = strlen(needle); if(needle_len > haystack_len) { free(tmp); return 0; } else { ptr = strchr(tmp, '\0'); ptr -= needle_len; match = !strcmp(ptr, needle); if(match) { *matchpoint = ptr - tmp; free(tmp); return 1; } else { free(tmp); return 0; } } } /* now deal with 'contains' and 'starts with' searches */ ptr = strstr(tmp, needle); if(ptr) match = (where==CONTAINS)? 1 : (ptr == tmp); /* else is 'starts with' condition */ *matchpoint = match? ptr - tmp : NO_MATCH; free(tmp); return match; } static int search_string_matches(const char *search, int sensitive, int where, int field, PROFILE_NODE *record) { int username_matches; int realname_matches; int id_matches; switch(field) { case ALL_FIELDS: username_matches = string_matches(search, sensitive, where, record->person.username, &record->username_match); realname_matches = string_matches(search, sensitive, where, record->person.realname, &record->realname_match); id_matches = string_matches(search, sensitive, where, record->person.id, &record->id_match); return (username_matches || realname_matches || id_matches); break; case USERNAME_FIELD: return string_matches(search, sensitive, where, record->person.username, &record->username_match); break; case ID_FIELD: return string_matches(search, sensitive, where, record->person.id, &record->id_match); break; case NAME_FIELD: return string_matches(search, sensitive, where, record->person.realname, &record->realname_match); break; default: return 0; /*should not happen */ } } static int user_meets_criteria(PROFILE_NODE *test_data, const char *search, int sensitive, int where, int field, int users) { return search_string_matches(search, sensitive, where, field, test_data) && user_type_matches(test_data->person.username, users); } static int person_cmp(USER_DATA *a, USER_DATA *b, int sort) { switch(sort) { case SORT_LAST: return(username_cmp (a, b)); /* shared_authenticate.c */ break; case SORT_USERNAME: return(strcmp(a->username, b->username)); break; case SORT_ID: return(strcmp(a->id, b->id)); break; case SORT_FIRST: return(strcmp(a->realname, b->realname)); break; default : return(username_cmp (a, b)); /* shared_authenticate.c */ break; } } PROFILE_NODE * sort_profile_list (PROFILE_NODE *pers_head, int sort) { PROFILE_NODE *q, *tail, *p, *r; if (pers_head != NULL) { tail = pers_head; while (tail->next) { q = tail->next; if (person_cmp (&(q->person), &(pers_head->person), sort) < 0) { tail->next = q->next; q->next = pers_head; pers_head = q; } else { r = pers_head; p = r->next; while (person_cmp (&(q->person), &(p->person), sort) > 0) /* shared_authenticate.c */ { r = p; p = r->next; } if (q == p) tail = q; else { tail->next = q->next; q->next = p; r->next = q; } } } } return pers_head; } void free_profile_list(PROFILE_NODE *head) { PROFILE_NODE *ptr; USER_COURSE_NODE *cptr; while(head) { ptr = head; head = head->next; while(ptr->course_head) { cptr = ptr->course_head; ptr->course_head = ptr->course_head -> next; free(cptr); } free(ptr); } } static PROFILE_NODE * shrink_profile_list(PROFILE_NODE *head, int count, int start_record, int records_per_page) { PROFILE_NODE *ptr, *new_head; int i; new_head = head; if((start_record <= count) && (count > records_per_page)) /* then some trimming is necessary */ { if(start_record != 1) /* then trim the start of the list */ { for(ptr = head, i = 1; ptr && (i < (start_record - 1)); ptr=ptr->next, i++); /* skip to the start_record record */ if(ptr) /* this should always be true */ { new_head = ptr->next; ptr->next = (PROFILE_NODE *) 0; free_profile_list(head); } else new_head = (PROFILE_NODE *) 0; } /* we've trimmed the start of the list, now trim the end */ for(ptr = new_head, i=1; ptr && i <= (records_per_page - 1); ptr=ptr->next, i++); /* skip records_per_page records */ if(ptr) { free_profile_list(ptr->next); ptr->next = (PROFILE_NODE *) 0; } } return new_head; } PROFILE_NODE *build_profile_list(const char *search, int sensitive, int where, int field, int users, int sort, int start_record, int records_per_page, int *count) { #define MAX_LINE 200 FILE *fp; int fd; char filename[MAX_PATH + 1]; char line[MAX_LINE + 1]; PROFILE_NODE *head = (PROFILE_NODE *) 0; PROFILE_NODE *last_ptr = (PROFILE_NODE *) 0; char *search_string; int search_len; char *ptr; PROFILE_NODE test_data; *count = 0; /* work with a copy of the original search string ** if the search is not case sensitive, convert the ** working copy to lowercase */ search_len = strlen(search); search_string = (char *) malloc((search_len + 1) * sizeof(char)); if(!search_string) cs_critical_error(ERR_MALLOC_FAILED, ""); strcpy(search_string, search); if(!sensitive) for(ptr=search_string; *ptr; ptr++) *ptr = tolower(*ptr); snprintf(filename, MAX_PATH + 1, "../%s/%s", USERS_DIR, USER_INDEX_FNAME); fp = fopen(filename, "r"); if(!fp) return (PROFILE_NODE *) 0; /* no users */ fd = fileno(fp); get_shared_lock(fd, 1); /* shared_lock.c */ while(fgets(line, MAX_LINE, fp)) { strtrm(line); /* shared_strtrm.c */ if( parse_index_line(line, &test_data) ) { if( user_meets_criteria(&test_data, search_string, sensitive, where, field, users)) { *(test_data.person.password) = '\0'; /* blank out password */ /* get_lastname is in shared_authenticate.c ** the value is needed later when we sort the list */ strncpy(test_data.person.lastname, get_lastname(test_data.person.realname),MAX_NAME + 1); if(!head) { head = (PROFILE_NODE *) malloc(sizeof(PROFILE_NODE)); if(!head) cs_critical_error(ERR_MALLOC_FAILED, ""); last_ptr = head; } else { last_ptr->next = (PROFILE_NODE *)malloc(sizeof(PROFILE_NODE)); if(!last_ptr->next) cs_critical_error(ERR_MALLOC_FAILED, ""); last_ptr = last_ptr->next; } *last_ptr = test_data; last_ptr->next = (PROFILE_NODE *) 0; (*count)++; } } } release_lock(fd); fclose(fp); head = sort_profile_list(head, sort); head = shrink_profile_list(head, *count, start_record, records_per_page); return head; #undef MAX_LINE } void set_highlighted(char *string, int match, int search_len, const char *name_string, int num) { #define MAX_TMP_NAME 50 char *ptr; int count; int end_highlight, j=0, flag =0; char name[MAX_TMP_NAME]; char temp[MAX_TMP_NAME +1]; char str[MAX_PATH +1]; str[0] = '\0'; temp[0] = '\0'; if( (match == NO_MATCH) || !search_len) { snprintf(name, MAX_TMP_NAME, "user.%d.%s", num, name_string); cs_set_value(name, string); } else { end_highlight = match + search_len; for(ptr=string, count=0; *ptr; ptr++, count++) { if(count == match) { if(match != 0) { strcat(str, temp); memset(temp, 0, MAX_TMP_NAME); j =0; } flag =1; } if(count == end_highlight) { strcat(str, ""); strcat(str, temp); strcat(str, ""); memset(temp, 0, MAX_TMP_NAME); flag =0; j=0; } temp[j] = *ptr; temp[j+1] = '\0'; j++; } if(strlen(temp)) { if(flag) { strcat(str, ""); strcat(str, temp); strcat(str, ""); } else strcat(str, temp); } snprintf(name, MAX_TMP_NAME, "user.%d.%s", num, name_string); cs_set_value(name, str); } #undef MAX_TMP_NAME } int find_user_in_course(P_NODE *person_crs, const char *username) { P_NODE *ptr; for(ptr = person_crs; ptr; ptr = ptr->next) { if(strcmp(ptr->data.username, username) ==0) return 1; } return 0; } int parse_line(const char *str, P_NODE *user_data) { char *ptr; char *ptr2; char line[strlen(str) +1]; strncpy(line, str, strlen(str) +1); ptr = strchr(line, ':'); if(!ptr) return 0; *ptr = '\0'; if(!strlen(line)) return 0; strncpy(user_data->data.username, line, MAX_USERNAME +1); *(user_data->data.username + MAX_USERNAME) = '\0'; *ptr = ':'; ptr++; ptr2 = strchr(ptr, ':'); if(!ptr2) return 0; *ptr2 = '\0'; if(!strlen(ptr)) return 0; strncpy(user_data->data.realname, ptr, MAX_NAME +1); *(user_data->data.realname + MAX_NAME) = '\0'; *ptr2 = ':'; ptr2++; if(!strlen(ptr2)) return 0; strncpy(user_data->data.id, ptr2, MAX_ID+1); *(user_data->data.id + MAX_ID)='\0'; return 1; }