diff --git a/src/server/user_mgr.c b/src/server/user_mgr.c --- a/src/server/user_mgr.c +++ b/src/server/user_mgr.c @@ -1,21 +1,21 @@ /* - Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando - - This file is a part of DistRen. - - DistRen is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - DistRen is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with DistRen. If not, see . -*/ + * Copyright 2010 Nathan Phillip Brink, Ethan Zonca, Matthew Orlando + * + * This file is a part of DistRen. + * + * DistRen is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * DistRen is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with DistRen. If not, see . + */ #include "common/config.h" @@ -23,6 +23,7 @@ #include "common/asprintf.h" +#include #include #include @@ -37,305 +38,288 @@ #include #include -struct user_mgr_info +struct user_mgr { - struct user *user_array; - int current_users; - int user_array_size; -} user_mgr_info; - -int resize_user_array() -{ - int counter; - int counter2; - - // create array twice the size of the current amount of users - user_mgr_info.user_array_size = user_mgr_info.current_users * 2; - struct user *new_user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size); + /* items are of type user_t */ + list_t user_list; + /* where to load/save the userlist */ + char *userlist_filename; +}; - // this copies the original user_array over to the new one - // using two counters allows the array to be resized at any time - // leaving exactly 1 open space between each user when it is done; - counter2 = 0; - for(counter = 0; counter < user_mgr_info.current_users; counter++) - { - if(user_mgr_info.user_array[counter].username != 0) - { - new_user_array[counter2*2] = user_mgr_info.user_array[counter]; - counter2++; - } - } +static int user_find_traverse_forw(char *search_username, user_t user) +{ + if(strcmp(search_username, user->username) >= 0) + return FALSE; + return TRUE; +} - // cleanup old array - free(user_mgr_info.user_array); - - // change the pointer to point to the new user array - user_mgr_info.user_array = new_user_array; - - return 1; +static int user_find_traverse_back(char *search_username, user_t user) +{ + if(strcmp(search_username, user->username) <= 0) + return FALSE; + return TRUE; } -struct user *findUser(char *nameOfUser) +user_t user_find(user_mgr_t user_mgr, const char *username) { - int high; - int low; - int middle; - int result; + int list_direction; + list_traverse_func_t traverse_func; + + user_t user; + char *username_copy; - high = user_mgr_info.user_array_size - 1; - low = 0; - result = -1; + if(list_empty(user_mgr->user_list)) + return NULL; + + /* grab the current user for tiny optimizations.. */ + user = list_curr(user_mgr->user_list); + if(!user) + return NULL; - for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2) - { - // in case middle lands on a part of the array with no user - while(user_mgr_info.user_array[middle].username == 0) - { - if(result < 0) - middle --; - else - middle ++; - } + list_direction = LIST_FORW; + traverse_func = (list_traverse_func_t)&user_find_traverse_forw; + if(strcmp(user->username, username) < 0) + { + list_direction = LIST_BACK; + traverse_func = (list_traverse_func_t)&user_find_traverse_back; + }; - // this is where the array is cut in half and the half that the nameOfUser is on is kept - result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username); - if(result == 0) - return &user_mgr_info.user_array[middle]; - else if(result < 0) - high = middle; - else - low = middle; + username_copy = strdup(username); + list_traverse(user_mgr->user_list, username_copy, traverse_func, list_direction|LIST_CURR|LIST_ALTR); + free(username_copy); + user = list_curr(user_mgr->user_list); + if(!user) + return NULL; - // in case the user doesn't exist - if(high-low <= 0) - return 0; - } + if(!strcmp(username, user->username)) + return user; + + return NULL; } -int deleteUser(struct user *user_ptr) +int user_add(user_mgr_t user_mgr, const char *username, const char *pass) { - free(user_ptr->username); - memset(user_ptr, '\0', sizeof(struct user)); + user_t user; + short insert_after; - user_mgr_info.current_users--; - - return 1; - - backup_list_XML(); -} + user = user_find(user_mgr, username); + if(user) + return 1; -int createUser(struct user *user_ptr, char *nameOfUser) -{ - // clear old memory - memset(user_ptr, '\0', sizeof(struct user)); + /* + * The list should be positioned within one element of where we want + * to insert username. + */ + insert_after = 1; + user = list_curr(user_mgr->user_list); + if(user) + { + if(strcmp(username, user->username) < 0) + insert_after = 0; + } - user_ptr->username = nameOfUser; - user_ptr->render_power = 0; - user_ptr->last_job = 0; + /* + * construct the new user. + */ + user = malloc(sizeof(struct user)); + if(!user) + return 1; + user->username = strdup(username); + user->pass = strdup(pass); + user->render_power = 0; + user->last_job = 0; - user_mgr_info.current_users++; + /* I admit it... I'm completely crazy --binki */ + if(insert_after) + list_insert_after(user_mgr->user_list, user, 0); + else + list_insert_before(user_mgr->user_list, user, 0); - return 1; + return 0; } -// places the new user at position index in the array, moves other users if it needs to -int placeUser(int index, char *nameOfUser) +/** + * \brief For list_free() et al + */ +static void user_free(user_t user) { - int higher; - int lower; - int total_moves; - - total_moves = 0; + free(user->username); + free(user->pass); + free(user); +} - // I shift data in the array to create an open the space where the user should be added - // but first I figure out which way is the shortest - if(user_mgr_info.user_array[index].username != 0) - { - higher = index + 1; - while(user_mgr_info.user_array[higher].username != 0) - higher++; - - lower = index - 1; - while(user_mgr_info.user_array[lower].username != 0) - lower--; +int user_delete(user_mgr_t user_mgr, user_t user) +{ + user_t user_found; + int ret; - // here the data is shifted to open up a space - if(index - lower < higher - index) - { - total_moves = index - lower; - for(; lower < index; lower++) - memcpy(&user_mgr_info.user_array[lower], &user_mgr_info.user_array[lower + 1], sizeof(struct user)); - } - else - { - total_moves = higher - index; - for(; higher > index; higher--) - memcpy(&user_mgr_info.user_array[higher], &user_mgr_info.user_array[higher - 1], sizeof(struct user)); - } - } + ret = 0; - // add the user to the array - createUser(&user_mgr_info.user_array[index], nameOfUser); + user_found = user_find(user_mgr, user->username); + if(user_found + && user_found == user + && user == list_curr(user_mgr->user_list)) + list_remove_curr(user_mgr->user_list); + else + { + fprintf(stderr, __FILE__ ":%d:user_delete(): List is inconsistent :-/\n", __LINE__); + ret = 1; + } - if(total_moves > 50) - resize_user_array(); + user_free(user); - return 1; + return ret; } -int addUser(char *nameOfUser) +static int user_mgr_save_traverse(xmlTextWriterPtr writer, user_t user) { - int high; - int low; - int middle; - int result; - - high = user_mgr_info.user_array_size - 1; - low = 0; - result = -1; + char *tmp; - for(middle = (low+high)/2; 1 == 1; middle = (low+high)/2) - { - // in case middle lands on a part of the array with no user - while(user_mgr_info.user_array[middle].username == 0) - { - if(result < 0) - middle--; - else - middle++; - } + xmlTextWriterStartElement(writer, (xmlChar *)"user"); + + xmlTextWriterWriteAttribute(writer, (xmlChar *)"name", (xmlChar*)user->username); + xmlTextWriterWriteAttribute(writer, (xmlChar *)"pass", (xmlChar*)user->pass); - // this is where the array is cut in half and the half that the nameOfUser is on is kept - result = strcmp(nameOfUser, user_mgr_info.user_array[middle].username); - if(result == 0) - return 0; - else if(result < 0) - high = middle; - else - low = middle; - - // once there are less than 10 possible places for the user to be placed - // break out of this loop and begin next loop - if(high-low <= 10) - break; - } + _distren_asprintf(&tmp, "%d", user->last_job); + xmlTextWriterWriteAttribute(writer, (xmlChar *)"last_job", (xmlChar*)tmp); + free(tmp); - // this function starts at the low index number, and goes up until it finds a - // username that is bigger than it alphabetically, and tells the userPlacer - // that it needs to go 1 before that spot - for(; low <= high; low++) - { - while(user_mgr_info.user_array[low].username == 0) - low++; + _distren_asprintf(&tmp, "%d", user->render_power); + xmlTextWriterWriteAttribute(writer, (xmlChar *)"render_power", (xmlChar*)tmp); + free(tmp); - result = strcmp(nameOfUser, user_mgr_info.user_array[low].username) < 0; - if(result < 0) - { - placeUser(low - 1, nameOfUser); - return 1; - } - if(result == 0) - { - fprintf(stderr, "user already exists"); - return 0; - } - } + xmlTextWriterEndElement(writer); - backup_list_XML(); - return 0; + return TRUE; } -int initialize_users() +int user_mgr_save(user_mgr_t user_mgr, const char *filename) { - struct stat buffer; - // cif user_list.xml exists - if(stat("user_list.xml", &buffer) == 0) - { - restart_From_XML_backup(); - } - else - { - user_mgr_info.current_users = 0; + xmlTextWriterPtr writer; + + if(!filename) + filename = user_mgr->userlist_filename; + + writer = xmlNewTextWriterFilename(filename, 0); + xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL); - user_mgr_info.user_array_size = 50; - user_mgr_info.user_array = malloc(sizeof(struct user) * 50); - } + /* + * create root element user_list + */ + xmlTextWriterStartElement(writer, (xmlChar*)"user_list"); - // if XML file is not found create new array of size 50 + /** + * \todo error checking/handling? + */ + list_traverse(user_mgr->user_list, writer, (list_traverse_func_t)&user_mgr_save_traverse, LIST_FRNT|LIST_FORW|LIST_SAVE); + xmlTextWriterEndElement(writer); + xmlTextWriterEndDocument(writer); + xmlTextWriterFlush(writer); - return 1; + return 0; } -/********************************** XMLness *****************************/ - -int backup_list_XML() +user_mgr_t user_mgr_init(const char *userfile) { - xmlTextWriterPtr writer; - char *tmp; - int counter; - - - writer = xmlNewTextWriterFilename("user_list.xml", 0); - xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL); - - // create root element user_list - xmlTextWriterStartElement(writer, (xmlChar*)"user_list"); - - _distren_asprintf(&tmp, "%d", user_mgr_info.current_users); - xmlTextWriterWriteAttribute(writer, (xmlChar*)"amount_of_users", (xmlChar*)tmp); - free(tmp); - - for(counter = 0; counter < user_mgr_info.user_array_size; counter++) - { - if(user_mgr_info.user_array[counter].username != 0) - { - xmlTextWriterStartElement(writer, (xmlChar*)"user"); - - xmlTextWriterWriteAttribute(writer, (xmlChar*)"name", (xmlChar*)user_mgr_info.user_array[counter].username); - - _distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].last_job); - xmlTextWriterWriteAttribute(writer, (xmlChar*)"last_job", (xmlChar*)tmp); - free(tmp); - - _distren_asprintf(&tmp, "%d", user_mgr_info.user_array[counter].render_power); - xmlTextWriterWriteAttribute(writer, (xmlChar*)"render_power", (xmlChar*)tmp); - free(tmp); - - xmlTextWriterEndElement(writer); - } - } - - return 0; - -} - -int restart_From_XML_backup(){ xmlDocPtr doc; xmlNodePtr cur; - int counter; + + user_mgr_t user_mgr; + + user_t user; + xmlChar *username; + xmlChar *pass; + xmlChar *tmp; + int render_power; + int last_job; - doc = xmlParseFile("user_list.xml"); + user_mgr = malloc(sizeof(struct user_mgr)); + user_mgr->user_list = list_init(); + user_mgr->userlist_filename = strdup(userfile); + + doc = xmlParseFile(userfile); + if (!doc) + { + fprintf(stderr, "user_mgr: Error opening userlist, assuming we should start with an empty userlist\n"); + return user_mgr; + } + cur = xmlDocGetRootElement(doc); if (xmlStrcmp(cur->name, (xmlChar*)"user_list")) { - fprintf(stderr, "xml document is wrong type"); + fprintf(stderr, "user_mgr: xml document is wrong type. Using empty userlist, which will overwrite the old userlist soon probably..."); xmlFreeDoc(doc); - return 1; + return user_mgr; } - user_mgr_info.current_users = atoi((char*)xmlGetProp(cur, (xmlChar*)"amount_of_users")); + for(cur = cur->xmlChildrenNode; cur; cur = cur->next) + { + if (cur->type != XML_ELEMENT_NODE) + /* skip the implicit XML_TEXT_NODEs */ + continue; + + if (xmlStrcmp(cur->name, (xmlChar *)"user")) + { + fprintf(stderr, "user_mgr: Unrecognized XML element: <%s />\n", + cur->name); + + continue; + } - user_mgr_info.user_array_size = user_mgr_info.current_users * 2; - user_mgr_info.user_array = malloc(sizeof(struct user) * user_mgr_info.user_array_size); + username = xmlGetProp(cur, (xmlChar *)"name"); + pass = xmlGetProp(cur, (xmlChar *)"pass"); + + if(!username) + { + fprintf(stderr, " is missing a name attribute! (skipping)\n"); + continue; + } + if(!pass) + { + fprintf(stderr, " is missing a pass attribute! (skipping)\n", + username ? (char *)username : ""); + continue; + } - cur = cur->xmlChildrenNode; - for(counter = 0; cur->next; counter++){ - user_mgr_info.user_array[counter*2].username = (char*)xmlGetProp(cur, (xmlChar*)"amount_of_users"); - user_mgr_info.user_array[counter*2].last_job = atoi((char*)xmlGetProp(cur, (xmlChar*)"last_job")); - user_mgr_info.user_array[counter*2].render_power = atoi((char*)xmlGetProp(cur, (xmlChar*)"render_power")); - cur = cur->next; - } + last_job = 0; + tmp = xmlGetProp(cur, (xmlChar *)"last_job"); + if(tmp) + { + last_job = atoi((char *)tmp); + xmlFree(tmp); + } + + render_power = 0; + if(tmp) + { + tmp = xmlGetProp(cur, (xmlChar *)"render_power"); + render_power = atoi((char *)tmp); + xmlFree(tmp); + } + + user_add(user_mgr, (char *)username, (char *)pass); + xmlFree(username); + xmlFree(pass); - return 0; + /* + * user_find should be a very inexpensive operation immediately + * after the user_add() above. I just don't want to trust to + * list_curr() right in this function ;-). + * + * Also, we set this information without passing the following + * as arguments to user_add() because user_add() is an external + * API used for when a user is initially added to the + * userlist. Thus, everybody'd be calling it with + * user_add("username", "pass", 0, 0); + */ + user = user_find(user_mgr, (char *)username); + if(user) + { + user->render_power = render_power; + user->last_job = last_job; + } + } + + return user_mgr; }