Logo Search packages:      
Sourcecode: dc-qt version File versions  Download package

HubManager.cpp

Go to the documentation of this file.
/* 
 * Copyright (C) 2001-2005 Jacek Sieka, arnetheduck on gmail point com
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "stdinc.h"
#include "DCPlusPlus.h"

#include "HubManager.h"

#include "ClientManager.h"
#include "ResourceManager.h"
#include "CryptoManager.h"

#include "HttpConnection.h"
#include "StringTokenizer.h"
#include "SimpleXML.h"
#include "UserCommand.h"

#define FAVORITES_FILE "Favorites.xml"

UserCommand HubManager::addUserCommand(int type, int ctx, int flags, const string& name, const string& command, const string& hub) {
      // No dupes, add it...
      Lock l(cs);
      userCommands.push_back(UserCommand(lastId++, type, ctx, flags, name, command, hub));
      UserCommand& uc = userCommands.back();
      if(!uc.isSet(UserCommand::FLAG_NOSAVE)) 
            save();
      return userCommands.back();
}

bool HubManager::getUserCommand(int cid, UserCommand& uc) {
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) {
            if(i->getId() == cid) {
                  uc = *i;
                  return true;
            }
      }
      return false;
}

bool HubManager::moveUserCommand(int cid, int pos) {
      dcassert(pos == -1 || pos == 1);
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) {
            if(i->getId() == cid) {
                  swap(*i, *(i + pos));
                  return true;
            }
      }
      return false;
}

void HubManager::updateUserCommand(const UserCommand& uc) {
      bool nosave = true;
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) {
            if(i->getId() == uc.getId()) {
                  *i = uc;
                  nosave = uc.isSet(UserCommand::FLAG_NOSAVE);
                  break;
            }
      }
      if(!nosave)
            save();
}

void HubManager::removeUserCommand(int cid) {
      bool nosave = true;
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) {
            if(i->getId() == cid) {
                  nosave = i->isSet(UserCommand::FLAG_NOSAVE);
                  userCommands.erase(i);
                  break;
            }
      }
      if(!nosave)
            save();
}
void HubManager::removeUserCommand(const string& srv) {
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ) {
            if((i->getHub() == srv) && i->isSet(UserCommand::FLAG_NOSAVE)) {
                  i = userCommands.erase(i);
            } else {
                  ++i;
            }
      }
}

void HubManager::removeHubUserCommands(int ctx, const string& hub) {
      Lock l(cs);
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ) {
            if(i->getHub() == hub && i->isSet(UserCommand::FLAG_NOSAVE) && i->getCtx() & ctx) {
                  i = userCommands.erase(i);
            } else {
                  ++i;
            }
      }
}


void HubManager::addFavoriteUser(User::Ptr& aUser) { 
      if(find(users.begin(), users.end(), aUser) == users.end()) {
            users.push_back(aUser);
            aUser->setFavoriteUser(new FavoriteUser());
            fire(HubManagerListener::UserAdded(), aUser);
            save();
      }
}

void HubManager::removeFavoriteUser(User::Ptr& aUser) {
      User::Iter i = find(users.begin(), users.end(), aUser);
      if(i != users.end()) {
            aUser->setFavoriteUser(NULL);
            fire(HubManagerListener::UserRemoved(), aUser);
            users.erase(i);
            save();
      }
}

void HubManager::addFavorite(const FavoriteHubEntry& aEntry) {
      FavoriteHubEntry* f;

      FavoriteHubEntry::Iter i = getFavoriteHub(aEntry.getServer());
      if(i != favoriteHubs.end()) {
            return;
      }
      f = new FavoriteHubEntry(aEntry);
      favoriteHubs.push_back(f);
      fire(HubManagerListener::FavoriteAdded(), f);
      save();
}

void HubManager::removeFavorite(FavoriteHubEntry* entry) {
      FavoriteHubEntry::Iter i = find(favoriteHubs.begin(), favoriteHubs.end(), entry);
      if(i == favoriteHubs.end()) {
            return;
      }

      fire(HubManagerListener::FavoriteRemoved(), entry);
      favoriteHubs.erase(i);
      delete entry;
      save();
}

bool HubManager::addFavoriteDir(const string& aDirectory, const string & aName){
      string path = aDirectory;

      if( path[ path.length() -1 ] != PATH_SEPARATOR )
            path += PATH_SEPARATOR;

      for(StringPairIter i = favoriteDirs.begin(); i != favoriteDirs.end(); ++i) {
            if((Util::strnicmp(path, i->first, i->first.length()) == 0) && (Util::strnicmp(path, i->first, path.length()) == 0)) {
                  return false;
            }
            if(Util::stricmp(aName, i->second) == 0) {
                  return false;
            }
      }
      favoriteDirs.push_back(make_pair(aDirectory, aName));
      save();
      return true;
}

bool HubManager::removeFavoriteDir(const string& aName) {
      string d(aName);

      if(d[d.length() - 1] != PATH_SEPARATOR)
            d += PATH_SEPARATOR;

      for(StringPairIter j = favoriteDirs.begin(); j != favoriteDirs.end(); ++j) {
            if(Util::stricmp(j->first.c_str(), d.c_str()) == 0) {
                  favoriteDirs.erase(j);
                  save();
                  return true;
            }
      }
      return false;
}

bool HubManager::renameFavoriteDir(const string& aName, const string& anotherName) {

      for(StringPairIter j = favoriteDirs.begin(); j != favoriteDirs.end(); ++j) {
            if(Util::stricmp(j->second.c_str(), aName.c_str()) == 0) {
                  j->second = anotherName;
                  save();
                  return true;
            }
      }
      return false;
}

void HubManager::onHttpFinished() throw() {
      string::size_type i, j;
      string* x;
      string bzlist;

      if(listType == TYPE_BZIP2) {
            try {
                  CryptoManager::getInstance()->decodeBZ2((u_int8_t*)downloadBuf.data(), downloadBuf.size(), bzlist);
            } catch(const CryptoException&) {
                  bzlist.clear();
            }
            x = &bzlist;
      } else {
            x = &downloadBuf;
      }

      {
            Lock l(cs);
            publicListMatrix[publicListServer].clear();

            if(x->compare(0, 5, "<?xml") == 0 || x->compare(0, 8, "\xEF\xBB\xBF<?xml") == 0) {
                  loadXmlList(*x);
            } else {
                  i = 0;

                  string utfText = Text::acpToUtf8(*x);

                  while( (i < utfText.size()) && ((j=utfText.find("\r\n", i)) != string::npos)) {
                        StringTokenizer<string> tok(utfText.substr(i, j-i), '|');
                        i = j + 2;
                        if(tok.getTokens().size() < 4)
                              continue;

                        StringList::const_iterator k = tok.getTokens().begin();
                        const string& name = *k++;
                        const string& server = *k++;
                        const string& desc = *k++;
                        const string& usersOnline = *k++;
                        publicListMatrix[publicListServer].push_back(HubEntry(name, server, desc, usersOnline));
                  }
            }
      }
      downloadBuf = Util::emptyString;
}

class XmlListLoader : public SimpleXMLReader::CallBack {
public:
      XmlListLoader(HubEntry::List& lst) : publicHubs(lst) { };
      virtual ~XmlListLoader() { }
      virtual void startTag(const string& name, StringPairList& attribs, bool) {
            if(name == "Hub") {
                  const string& name = getAttrib(attribs, "Name", 0);
                  const string& server = getAttrib(attribs, "Address", 1);
                  const string& description = getAttrib(attribs, "Description", 2);
                  const string& users = getAttrib(attribs, "Users", 3);
                  const string& country = getAttrib(attribs, "Country", 4);
                  const string& shared = getAttrib(attribs, "Shared", 5);
                  const string& minShare = getAttrib(attribs, "Minshare", 5);
                  const string& minSlots = getAttrib(attribs, "Minslots", 5);
                  const string& maxHubs = getAttrib(attribs, "Maxhubs", 5);
                  const string& maxUsers = getAttrib(attribs, "Maxusers", 5);
                  const string& reliability = getAttrib(attribs, "Reliability", 5);
                  const string& rating = getAttrib(attribs, "Rating", 5);
                  publicHubs.push_back(HubEntry(name, server, description, users, country, shared, minShare, minSlots, maxHubs, maxUsers, reliability, rating));
            }
      }
      virtual void endTag(const string&, const string&) {

      }
private:
      HubEntry::List& publicHubs;
};

void HubManager::loadXmlList(const string& xml) {
      try {
            XmlListLoader loader(publicListMatrix[publicListServer]);
            SimpleXMLReader(&loader).fromXML(xml);
      } catch(const SimpleXMLException&) {

      }
}

void HubManager::save() {
      if(dontSave)
            return;

      Lock l(cs);
      try {
            SimpleXML xml;

            xml.addTag("Favorites");
            xml.stepIn();

            xml.addTag("Hubs");
            xml.stepIn();

            for(FavoriteHubEntry::Iter i = favoriteHubs.begin(); i != favoriteHubs.end(); ++i) {
                  xml.addTag("Hub");
                  xml.addChildAttrib("Name", (*i)->getName());
                  xml.addChildAttrib("Connect", (*i)->getConnect());
                  xml.addChildAttrib("Description", (*i)->getDescription());
                  xml.addChildAttrib("Nick", (*i)->getNick(false));
                  xml.addChildAttrib("Password", (*i)->getPassword());
                  xml.addChildAttrib("Server", (*i)->getServer());
                  xml.addChildAttrib("UserDescription", (*i)->getUserDescription());
                  xml.addChildAttrib("Bottom", Util::toString((*i)->getBottom()));
                  xml.addChildAttrib("Top", Util::toString((*i)->getTop()));
                  xml.addChildAttrib("Right", Util::toString((*i)->getRight()));
                  xml.addChildAttrib("Left", Util::toString((*i)->getLeft()));
            }
            xml.stepOut();
            xml.addTag("Users");
            xml.stepIn();
            for(User::Iter j = users.begin(); j != users.end(); ++j) {
                  xml.addTag("User");
                  xml.addChildAttrib("Nick", (*j)->getNick());
                  xml.addChildAttrib("LastHubAddress", (*j)->getLastHubAddress());
                  xml.addChildAttrib("LastHubName", (*j)->getLastHubName());
                  xml.addChildAttrib("LastSeen", (*j)->getFavoriteLastSeen());
                  xml.addChildAttrib("GrantSlot", (*j)->getFavoriteGrantSlot());
                  xml.addChildAttrib("UserDescription", (*j)->getUserDescription());
            }
            xml.stepOut();
            xml.addTag("UserCommands");
            xml.stepIn();
            for(UserCommand::Iter k = userCommands.begin(); k != userCommands.end(); ++k) {
                  if(!k->isSet(UserCommand::FLAG_NOSAVE)) {
                        xml.addTag("UserCommand");
                        xml.addChildAttrib("Type", k->getType());
                        xml.addChildAttrib("Context", k->getCtx());
                        xml.addChildAttrib("Name", k->getName());
                        xml.addChildAttrib("Command", k->getCommand());
                        xml.addChildAttrib("Hub", k->getHub());
                  }
            }
            xml.stepOut();
            //Favorite download to dirs
            xml.addTag("FavoriteDirs");
            xml.stepIn();
            StringPairList spl = getFavoriteDirs();
            for(StringPairIter i = spl.begin(); i != spl.end(); ++i) {
                  xml.addTag("Directory", i->first);
                  xml.addChildAttrib("Name", i->second);
            }
            xml.stepOut();

            xml.stepOut();

            string fname = Util::getAppPath() + FAVORITES_FILE;

            File f(fname + ".tmp", File::WRITE, File::CREATE | File::TRUNCATE);
            f.write(SimpleXML::utf8Header);
            f.write(xml.toXML());
            f.close();
            File::deleteFile(fname);
            File::renameFile(fname + ".tmp", fname);

      } catch(const Exception& e) {
            dcdebug("HubManager::save: %s\n", e.getError().c_str());
      }
}

void HubManager::load() {
      
      // Add NMDC standard op commands
      static const char kickstr[] = 
            "$To: %[nick] From: %[mynick] $<%[mynick]> You are being kicked because: %[line:Reason]|<%[mynick]> %[mynick] is kicking %[nick] because: %[line:Reason]|$Kick %[nick]|";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
            STRING(KICK_USER), kickstr, "op");
      static const char redirstr[] =
            "$OpForceMove $Who:%[nick]$Where:%[line:Target Server]$Msg:%[line:Message]|";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE, 
            STRING(REDIRECT_USER), redirstr, "op");

      // Add ADC standard op commands
      static const char adc_disconnectstr[] =
            "HDSC %[mycid] %[cid] DI ND Friendly\\ disconnect\n";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
            STRING(DISCONNECT_USER), adc_disconnectstr, "adc://op");
      static const char adc_kickstr[] =
            "HDSC %[mycid] %[cid] KK KK %[line:Reason]\n";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
            STRING(KICK_USER), adc_kickstr, "adc://op");
      static const char adc_banstr[] =
            "HDSC %[mycid] %[cid] BN BN %[line:Seconds (-1 = forever)] %[line:Reason]\n";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
            STRING(BAN_USER), adc_banstr, "adc://op");
      static const char adc_redirstr[] =
            "HDSC %[mycid] %[cid] RD RD %[line:Redirect address] %[line:Reason]\n";
      addUserCommand(UserCommand::TYPE_RAW_ONCE, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, UserCommand::FLAG_NOSAVE,
            STRING(REDIRECT_USER), adc_redirstr, "adc://op");


      try {
            SimpleXML xml;
            xml.fromXML(File(Util::getAppPath() + FAVORITES_FILE, File::READ, File::OPEN).read());
            
            if(xml.findChild("Favorites")) {
                  xml.stepIn();
                  load(&xml);
                  xml.stepOut();
            }
      } catch(const Exception& e) {
            dcdebug("HubManager::load: %s\n", e.getError().c_str());
      }
}

void HubManager::load(SimpleXML* aXml) {
      dontSave = true;

      // Old names...load for compatibility.
      aXml->resetCurrentChild();
      if(aXml->findChild("Favorites")) {
            aXml->stepIn();
            while(aXml->findChild("Favorite")) {
                  FavoriteHubEntry* e = new FavoriteHubEntry();
                  e->setName(aXml->getChildAttrib("Name"));
                  e->setConnect(aXml->getBoolChildAttrib("Connect"));
                  e->setDescription(aXml->getChildAttrib("Description"));
                  e->setNick(aXml->getChildAttrib("Nick"));
                  e->setPassword(aXml->getChildAttrib("Password"));
                  e->setServer(aXml->getChildAttrib("Server"));
                  e->setUserDescription(aXml->getChildAttrib("UserDescription"));
                  favoriteHubs.push_back(e);
            }
            aXml->stepOut();
      }
      aXml->resetCurrentChild();
      if(aXml->findChild("Commands")) {
            aXml->stepIn();
            while(aXml->findChild("Command")) {
                  const string& name = aXml->getChildAttrib("Name");
                  const string& command = aXml->getChildAttrib("Command");
                  const string& hub = aXml->getChildAttrib("Hub");
                  const string& nick = aXml->getChildAttrib("Nick");
                  if(nick.empty()) {
                        // Old mainchat style command
                        addUserCommand(UserCommand::TYPE_RAW, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH, 
                              0, name, "<%[mynick]> " + command + "|", hub);
                  } else {
                        addUserCommand(UserCommand::TYPE_RAW, UserCommand::CONTEXT_CHAT | UserCommand::CONTEXT_SEARCH,
                              0, name, "$To: " + nick + " From: %[mynick] $" + command + "|", hub);
                  }
            }
            aXml->stepOut();
      }
      // End old names

      aXml->resetCurrentChild();
      if(aXml->findChild("Hubs")) {
            aXml->stepIn();
            while(aXml->findChild("Hub")) {
                  FavoriteHubEntry* e = new FavoriteHubEntry();
                  e->setName(aXml->getChildAttrib("Name"));
                  e->setConnect(aXml->getBoolChildAttrib("Connect"));
                  e->setDescription(aXml->getChildAttrib("Description"));
                  e->setNick(aXml->getChildAttrib("Nick"));
                  e->setPassword(aXml->getChildAttrib("Password"));
                  e->setServer(aXml->getChildAttrib("Server"));
                  e->setUserDescription(aXml->getChildAttrib("UserDescription"));
                  e->setBottom((u_int16_t)aXml->getIntChildAttrib("Bottom") );
                  e->setTop((u_int16_t)aXml->getIntChildAttrib("Top"));
                  e->setRight((u_int16_t)aXml->getIntChildAttrib("Right"));
                  e->setLeft((u_int16_t)aXml->getIntChildAttrib("Left"));
                  favoriteHubs.push_back(e);
            }
            aXml->stepOut();
      }
      aXml->resetCurrentChild();
      if(aXml->findChild("Users")) {
            aXml->stepIn();
            while(aXml->findChild("User")) {
                  User::Ptr u = ClientManager::getInstance()->getUser(aXml->getChildAttrib("Nick"), aXml->getChildAttrib("LastHubAddress"));
                  if(!u->isOnline()) {
                        u->setLastHubAddress(aXml->getChildAttrib("LastHubAddress"));
                        u->setLastHubName(aXml->getChildAttrib("LastHubName"));
                  }
                  addFavoriteUser(u);
                  u->setFavoriteGrantSlot(aXml->getBoolChildAttrib("GrantSlot"));
                  u->setFavoriteLastSeen((u_int32_t)aXml->getIntChildAttrib("LastSeen"));
                  u->setUserDescription(aXml->getChildAttrib("UserDescription"));
            }
            aXml->stepOut();
      }
      aXml->resetCurrentChild();
      if(aXml->findChild("UserCommands")) {
            aXml->stepIn();
            while(aXml->findChild("UserCommand")) {
                  addUserCommand(aXml->getIntChildAttrib("Type"), aXml->getIntChildAttrib("Context"),
                        0, aXml->getChildAttrib("Name"), aXml->getChildAttrib("Command"), aXml->getChildAttrib("Hub"));
            }
            aXml->stepOut();
      }
      //Favorite download to dirs
      aXml->resetCurrentChild();
      if(aXml->findChild("FavoriteDirs")) {
            aXml->stepIn();
            while(aXml->findChild("Directory")) {
                  string virt = aXml->getChildAttrib("Name");
                  string d(aXml->getChildData());
                  HubManager::getInstance()->addFavoriteDir(d, virt);
            }
            aXml->stepOut();
      }

      dontSave = false;
}

StringList HubManager::getHubLists() {
      StringTokenizer<string> lists(SETTING(HUBLIST_SERVERS), ';');
      return lists.getTokens();
}

bool HubManager::setHubList(int aHubList) {
      if(!running) {
            lastServer = aHubList;
            StringList sl = getHubLists();
            publicListServer = sl[(lastServer) % sl.size()];
            return true;
      }
      return false;
}

void HubManager::refresh() {
      StringList sl = getHubLists();
      if(sl.empty())
            return;
      publicListServer = sl[(lastServer) % sl.size()];
      if(Util::strnicmp(publicListServer.c_str(), "http://", 7) != 0) {
            lastServer++;
            return;
      }

      fire(HubManagerListener::DownloadStarting(), publicListServer);
      if(!running) {
            if(!c)
                  c = new HttpConnection();
            {
                  Lock l(cs);
                  publicListMatrix[publicListServer].clear();
            }
            c->addListener(this);
            c->downloadFile(publicListServer);
            running = true;
      }
}

UserCommand::List HubManager::getUserCommands(int ctx, const string& hub, bool op) {
      Lock l(cs);
      UserCommand::List lst;
      bool adc = hub.size() >= 6 && hub.substr(0, 6) == "adc://";
      for(UserCommand::Iter i = userCommands.begin(); i != userCommands.end(); ++i) {
            UserCommand& uc = *i;
            if(uc.getCtx() & ctx) {
            if( (!adc && (uc.getHub().empty() || (op && uc.getHub() == "op"))) ||
                        (adc && (uc.getHub() == "adc://" || (op && uc.getHub() == "adc://op"))) ||
                        (Util::stricmp(hub, uc.getHub()) == 0) )
                  {
                        lst.push_back(*i);
                  }
            }
      }
      return lst;
}

// HttpConnectionListener
void HubManager::on(Data, HttpConnection*, const u_int8_t* buf, size_t len) throw() { 
      downloadBuf.append((const char*)buf, len);
}

void HubManager::on(Failed, HttpConnection*, const string& aLine) throw() { 
      c->removeListener(this);
      lastServer++;
      running = false;
      fire(HubManagerListener::DownloadFailed(), aLine);
}
void HubManager::on(Complete, HttpConnection*, const string& aLine) throw() {
      c->removeListener(this);
      onHttpFinished();
      running = false;
      fire(HubManagerListener::DownloadFinished(), aLine);
}
void HubManager::on(Redirected, HttpConnection*, const string& aLine) throw() { 
      fire(HubManagerListener::DownloadStarting(), aLine);
}
void HubManager::on(TypeNormal, HttpConnection*) throw() { 
      listType = TYPE_NORMAL; 
}
void HubManager::on(TypeBZ2, HttpConnection*) throw() { 
      listType = TYPE_BZIP2; 
}

/**
 * @file
 * $Id: HubManager.cpp,v 1.2 2005/08/21 14:03:43 olof Exp $
 */

Generated by  Doxygen 1.6.0   Back to index