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/modules/avatar/libkviavatar.cpp

586 lines
16 KiB

//=============================================================================
//
// File : libkviavatar.cpp
// Creation date : Thu Nov 12 02:32:59 2004 GMT by Szymon Stefanek
//
// This file is part of the KVirc irc client distribution
// Copyright (C) 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.
//
//=============================================================================
#include "libkviavatar.h"
#include "kvi_module.h"
#include "kvi_fileutils.h"
#include "kvi_locale.h"
#include "kvi_malloc.h"
#include "kvi_app.h"
#include "kvi_options.h"
#include "kvi_http.h"
#include "kvi_iconmanager.h"
#include "kvi_avatar.h"
#include "kvi_ircuserdb.h"
#include "kvi_ircconnection.h"
#include "kvi_ircconnectionuserinfo.h"
#include "kvi_console.h"
#include "kvi_filedialog.h"
#include "kvi_pointerlist.h"
#include "kvi_frame.h"
#include "kvi_sharedfiles.h"
#include "kvi_out.h"
#include "kvi_ircmask.h"
#include "kvi_qcstring.h"
#include <tqlineedit.h>
#include <tqpushbutton.h>
#include <tqmessagebox.h>
#include <tqtimer.h>
#include <tqlabel.h>
#include "kvi_tal_hbox.h"
#include <tqlayout.h>
static KviPointerList<KviAsyncAvatarSelectionDialog> * g_pAvatarSelectionDialogList = 0;
extern KVIRC_API KviSharedFilesManager * g_pSharedFilesManager;
KviAsyncAvatarSelectionDialog::KviAsyncAvatarSelectionDialog(TQWidget * par,const TQString &szInitialPath,KviIrcConnection * c)
: TQDialog(par,0,false,TQt::WType_Dialog | TQt::WStyle_DialogBorder | TQt::WStyle_StaysOnTop)
{
g_pAvatarSelectionDialogList->append(this);
m_pConnection = c;
setCaption(__tr2qs("Choose Avatar - KVIrc"));
TQGridLayout * g = new TQGridLayout(this,3,3,4,8);
TQString msg = "<center>";
msg += __tr2qs("Please select an avatar image. " \
"The full path to a local file or an image on the Web can be used.<br>" \
"If you wish to use a local image file, click the \"<b>Browse</b>\"" \
"button to browse local folders.<br>" \
"The full URL for an image (including <b>http://</b>) can be entered manually.");
msg += "</center><br>";
TQLabel * l = new TQLabel(msg,this);
l->setMinimumWidth(250);
g->addMultiCellWidget(l,0,0,0,2);
m_pLineEdit = new TQLineEdit(this);
m_pLineEdit->setText(szInitialPath);
m_pLineEdit->setMinimumWidth(180);
g->addMultiCellWidget(m_pLineEdit,1,1,0,1);
TQPushButton * b = new TQPushButton(__tr2qs("&Browse..."),this);
connect(b,TQT_SIGNAL(clicked()),this,TQT_SLOT(chooseFileClicked()));
g->addWidget(b,1,2);
KviTalHBox * h = new KviTalHBox(this);h->setSpacing(8);g->addMultiCellWidget(h,2,2,1,2);
b = new TQPushButton(__tr2qs("&OK"),h);
b->setMinimumWidth(80);
b->setDefault(true);
connect(b,TQT_SIGNAL(clicked()),this,TQT_SLOT(okClicked()));
b = new TQPushButton(__tr2qs("Cancel"),h);
b->setMinimumWidth(80);
connect(b,TQT_SIGNAL(clicked()),this,TQT_SLOT(cancelClicked()));
g->setRowStretch(0,1);
g->setColStretch(0,1);
}
KviAsyncAvatarSelectionDialog::~KviAsyncAvatarSelectionDialog()
{
g_pAvatarSelectionDialogList->removeRef(this);
}
void KviAsyncAvatarSelectionDialog::okClicked()
{
m_szAvatarName = m_pLineEdit->text();
if(!g_pApp->connectionExists(m_pConnection))return; // the connection no longer exists :/
if(!m_szAvatarName.isEmpty())
{
TQString tmp = m_szAvatarName;
tmp.replace("\\","\\\\");
TQString szBuffer=TQString("avatar.set \"%1\"").arg(tmp);
KviKvsScript::run(szBuffer,m_pConnection->console());
}
accept();
deleteLater();
}
void KviAsyncAvatarSelectionDialog::cancelClicked()
{
reject();
deleteLater();
}
void KviAsyncAvatarSelectionDialog::chooseFileClicked()
{
TQString tmp;
if(KviFileDialog::askForOpenFileName(tmp,__tr2qs("Choose an Image File - KVIrc")))
{
m_pLineEdit->setText(tmp);
}
}
void KviAsyncAvatarSelectionDialog::closeEvent(TQCloseEvent * e)
{
e->ignore();
reject();
deleteLater();
}
/*
@doc: avatar.set
@type:
command
@title:
avatar.set
@keyterms:
setting your avatar, avatar
@short:
Sets the local user's avatar
@syntax:
avatar.set [avatar:string]
@description:
Sets your avatar in the current connection to <avatar>.
<avatar> may be a local filename or a http url.[br]
If avatar is an empty string then an asynchronous dialog
will be opened that will allow choosing an avatar.[br]
Note that this command does NOT notify the avatar to
any target: use [cmd]avatar.notify[/cmd] for that purpose.
Note also that this will NOT set your default avatar
option: you must use the options dialog for that.[br]
@examples:
[example]
avatar.set /home/myavatar.png
avatar.set http://www.kvirc.net/img/pragma.png
[/example]
@seealso:
[cmd]avatar.unset[/cmd]
*/
static bool avatar_kvs_cmd_set(KviKvsModuleCommandCall * c)
{
TQString szAvatar;
KVSM_PARAMETERS_BEGIN(c)
KVSM_PARAMETER("avatar",KVS_PT_NONEMPTYSTRING,KVS_PF_OPTIONAL,szAvatar)
KVSM_PARAMETERS_END(c)
KVSM_REQUIRE_CONNECTION(c)
TQString absPath;
if(szAvatar.isEmpty())
{
KviAsyncAvatarSelectionDialog * d = new KviAsyncAvatarSelectionDialog(g_pFrame,TQString(),c->window()->connection());
d->show();
return true;
}
// new avatar specified...try to load it
KviIrcUserEntry * e = c->window()->connection()->userDataBase()->find(c->window()->connection()->currentNickName());
if(!e)
{
c->warning(__tr2qs("Internal error: I'm not in the user database ?"));
return true;
}
KviAvatar * av = g_pIconManager->getAvatar(TQString(),szAvatar);
if(av)
{
// Ok...got it...
e->setAvatar(av);
c->window()->console()->avatarChanged(av,
c->window()->connection()->userInfo()->nickName(),
c->window()->connection()->userInfo()->userName(),
c->window()->connection()->userInfo()->hostName(),
TQString());
} else {
bool bIsUrl = KviTQString::equalCIN(szAvatar,"http://",7) && (szAvatar.length() > 7);
if(bIsUrl)
{
// This is an url, and we don't have a cached copy for now
TQString szLocalFilePath;
TQString szLocalFile = szAvatar;
g_pIconManager->urlToCachedFileName(szLocalFile);
g_pApp->getLocalKvircDirectory(szLocalFilePath,KviApp::Avatars,szLocalFile);
szLocalFilePath.replace("\\","\\\\");
TQString szCommand = "http.get -w=nm ";
szCommand += szAvatar;
szCommand += " ";
szCommand += szLocalFilePath;
if(KviKvsScript::run(szCommand,c->window()->console()))
{
g_pApp->setAvatarOnFileReceived(c->window()->console(),
szAvatar,
c->window()->connection()->userInfo()->nickName(),
c->window()->connection()->userInfo()->userName(),
c->window()->connection()->userInfo()->hostName());
} else {
c->warning(__tr2qs("Can't set the current avatar to '%Q': failed to start the http transfer"),&szAvatar);
return true;
}
} else {
c->warning(__tr2qs("Can't set the current avatar to '%Q': can't load the image"),&szAvatar);
return true;
}
}
return true;
}
/*
@doc: avatar.unset
@type:
command
@title:
avatar.unset
@short:
Unsets the local user's avatar
@syntax:
avatar.unset
@description:
Unsets the local user's avatar.
Note also that this will NOT unset your default avatar
option: you must use the options dialog for that.[br]
@seealso:
[cmd]avatar.set[/cmd]
*/
static bool avatar_kvs_cmd_unset(KviKvsModuleCommandCall * c)
{
KVSM_REQUIRE_CONNECTION(c)
KviIrcUserEntry * e = c->window()->connection()->userDataBase()->find(c->window()->connection()->currentNickName());
if(!e)
{
c->warning(__tr2qs("Internal error: I'm not in the user database ?"));
return true;
}
e->setAvatar(0);
c->window()->console()->avatarChanged(0,
c->window()->connection()->userInfo()->nickName(),
c->window()->connection()->userInfo()->userName(),
c->window()->connection()->userInfo()->hostName(),
TQString());
return true;
}
/*
@doc: avatar.notify
@type:
command
@title:
avatar.notify
@short:
Notifies the current avatar to a remote target
@syntax:
avatar.notify [-q] [-t=<timeout:integer>] <target:string>
@switches:
!sw: -q | --quiet
Do not print warnings
!sw: -t=<timeout> | --timeout=<integer>
@description:
Notifies the current avatar to the remote <target> via CTCP AVATAR.
See the [doc:ctcp_avatar]avatar protocol documentation[/doc] for the
description of the protocol.[br]
This has the effect to notify your avatar image to the <target>.[br]
The CTCP is sent thru a NOTICE and the current avatar image
is added to the public offer list for <timeout> seconds (or a default timeout if the -t switch is not used).[br]
If the -q switch is specified, the command executes in quet mode and
prints nothing in the current window.[br]
If you don't have an avatar set, the ctcp will unset the previous avatar
on the target side.[br]
[b]Warning:[/b] The implementation of the avatar protocol is actually
restricted to KVIrc clients only. In the future other clients may implement it.[br]
This command is [doc:connection_dependant_commands]connection dependant[/doc].[br]
@examples:
[example]
[comment]# Notify your current avatar to Pragma[/comment]
avatar.notify Pragma
[comment]# Notify your avatar to the channel #kvirc and to Pragma[/comment]
avatar #kvirc,Pragma
[/example]
@seealso:
[cmd]avatar.set[/cmd], [cmd]avatar.unset[/cmd]
*/
static bool avatar_kvs_cmd_notify(KviKvsModuleCommandCall * c)
{
TQString szTarget;
KVSM_PARAMETERS_BEGIN(c)
KVSM_PARAMETER("target",KVS_PT_NONEMPTYSTRING,0,szTarget)
KVSM_PARAMETERS_END(c)
KVSM_REQUIRE_CONNECTION(c)
kvs_int_t iTimeout = (kvs_int_t)KVI_OPTION_UINT(KviOption_uintAvatarOfferTimeoutInSecs);
if(KviKvsVariant * pTimeout = c->switches()->find('t',"timeout"))
{
if(!pTimeout->asInteger(iTimeout))
{
if(!c->switches()->find('q',"quiet"))
c->warning(__tr2qs("Invalid timeout specified, using default"));
}
}
KviIrcUserEntry * e = c->window()->connection()->userDataBase()->find(c->window()->connection()->currentNickName());
if(!e)
{
c->warning(__tr2qs("Internal error: I'm not in the user database ?"));
return true;
}
TQString absPath,avatar;
if(e->avatar())
{
absPath = e->avatar()->localPath();
avatar = e->avatar()->name();
}
KviSharedFile * o = 0;
if((!absPath.isEmpty()) && (!avatar.isEmpty()))
{
bool bTargetIsChan = (szTarget.contains('#') || szTarget.contains('&') || szTarget.contains('!'));
if(bTargetIsChan)o = g_pSharedFilesManager->lookupSharedFile(avatar,0);
else {
KviIrcMask u(szTarget);
o = g_pSharedFilesManager->lookupSharedFile(avatar,&u);
}
if(!o)
{
// FIXME: #warning "OPTION FOR PERMANENT OR TIMEDOUT OFFER...TIMEDOUT WOULD ALSO NEED TO EXTEND EXISTING OFFERS LIFETIME"
TQString szUserMask = bTargetIsChan ? TQString("*") : szTarget;
szUserMask += "!*@*";
o = g_pSharedFilesManager->addSharedFile(avatar,absPath,szUserMask,iTimeout);
if(!o)
{
// Don't delete o...it has been already deleted by g_pFileTrader
if(!c->switches()->find('q',"quiet"))
c->warning(__tr2qs("Can't add a file offer for file %Q (huh ? file not readable ?)"),&absPath);
return true;
}
if(_OUTPUT_VERBOSE)
{
if(!c->switches()->find('q',"quiet"))
c->window()->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("Added %d secs file offer for file %Q (%Q) and receiver %Q"),
iTimeout,&(o->absFilePath()),&avatar,&(o->userMask()));
}
}
}
if(!c->switches()->find('q',"quiet"))
c->window()->output(KVI_OUT_AVATAR,__tr2qs("Notifying avatar '%Q' to %Q"),&avatar,&szTarget);
KviTQCString encodedTarget = c->window()->connection()->encodeText(szTarget);
if(!avatar.isEmpty())
{
KviTQCString encodedAvatar = c->window()->connection()->encodeText(avatar);
if(o)
{
c->window()->connection()->sendFmtData("NOTICE %s :%cAVATAR %s %u%c",encodedTarget.data(),0x01,
encodedAvatar.data(),o->fileSize(),0x01);
} else {
c->window()->connection()->sendFmtData("NOTICE %s :%cAVATAR %s%c",encodedTarget.data(),0x01,
encodedAvatar.data(),0x01);
}
} else {
c->window()->connection()->sendFmtData("NOTICE %s :%cAVATAR%c",encodedTarget.data(),0x01,0x01);
}
return true;
}
/*
@doc: avatar.name
@type:
function
@title:
$avatar.name
@short:
Returns the avatar name for the specified user
@syntax:
<string> $avatar.name
<string> $avatar.name(<nick:string>)
@description:
Returns the name of the avatar belonging to <nick> in the current IRC context.
If <nick> is omitted then the name of the avatar of the current local user
is returned. The returned string is empty if the specified user has no
avatar set or there is no such user at all.
@seealso:
[fnc]$avatar.path[/fnc]
*/
static bool avatar_kvs_fnc_name(KviKvsModuleFunctionCall * c)
{
TQString szNick;
KVSM_PARAMETERS_BEGIN(c)
KVSM_PARAMETER("nick",KVS_PT_STRING,KVS_PF_OPTIONAL,szNick)
KVSM_PARAMETERS_END(c)
KVSM_REQUIRE_CONNECTION(c)
if(szNick.isEmpty())szNick = c->window()->connection()->currentNickName();
KviIrcUserEntry * e = c->window()->connection()->userDataBase()->find(szNick);
if(e)
{
if(e->avatar())
{
c->returnValue()->setString(e->avatar()->name());
return true;
}
}
c->returnValue()->setNothing();
return true;
}
/*
@doc: avatar.path
@type:
function
@title:
$avatar.path
@short:
Returns the avatar path for the specified user
@syntax:
<string> $avatar.path
<string> $avatar.path(<nick:string>)
@description:
Returns the local path of the avatar belonging to <nick> in the current IRC context.
If <nick> is omitted then the path of the avatar of the current local user
is returned. The returned string is empty if the specified user has no
avatar set or there is no such user at all.
@seealso:
[fnc]$avatar.name[/fnc]
*/
static bool avatar_kvs_fnc_path(KviKvsModuleFunctionCall * c)
{
TQString szNick;
KVSM_PARAMETERS_BEGIN(c)
KVSM_PARAMETER("path",KVS_PT_STRING,KVS_PF_OPTIONAL,szNick)
KVSM_PARAMETERS_END(c)
KVSM_REQUIRE_CONNECTION(c)
if(szNick.isEmpty())szNick = c->window()->connection()->currentNickName();
KviIrcUserEntry * e = c->window()->connection()->userDataBase()->find(szNick);
if(e)
{
if(e->avatar())
{
c->returnValue()->setString(e->avatar()->localPath());
return true;
}
}
c->returnValue()->setNothing();
return true;
}
/*
@doc: avatar.query
@type:
command
@title:
avatar.query
@short:
Queries the avatar of a remote target
@syntax:
avatar.query <target:string>
@description:
Queries the avatar of a remote target via CTCP AVATAR.
The <target> can be a channel or a nickname.
This command is equivalent to "[cmd]ctcp[/cmd] <target> AVATAR".
@seealso:
[cmd]avatar.set[/cmd]
*/
static bool avatar_kvs_cmd_query(KviKvsModuleCommandCall * c)
{
TQString szName;
KVSM_PARAMETERS_BEGIN(c)
KVSM_PARAMETER("target",KVS_PT_NONEMPTYSTRING,0,szName)
KVSM_PARAMETERS_END(c)
KVSM_REQUIRE_CONNECTION(c)
KviTQCString target = c->window()->connection()->encodeText(szName);
c->window()->connection()->sendFmtData("PRIVMSG %s :%cAVATAR%c",target.data(),0x01,0x01);
return true;
}
static bool avatar_module_init(KviModule * m)
{
g_pAvatarSelectionDialogList = new KviPointerList<KviAsyncAvatarSelectionDialog>;
g_pAvatarSelectionDialogList->setAutoDelete(false);
KVSM_REGISTER_SIMPLE_COMMAND(m,"query",avatar_kvs_cmd_query);
KVSM_REGISTER_SIMPLE_COMMAND(m,"set",avatar_kvs_cmd_set);
KVSM_REGISTER_SIMPLE_COMMAND(m,"unset",avatar_kvs_cmd_set);
KVSM_REGISTER_SIMPLE_COMMAND(m,"notify",avatar_kvs_cmd_notify);
KVSM_REGISTER_FUNCTION(m,"name",avatar_kvs_fnc_name);
KVSM_REGISTER_FUNCTION(m,"path",avatar_kvs_fnc_path);
return true;
}
static bool avatar_module_can_unload(KviModule *m)
{
return g_pAvatarSelectionDialogList->isEmpty();
}
static bool avatar_module_cleanup(KviModule *m)
{
while(KviAsyncAvatarSelectionDialog * d = g_pAvatarSelectionDialogList->first())
delete d;
delete g_pAvatarSelectionDialogList;
return true;
}
KVIRC_MODULE(
"Avatar",
"1.0.0",
"Copyright (C) 2004 Szymon Stefanek (pragma at kvirc dot net)",
"Avatar manipulation routines",
avatar_module_init,
avatar_module_can_unload,
0,
avatar_module_cleanup
)