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