roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * proxy.cpp
 *	 Source file for proxy access
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */

#include "mud.h"

#include <sstream>
#include <iomanip>
#include <locale>
#include <iostream>
#include <fstream>

#include "boost/format.hpp"

//*********************************************************************
// CmdProxy
//*********************************************************************
// Allows a player to view, grant, or revoke proxy access
// to their character

int cmdProxy(Player* player, cmd* cmnd) {

	if(cmnd->num == 1) {
		bstring proxyList = gConfig->getProxyList(player);
		if(proxyList.empty())
			*player << "No proxy access currently allowed.\n";
		else
			*player << proxyList;
		return(0);
	}
	if(player->getProxyName() != "") {
		*player << "You cannot change the proxy access of a proxied character.\n";
		return(0);
	}
	if(player->isStaff()) {
		*player << "You cannot allow proxy access to a staff character!\n";
		return(0);
	}
	bool online=true;

	Player*	target=0;
	bstring name =  cmnd->str[1];

	if(name.length() > 1 && name.getAt(0) == 'p' && isdigit(name.getAt(1))) {
		target = gServer->lookupPlyId(name);
	}

	if(!target && name.length() > 1 && name.getAt(0) == 'p' && isdigit(name.getAt(1))) {
		// Dealing with an ID
		name.setAt(0, up(name.getAt(0)));
		// TODO: Print success/failure

		if(gConfig->removeProxyAccess(name, player) )
		    *player << "Proxy access removed for PlayerID: " << name << "\n";
		else
		    *player << "PlayerID: " << name << " does not have proxy access to your character.\n";
		return(0);
	}
	else {
		// We're dealing with a player
		if(!target) {
			name = name.toLower();
			name.setAt(0, up(name.getAt(0)));
			target = gServer->findPlayer(name);
		}

		if(!target) {
			if(!loadPlayer(name.c_str(), &target)) {
				*player << "Player does not exist.\n";
				return(0);
			}

			online = false;
		}
		if(target->isStaff()) {
			if(!online)
				free_crt(target);
			*player << "You cannot give staff proxy access!.\n";
			return(0);
		}
		if(target->getId() == player->getId()) {
			*player << "That's just silly.\n";
			if(!online)
				free_crt(target);
			return(0);
		}

		if(gConfig->hasProxyAccess(target, player)) {
			*player << "You remove " << target->getName() << "'s proxy access to your character.\n";

			gConfig->removeProxyAccess(target, player);
			if(online)
				*target << "Your proxy access to " << player->getName() << " has been revoked.\n";
			else
				free_crt(target);
		} else {
			*player << "You grant " << target->getName() << " proxy access to your character.\n";

			gConfig->grantProxyAccess(target, player);
			if(online)
				*target << "Your now have been granted proxy access to " << player->getName() << ".\n";
			else
				free_crt(target);

		}
	}
	return(0);
}

//*********************************************************************
//                      Config proxy functions
//*********************************************************************

//*********************************************************************
// HasProxyAccess
//*********************************************************************
// Does (proxy) have access to (proxied)

bool Config::hasProxyAccess(Player* proxy, Player* proxied) {
    return(proxyManager->hasProxyAccess(proxy, proxied));
}

//*********************************************************************
// getProxyList
//*********************************************************************
// Returns a bstring showing proxy access for the given player
// or all players if player is NULL

bstring Config::getProxyList(Player* player) {
    std::ostringstream oStr;
    bstring lastId = "";

    oStr.setf(std::ios::left, std::ios::adjustfield);
    boost::format format("%1% %|15t|%2% %|45t|%3%\n");

    oStr << format % "" % "Character Name" % "Proxy Access";
    for(ProxyMultiMap::value_type p : proxyManager->proxies) {
        ProxyAccess &proxy = p.second;

        if(player && proxy.getProxiedId() != player->getId())
            continue;

        format.exceptions( boost::io::all_error_bits ^ ( boost::io::too_many_args_bit | boost::io::too_few_args_bit )  );
        if(proxy.getProxiedId() != lastId) {
            lastId = proxy.getProxiedId();
            oStr << format % "Character: "
                           % (proxy.getProxiedName() + "(" + proxy.getProxiedId() + ")")
                           % (bstring("- ") + proxy.getProxyName() + "(" + proxy.getProxyId() + ")");
        } else {
            oStr << format % ""
                           % ""
                           % (bstring("- ") + proxy.getProxyName() + "(" + proxy.getProxyId() + ")");
        }
    }
    return(oStr.str());
}

