/*
* 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"
#include "user_mgr.h"
#include "common/asprintf.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
struct user_mgr
{
/* items are of type user_t */
list_t user_list;
/* where to load/save the userlist */
char *userlist_filename;
};
static int user_find_traverse_forw(char *search_username, user_t user)
{
if(strcmp(search_username, user->username) >= 0)
return FALSE;
return TRUE;
}
static int user_find_traverse_back(char *search_username, user_t user)
{
if(strcmp(search_username, user->username) <= 0)
return FALSE;
return TRUE;
}
user_t user_find(user_mgr_t user_mgr, const char *username)
{
int list_direction;
list_traverse_func_t traverse_func;
user_t user;
char *username_copy;
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;
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;
};
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;
if(!strcmp(username, user->username))
return user;
return NULL;
}
int user_add(user_mgr_t user_mgr, const char *username, const char *pass)
{
user_t user;
short insert_after;
user = user_find(user_mgr, username);
if(user)
return 1;
/*
* 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;
}
/*
* 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;
/* 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 0;
}
/**
* \brief For list_free() et al
*/
static void user_free(user_t user)
{
free(user->username);
free(user->pass);
free(user);
}
int user_delete(user_mgr_t user_mgr, user_t user)
{
user_t user_found;
int ret;
ret = 0;
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;
}
user_free(user);
return ret;
}
static int user_mgr_save_traverse(xmlTextWriterPtr writer, user_t user)
{
char *tmp;
xmlTextWriterStartElement(writer, (xmlChar *)"user");
xmlTextWriterWriteAttribute(writer, (xmlChar *)"name", (xmlChar*)user->username);
xmlTextWriterWriteAttribute(writer, (xmlChar *)"pass", (xmlChar*)user->pass);
_distren_asprintf(&tmp, "%d", user->last_job);
xmlTextWriterWriteAttribute(writer, (xmlChar *)"last_job", (xmlChar*)tmp);
free(tmp);
_distren_asprintf(&tmp, "%d", user->render_power);
xmlTextWriterWriteAttribute(writer, (xmlChar *)"render_power", (xmlChar*)tmp);
free(tmp);
xmlTextWriterEndElement(writer);
return TRUE;
}
int user_mgr_save(user_mgr_t user_mgr, const char *filename)
{
xmlTextWriterPtr writer;
if(!filename)
filename = user_mgr->userlist_filename;
writer = xmlNewTextWriterFilename(filename, 0);
xmlTextWriterStartDocument(writer, NULL, "utf-8", NULL);
/*
* create root element user_list
*/
xmlTextWriterStartElement(writer, (xmlChar*)"user_list");
/**
* \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 0;
}
user_mgr_t user_mgr_init(const char *userfile)
{
xmlDocPtr doc;
xmlNodePtr cur;
user_mgr_t user_mgr;
user_t user;
xmlChar *username;
xmlChar *pass;
xmlChar *tmp;
int render_power;
int last_job;
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, "user_mgr: xml document is wrong type. Using empty userlist, which will overwrite the old userlist soon probably...");
xmlFreeDoc(doc);
return user_mgr;
}
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;
}
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;
}
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);
/*
* 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;
}