/* libobby - Network text editing library * Copyright (C) 2005 0x539 dev group * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program 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 * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "common.hpp" #include "serialise/error.hpp" #include "user_table.hpp" obby::user_table::user_table() { } obby::user_table::~user_table() { clear(); } void obby::user_table::serialise(serialise::object& obj) const { for(base_iterator i = m_user_map.begin(); i != m_user_map.end(); ++ i) { serialise::object& user = obj.add_child(); user.set_name("user"); i->second->serialise(user); } } void obby::user_table::deserialise(const serialise::object& obj) { for(serialise::object::child_iterator iter = obj.children_begin(); iter != obj.children_end(); ++ iter) { if(iter->get_name() == "user") { // Create new user user* new_user = new user(*iter); // Check for conflicts if(m_user_map.find(new_user->get_id()) != m_user_map.end() || new_user->get_id() == 0) { format_string str( _("User ID %0% is already in use") ); str << new_user->get_id(); delete new_user; throw serialise::error( str.str(), iter->get_line() ); } // Insert into user map m_user_map[new_user->get_id()] = new_user; } else { // TODO: unexpected_child_error format_string str(_("Unexpected child node: '%0%'") ); str << iter->get_name(); throw serialise::error(str.str(), iter->get_line() ); } } m_signal_deserialised.emit(); } void obby::user_table::clear() { for(base_iterator i = m_user_map.begin(); i != m_user_map.end(); ++ i) delete i->second; m_user_map.clear(); } const obby::user* obby::user_table::add_user(unsigned int id, const net6::user& user6, const colour& colour) { // Find already exiting user with the given name user* existing_user = find_int(user6.get_name() ); if(existing_user != NULL) { // If this user would be connected, net6 should have denied // the login process with the "Name is already in use" error if(existing_user->get_flags() & user::flags::CONNECTED) throw std::logic_error("obby::user_table::add_user"); // Assign new net6::user to existing obby::user. existing_user->assign_net6(user6, colour); return existing_user; } else { // Make sure the ID is not already in use. if(id == 0 || m_user_map.find(id) != m_user_map.end() ) throw std::logic_error("obby::user_table::add_user"); // User seems to be here for his first time: Create a new user. user* new_user = new user(id, user6, colour); // Insert user into user list m_user_map[id] = new_user; return new_user; } } const obby::user* obby::user_table::add_user(unsigned int id, const std::string& name, const colour& colour) { // Look for an existing user with this name. user* existing_user = find_int(name); // We can not assign the new user to this one, because the user // we are currently adding is not connected to the obby session. if(existing_user != NULL) throw std::logic_error("obby::user_table::add_user"); // Make sure the ID is not already in use. if(id == 0 || m_user_map.find(id) != m_user_map.end() ) throw std::logic_error("obby::user_table::add_user"); user* new_user = new user(id, name, colour); m_user_map[id] = new_user; return new_user; } void obby::user_table::remove_user(const user& user_to_remove) { // Release underlaying net6::user object, this disables the connected // flag, too. Keep the user in the list to recognize him if he rejoins. const_cast(user_to_remove).release_net6(); } void obby::user_table::set_user_password(const user& user, const std::string& password) { lookup(user.get_id()).set_password(password); } void obby::user_table::set_user_colour(const user& user, const colour& colour) { lookup(user.get_id()).set_colour(colour); } unsigned int obby::user_table::find_free_id() const { unsigned int free_id = 1; for(base_iterator i = m_user_map.begin(); i != m_user_map.end(); ++ i) if( i->second->get_id() >= free_id) free_id = i->second->get_id() + 1; return free_id; } obby::user_table::iterator obby::user_table::begin(user::flags inc_flags, user::flags exc_flags) const { return iterator(m_user_map, m_user_map.begin(), inc_flags, exc_flags); } obby::user_table::iterator obby::user_table::end(user::flags inc_flags, user::flags exc_flags) const { return iterator(m_user_map, m_user_map.end(), inc_flags, exc_flags); } const obby::user* obby::user_table::find(unsigned int id, user::flags inc_flags, user::flags exc_flags) const { base_iterator iter = m_user_map.find(id); if(iter == m_user_map.end() ) return NULL; user::flags flags = iter->second->get_flags(); if(!iterator::check_flags(flags, inc_flags, exc_flags) ) return NULL; return iter->second; } const obby::user* obby::user_table::find(const net6::user& user, user::flags inc_flags, user::flags exc_flags) const { for(base_iterator i = m_user_map.begin(); i != m_user_map.end(); ++ i) { if(~i->second->get_flags() & user::flags::CONNECTED) continue; if( &i->second->get_net6() != &user) continue; user::flags flags = i->second->get_flags(); if(!iterator::check_flags(flags, inc_flags, exc_flags) ) continue; return i->second; } return NULL; } const obby::user* obby::user_table::find(const std::string& name, user::flags inc_flags, user::flags exc_flags) const { for(base_iterator i = m_user_map.begin(); i != m_user_map.end(); ++ i) { if(i->second->get_name() != name) continue; user::flags flags = i->second->get_flags(); if(!iterator::check_flags(flags, inc_flags, exc_flags) ) continue; return i->second; } return NULL; } obby::user_table::size_type obby::user_table::count(user::flags inc_flags, user::flags exc_flags) const { // No criteria: Optimize by returning the cached value from the map if(inc_flags == user::flags::NONE && exc_flags == user::flags::NONE) return m_user_map.size(); size_type c = 0; for(iterator iter = begin(inc_flags, exc_flags); iter != end(inc_flags, exc_flags); ++ iter) { ++ c; } return c; } obby::user_table::signal_deserialised_type obby::user_table::deserialised_event() const { return m_signal_deserialised; } obby::user& obby::user_table::lookup(unsigned int id) { base_iterator iter = m_user_map.find(id); if(iter == m_user_map.end() ) throw std::logic_error("obby::user_table::lookup"); return *iter->second; } obby::user* obby::user_table::find_int(const std::string& name) { for(base_iterator iter = m_user_map.begin(); iter != m_user_map.end(); ++ iter) { if(iter->second->get_name() == name) return iter->second; } return NULL; }