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