You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kvirc/src/kvilib/irc/kvi_ircserverdb.cpp

647 lines
17 KiB

//=============================================================================
//
// File : kvi_ircserverdb.cpp
// Creation date : Mon Jul 10 2000 14:25:00 by Szymon Stefanek
//
// This file is part of the KVirc irc client distribution
// Copyright (C) 1999-2004 Szymon Stefanek (pragma at kvirc dot net)
//
// 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 opinion) 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. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================
#define __KVILIB__
#include <tqapplication.h>
#include <tqlayout.h>
#include <tqmessagebox.h>
#include <tqcheckbox.h>
#include "kvi_ircserverdb.h"
#include "kvi_config.h"
#include "kvi_locale.h"
#include "kvi_netutils.h"
#include "kvi_nickserv.h"
KviIrcServerDataBaseRecord::KviIrcServerDataBaseRecord(KviIrcNetwork * n)
{
m_pNetwork = n;
m_pServerList = new KviPointerList<KviIrcServer>;
m_pServerList->setAutoDelete(true);
m_pCurrentServer = 0;
}
KviIrcServerDataBaseRecord::~KviIrcServerDataBaseRecord()
{
delete m_pNetwork;
delete m_pServerList;
}
void KviIrcServerDataBaseRecord::insertServer(KviIrcServer *srv)
{
m_pServerList->append(srv);
}
KviIrcServer * KviIrcServerDataBaseRecord::findServer(const KviIrcServer * pServer)
{
for(KviIrcServer *s=m_pServerList->first();s;s=m_pServerList->next())
{
if(KviTQString::equalCI(s->m_szHostname,pServer->m_szHostname) &&
(s->m_uPort == pServer->m_uPort) &&
(s->useSSL() == pServer->useSSL()) &&
(s->isIpV6() == pServer->isIpV6()))return s;
}
return 0;
}
void KviIrcServerDataBaseRecord::setCurrentServer(KviIrcServer *srv)
{
if(m_pServerList->tqfindRef(srv) != -1)m_pCurrentServer = srv;
}
KviIrcServer * KviIrcServerDataBaseRecord::currentServer()
{
if(m_pCurrentServer)return m_pCurrentServer;
m_pCurrentServer = m_pServerList->first();
return m_pCurrentServer;
}
KviIrcServerDataBase::KviIrcServerDataBase()
{
m_pRecords = new KviPointerHashTable<TQString,KviIrcServerDataBaseRecord>(17,false);
m_pRecords->setAutoDelete(true);
m_pAutoConnectOnStartupServers = 0;
m_pAutoConnectOnStartupNetworks = 0;
}
KviIrcServerDataBase::~KviIrcServerDataBase()
{
delete m_pRecords;
if(m_pAutoConnectOnStartupServers)delete m_pAutoConnectOnStartupServers;
if(m_pAutoConnectOnStartupNetworks)delete m_pAutoConnectOnStartupNetworks;
}
void KviIrcServerDataBase::clearAutoConnectOnStartupServers()
{
if(!m_pAutoConnectOnStartupServers)return;
delete m_pAutoConnectOnStartupServers;
m_pAutoConnectOnStartupServers = 0;
}
void KviIrcServerDataBase::clearAutoConnectOnStartupNetworks()
{
if(!m_pAutoConnectOnStartupNetworks)return;
delete m_pAutoConnectOnStartupNetworks;
m_pAutoConnectOnStartupNetworks = 0;
}
void KviIrcServerDataBase::clear()
{
m_pRecords->clear();
m_szCurrentNetwork = "";
}
KviIrcServerDataBaseRecord * KviIrcServerDataBase::insertNetwork(KviIrcNetwork *n)
{
KviIrcServerDataBaseRecord * r = new KviIrcServerDataBaseRecord(n);
m_pRecords->tqreplace(n->name(),r);
return r;
}
KviIrcServerDataBaseRecord * KviIrcServerDataBase::findRecord(const TQString &szNetName)
{
return m_pRecords->tqfind(szNetName);
}
KviIrcNetwork * KviIrcServerDataBase::findNetwork(const TQString &szName)
{
KviIrcServerDataBaseRecord * r = m_pRecords->tqfind(szName);
if(!r)return 0;
return r->network();
}
KviIrcServerDataBaseRecord * KviIrcServerDataBase::currentRecord()
{
KviIrcServerDataBaseRecord * r = 0;
if(!m_szCurrentNetwork.isEmpty())r = m_pRecords->tqfind(m_szCurrentNetwork);
if(r)return r;
KviPointerHashTableIterator<TQString,KviIrcServerDataBaseRecord> it(*m_pRecords);
r = it.current();
if(!r)return 0;
m_szCurrentNetwork = r->network()->name();
return r;
}
void KviIrcServerDataBase::updateServerIp(KviIrcServer * pServer,const TQString & ip)
{
KviPointerHashTableIterator<TQString,KviIrcServerDataBaseRecord> it(*m_pRecords);
while(KviIrcServerDataBaseRecord * r = it.current())
{
KviIrcServer * srv = r->findServer(pServer);
if(srv)
{
srv->m_szIp = ip;
return;
}
++it;
}
}
bool KviIrcServerDataBase::makeCurrentBestServerInNetwork(const TQString &szNetName,KviIrcServerDataBaseRecord * r,TQString &szError)
{
m_szCurrentNetwork = szNetName;
// find a round-robin server in that network
if(r->m_pServerList->isEmpty())
{
szError = __tr2qs("The specified network has no server entries");
return false;
}
for(KviIrcServer * s = r->m_pServerList->first();s;s = r->m_pServerList->next())
{
#ifdef COMPILE_USE_QT4
if(s->m_szDescription.tqcontains("random",TQt::CaseInsensitive) ||
(s->m_szDescription.tqcontains("round",TQt::CaseInsensitive) && s->m_szDescription.tqcontains("robin",TQt::CaseInsensitive)))
#else
if(s->m_szDescription.tqcontains("random",false) ||
(s->m_szDescription.tqcontains("round",false) && s->m_szDescription.tqcontains("robin",false)))
#endif
{
r->setCurrentServer(s);
return true;
}
}
// no explicit round robin... try some common names
TQString tryAlso1,tryAlso2,tryAlso3;
KviTQString::sprintf(tryAlso1,"irc.%Q.org",&szNetName);
KviTQString::sprintf(tryAlso2,"irc.%Q.net",&szNetName);
KviTQString::sprintf(tryAlso3,"irc.%Q.com",&szNetName);
for(KviIrcServer * ss = r->m_pServerList->first();ss;ss = r->m_pServerList->next())
{
if(KviTQString::equalCI(ss->m_szHostname,tryAlso1) ||
KviTQString::equalCI(ss->m_szHostname,tryAlso2) ||
KviTQString::equalCI(ss->m_szHostname,tryAlso3))
{
r->setCurrentServer(ss);
return true;
}
}
// a random one in this network
return true;
}
bool KviIrcServerDataBase::makeCurrentServer(KviIrcServerDefinition * d,TQString &szError)
{
KviIrcServer * pServer = 0;
KviPointerHashTableIterator<TQString,KviIrcServerDataBaseRecord> it(*m_pRecords);
KviIrcServerDataBaseRecord * r = 0;
KviIrcServer * srv;
if(KviTQString::equalCIN(d->szServer,"net:",4))
{
// net:networkname form
TQString szNet = d->szServer;
szNet.remove(0,4);
KviIrcServerDataBaseRecord * r = m_pRecords->tqfind(szNet);
if(r)return makeCurrentBestServerInNetwork(szNet,r,szError);
szError = __tr2qs("The server specification seems to be in the net:<string> but the network couln't be found in the database");
return false;
}
if(KviTQString::equalCIN(d->szServer,"id:",3))
{
// id:serverid form
TQString szId = d->szServer;
szId.remove(0,3);
while((r = it.current()))
{
for(srv = r->serverList()->first();srv && (!pServer);srv = r->serverList()->next())
{
if(KviTQString::equalCI(srv->id(),szId))
{
pServer = srv;
goto search_finished;
}
}
++it;
}
szError = __tr2qs("The server specification seems to be in the id:<string> form but the identifier coulnd't be found in the database");
return false;
}
it.toFirst();
while((r = it.current()))
{
for(srv = r->serverList()->first();srv && (!pServer);srv = r->serverList()->next())
{
if(KviTQString::equalCI(srv->hostName(),d->szServer))
{
if(d->bIpV6 == srv->isIpV6())
{
if(d->bSSL == srv->useSSL())
{
if(d->bPortIsValid)
{
// must match the port
if(d->uPort == srv->port())
{
// port matches
if(!d->szLinkFilter.isEmpty())
{
// must match the link filter
if(KviTQString::equalCI(d->szLinkFilter,srv->linkFilter()))
{
// link filter matches
pServer = srv;
goto search_finished;
} // else link filter doesn't match
} else {
// no need to match the link filter
pServer = srv;
goto search_finished;
}
} // else port doesn't match
} else {
// no need to match the port
if(!d->szLinkFilter.isEmpty())
{
// must match the link filter
if(KviTQString::equalCI(d->szLinkFilter,srv->linkFilter()))
{
// link filter matches
pServer = srv;
goto search_finished;
} // else link filter doesn't match
} else {
// no need to match the link filter
pServer = srv;
goto search_finished;
}
}
}
}
}
}
++it;
}
search_finished:
if(r && pServer)
{
if(!d->szNick.isEmpty())pServer->m_szNick = d->szNick;
if(!d->szPass.isEmpty())pServer->m_szPass = d->szPass; // don't clear the pass!
if(!d->szInitUMode.isEmpty())pServer->m_szInitUMode = d->szInitUMode;
m_szCurrentNetwork = r->network()->name();
r->setCurrentServer(pServer);
return true;
}
// no such server: is it a valid ip address or hostname ?
bool bIsValidIpV4 = KviNetUtils::isValidStringIp(d->szServer);
#ifdef COMPILE_IPV6_SUPPORT
bool bIsValidIpV6 =KviNetUtils::isValidStringIp_V6(d->szServer);
#else
bool bIsValidIpV6 = false;
#endif
if(!(bIsValidIpV4 || bIsValidIpV6))
{
// is it a valid hostname ? (must contain at least one dot)
#ifdef COMPILE_USE_QT4
if(!d->szServer.tqcontains('.'))
#else
if(d->szServer.tqcontains('.') < 1)
#endif
{
// assume it is a network name!
KviIrcServerDataBaseRecord * r = m_pRecords->tqfind(d->szServer);
if(r)return makeCurrentBestServerInNetwork(d->szServer,r,szError);
// else probably not a network name
}
}
// a valid hostname or ip address , not found in list : add it and make it current
r = m_pRecords->tqfind(__tr2qs("Standalone Servers"));
if(!r)
{
r = new KviIrcServerDataBaseRecord(new KviIrcNetwork(__tr2qs("Standalone Servers")));
m_pRecords->tqreplace(r->network()->name(),r);
}
KviIrcServer * s = new KviIrcServer();
s->m_szHostname = d->szServer;
if(bIsValidIpV4)
{
s->m_szIp = d->szServer;
s->setCacheIp(true);
#ifdef COMPILE_IPV6_SUPPORT
} else {
if(bIsValidIpV6)
{
s->m_szIp = d->szServer;
s->setCacheIp(true);
d->bIpV6 = true;
}
}
#else
}
#endif
s->m_uPort = d->bPortIsValid ? d->uPort : 6667;
s->setLinkFilter(d->szLinkFilter);
s->m_szPass= d->szPass;
s->m_szNick= d->szNick;
s->m_szInitUMode = d->szInitUMode;
s->setIpV6(d->bIpV6);
s->setUseSSL(d->bSSL);
r->insertServer(s);
m_szCurrentNetwork = r->network()->name();
r->setCurrentServer(s);
return true;
}
void parseMircServerRecord(TQString entry,TQString& szNet,
TQString& szDescription,TQString& szHost,TQString& szPort,bool& bSsl,kvi_u32_t& uPort)
{
bSsl = false;
int idx = KviTQString::tqfind(entry,"SERVER:");
if(idx != -1)
{
szDescription = entry.left(idx);
szNet=szDescription.section(':',0,0);
szDescription=szDescription.section(':',1,1);
entry.remove(0,idx + 7);
idx = KviTQString::tqfind(entry,"GROUP:");
if(idx != -1)
{
szHost = entry.left(idx);
} else {
szHost = entry;
}
szPort = szHost.section(':',1,1);
if(szPort[0]=='+')
{
bSsl = true;
szPort.remove(0,1);
}
szHost = szHost.section(':',0,0);
bool bOk;
uPort = szPort.toUInt(&bOk);
if(!bOk)uPort = 6667;
}
}
void KviIrcServerDataBase::loadFromMircIni(const TQString & filename, const TQString & szMircIni, TQStringList& recentServers)
{
clear();
recentServers.clear();
TQString szDefaultServer;
KviConfig mircCfg(szMircIni,KviConfig::Read,true);
if(mircCfg.hasGroup("mirc"))
{
mircCfg.setGroup("mirc");
szDefaultServer = mircCfg.readTQStringEntry("host");
}
KviConfig cfg(filename,KviConfig::Read,true);
int i = 0;
TQString entry;
TQString key;
if(cfg.hasGroup("recent"))
{
cfg.setGroup("recent");
do {
KviTQString::sprintf(key,"n%d",i);
entry = cfg.readEntry(key);
if(!entry.isEmpty())
{
TQString szNet;
TQString szDescription;
TQString szHost;
TQString szPort;
bool bSsl = false;
kvi_u32_t uPort = 0;
parseMircServerRecord(entry,szNet,
szDescription,szHost,szPort,bSsl,uPort);
recentServers << (bSsl ? "ircs://" : "irc://" ) +szHost+":"+szPort;
}
i++;
} while(!entry.isEmpty());
}
i = 0;
if(cfg.hasGroup("servers"))
{
cfg.setGroup("servers");
do {
KviTQString::sprintf(key,"n%d",i);
entry = cfg.readEntry(key);
if(!entry.isEmpty())
{
bool bDefault = false;
TQString szNet;
TQString szDescription;
TQString szHost;
TQString szPort;
bool bSsl = false;
kvi_u32_t uPort = 0;
// <net>:<description>SERVER:<server:port>GROUP:<group???>
if(entry==szDefaultServer)
bDefault = true;
parseMircServerRecord(entry,szNet,
szDescription,szHost,szPort,bSsl,uPort);
KviIrcServerDataBaseRecord * r = findRecord(szNet);
if(!r) {
KviIrcNetwork * n = new KviIrcNetwork(szNet);
r = insertNetwork(n);
}
KviIrcServer *s = new KviIrcServer();
s->m_szHostname = szHost;
s->m_szDescription = szDescription;
s->m_uPort = uPort;
r->m_pServerList->append(s);
if(bDefault)
{
m_szCurrentNetwork = szNet;
}
}
i++;
} while(!entry.isEmpty());
}
}
void KviIrcServerDataBase::load(const TQString & filename)
{
clear();
KviConfig cfg(filename,KviConfig::Read);
KviConfigIterator it(*(cfg.dict()));
TQString tmp;
while(it.current())
{
if(it.current()->count() > 0)
{
KviIrcNetwork * n = new KviIrcNetwork(it.currentKey());
KviIrcServerDataBaseRecord * r = insertNetwork(n);
cfg.setGroup(it.currentKey());
n->m_szEncoding = cfg.readTQStringEntry("Encoding");
n->m_szDescription = cfg.readTQStringEntry("Description");
n->m_szNickName = cfg.readTQStringEntry("NickName");
n->m_szRealName = cfg.readTQStringEntry("RealName");
n->m_szUserName = cfg.readTQStringEntry("UserName");
n->m_szOnConnectCommand = cfg.readTQStringEntry("OnConnectCommand");
n->m_szOnLoginCommand = cfg.readTQStringEntry("OnLoginCommand");
n->m_pNickServRuleSet = KviNickServRuleSet::load(&cfg,TQString());
n->m_bAutoConnect = cfg.readBoolEntry("AutoConnect",false);
n->m_szUserIdentityId = cfg.readTQStringEntry("UserIdentityId");
if(n->m_bAutoConnect)
{
if(!m_pAutoConnectOnStartupNetworks)
{
m_pAutoConnectOnStartupNetworks = new KviPointerList<KviIrcServerDataBaseRecord>;
m_pAutoConnectOnStartupNetworks->setAutoDelete(false);
}
m_pAutoConnectOnStartupNetworks->append(r);
}
TQStringList l = cfg.readStringListEntry("AutoJoinChannels",TQStringList());
if(l.count() > 0)n->setAutoJoinChannelList(new TQStringList(l));
if(cfg.readBoolEntry("Current",false))m_szCurrentNetwork = it.currentKey();
int nServers = cfg.readIntEntry("NServers",0);
for(int i=0;i < nServers;i++)
{
KviIrcServer *s = new KviIrcServer();
KviTQString::sprintf(tmp,"%d_",i);
if(s->load(&cfg,tmp))
{
r->m_pServerList->append(s);
KviTQString::sprintf(tmp,"%d_Current",i);
if(cfg.readBoolEntry(tmp,false))r->m_pCurrentServer = s;
if(s->autoConnect())
{
if(!m_pAutoConnectOnStartupServers)
{
m_pAutoConnectOnStartupServers = new KviPointerList<KviIrcServer>;
m_pAutoConnectOnStartupServers->setAutoDelete(false);
}
m_pAutoConnectOnStartupServers->append(s);
}
} else delete s;
}
if(!r->m_pCurrentServer)r->m_pCurrentServer = r->m_pServerList->first();
}
++it;
}
}
void KviIrcServerDataBase::save(const TQString &filename)
{
KviConfig cfg(filename,KviConfig::Write);
cfg.clear(); // clear any old entry
KviPointerHashTableIterator<TQString,KviIrcServerDataBaseRecord> it(*m_pRecords);
TQString tmp;
while(KviIrcServerDataBaseRecord * r = it.current())
{
KviIrcNetwork * n = r->network();
cfg.setGroup(n->m_szName);
cfg.writeEntry("NServers",r->m_pServerList->count());
if(n->m_bAutoConnect)
cfg.writeEntry("AutoConnect",true);
if(!n->m_szEncoding.isEmpty())
cfg.writeEntry("Encoding",n->m_szEncoding);
if(!n->m_szDescription.isEmpty())
cfg.writeEntry("Description",n->m_szDescription);
if(!n->m_szNickName.isEmpty())
cfg.writeEntry("NickName",n->m_szNickName);
if(!n->m_szRealName.isEmpty())
cfg.writeEntry("RealName",n->m_szRealName);
if(!n->m_szUserName.isEmpty())
cfg.writeEntry("UserName",n->m_szUserName);
if(!n->m_szOnConnectCommand.isEmpty())
cfg.writeEntry("OnConnectCommand",n->m_szOnConnectCommand);
if(!n->m_szOnLoginCommand.isEmpty())
cfg.writeEntry("OnLoginCommand",n->m_szOnLoginCommand);
if(n->m_pNickServRuleSet)n->m_pNickServRuleSet->save(&cfg,TQString());
if(n->autoJoinChannelList())
cfg.writeEntry("AutoJoinChannels",*(n->autoJoinChannelList()));
if(n->m_szName == m_szCurrentNetwork)cfg.writeEntry("Current",true);
if(!n->m_szUserIdentityId.isEmpty())
cfg.writeEntry("UserIdentityId",n->m_szUserIdentityId);
int i=0;
for(KviIrcServer *s = r->m_pServerList->first();s;s = r->m_pServerList->next())
{
KviTQString::sprintf(tmp,"%d_",i);
s->save(&cfg,tmp);
if(s == r->m_pCurrentServer)
{
KviTQString::sprintf(tmp,"%d_Current",i);
cfg.writeEntry(tmp,true);
}
i++;
}
++it;
}
}