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.
1139 lines
34 KiB
1139 lines
34 KiB
/***************************************************************************
|
|
io_internet.cpp - description
|
|
-------------------
|
|
begin : Thu Aug 16 2001
|
|
copyright : (C) 2003 by Troy Corbin Jr.
|
|
email : tcorbin@users.sourceforge.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 option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
/* KDE */
|
|
#include <ksock.h>
|
|
#include <kprocess.h>
|
|
#include <tdemessagebox.h>
|
|
|
|
/* TQt */
|
|
#include <tqobject.h>
|
|
#include <tqwidget.h>
|
|
#include <tqregexp.h>
|
|
#include <tqdns.h>
|
|
#include <tqsocket.h>
|
|
#include <tqptrlist.h>
|
|
|
|
/* Local */
|
|
#include "io_internet.moc"
|
|
#include "resource.h"
|
|
#include "dlg_login.h"
|
|
#include "dlg_challenge.h"
|
|
#include "match.h"
|
|
#include "core.h"
|
|
#include "audio.h"
|
|
#include "../config.h"
|
|
|
|
static const int TXT_Std = 0;
|
|
static const int TXT_Pvt = 1;
|
|
static const int TXT_Ch = 2;
|
|
static const int TXT_Sht = 3;
|
|
static const int TXT_Wsp = 4;
|
|
static const int TXT_Not = 5;
|
|
|
|
io_internet::io_internet( TQWidget *parent, resource *rsrc )
|
|
{
|
|
myResource = rsrc;
|
|
challenge = NULL;
|
|
myTimeseal = NULL;
|
|
socket = NULL;
|
|
loginStage = LOGIN_STAGE_NAME;
|
|
lineBuffer = "";
|
|
Log = NULL;
|
|
|
|
/* set type */
|
|
this->myType = io_base::INTERNET;
|
|
|
|
/* initialize various variables */
|
|
this->waiting_for_move_list = false;
|
|
this->myParent = parent;
|
|
connected = false; /* we are not connected to a server */
|
|
|
|
/* create the login dialog and show it to the user */
|
|
loginDlg = new dlg_login( myParent, "LoginDialog", myResource);
|
|
connect(loginDlg, TQT_SIGNAL( okClicked() ), this, TQT_SLOT( connectToServer() ) );
|
|
connect(loginDlg, TQT_SIGNAL( cancelClicked() ), this, TQT_SLOT( selfDestruct() ) );
|
|
connect(loginDlg, TQT_SIGNAL( login(TQString, TQString) ), this, TQT_SLOT( setUserInfo(TQString, TQString) ) );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Destructor
|
|
///////////////////////////////////////////////////////////
|
|
io_internet::~io_internet()
|
|
{
|
|
TabMap::Iterator i;
|
|
|
|
/* Close and remove socket */
|
|
if( socket != NULL )
|
|
{
|
|
if(socket->socket() != -1)
|
|
{
|
|
send("quit");
|
|
}
|
|
delete socket;
|
|
}
|
|
/* Close and remove logfile */
|
|
if( Log )
|
|
{
|
|
Log->close();
|
|
delete Log;
|
|
Log = NULL;
|
|
}
|
|
/* Remove Timeseal */
|
|
if( myTimeseal != NULL )
|
|
{
|
|
myTimeseal->kill();
|
|
delete myTimeseal;
|
|
}
|
|
/* Close and remove Tabs */
|
|
|
|
for(i = myTabList.begin(); i != myTabList.end(); i++)
|
|
{
|
|
if(myResource->tabManager->isTab(*i))
|
|
{
|
|
myResource->tabManager->removeTab(TQT_TQOBJECT(*i));
|
|
}
|
|
}
|
|
}
|
|
|
|
void io_internet::connectToServer()
|
|
{
|
|
serverList::iterator i;
|
|
TQWidget *tempTab;
|
|
TQWidget *consoleTab;
|
|
TQValueList<Command>::iterator j;
|
|
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Thinking );
|
|
/* Get and parse server config from resource */
|
|
myServer = NULL;
|
|
for( i = myResource->servers.begin(); i != myResource->servers.end(); i++ )
|
|
{
|
|
if( (*i).CurrentRef )
|
|
{
|
|
myServer = &(*i);
|
|
}
|
|
}
|
|
if(myServer == NULL)
|
|
{
|
|
/* No server configured. Notify User and die gracefully */
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
kdError() << "internetio::internetio: Can not find server resource CurrentRef " << endl;
|
|
KMessageBox::sorry( (TQWidget*)myParent, i18n( "There are no servers configured.\nPlease make sure you have at least one server configured." ), i18n( "Cannot find a server."));
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
return;
|
|
}
|
|
|
|
if(myServer->Port == 0)
|
|
{
|
|
myServer->Port = 5000;
|
|
}
|
|
|
|
if(!myServer->Timeseal.isEmpty())
|
|
{
|
|
myTimeseal = new TDEProcess();
|
|
(*myTimeseal) << myServer->Timeseal << myServer->URL << TQString().setNum( myServer->Port )
|
|
<< TQString( "-p" ) << TQString().setNum(myServer->Port + 1);
|
|
if(!myTimeseal->start())
|
|
{
|
|
/* Couldn't start Timeseal. Notify User and die gracefully */
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
KMessageBox::sorry( (TQWidget*)myParent, i18n( "Knights can not start Timeseal.\nPlease make sure you have the correct path and filename configured." ), i18n( "Cannot find Timeseal."));
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
return;
|
|
}
|
|
socket = new TDESocket("127.0.0.1", myServer->Port + 1, 30);
|
|
if(socket->socket() == -1)
|
|
{
|
|
/* try again on a different port, somehow the port hasn't been freed yet */
|
|
delete socket;
|
|
myTimeseal->kill();
|
|
|
|
myTimeseal = new TDEProcess();
|
|
(*myTimeseal) << myServer->Timeseal << myServer->URL << TQString().setNum( myServer->Port )
|
|
<< TQString( "-p" ) << TQString().setNum(myServer->Port + 2);
|
|
if(!myTimeseal->start())
|
|
{
|
|
/* Couldn't start Timeseal. Notify User and die gracefully */
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
KMessageBox::sorry( (TQWidget*)myParent, i18n( "Knights can not start Timeseal.\nPlease make sure you have the correct path and filename configured." ), i18n( "Cannot find Timeseal."));
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
return;
|
|
}
|
|
socket = new TDESocket("127.0.0.1", myServer->Port + 2, 30);
|
|
if(socket->socket() == -1)
|
|
{
|
|
/* if we can't do it the second time, give up */
|
|
/* Couldn't connect to server through Timeseal. Notify User and die gracefully */
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
KMessageBox::sorry( (TQWidget*)myParent, i18n( "Knights is unable to connect to the server.\n Please make sure your internet connection is working and try again."), i18n( "Cannot connect to server(timeseal)."));
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
socket = new TDESocket(myServer->URL, myServer->Port, 30);
|
|
if(socket->socket() == -1)
|
|
{
|
|
/* Couldn't connect to server. Notify User and die gracefully */
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
KMessageBox::sorry( (TQWidget*)myParent, i18n( "Knights is unable to connect to the server.\n Please make sure your internet connection is working and try again."), i18n( "Cannot connect to server."));
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
return;
|
|
}
|
|
}
|
|
socket->enableRead(true);
|
|
socket->enableWrite(true);
|
|
|
|
/* connect a signal to readReady */
|
|
connect(socket, TQT_SIGNAL(readEvent(TDESocket *)), this, TQT_SLOT(readCommand(TDESocket *)));
|
|
|
|
/* setup the seekTimer and turn it off by default */
|
|
seekTimer = new TQTimer(this);
|
|
connect(seekTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(processSeekTimer()));
|
|
|
|
/* succesfully connected to the server, turn connected on and flush the command buffer */
|
|
connected = true;
|
|
for(j = myCommandBuffer.begin(); j != myCommandBuffer.end(); j++)
|
|
{
|
|
recvCMD(*j);
|
|
}
|
|
|
|
/*
|
|
Create ICS Related Tabs
|
|
|
|
These will need to be moved into thier own functions because we want to be able to open
|
|
and close these tabs at will, or have multiple open at once. ALL communication to our tabs
|
|
needs to be done with SIGNALS & SLOTS to facilitate this.
|
|
*/
|
|
consoleTab = new Console( 0, myServer->Name, myResource );
|
|
myTabList[consoleTab] = consoleTab;
|
|
myResource->tabManager->addTab( myTabList[consoleTab], i18n( "%1 Console" ).arg( myServer->Name ) );
|
|
connect( myTabList[consoleTab], TQT_SIGNAL( sendCMD( const Command& ) ), this, TQT_SLOT( recvCMD( const Command& ) ) );
|
|
connect( this, TQT_SIGNAL( sendCMD( const Command& ) ), myTabList[consoleTab], TQT_SLOT( recvCMD( const Command& ) ) );
|
|
|
|
tempTab = new tab_SeekList( 0, "seekList", myResource );
|
|
myTabList[tempTab] = tempTab;
|
|
myResource->tabManager->addTab( myTabList[tempTab], i18n( "Sought Matches List" ) );
|
|
connect( myTabList[tempTab], TQT_SIGNAL( sendCMD( const Command& ) ), this, TQT_SLOT( recvCMD( const Command& ) ) );
|
|
connect( this, TQT_SIGNAL( sendCMD( const Command& ) ), myTabList[tempTab], TQT_SLOT( recvCMD( const Command& ) ) );
|
|
|
|
tempTab = new Challenge_Graph( 0, "seekGraph", myResource );
|
|
myTabList[tempTab] = tempTab;
|
|
myResource->tabManager->addTab( myTabList[tempTab], i18n( "Sought Matches Graph" ) );
|
|
connect( myTabList[tempTab], TQT_SIGNAL( sendCMD( const Command& ) ), this, TQT_SLOT( recvCMD( const Command& ) ) );
|
|
connect( this, TQT_SIGNAL( sendCMD( const Command& ) ), myTabList[tempTab], TQT_SLOT( recvCMD( const Command& ) ) );
|
|
|
|
myResource->tabManager->showTab(consoleTab);
|
|
|
|
/* ...log file */
|
|
if( !myServer->LogFile.isEmpty() )
|
|
{
|
|
Log = new TQFile( myServer->LogFile );
|
|
if( !Log->open( IO_WriteOnly | IO_Append ) )
|
|
{
|
|
if( !Log->open( IO_WriteOnly ) )
|
|
{
|
|
kdError() << "Can not open " << myServer->LogFile << " for writing." << endl;
|
|
}
|
|
}
|
|
}
|
|
tqApp->mainWidget()->setCursor( myResource->CURSOR_Standard );
|
|
}
|
|
|
|
void io_internet::recvCMD(const Command& command)
|
|
{
|
|
TQString error_message;
|
|
|
|
if(!connected)
|
|
{
|
|
myCommandBuffer.push_back(command);
|
|
return;
|
|
}
|
|
|
|
switch(((Command)command).getCommand())
|
|
{
|
|
case CMD_Move:
|
|
send(((Command)command).getMove().SAN);
|
|
break;
|
|
case CMD_Reset_Server:
|
|
sendUserSettings();
|
|
break;
|
|
case CMD_Toggle_Seek:
|
|
if(seekTimer->isActive())
|
|
{
|
|
/* timer running stop it */
|
|
seekTimer->stop();
|
|
emit sendCMD( Command( 0, CMD_Hide_Sought_List ) );
|
|
}
|
|
else
|
|
{
|
|
/* timer not running start it */
|
|
seekTimer->start(myResource->Seek_Timer * 100);
|
|
/* send a sought now */
|
|
processSeekTimer();
|
|
}
|
|
break;
|
|
case CMD_Player_Finger:
|
|
send("$finger " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Add_Friend:
|
|
send("$+notify " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Ignore_Player:
|
|
send("$+censor " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Player_History:
|
|
send("$history " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Start_Match:
|
|
send("$play " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Assess:
|
|
send("$assess " + ((Command)command).getData());
|
|
break;
|
|
case CMD_Set_Input:
|
|
sendCMD( command );
|
|
break;
|
|
case CMD_Send_To_ICS:
|
|
if(((Command)command).getData().contains(TQRegExp("^(?:\\.|tell)")))
|
|
{
|
|
writeToConsole(((Command)command).getData(), "K_PVT");
|
|
}
|
|
send(((Command)command).getData());
|
|
break;
|
|
case CMD_Examine_Forward:
|
|
send("$forward 1");
|
|
break;
|
|
case CMD_Examine_Backward:
|
|
send("$backward 1");
|
|
break;
|
|
case CMD_White_Resign:
|
|
case CMD_Black_Resign:
|
|
send("$resign");
|
|
break;
|
|
case CMD_Offer_Draw:
|
|
send("$draw");
|
|
break;
|
|
case CMD_Reject_Draw:
|
|
send("$decline t draw");
|
|
break;
|
|
default:
|
|
/* do nothing unknown command */
|
|
kdWarning() << "InternetIO::sendCMD received an unknown command: " << ((Command)command).getCommand() << endl;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::send
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::send(const TQString& msg)
|
|
{
|
|
TQString tmp(msg);
|
|
ssize_t len;
|
|
|
|
/* Attach events to specific outgoing text */
|
|
if( ( tmp == "accept" ) ||
|
|
( tmp == "decline" ) ||
|
|
( tmp.left(6) == "match " ) )
|
|
{
|
|
if( challenge != NULL )
|
|
{
|
|
delete challenge;
|
|
nullifyChallenge();
|
|
}
|
|
}
|
|
if( tmp.right(1) != "\n" )
|
|
{
|
|
tmp += "\n";
|
|
}
|
|
|
|
len = write(socket->socket(), tmp.latin1(), tmp.length() );
|
|
|
|
if( Log )
|
|
{
|
|
Log->writeBlock( TQString("<< ").latin1(), 3 );
|
|
Log->writeBlock( tmp.latin1(), tmp.length() );
|
|
}
|
|
if( len < (signed)tmp.length() )
|
|
{
|
|
kdWarning() << "io_internet::Send: Failed to write full block of data to socket." << endl;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::readCommand
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::readCommand(TDESocket* socket)
|
|
{
|
|
char buffer[READ_BUFFER_SIZE];
|
|
TQString tmp;
|
|
TQStringList lines;
|
|
|
|
memset(buffer, 0, READ_BUFFER_SIZE);
|
|
read(socket->socket(), buffer, READ_BUFFER_SIZE);
|
|
tmp = buffer;
|
|
|
|
tmp = lineBuffer + tmp;
|
|
if( Log )
|
|
{
|
|
Log->writeBlock( tmp.latin1(), tmp.length() );
|
|
}
|
|
if(loginStage != LOGIN_STAGE_LOGGED_IN)
|
|
{
|
|
// route all the data to the login parser
|
|
parseLoginData(tmp);
|
|
this->parseMode = NORMAL_MODE;
|
|
}
|
|
else
|
|
{
|
|
lines = TQStringList::split( TQRegExp("\n\r?"), tmp, FALSE );
|
|
if(!(tmp.endsWith("\n\r") || tmp.endsWith("\n")))
|
|
{
|
|
lineBuffer = (*(--lines.end()));
|
|
}
|
|
else
|
|
{
|
|
lineBuffer = "";
|
|
}
|
|
for(TQStringList::iterator i = lines.begin(); i != lines.end(); i++)
|
|
{
|
|
if(lineBuffer == "" || i != --lines.end())
|
|
{
|
|
(*i).replace( TQRegExp( "\\a" ), "" );
|
|
parseLine(*i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::sendUserName
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::sendUserName()
|
|
{
|
|
loginStage = LOGIN_STAGE_PASSWORD;
|
|
send(userName);
|
|
}
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::sendPassword
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::sendPassword()
|
|
{
|
|
send(passWord);
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::parseLoginData
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::parseLoginData( TQString data )
|
|
{
|
|
TQStringList lines;
|
|
|
|
if(loginStage == LOGIN_STAGE_NAME)
|
|
{
|
|
if(data.contains( "login:" ))
|
|
{
|
|
sendUserName();
|
|
}
|
|
lines = TQStringList::split( TQRegExp("\n\r?"), data, FALSE );
|
|
for(TQStringList::iterator i = lines.begin(); i != lines.end(); i++)
|
|
{
|
|
writeToConsole((*i), "K_STD");
|
|
}
|
|
}
|
|
else if(loginStage == LOGIN_STAGE_PASSWORD)
|
|
{
|
|
if(data.contains("**** Invalid password! ****") ||
|
|
data.contains("Sorry, names can only consist of lower and upper case letters. Try again.") ||
|
|
data.contains("If you are not a registered player, enter guest or a unique ID."))
|
|
{
|
|
loginDlg = new dlg_login( myParent, "LoginDialog", myResource);
|
|
loginDlg->disableServerSelect();
|
|
connect(loginDlg, TQT_SIGNAL( okClicked() ), this, TQT_SLOT( sendUserName() ) );
|
|
connect(loginDlg, TQT_SIGNAL( cancelClicked() ), this, TQT_SLOT( selfDestruct() ) );
|
|
connect(loginDlg, TQT_SIGNAL( login(TQString, TQString) ), this, TQT_SLOT( setUserInfo(TQString, TQString) ) );
|
|
}
|
|
else if(data.contains("Press return to enter the server as"))
|
|
{
|
|
TQRegExp guestName("Logging you in as \"(\\w*)\"");
|
|
int pos = guestName.search(data);
|
|
if(pos > -1)
|
|
{
|
|
userName = guestName.cap(1);
|
|
}
|
|
send("\n");
|
|
}
|
|
else if(data.contains("password:"))
|
|
{
|
|
sendPassword();
|
|
}
|
|
else
|
|
{
|
|
loginStage = LOGIN_STAGE_LOGGED_IN;
|
|
sendUserSettings();
|
|
}
|
|
lines = TQStringList::split( TQRegExp("\n\r?"), data, FALSE );
|
|
for(TQStringList::iterator i = lines.begin(); i != lines.end(); i++)
|
|
{
|
|
writeToConsole((*i), "K_STD");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lines = TQStringList::split( TQRegExp("\n\r?"), data, FALSE );
|
|
for(TQStringList::iterator i = lines.begin(); i != lines.end(); i++)
|
|
{
|
|
writeToConsole((*i), "K_STD");
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::ParseLine
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::parseLine( TQString line )
|
|
{
|
|
int i, j;
|
|
TQString tmp;
|
|
|
|
switch(parseMode)
|
|
{
|
|
case NORMAL_MODE: /* determine which mode we should go into */
|
|
if(line.contains(TQRegExp("^\\s*\\d{1,3}\\s+(?:\\d{1,4}|\\+\\+\\+\\+|\\-\\-\\-\\-)\\s+\\w{3,17}(\\(C\\))?\\s+\\d{1,3}\\s+\\d{1,3}")))
|
|
{
|
|
updateSoughtList(line);
|
|
parseMode = UPDATE_SOUGHT_MODE;
|
|
}
|
|
/* CHALLENGE */
|
|
else if( line.contains(TQRegExp("^\\s*Challenge: ")))
|
|
{
|
|
myResource->play( SND_CHALLENGE );
|
|
if( challenge != NULL )
|
|
{
|
|
delete challenge;
|
|
}
|
|
challenge = new dlg_challenge( 0, "Challenge", myResource );
|
|
connect( challenge, TQT_SIGNAL( destroyed() ), this, TQT_SLOT( nullifyChallenge() ) );
|
|
connect( challenge, TQT_SIGNAL( user1Clicked() ), this, TQT_SLOT( acceptChallenge() ) );
|
|
connect( challenge, TQT_SIGNAL( user2Clicked() ), this, TQT_SLOT( declineChallenge() ) );
|
|
line.replace(TQRegExp("^\\s*Challenge: "), "");
|
|
challenge->setValues( line, userName );
|
|
parseMode = CHALLENGE_MODE;
|
|
}
|
|
else if( ( line.left(15) == "Challenge from " ) && ( line.right(9) == " removed." ) )
|
|
{
|
|
if( challenge != NULL )
|
|
{
|
|
delete challenge;
|
|
}
|
|
}
|
|
/* SOUGHT GAME */
|
|
else if(line.contains("seeking"))
|
|
{
|
|
// writeToConsole("seeking", "K_CH");
|
|
}
|
|
/* PRIVATE TELL */
|
|
else if(line.contains(TQRegExp(".+ tells you: .*")))
|
|
{
|
|
/* First grab the user name so we can auto-respond later */
|
|
emit sendCMD( Command( 0, CMD_Set_Src_Tell, line.section(' ', 0, 0) ) );
|
|
myResource->play( SND_TELL );
|
|
writeToConsole(line, "K_PVT");
|
|
}
|
|
/* SAY */
|
|
else if(line.contains( TQRegExp(".+ says: .*")))
|
|
{
|
|
myResource->play(SND_SAY);
|
|
writeToConsole(line, "K_PVT");
|
|
return;
|
|
}
|
|
/* WHISPER & KIBITZ */
|
|
else if(line.contains(TQRegExp(".+ whispers: .*")) || line.contains(TQRegExp(".+ kibitzes: .*")))
|
|
{
|
|
writeToConsole(line, "K_WSP");
|
|
}
|
|
/* Important System Messages: Use Whisper Color */
|
|
else if(line.contains(TQRegExp("declines the draw request\\.$" )))
|
|
{
|
|
writeToConsole(line, "K_WSP");
|
|
}
|
|
/* DRAW OFFER */
|
|
else if(line.right(19) == " offers you a draw.")
|
|
{
|
|
writeToConsole(line, "K_WSP");
|
|
}
|
|
else if( line.contains( TQRegExp(".+rating adjustment:.+" ) ) )
|
|
{
|
|
writeToConsole(line, "K_WSP");
|
|
}
|
|
/* SHOUTS */
|
|
else if( line.contains( TQRegExp("^c?t?s?-?shouts: ") ) )
|
|
{
|
|
writeToConsole(line, "K_SHT");
|
|
}
|
|
/* NOTIFY */
|
|
else if((line.contains(TQRegExp("\\s*Notification:"))) ||
|
|
(line.contains(TQRegExp("\\s*Present company includes:"))) ||
|
|
(line.contains(TQRegExp("\\s*Your arrival was noted by:"))))
|
|
{
|
|
writeToConsole(line, "K_NOT");
|
|
myResource->play( SND_NOTIFICATION );
|
|
}
|
|
/* CHANNEL TELLS */
|
|
else if(line.contains(TQRegExp( ".\\(\\d+\\):" )))
|
|
{
|
|
/* First grab the channel # so we can auto-respond later */
|
|
j = line.find(TQString("):"));
|
|
i = line.findRev(TQString("("), j) + 1;
|
|
emit sendCMD( Command( 0, CMD_Set_Src_Channel, line.mid(i, j - i) ) );
|
|
writeToConsole(line, "K_CH");
|
|
}
|
|
else if(line.contains(TQRegExp("^<12>\\s")))
|
|
{
|
|
/* a game move */
|
|
parseStyle12(line, PARSE12_MODE_MOVE);
|
|
}
|
|
else if(line.contains(TQRegExp("^<b1>\\s")))
|
|
{
|
|
/* a bughouse piece has been passed or a piece has been captured in crazyhouse */
|
|
writeToConsole(line, "K_CH");
|
|
}
|
|
else if(line.contains(TQRegExp("^\\\\")))
|
|
{
|
|
writeToConsole(line, lastTag);
|
|
}
|
|
else if(line.contains(TQRegExp("^\\{?Game \\d+")) && line.contains("Creating", TRUE))
|
|
{
|
|
parseMode = NEW_GAME_MODE;
|
|
}
|
|
else if(line.contains("You are now observing game"))
|
|
{
|
|
parseMode = OBSERVE_GAME_MODE;
|
|
}
|
|
else if(line.startsWith("Movelist for game"))
|
|
{
|
|
TQRegExp gameNumber("\\d+");
|
|
int pos = gameNumber.search(line);
|
|
if(pos > -1)
|
|
{
|
|
ficsMoveListNumber = gameNumber.cap(0).toInt();
|
|
}
|
|
parseMode = PARSE_MOVE_LIST_MODE;
|
|
}
|
|
else if((line.contains(TQRegExp("^\\{?Game \\d+")) || line.contains(TQRegExp("Game \\d+"))) &&
|
|
(
|
|
line.contains(" forfeits by disconnection", TRUE) ||
|
|
line.contains(" forfeits by disconnection}", TRUE) ||
|
|
line.contains(" forfeits on time} ", TRUE) ||
|
|
line.contains(" forfeits on time ", TRUE) ||
|
|
line.contains(" resigns} ", TRUE) ||
|
|
line.contains(" resigns ", TRUE) ||
|
|
line.contains(" Game drawn by mutual agreement ", TRUE) ||
|
|
line.contains(" Game drawn by mutual agreement} ", TRUE) ||
|
|
line.contains(", has lost contact or quit.", TRUE) ||
|
|
line.contains(" checkmated ", TRUE) ||
|
|
line.contains(" checkmated} ", TRUE) ||
|
|
line.contains("lost connection", TRUE) ||
|
|
line.contains("has no material to mate", TRUE)
|
|
)
|
|
)
|
|
{
|
|
sendEndOfGameCommand(line);
|
|
}
|
|
else
|
|
{
|
|
/* don't know what to do with it, just send it to the console */
|
|
/* don't write the prompt to the console */
|
|
if( line.contains( TQRegExp( "^a?d?f?g?s?z?ics% " ) ) ||
|
|
line.contains( TQRegExp( "^cex% " ) ) ||
|
|
line.contains( TQRegExp( "^chess% " ) ) )
|
|
break;
|
|
writeToConsole(line, "K_STD");
|
|
}
|
|
break;
|
|
case UPDATE_SOUGHT_MODE:
|
|
if(line.contains(TQRegExp("\\d+\\s+ads? displayed.")))
|
|
{
|
|
updateSoughtList(line);
|
|
parseMode = NORMAL_MODE;
|
|
}
|
|
else
|
|
{
|
|
updateSoughtList(line);
|
|
}
|
|
break;
|
|
case NEW_GAME_MODE:
|
|
if(line.contains(TQRegExp("<12>\\s")))
|
|
{
|
|
/* a game move */
|
|
parseStyle12(line, PARSE12_MODE_NEW);
|
|
}
|
|
else if((line.startsWith("fics%") && line.length() == 6))
|
|
{
|
|
parseMode = NORMAL_MODE;
|
|
}
|
|
break;
|
|
case OBSERVE_GAME_MODE:
|
|
if(line.contains(TQRegExp("<12>\\s")))
|
|
{
|
|
/* a game move */
|
|
parseStyle12(line, PARSE12_MODE_NEW);
|
|
send("moves");
|
|
parseMode = NORMAL_MODE;
|
|
}
|
|
break;
|
|
case CHALLENGE_MODE:
|
|
if(line.startsWith("You can \"accept\" or \"decline\", or propose"))
|
|
{
|
|
parseMode = NORMAL_MODE;
|
|
}
|
|
break;
|
|
case PARSE_MOVE_LIST_MODE:
|
|
if(!line.contains("{Still in progress}"))
|
|
{
|
|
if(line.contains(TQRegExp("\\d\\.")))
|
|
{
|
|
parseMoveList(line);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
parseMode = NORMAL_MODE;
|
|
}
|
|
break;
|
|
default: /* do nothing */
|
|
break;
|
|
};
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::ParseStyle12
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::parseStyle12(TQString line, const unsigned int Mode)
|
|
{
|
|
// kdWarning() << line << endl;
|
|
|
|
struct ChessMove move;
|
|
TQStringList fields;
|
|
TQString position_line = "";
|
|
match_param *param = NULL;
|
|
Command::clearMove(&move);
|
|
switch(Mode)
|
|
{
|
|
case PARSE12_MODE_NEW:
|
|
{
|
|
/* a new game that we are playing, or observing */
|
|
param = new match_param(this->myResource);
|
|
fields = TQStringList::split( TQChar(' '), line, FALSE );
|
|
|
|
/* set white time control */
|
|
TCPList tmpListWhite(param->time(WHITE));
|
|
TCP tmpTCPWhite = tmpListWhite[0];
|
|
tmpTCPWhite.Seconds = fields[20].toInt() * 60;
|
|
tmpTCPWhite.Increment = fields[21].toInt();
|
|
tmpListWhite[0] = tmpTCPWhite;
|
|
param->setTime(WHITE, tmpListWhite);
|
|
|
|
/* set black time control */
|
|
TCPList tmpListBlack(param->time(BLACK));
|
|
TCP tmpTCPBlack = tmpListBlack[0];
|
|
tmpTCPBlack.Seconds = fields[20].toInt() * 60;
|
|
tmpTCPBlack.Increment = fields[21].toInt();
|
|
tmpListBlack[0] = tmpTCPBlack;
|
|
param->setTime(BLACK, tmpListBlack);
|
|
|
|
if((userName.upper() == fields[17].upper()) &&
|
|
((fields[19].toInt() == -1) || (fields[19].toInt() == 1)))
|
|
{
|
|
/* I am playing white */
|
|
param->setType(WHITE, PLAYERLOCAL);
|
|
}
|
|
else if(fields[19].toInt() != 2)
|
|
{
|
|
/* I am not playing white */
|
|
param->setType(WHITE, PLAYERTCP);
|
|
}
|
|
|
|
if((userName.upper() == fields[18].upper()) &&
|
|
((fields[19].toInt() == -1) || (fields[19].toInt() == 1)))
|
|
{
|
|
/* I am playing black */
|
|
param->setType(BLACK, PLAYERLOCAL);
|
|
}
|
|
else if(fields[19].toInt() != 2)
|
|
{
|
|
/* I am not playing black */
|
|
param->setType(BLACK, PLAYERTCP);
|
|
}
|
|
|
|
if(fields[19].toInt() == 2)
|
|
{
|
|
param->setType(WHITE, PLAYEREXAMINE);
|
|
param->setType(BLACK, PLAYEREXAMINE);
|
|
}
|
|
//param->setVariation(something); figure out how to get the variation
|
|
param->setName(WHITE, fields[17]);
|
|
param->setName(BLACK, fields[18]);
|
|
/* tell core to connect us to a new match */
|
|
fics_to_knights[fields[16].toInt()] = ((core*)myParent)->newMatch(param)->getID();
|
|
}
|
|
case PARSE12_MODE_MOVE:
|
|
{
|
|
fields = TQStringList::split( TQChar(' '), line, FALSE );
|
|
|
|
/* various ICS stuff for ChessMove */
|
|
move.ICS_ClockTicking = fields[31].toInt();
|
|
move.ICS_PawnPushFile = fields[10].toShort();
|
|
move.ICS_MoveCounter = fields[15].toInt();
|
|
if(fields[9] == "W")
|
|
{
|
|
move.ICS_OnMove = BLACK;
|
|
}
|
|
else if( fields[9] == "B" )
|
|
{
|
|
move.ICS_OnMove = WHITE;
|
|
}
|
|
|
|
switch( fields[19].toInt() )
|
|
{
|
|
/* Examining a game */
|
|
case 2:
|
|
move.ICS_Mode = ICS_Examine;
|
|
if(fics_to_knights[fields[16].toInt()] == 0)
|
|
{
|
|
/* no new game started yet, call parsestyle 12 with a different mode */
|
|
parseStyle12(line, PARSE12_MODE_NEW);
|
|
return;
|
|
}
|
|
break;
|
|
/* Observing a game */
|
|
case -2:
|
|
case 0:
|
|
move.ICS_Mode = ICS_Observe;
|
|
break;
|
|
/* Playing a game */
|
|
default:
|
|
move.ICS_Mode = ICS_Normal;
|
|
break;
|
|
}
|
|
|
|
/* Verbose Coordinate Notation of previous move ( USE AS CAN ) */
|
|
strcpy(move.CAN, fields[27].right(fields[27].length() - 2).replace(TQRegExp("-"), ""));
|
|
/* SAN */
|
|
strcpy(move.SAN, fields[29].replace(TQRegExp("\\+"), "").replace(TQRegExp("#"), ""));
|
|
|
|
/* fill the line for the command */
|
|
position_line += fields[1]; /* Internal Rank #7 */
|
|
position_line += fields[2]; /* Internal Rank #6 */
|
|
position_line += fields[3]; /* Internal Rank #5 */
|
|
position_line += fields[4]; /* Internal Rank #4 */
|
|
position_line += fields[5]; /* Internal Rank #3 */
|
|
position_line += fields[6]; /* Internal Rank #2 */
|
|
position_line += fields[7]; /* Internal Rank #1 */
|
|
position_line += fields[8]; /* Internal Rank #0 */
|
|
/* Can White Castle Short (boolean) */
|
|
position_line += fields[11];
|
|
/* Can White Castle Long (boolean) */
|
|
position_line += fields[12];
|
|
/* Can Black Castle Short (boolean) */
|
|
position_line += fields[13];
|
|
/* Can Black Castle Long (boolean) */
|
|
position_line += fields[14];
|
|
|
|
Command command(fics_to_knights[fields[16].toInt()], CMD_Move, fields[24].toInt() * 100,
|
|
fields[25].toInt() * 100, move);
|
|
command.setData(position_line);
|
|
emit sendCMD(command);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::ParsePlayer
|
|
//
|
|
///////////////////////////////////////
|
|
//void io_internet::ParsePlayer( TQString Handle )
|
|
//{
|
|
// player.Raw = Handle;
|
|
/* SysAdmin */
|
|
// if( Handle.contains( TQRegExp("\\(\\*\\)") ) )
|
|
// {
|
|
// player.SysAdmin = TRUE;
|
|
// Handle.replace( TQRegExp("\\(\\*\\)"), TQString("") );
|
|
// }
|
|
// else player.SysAdmin = FALSE;
|
|
/* ServiceRep */
|
|
// if( Handle.contains( TQRegExp("\\(SR\\)") ) )
|
|
// {
|
|
// player.ServiceRep = TRUE;
|
|
// Handle.replace( TQRegExp("\\(SR\\)"), TQString("") );
|
|
// }
|
|
// else player.ServiceRep = FALSE;
|
|
/* Computer */
|
|
// if( Handle.contains( TQRegExp("\\(C\\)") ) )
|
|
// {
|
|
// player.Computer = TRUE;
|
|
// Handle.replace( TQRegExp("\\(C\\)"), TQString("") );
|
|
// }
|
|
// else player.Computer = FALSE;
|
|
/* Unregistered */
|
|
// if( Handle.contains( TQRegExp("\\(U\\)") ) )
|
|
// {
|
|
// player.Unregistered = TRUE;
|
|
// Handle.replace( TQRegExp("\\(U\\)"), TQString("") );
|
|
// }
|
|
// else player.Unregistered = FALSE;
|
|
// return;
|
|
//}
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::nullifyChallenge
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::nullifyChallenge( void )
|
|
{
|
|
challenge = NULL;
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::declineChallenge
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::declineChallenge( void )
|
|
{
|
|
send( "decline" );
|
|
delete challenge;
|
|
challenge = NULL;
|
|
}
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::acceptChallenge
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::acceptChallenge( void )
|
|
{
|
|
send( challenge->values() );
|
|
delete challenge;
|
|
challenge = NULL;
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::writeToConsole
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::writeToConsole(TQString text, TQString tag)
|
|
{
|
|
lastTag = tag;
|
|
/* Remove Bells */
|
|
text.replace( TQRegExp("\\x0007") , "" );
|
|
/* Replace misc characters with rich-text friendly counterparts */
|
|
text.replace( TQRegExp("\\x003c"), "<" );
|
|
text.replace( TQRegExp("\\x007c"), "|" );
|
|
text.replace( TQRegExp( "\\f"), "");
|
|
text.replace( TQRegExp( "\\n"), "");
|
|
text.replace( TQRegExp( "\\r*" ), "" );
|
|
emit sendCMD( Command( 0, CMD_Append_To_Console, "<" + tag + ">" + text + "</" + tag + ">" ) );
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::updateSoughtList
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::updateSoughtList(TQString soughtLine)
|
|
{
|
|
/* "ADS DISPLAYED" MESSAGE */
|
|
if(soughtLine.contains(TQRegExp("\\d+\\s+ads? displayed.")))
|
|
{
|
|
emit sendCMD( Command( 0, CMD_Show_Sought_List ) );
|
|
}
|
|
else
|
|
{
|
|
emit sendCMD( Command( 0, CMD_Add_Sought_Match, soughtLine ) );
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::sendUserSettings()
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::sendUserSettings()
|
|
{
|
|
send("set style 12");
|
|
send(TQString("set interface Knights %1").arg(_VERSION_));
|
|
send(TQString("set private %1").arg(myResource->OPTION_Private));
|
|
send(TQString("set kibitz %1").arg(myResource->OPTION_Kibitz));
|
|
send(TQString("set tell %1").arg(myResource->OPTION_Tell));
|
|
send(TQString("set shout %1").arg(myResource->OPTION_Shout));
|
|
send(TQString("set seek %1").arg(myResource->OPTION_Seek));
|
|
send(TQString("set tolerance %1").arg(myResource->OPTION_Profanity));
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::parseMoveList(TQString data)
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::parseMoveList(TQString line)
|
|
{
|
|
TQStringList two_plys;
|
|
struct ChessMove move;
|
|
Command command;
|
|
int move_counter = 0;
|
|
|
|
/* white */
|
|
two_plys = TQStringList::split(TQRegExp("\\s+"), line, FALSE);
|
|
Command::clearMove(&move);
|
|
move_counter = two_plys[0].left(two_plys[0].length() - 1).length(); /* remove the . */
|
|
move.ICS_MoveCounter = move_counter;
|
|
move.ICS_Mode = ICS_Movelist;
|
|
move.ICS_OnMove = WHITE;
|
|
strcpy(move.SAN, two_plys[1]);
|
|
command.setCommand((int&)CMD_Move);
|
|
command.setID(fics_to_knights[ficsMoveListNumber]);
|
|
command.setMove(move);
|
|
emit sendCMD(command);
|
|
|
|
/* black */
|
|
if(two_plys.size() > 3)
|
|
{
|
|
Command::clearMove(&move);
|
|
move.ICS_MoveCounter = move_counter;
|
|
move.ICS_Mode = ICS_Movelist;
|
|
move.ICS_OnMove = BLACK;
|
|
strcpy(move.SAN, two_plys[3]);
|
|
command.setCommand((int&)CMD_Move);
|
|
command.setID(fics_to_knights[ficsMoveListNumber]);
|
|
command.setMove(move);
|
|
emit sendCMD(command);
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::sendEndOfGameCommand(TQString line)
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::sendEndOfGameCommand(TQString line)
|
|
{
|
|
TQStringList fields;
|
|
Command command;
|
|
|
|
fields = TQStringList::split( TQChar(' '), line, FALSE );
|
|
if(fields[1].endsWith(":"))
|
|
{
|
|
fields[1] = fields[1].left(fields[1].length() - 1);
|
|
}
|
|
command.setID(fics_to_knights[fields[1].toInt()]);
|
|
fields[fields.count() - 1] = fields[fields.count() - 1].stripWhiteSpace();
|
|
if(fields[fields.count() - 1] == "1-0" )
|
|
{
|
|
if(fields[fields.count() - 2].contains("resigns"))
|
|
{
|
|
command.setCommand((int&)CMD_Black_Resign);
|
|
}
|
|
else if(fields[fields.count() - 2].contains("time"))
|
|
{
|
|
command.setCommand((int&)CMD_White_Called_Flag);
|
|
}
|
|
else
|
|
{
|
|
command.setCommand((int&)CMD_Result_White);
|
|
}
|
|
}
|
|
else if(fields[fields.count() - 1] == "0-1")
|
|
{
|
|
if(fields[fields.count() - 2].contains("resigns"))
|
|
{
|
|
command.setCommand((int&)CMD_White_Resign);
|
|
}
|
|
else if(fields[fields.count() - 2].contains("time"))
|
|
{
|
|
command.setCommand((int&)CMD_Black_Called_Flag);
|
|
}
|
|
else
|
|
{
|
|
command.setCommand((int&)CMD_Result_Black);
|
|
}
|
|
}
|
|
else if(fields[fields.count() - 1] == "1/2-1/2")
|
|
{
|
|
command.setCommand((int&)CMD_Result_Draw);
|
|
}
|
|
else
|
|
{
|
|
command.setCommand((int&)CMD_Lost_Contact);
|
|
}
|
|
emit sendCMD(command);
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::processSeekTimer()
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::processSeekTimer()
|
|
{
|
|
/* timer timed out, send out a sought */
|
|
send("sought");
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::selfDestruct()
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::selfDestruct()
|
|
{
|
|
/* cause the io_internet to delete itself */
|
|
TQApplication::postEvent( tqApp->mainWidget(), new TQCustomEvent( EVENT_Del_IO_Net ) );
|
|
}
|
|
|
|
///////////////////////////////////////
|
|
//
|
|
// io_internet::setUserInfo()
|
|
//
|
|
///////////////////////////////////////
|
|
void io_internet::setUserInfo(TQString userName, TQString passWord)
|
|
{
|
|
this->userName = userName;
|
|
this->passWord = passWord;
|
|
}
|
|
|