|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Copyright (C) 2002 Dario Abatianni <eisfuchs@tigress.com>
|
|
|
|
Copyright (C) 2006 Eike Hein <hein@kde.org>
|
|
|
|
Copyright (C) 2004,2007 Shintaro Matsuoka <shin@shoegazed.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dccchat.h"
|
|
|
|
#include "dcccommon.h"
|
|
|
|
#include "konversationapplication.h"
|
|
|
|
#include "konversationmainwindow.h"
|
|
|
|
#include "irccharsets.h"
|
|
|
|
#include "ircview.h"
|
|
|
|
#include "ircviewbox.h"
|
|
|
|
#include "ircinput.h"
|
|
|
|
#include "topiclabel.h"
|
|
|
|
#include "server.h"
|
|
|
|
#include "channel.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
|
|
|
#include <tqvbox.h>
|
|
|
|
#include <tqhostaddress.h>
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
#include <tqsplitter.h>
|
|
|
|
#include <tqpopupmenu.h>
|
|
|
|
|
|
|
|
#include <klineedit.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tdemessagebox.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kserversocket.h>
|
|
|
|
#include <tdesocketaddress.h>
|
|
|
|
#include <kstreamsocket.h>
|
|
|
|
#include <tdeaction.h>
|
|
|
|
|
|
|
|
#define DCCCHAT_BUFFER_SIZE 1024
|
|
|
|
|
|
|
|
|
|
|
|
DccChat::DccChat(TQWidget* parent, bool listen, Server* server, const TQString& ownNick, const TQString& partnerNick, const TQString& partnerHost, int partnerPort)
|
|
|
|
: ChatWindow(parent)
|
|
|
|
{
|
|
|
|
kdDebug() << "DccChat::DccChat() [BEGIN]" << endl;
|
|
|
|
|
|
|
|
m_dccSocket = 0;
|
|
|
|
m_listenSocket = 0;
|
|
|
|
|
|
|
|
m_ownNick = ownNick;
|
|
|
|
|
|
|
|
m_partnerNick = partnerNick;
|
|
|
|
m_partnerHost = partnerHost;
|
|
|
|
m_partnerPort = partnerPort;
|
|
|
|
|
|
|
|
setType(ChatWindow::DccChat);
|
|
|
|
setChannelEncodingSupported(true);
|
|
|
|
|
|
|
|
m_headerSplitter = new TQSplitter(TQt::Vertical, this);
|
|
|
|
|
|
|
|
m_sourceLine = new Konversation::TopicLabel(m_headerSplitter);
|
|
|
|
|
|
|
|
IRCViewBox* ircViewBox = new IRCViewBox(m_headerSplitter, NULL);
|
|
|
|
setTextView(ircViewBox->ircView());
|
|
|
|
|
|
|
|
m_dccChatInput = new IRCInput(this);
|
|
|
|
getTextView()->installEventFilter(m_dccChatInput);
|
|
|
|
m_dccChatInput->setEnabled( false );
|
|
|
|
|
|
|
|
ChatWindow::setName( '-' + m_partnerNick + '-' );
|
|
|
|
ChatWindow::setLogfileName( '-' + m_partnerNick + '-' );
|
|
|
|
|
|
|
|
TQPopupMenu* popup = textView->getPopup();
|
|
|
|
|
|
|
|
if (popup)
|
|
|
|
{
|
|
|
|
TDEAction* action = KonversationApplication::instance()->getMainWindow()->actionCollection()->action("open_logfile");
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
{
|
|
|
|
popup->insertSeparator();
|
|
|
|
action->plug(popup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// connect the signals and slots
|
|
|
|
connect( m_dccChatInput, TQ_SIGNAL( submit() ), this, TQ_SLOT( dccChatTextEntered() ) );
|
|
|
|
connect( m_dccChatInput, TQ_SIGNAL( textPasted( const TQString& ) ), this, TQ_SLOT( textPasted( const TQString& ) ) );
|
|
|
|
|
|
|
|
connect( getTextView(), TQ_SIGNAL( textPasted(bool) ), m_dccChatInput, TQ_SLOT( paste(bool) ) );
|
|
|
|
connect( getTextView(), TQ_SIGNAL( gotFocus() ), m_dccChatInput, TQ_SLOT( setFocus() ) );
|
|
|
|
connect( getTextView(), TQ_SIGNAL( autoText(const TQString&) ), this, TQ_SLOT( sendDccChatText( const TQString& ) ) );
|
|
|
|
|
|
|
|
if (listen)
|
|
|
|
{
|
|
|
|
listenForPartner();
|
|
|
|
TQString ownNumericalIp = DccCommon::textIpToNumericalIp( DccCommon::getOwnIp( server ) );
|
|
|
|
server->requestDccChat( m_partnerNick, ownNumericalIp, TQString::number( m_ownPort ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
connectToPartner();
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug() << "DccChat::DccChat() [END]" << endl;
|
|
|
|
|
|
|
|
updateAppearance();
|
|
|
|
}
|
|
|
|
|
|
|
|
DccChat::~DccChat()
|
|
|
|
{
|
|
|
|
kdDebug() << "DccChat::~DccChat()" << endl;
|
|
|
|
if(m_dccSocket)
|
|
|
|
m_dccSocket->close();
|
|
|
|
if(m_listenSocket)
|
|
|
|
m_listenSocket->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::listenForPartner()
|
|
|
|
{
|
|
|
|
kdDebug() << "DccChat::listenForPartner() [BEGIN]" << endl;
|
|
|
|
|
|
|
|
// Set up server socket
|
|
|
|
TQString failedReason;
|
|
|
|
if ( Preferences::dccSpecificChatPorts() )
|
|
|
|
m_listenSocket = DccCommon::createServerSocketAndListen( this, &failedReason, Preferences::dccChatPortsFirst(), Preferences::dccChatPortsLast() );
|
|
|
|
else
|
|
|
|
m_listenSocket = DccCommon::createServerSocketAndListen( this, &failedReason );
|
|
|
|
if ( !m_listenSocket )
|
|
|
|
{
|
|
|
|
getTextView()->appendServerMessage( i18n( "DCC" ), i18n( "Could not open a socket for listening: %1" ).arg( failedReason ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
connect( m_listenSocket, TQ_SIGNAL(readyAccept()), this, TQ_SLOT(heardPartner()) );
|
|
|
|
|
|
|
|
// Get our own port number
|
|
|
|
m_ownPort = DccCommon::getServerSocketPort( m_listenSocket );
|
|
|
|
kdDebug() << "DccChat::listenForPartner(): using port " << m_ownPort << endl;
|
|
|
|
|
|
|
|
getTextView()->appendServerMessage( i18n("DCC"), i18n("Offering DCC Chat connection to %1 on port %2...").arg( m_partnerNick ).arg( m_ownPort ) );
|
|
|
|
m_sourceLine->setText(i18n( "DCC chat with %1 on port %2." ).arg( m_partnerNick ).arg( m_ownPort ) );
|
|
|
|
kdDebug() << "DccChat::listenForPartner() [END]" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::connectToPartner()
|
|
|
|
{
|
|
|
|
TQHostAddress ip;
|
|
|
|
|
|
|
|
ip.setAddress(m_partnerHost.toUInt());
|
|
|
|
m_partnerHost=ip.toString();
|
|
|
|
|
|
|
|
getTextView()->appendServerMessage( i18n( "DCC" ), i18n( "%1 = nickname, %2 = IP, %3 = port",
|
|
|
|
"Establishing DCC Chat connection to %1 (%2:%3)..." ).arg( m_partnerNick ).arg( m_partnerHost ).arg( m_partnerPort ) );
|
|
|
|
|
|
|
|
m_sourceLine->setText( i18n( "%1 = nickname, %2 = IP, %3 = port", "DCC chat with %1 on %2:%3." ).arg( m_partnerNick ).arg( host ).arg( m_partnerPort ) );
|
|
|
|
|
|
|
|
m_dccSocket = new KNetwork::KStreamSocket( m_partnerHost, TQString::number( m_partnerPort ), this );
|
|
|
|
|
|
|
|
m_dccSocket->setBlocking(false);
|
|
|
|
m_dccSocket->setFamily(KNetwork::KResolver::InetFamily);
|
|
|
|
m_dccSocket->enableRead(false);
|
|
|
|
m_dccSocket->enableWrite(false);
|
|
|
|
m_dccSocket->setTimeout(10000);
|
|
|
|
m_dccSocket->blockSignals(false);
|
|
|
|
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( hostFound() ), this, TQ_SLOT( lookupFinished() ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( connected( const KResolverEntry& ) ), this, TQ_SLOT( dccChatConnectionSuccess() ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( gotError( int ) ), this, TQ_SLOT( dccChatBroken( int ) ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( readyRead() ), this, TQ_SLOT( readData() ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( closed() ), this, TQ_SLOT( socketClosed() ) );
|
|
|
|
|
|
|
|
m_dccSocket->connect();
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
//getTextView()->appendServerMessage(i18n("DCC"),i18n("Looking for host %1...").arg(host));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::lookupFinished()
|
|
|
|
{
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
//getTextView()->appendServerMessage(i18n("DCC"),i18n("Host found, connecting..."));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::dccChatConnectionSuccess()
|
|
|
|
{
|
|
|
|
getTextView()->appendServerMessage( i18n( "DCC" ), i18n( "Established DCC Chat connection to %1." ).arg( m_partnerNick ) );
|
|
|
|
m_dccSocket->enableRead(true);
|
|
|
|
m_dccChatInput->setEnabled(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::dccChatBroken(int error)
|
|
|
|
{
|
|
|
|
getTextView()->appendServerMessage(i18n("Error"),i18n("Connection broken, error code %1.").arg(error));
|
|
|
|
m_dccSocket->enableRead(false);
|
|
|
|
m_dccSocket->blockSignals(true);
|
|
|
|
m_dccSocket->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::readData()
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << ( m_listenSocket == 0 ) << " BEGIN" << endl;
|
|
|
|
int available=0;
|
|
|
|
int actual=0;
|
|
|
|
char* buffer=0;
|
|
|
|
TQString line;
|
|
|
|
TQTextCodec* codec = Konversation::IRCCharsets::self()->codecForName(m_encoding.isEmpty() ? Konversation::IRCCharsets::self()->encodingForLocale() : m_encoding);
|
|
|
|
|
|
|
|
available = m_dccSocket->bytesAvailable();
|
|
|
|
if( available > 0 )
|
|
|
|
{
|
|
|
|
buffer = new char[ available + 1 ];
|
|
|
|
actual = m_dccSocket->readBlock( buffer, available );
|
|
|
|
buffer[ actual ] = 0;
|
|
|
|
line.append( codec->toUnicode( buffer ) );
|
|
|
|
delete[] buffer;
|
|
|
|
|
|
|
|
TQStringList lines = TQStringList::split( '\n', line );
|
|
|
|
|
|
|
|
for( TQStringList::iterator itLine = lines.begin() ; itLine != lines.end() ; itLine++ )
|
|
|
|
{
|
|
|
|
if( (*itLine).startsWith( "\x01" ) )
|
|
|
|
{
|
|
|
|
// cut out the CTCP command
|
|
|
|
TQString ctcp = (*itLine).mid( 1, (*itLine).find( 1, 1 ) - 1 );
|
|
|
|
|
|
|
|
TQString ctcpCommand = ctcp.section( " ", 0, 0 );
|
|
|
|
TQString ctcpArgument = ctcp.section( " ", 1 );
|
|
|
|
|
|
|
|
if( ctcpCommand.lower() == "action" )
|
|
|
|
appendAction( m_partnerNick, ctcpArgument );
|
|
|
|
else
|
|
|
|
getTextView()->appendServerMessage( i18n( "CTCP" ), i18n( "Received unknown CTCP-%1 request from %2" ).arg( ctcp ).arg( m_partnerNick ) );
|
|
|
|
}
|
|
|
|
else getTextView()->append( m_partnerNick, *itLine );
|
|
|
|
} // endfor
|
|
|
|
} else {
|
|
|
|
dccChatBroken(m_dccSocket->error());
|
|
|
|
}
|
|
|
|
|
|
|
|
kdDebug() << k_funcinfo << " END" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::dccChatTextEntered()
|
|
|
|
{
|
|
|
|
TQString line = m_dccChatInput->text();
|
|
|
|
m_dccChatInput->setText("");
|
|
|
|
if ( line.lower() == Preferences::commandChar()+"clear" )
|
|
|
|
{
|
|
|
|
textView->clear();
|
|
|
|
}
|
|
|
|
else if ( !line.isEmpty() )
|
|
|
|
{
|
|
|
|
sendDccChatText(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::sendDccChatText(const TQString& sendLine)
|
|
|
|
{
|
|
|
|
kdDebug() << k_funcinfo << " BEGIN" << endl;
|
|
|
|
// create a work copy
|
|
|
|
TQString output(sendLine);
|
|
|
|
TQString cc=Preferences::commandChar();
|
|
|
|
|
|
|
|
if(!output.isEmpty())
|
|
|
|
{
|
|
|
|
TQStringList lines = TQStringList::split('\n',output);
|
|
|
|
// wrap socket into a stream
|
|
|
|
TQTextStream stream(m_dccSocket);
|
|
|
|
// init stream props
|
|
|
|
stream.setCodec(Konversation::IRCCharsets::self()->codecForName(m_encoding.isEmpty() ? Konversation::IRCCharsets::self()->encodingForLocale() : m_encoding));
|
|
|
|
|
|
|
|
for( TQStringList::iterator itLine = lines.begin() ; itLine != lines.end() ; itLine++ )
|
|
|
|
{
|
|
|
|
TQString line( *itLine );
|
|
|
|
|
|
|
|
// replace aliases and wildcards
|
|
|
|
// if(filter.replaceAliases(line)) line=server->parseWildcards(line,nick,getName(),TQString(),TQString(),TQString());
|
|
|
|
|
|
|
|
// line=filter.parse(nick,line,getName());
|
|
|
|
|
|
|
|
// convert /me actions
|
|
|
|
TQString cmd=line.section(' ', 0,0).lower();
|
|
|
|
if (cmd == cc+"me")
|
|
|
|
{
|
|
|
|
appendAction( m_ownNick, line.section( " ", 1 ) );
|
|
|
|
line=TQString("\x01%1 %2\x01").arg("ACTION").arg(line.section(" ",1));
|
|
|
|
}
|
|
|
|
else if (cmd == cc+"close")
|
|
|
|
{
|
|
|
|
closeYourself(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
getTextView()->append( m_ownNick, line );
|
|
|
|
|
|
|
|
stream << line << endl;
|
|
|
|
} // endfor
|
|
|
|
|
|
|
|
// detach stream
|
|
|
|
stream.unsetDevice();
|
|
|
|
}
|
|
|
|
kdDebug() << k_funcinfo << " END" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::heardPartner()
|
|
|
|
{
|
|
|
|
m_dccSocket = static_cast<KNetwork::KStreamSocket*>( m_listenSocket->accept() );
|
|
|
|
|
|
|
|
if( !m_dccSocket )
|
|
|
|
{
|
|
|
|
getTextView()->appendServerMessage( i18n( "Error" ),i18n( "Could not accept the client." ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( readyRead() ), this, TQ_SLOT( readData() ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( closed() ), this, TQ_SLOT( socketClosed() ) );
|
|
|
|
connect( m_dccSocket, TQ_SIGNAL( gotError( int ) ), this, TQ_SLOT( dccChatBroken( int ) ) );
|
|
|
|
|
|
|
|
// the listen socket isn't needed anymore
|
|
|
|
disconnect( m_listenSocket, 0, 0, 0 );
|
|
|
|
m_listenSocket->close();
|
|
|
|
m_listenSocket = 0;
|
|
|
|
|
|
|
|
m_dccSocket->enableRead(true);
|
|
|
|
m_dccChatInput->setEnabled(true);
|
|
|
|
|
|
|
|
getTextView()->appendServerMessage( i18n( "DCC" ), i18n( "Established DCC Chat connection to %1." ).arg( m_partnerNick ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::socketClosed()
|
|
|
|
{
|
|
|
|
getTextView()->appendServerMessage(i18n("DCC"),"Connection closed.");
|
|
|
|
m_dccChatInput->setEnabled(false);
|
|
|
|
m_dccSocket = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::textPasted(const TQString& text)
|
|
|
|
{
|
|
|
|
sendDccChatText(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::childAdjustFocus()
|
|
|
|
{
|
|
|
|
m_dccChatInput->setFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DccChat::canBeFrontView()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DccChat::searchView()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DccChat::getOwnPort()
|
|
|
|
{
|
|
|
|
return m_ownPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString DccChat::getTextInLine()
|
|
|
|
{
|
|
|
|
return m_dccChatInput->text();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::appendInputText( const TQString& s, bool fromCursor )
|
|
|
|
{
|
|
|
|
if(!fromCursor)
|
|
|
|
{
|
|
|
|
m_dccChatInput->append(s);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int para = 0, index = 0;
|
|
|
|
m_dccChatInput->getCursorPosition(¶, &index);
|
|
|
|
m_dccChatInput->insertAt(s, para, index);
|
|
|
|
m_dccChatInput->setCursorPosition(para, index + s.length());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//FIXME uh... where is the confimation for this?
|
|
|
|
bool DccChat::closeYourself(bool)
|
|
|
|
{
|
|
|
|
deleteLater();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::setChannelEncoding(const TQString& encoding) // virtual
|
|
|
|
{
|
|
|
|
m_encoding = encoding;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString DccChat::getChannelEncoding() // virtual
|
|
|
|
{
|
|
|
|
return m_encoding;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString DccChat::getChannelEncodingDefaultDesc() // virtual
|
|
|
|
{
|
|
|
|
return i18n("Default ( %1 )").arg(Konversation::IRCCharsets::self()->encodingForLocale());
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::showEvent(TQShowEvent* /* event */)
|
|
|
|
{
|
|
|
|
if(m_initialShow) {
|
|
|
|
m_initialShow = false;
|
|
|
|
TQValueList<int> sizes;
|
|
|
|
sizes << m_sourceLine->sizeHint().height() << (height() - m_sourceLine->sizeHint().height());
|
|
|
|
m_headerSplitter->setSizes(sizes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DccChat::updateAppearance()
|
|
|
|
{
|
|
|
|
TQColor fg;
|
|
|
|
TQColor bg;
|
|
|
|
|
|
|
|
if(Preferences::inputFieldsBackgroundColor())
|
|
|
|
{
|
|
|
|
fg=Preferences::color(Preferences::ChannelMessage);
|
|
|
|
bg=Preferences::color(Preferences::TextViewBackground);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fg=colorGroup().foreground();
|
|
|
|
bg=colorGroup().base();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_dccChatInput->unsetPalette();
|
|
|
|
m_dccChatInput->setPaletteForegroundColor(fg);
|
|
|
|
m_dccChatInput->setPaletteBackgroundColor(bg);
|
|
|
|
|
|
|
|
getTextView()->unsetPalette();
|
|
|
|
|
|
|
|
if(Preferences::showBackgroundImage())
|
|
|
|
{
|
|
|
|
getTextView()->setViewBackground(Preferences::color(Preferences::TextViewBackground),
|
|
|
|
Preferences::backgroundImage());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getTextView()->setViewBackground(Preferences::color(Preferences::TextViewBackground),
|
|
|
|
TQString());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Preferences::customTextFont())
|
|
|
|
{
|
|
|
|
getTextView()->setFont(Preferences::textFont());
|
|
|
|
m_dccChatInput->setFont(Preferences::textFont());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getTextView()->setFont(TDEGlobalSettings::generalFont());
|
|
|
|
m_dccChatInput->setFont(TDEGlobalSettings::generalFont());
|
|
|
|
}
|
|
|
|
|
|
|
|
ChatWindow::updateAppearance();
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "dccchat.moc"
|