//*********************************************************************
// GrantProxyAccess
//*********************************************************************
// Grant proxy access to (proxied) for (proxy)

void Config::grantProxyAccess(Player* proxy, Player* proxied) {
    proxyManager->grantProxyAccess(proxy, proxied);
}

//*********************************************************************
// RemoveProxyAccess
//*********************************************************************
// Remove proxy access to (proxied) for (proxy)

bool Config::removeProxyAccess(Player* proxy, Player* proxied) {
    return(proxyManager->removeProxyAccess(proxy, proxied));
}
//*********************************************************************
// RemoveProxyAccess
//*********************************************************************
// Remove proxy access to (proxied) for (id)

bool Config::removeProxyAccess(bstring id, Player* proxied) {
    return(proxyManager->removeProxyAccess(id, proxied));
}


//*********************************************************************
// LoadProxyAccess
//*********************************************************************
// Reset the proxy manager if necessary and load in proxy access

void Config::loadProxyAccess() {
    if(proxyManager)
        proxyManager->clear();
    proxyManager = new ProxyManager;
}
//*********************************************************************
// SaveProxyAccess
//*********************************************************************
// Save proxy access list

void Config::saveProxyAccess() {
    proxyManager->save();
}

//*********************************************************************
//                      Player proxy functions
//*********************************************************************

//*********************************************************************
// SetProxy
//*********************************************************************
// Set's player as the current proxy user

void Player::setProxy(Player* proxy) {
	proxyName = proxy->getName();
	proxyId = proxy->getId();
}

//*********************************************************************
// SetProxy
//*********************************************************************
// Set's proxyName & proxyId as the current proxy user & ID

void Player::setProxy(bstring pProxyName, bstring pProxyId) {
	proxyName = pProxyName;
	proxyId = pProxyId;
}

//*********************************************************************
// SetProxyName
//*********************************************************************
// Set's proxyName as the current proxy user

void Player::setProxyName(bstring pProxyName) {
	proxyName = pProxyName;
}

//*********************************************************************
// SetProxyID
//*********************************************************************
// Set's proxyId as the current proxy ID

void Player::setProxyId(bstring pProxyId) {
	proxyId = pProxyId;
}


bstring Player::getProxyName() const { return(proxyName); }
bstring Player::getProxyId() const { return(proxyId); }



//*********************************************************************
//                ProxyManager proxy functions
//*********************************************************************

ProxyManager::ProxyManager() {
    loadProxies();
}

void ProxyManager::clear() {
    proxies.clear();
    delete this;
}

//*********************************************************************
// grantProxyAccess
//*********************************************************************
// Grant proxy access to (proxied) for (proxy)

void ProxyManager::grantProxyAccess(Player* proxy, Player* proxied) {
    if(hasProxyAccess(proxy, proxied))
        return;
    proxies.insert(ProxyMultiMap::value_type(proxied->getId(), ProxyAccess(proxy, proxied)));
    gConfig->saveProxyAccess();
}

//*********************************************************************
// removeProxyAccess
//*********************************************************************
// Remove proxy access to (proxied) for (proxy)

bool ProxyManager::removeProxyAccess(Player* proxy, Player* proxied) {
    return(removeProxyAccess(proxy->getId(), proxied));
}

//*********************************************************************
// removeProxyAccess
//*********************************************************************
// Remove proxy access to (proxied) for (proxy)

bool ProxyManager::removeProxyAccess(bstring id, Player* proxied) {
    ProxyMultiMapRange range = proxies.equal_range(proxied->getId());
    for(ProxyMultiMap::iterator it = range.first ; it != range.second ; it++) {
        ProxyAccess& proxyAccess = it->second;
        if(proxyAccess.getProxyId() == id) {
            proxies.erase(it);
            gConfig->saveProxyAccess();
            return(true);
        }
    }
    return(false);
}

