|
|
|
//=============================================================================
|
|
|
|
//
|
|
|
|
// File : kvi_filetrader.cpp
|
|
|
|
// Creation date : Wed Aug 27 2000 10:33:11 CEST by Szymon Stefanek
|
|
|
|
//
|
|
|
|
// This file is part of the KVirc irc client distribution
|
|
|
|
// Copyright (C) 1999-2007 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 "kvi_sharedfiles.h"
|
|
|
|
|
|
|
|
#include "kvi_config.h"
|
|
|
|
#include "kvi_fileutils.h"
|
|
|
|
|
|
|
|
#include <tqfileinfo.h>
|
|
|
|
|
|
|
|
// TODO: Match servers that the file requests come from
|
|
|
|
// TODO: Max number of downloads ?
|
|
|
|
|
|
|
|
// FIXME: MD5SUM ?
|
|
|
|
|
|
|
|
/*
|
|
|
|
@doc: shared_files
|
|
|
|
@title:
|
|
|
|
Sharing files with KVIrc
|
|
|
|
@type:
|
|
|
|
generic
|
|
|
|
@short:
|
|
|
|
Automatically sharing your files with other IRC users
|
|
|
|
@keyterms:
|
|
|
|
file sharing
|
|
|
|
@body:
|
|
|
|
[big]What is this ?[/big]
|
|
|
|
The "file offers" are a simple way to share your files with other IRC users.[br]
|
|
|
|
Basically , you setup an offer by selecting a local file, choosing a "visible name" for it.
|
|
|
|
Remote users will be able to request you the file and download it automatically by
|
|
|
|
issuing a simple DCC GET request.[br]
|
|
|
|
[big]Details[/big]
|
|
|
|
Each offer refers to an existing file on one of your locally mounted file systems.
|
|
|
|
The offer is given a visible name that the remote users will effectively request.
|
|
|
|
To share the file /usr/arch/mp3/SonataArctica_SingInSilence_Live.mp3 you will add a file offer
|
|
|
|
with /usr/arch/mp3/SonataArctica_SingInSilence_Live.mp3 as real file path , something like
|
|
|
|
"SonataArctica_SingInSilence.mp3". A remote user will then request you a DCC GET SonataArctica_SingInSilence.mp3
|
|
|
|
and KVIrc will automatically send the file.[br]
|
|
|
|
Each file offer has an "user mask" that the requesting remote users must match to
|
|
|
|
obtain the file: *!*@* matches any user, Pragma!*@* matches any user with nickname pragma,
|
|
|
|
*!*@*.omnikron.net matches any user coming from the omnikron.net domain.[br]
|
|
|
|
Each offer can have an expire time: the offer will be automatically removed after
|
|
|
|
a defined number of seconds. An expire time of '0' seconds means that the offer should never expire.[br]
|
|
|
|
If you have two file offers with the same name and different file, the remote user can
|
|
|
|
use an additional "size" parameter in the DCC GET request.[br]
|
|
|
|
[big]Security issues[/big]
|
|
|
|
This is a nice but unsecure method of sharing files.[br]
|
|
|
|
The user mask is a good protection but you have to use it properly!.[br]
|
|
|
|
Setting the user mask to Nick!*@* can be easily exploited (just by making an user disconnect
|
|
|
|
in one of the well known ways and then by using his nickname).[br]
|
|
|
|
On the other side, the remote end must know exactly the visible name of the offer to request
|
|
|
|
and noone but you will tell him that name.[br]
|
|
|
|
In sum:[br]
|
|
|
|
Don't share any really important files: this *might* be like putting it on your webpage :D[br]
|
|
|
|
Please don't send complains if someone stoles your /etc/passwd : it is because you have permitted that.[br]
|
|
|
|
*/
|
|
|
|
|
|
|
|
KviSharedFile::KviSharedFile(const TQString &szName,const TQString &szAbsPath,const TQString &szUserMask,time_t expireTime,unsigned int uFileSize)
|
|
|
|
{
|
|
|
|
m_szName = szName;
|
|
|
|
m_szAbsFilePath = szAbsPath;
|
|
|
|
m_szUserMask = szUserMask;
|
|
|
|
m_expireTime = expireTime;
|
|
|
|
m_uFileSize = uFileSize;
|
|
|
|
m_uWildCount = m_szUserMask.contains('*');
|
|
|
|
m_uNonWildCount = m_szUserMask.length() - m_uWildCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
KviSharedFile::~KviSharedFile()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
KviSharedFilesManager::KviSharedFilesManager()
|
|
|
|
: TQObject()
|
|
|
|
{
|
|
|
|
m_pSharedListDict = new KviPointerHashTable<TQString,KviSharedFileList>();
|
|
|
|
m_pSharedListDict->setAutoDelete(true);
|
|
|
|
m_pCleanupTimer = new TQTimer();
|
|
|
|
connect(m_pCleanupTimer,TQT_SIGNAL(timeout()),this,TQT_SLOT(cleanup()));
|
|
|
|
}
|
|
|
|
|
|
|
|
KviSharedFilesManager::~KviSharedFilesManager()
|
|
|
|
{
|
|
|
|
if(m_pCleanupTimer->isActive())m_pCleanupTimer->stop();
|
|
|
|
delete m_pCleanupTimer;
|
|
|
|
delete m_pSharedListDict;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KviSharedFilesManager::cleanup()
|
|
|
|
{
|
|
|
|
KviPointerHashTableIterator<TQString,KviSharedFileList> it(*m_pSharedListDict);
|
|
|
|
time_t curTime = time(0);
|
|
|
|
|
|
|
|
bool bOtherStuffToCleanup = false;
|
|
|
|
//bool bChanged = false;
|
|
|
|
|
|
|
|
KviPointerList<TQString> lDying;
|
|
|
|
lDying.setAutoDelete(true);
|
|
|
|
|
|
|
|
while(KviSharedFileList * l = it.current())
|
|
|
|
{
|
|
|
|
KviPointerList<KviSharedFile> tmp;
|
|
|
|
tmp.setAutoDelete(false);
|
|
|
|
for(KviSharedFile * o = l->first();o;o = l->next())
|
|
|
|
{
|
|
|
|
if(o->expireTime() > 0)
|
|
|
|
{
|
|
|
|
if(((int)o->expireTime()) <= ((int)curTime))
|
|
|
|
{
|
|
|
|
tmp.append(o);
|
|
|
|
//bChanged = true;
|
|
|
|
} else {
|
|
|
|
bOtherStuffToCleanup = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for(KviSharedFile * fo = tmp.first();fo;fo = tmp.next())
|
|
|
|
{
|
|
|
|
l->removeRef(fo);
|
|
|
|
emit sharedFileRemoved(fo);
|
|
|
|
}
|
|
|
|
if(l->count() == 0)
|
|
|
|
lDying.append(new TQString(it.currentKey()));
|
|
|
|
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(TQString * pDyingKey = lDying.first();pDyingKey;pDyingKey = lDying.next())
|
|
|
|
m_pSharedListDict->remove(*pDyingKey);
|
|
|
|
|
|
|
|
if(!bOtherStuffToCleanup)m_pCleanupTimer->stop();
|
|
|
|
//if(bChanged)emit sharedFilesChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KviSharedFilesManager::clear()
|
|
|
|
{
|
|
|
|
m_pSharedListDict->clear();
|
|
|
|
emit sharedFilesChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
void KviSharedFilesManager::doInsert(KviSharedFileList * l, KviSharedFile * o)
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
for(KviSharedFile * fo =l->first();fo;fo = l->next())
|
|
|
|
{
|
|
|
|
if(o->wildcardCount() > 0)
|
|
|
|
{
|
|
|
|
// the new mask has wildcards... if the current one has none, skip it
|
|
|
|
if(fo->wildcardCount() > 0)
|
|
|
|
{
|
|
|
|
// the one in the list has wildcards too...
|
|
|
|
// the ones with more non-wild chars go first...
|
|
|
|
if(fo->nonWildcardCount() < o->nonWildcardCount())
|
|
|
|
{
|
|
|
|
// ok...the new one has more non-wildcards , insert
|
|
|
|
l->insert(index,o);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
if(o->nonWildcardCount() == fo->nonWildcardCount())
|
|
|
|
{
|
|
|
|
// the same number of non-wildcards
|
|
|
|
// let the number of wildcards decide (it will be eventually equal)
|
|
|
|
if(o->wildcardCount() < fo->wildcardCount())
|
|
|
|
{
|
|
|
|
// the new one has less wildcards... goes first
|
|
|
|
l->insert(index,o);
|
|
|
|
return;
|
|
|
|
} // else the same number of wildcards and non-wildcards...skip
|
|
|
|
} // else the existing one has more non-wildcards...skip
|
|
|
|
}
|
|
|
|
} // else the current has no wildcards...skip
|
|
|
|
} else {
|
|
|
|
// the new mask has no wildcards....
|
|
|
|
if(fo->wildcardCount() > 0)
|
|
|
|
{
|
|
|
|
// current one has wildcards...insert
|
|
|
|
l->insert(index,o);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// the current one has no wildcards...
|
|
|
|
// the longer masks go first....
|
|
|
|
if(fo->maskLength() < o->maskLength())
|
|
|
|
{
|
|
|
|
// the current one is shorter than the new one...insert
|
|
|
|
l->insert(index,o);
|
|
|
|
return;
|
|
|
|
} // else current one is longer...skip
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
l->append(o);
|
|
|
|
}
|
|
|
|
|
|
|
|
void KviSharedFilesManager::addSharedFile(KviSharedFile * f)
|
|
|
|
{
|
|
|
|
// First find the list
|
|
|
|
KviSharedFileList * l = m_pSharedListDict->find(f->name());
|
|
|
|
if(!l)
|
|
|
|
{
|
|
|
|
l = new KviSharedFileList;
|
|
|
|
l->setAutoDelete(true);
|
|
|
|
m_pSharedListDict->replace(f->name(),l);
|
|
|
|
}
|
|
|
|
|
|
|
|
doInsert(l,f);
|
|
|
|
|
|
|
|
if(((int)f->expireTime()) > 0)
|
|
|
|
{
|
|
|
|
if(!m_pCleanupTimer->isActive())m_pCleanupTimer->start(60000);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit sharedFileAdded(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
KviSharedFile * KviSharedFilesManager::addSharedFile(const TQString &szName,const TQString &szAbsPath,const TQString &szMask,int timeoutInSecs)
|
|
|
|
{
|
|
|
|
TQFileInfo inf(szAbsPath);
|
|
|
|
if(inf.exists() && inf.isFile() && inf.isReadable() && (inf.size() > 0))
|
|
|
|
{
|
|
|
|
// First find the list
|
|
|
|
KviSharedFileList * l = m_pSharedListDict->find(szName);
|
|
|
|
if(!l)
|
|
|
|
{
|
|
|
|
l = new KviSharedFileList;
|
|
|
|
l->setAutoDelete(true);
|
|
|
|
m_pSharedListDict->replace(szName,l);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now insert
|
|
|
|
KviSharedFile * o = new KviSharedFile(szName,szAbsPath,szMask,timeoutInSecs > 0 ? (((int)(time(0))) + timeoutInSecs) : 0,inf.size());
|
|
|
|
|
|
|
|
doInsert(l,o);
|
|
|
|
|
|
|
|
if(((int)o->expireTime()) > 0)
|
|
|
|
{
|
|
|
|
if(!m_pCleanupTimer->isActive())m_pCleanupTimer->start(60000);
|
|
|
|
}
|
|
|
|
|
|
|
|
emit sharedFileAdded(o);
|
|
|
|
|
|
|
|
return o;
|
|
|
|
} else {
|
|
|
|
tqDebug("File %s unreadable: can't add offer",KviTQString::toUtf8(szAbsPath).data());
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KviSharedFile * KviSharedFilesManager::lookupSharedFile(const TQString &szName,KviIrcMask * mask,unsigned int uFileSize)
|
|
|
|
{
|
|
|
|
KviSharedFileList * l = m_pSharedListDict->find(szName);
|
|
|
|
if(!l)return 0;
|
|
|
|
|
|
|
|
for(KviSharedFile * o = l->first();o;o = l->next())
|
|
|
|
{
|
|
|
|
bool bMatch;
|
|
|
|
if(mask)
|
|
|
|
{
|
|
|
|
KviIrcMask umask(o->userMask());
|
|
|
|
bMatch = mask->matchedBy(umask);
|
|
|
|
} else bMatch = KviTQString::equalCS(o->userMask(),"*!*@*");
|
|
|
|
if(bMatch)
|
|
|
|
{
|
|
|
|
if(uFileSize > 0)
|
|
|
|
{
|
|
|
|
if(uFileSize == o->fileSize())return o;
|
|
|
|
} else return o;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
bool KviSharedFilesManager::removeSharedFile(const TQString &szName,const TQString &szMask,unsigned int uFileSize)
|
|
|
|
{
|
|
|
|
KviSharedFileList * l = m_pSharedListDict->find(szName);
|
|
|
|
if(!l)return false;
|
|
|
|
for(KviSharedFile * o = l->first();o;o = l->next())
|
|
|
|
{
|
|
|
|
if(KviTQString::equalCI(szMask,o->userMask()))
|
|
|
|
{
|
|
|
|
bool bMatch = uFileSize > 0 ? uFileSize == o->fileSize() : true;
|
|
|
|
if(bMatch)
|
|
|
|
{
|
|
|
|
TQString save = szName; // <-- szName MAY Be a pointer to o->name()
|
|
|
|
l->removeRef(o);
|
|
|
|
if(l->count() == 0)m_pSharedListDict->remove(save);
|
|
|
|
emit sharedFileRemoved(o);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KviSharedFilesManager::removeSharedFile(const TQString &szName,KviSharedFile * off)
|
|
|
|
{
|
|
|
|
KviSharedFileList * l = m_pSharedListDict->find(szName);
|
|
|
|
if(!l)return false;
|
|
|
|
for(KviSharedFile * o = l->first();o;o = l->next())
|
|
|
|
{
|
|
|
|
if(off == o)
|
|
|
|
{
|
|
|
|
TQString save = szName; // <-- szName MAY Be a pointer to o->name()
|
|
|
|
l->removeRef(o);
|
|
|
|
if(l->count() == 0)m_pSharedListDict->remove(save);
|
|
|
|
emit sharedFileRemoved(off);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KviSharedFilesManager::load(const TQString &filename)
|
|
|
|
{
|
|
|
|
KviConfig cfg(filename,KviConfig::Read);
|
|
|
|
//cfg.clear();
|
|
|
|
cfg.setGroup("PermanentFileOffers");
|
|
|
|
int num = cfg.readIntEntry("NEntries",0);
|
|
|
|
for(int idx=0;idx<num;idx++)
|
|
|
|
{
|
|
|
|
TQString tmp;
|
|
|
|
KviTQString::sprintf(tmp,"%dFName",idx);
|
|
|
|
TQString szName = cfg.readTQStringEntry(tmp,"");
|
|
|
|
KviTQString::sprintf(tmp,"%dFilePath",idx);
|
|
|
|
TQString szPath = cfg.readTQStringEntry(tmp,"");
|
|
|
|
KviTQString::sprintf(tmp,"%dUserMask",idx);
|
|
|
|
TQString szMask = cfg.readTQStringEntry(tmp,"");
|
|
|
|
if(!szMask.isEmpty() && !szPath.isEmpty() && !szName.isEmpty())
|
|
|
|
addSharedFile(szName,szPath,szMask,0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KviSharedFilesManager::save(const TQString &filename)
|
|
|
|
{
|
|
|
|
KviConfig cfg(filename,KviConfig::Write);
|
|
|
|
cfg.clear();
|
|
|
|
cfg.setGroup("PermanentFileOffers");
|
|
|
|
|
|
|
|
KviPointerHashTableIterator<TQString,KviSharedFileList> it(*m_pSharedListDict);
|
|
|
|
int idx = 0;
|
|
|
|
while(KviSharedFileList * l = it.current())
|
|
|
|
{
|
|
|
|
for(KviSharedFile * o = l->first();o;o = l->next())
|
|
|
|
{
|
|
|
|
if(((int)(o->expireTime())) == 0)
|
|
|
|
{
|
|
|
|
TQString tmp;
|
|
|
|
KviTQString::sprintf(tmp,"%dFName",idx);
|
|
|
|
cfg.writeEntry(tmp,it.currentKey());
|
|
|
|
KviTQString::sprintf(tmp,"%dFilePath",idx);
|
|
|
|
cfg.writeEntry(tmp,o->absFilePath());
|
|
|
|
KviTQString::sprintf(tmp,"%dUserMask",idx);
|
|
|
|
cfg.writeEntry(tmp,o->userMask());
|
|
|
|
++idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++it;
|
|
|
|
}
|
|
|
|
cfg.writeEntry("NEntries",idx);
|
|
|
|
}
|
|
|
|
|