//*********************************************************************
// hasProxyAccess
//*********************************************************************
// True if (proxy) has proxy access to (proxied)

bool ProxyManager::hasProxyAccess(Player* proxy, Player* proxied) {
    if(!proxy || !proxied)
        return(false);

    ProxyMultiMapRange range = proxies.equal_range(proxied->getId());
    for(ProxyMultiMap::iterator it = range.first ; it != range.second ; it++) {
        ProxyAccess& proxyAccess = it->second;
        if(proxyAccess.hasProxyAccess(proxy, proxied))
            return(true);
    }
    return(false);
}


void ProxyManager::save() {
	xmlDocPtr	xmlDoc;
	xmlNodePtr		rootNode;
	char			filename[80];


	xmlDoc = xmlNewDoc(BAD_CAST "1.0");
	rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Proxies", NULL);
	xmlDocSetRootElement(xmlDoc, rootNode);

	for(ProxyMultiMap::value_type p : proxies) {
		p.second.save(rootNode);
	}

	sprintf(filename, "%s/proxies.xml", Path::PlayerData);

	xml::saveFile(filename, xmlDoc);
	xmlFreeDoc(xmlDoc);
}

void ProxyManager::loadProxies() {
    xmlDocPtr   xmlDoc;
    xmlNodePtr  rootNode;
    xmlNodePtr  curNode;
    char        filename[80];

    sprintf(filename, "%s/proxies.xml", Path::PlayerData);

    if(!file_exists(filename))
        return;

    if((xmlDoc = xml::loadFile(filename, "Proxies")) == NULL)
    	return;

    rootNode = xmlDocGetRootElement(xmlDoc);
    curNode = rootNode->children;

    while(curNode) {
        if(NODE_NAME(curNode, "ProxyAccess")) {
            ProxyAccess access(curNode);
            proxies.insert(ProxyMultiMap::value_type(access.getProxiedId(), access));
        }
        curNode = curNode->next;
    }

    xmlFreeDoc(xmlDoc);
    xmlCleanupParser();
}


//*********************************************************************
//                ProxyAccess proxy functions
//*********************************************************************



ProxyAccess::ProxyAccess(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;
	while(curNode) {
		     if(NODE_NAME(curNode, "ProxyId")) xml::copyToBString(proxyId, curNode);
		else if (NODE_NAME(curNode, "ProxyName")) xml::copyToBString(proxyName, curNode);
		else if (NODE_NAME(curNode, "ProxiedId")) xml::copyToBString(proxiedId, curNode);
		else if (NODE_NAME(curNode, "ProxiedName")) xml::copyToBString(proxiedName, curNode);

		curNode = curNode->next;
	}
}
ProxyAccess::ProxyAccess(Player* proxy, Player* proxied) {
	proxyName = proxy->getName();
	proxyId = proxy->getId();
	proxiedName = proxied->getName();
	proxiedId = proxied->getId();
}

void ProxyAccess::save(xmlNodePtr rootNode) {
    xmlNodePtr curNode = xml::newStringChild(rootNode, "ProxyAccess");
    xml::newStringChild(curNode, "ProxiedId", proxiedId);
    xml::newStringChild(curNode, "ProxiedName", proxiedName);
    xml::newStringChild(curNode, "ProxyId", proxyId);
    xml::newStringChild(curNode, "ProxyName", proxyName);

}

//*********************************************************************
// hasProxyAccess
//*********************************************************************
// True if (proxy) has proxy access to (proxied)

bool ProxyAccess::hasProxyAccess(Player* proxy, Player* proxied) {
	if(proxiedId == proxied->getId() && proxiedName == proxied->getName() &&
			proxyId == proxy->getId() && proxyName == proxy->getName())
		return(true);
	return(false);
}
bstring ProxyAccess::getProxiedId() const { return proxiedId; }
bstring ProxyAccess::getProxiedName() const { return proxiedName; }
bstring ProxyAccess::getProxyId() const { return proxyId; }

bstring ProxyAccess::getProxyName() const { return proxyName; }