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.
2314 lines
65 KiB
2314 lines
65 KiB
/*
|
|
Copyright (C) 1999-2001 Jens Hoefkens
|
|
jens@hoefkens.com
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
$Id$
|
|
|
|
*/
|
|
|
|
/*
|
|
|
|
TODO: popup dialog for accept/reject and join ??
|
|
clear the chat history?
|
|
game over, clear the caption?
|
|
need show saved
|
|
need buddy list
|
|
need wait for player,...
|
|
|
|
*/
|
|
|
|
#include "kbgfibs.h"
|
|
#include "kbgfibs.moc"
|
|
|
|
#include <tdeapplication.h>
|
|
#include <tdeconfig.h>
|
|
#include <tqtimer.h>
|
|
#include <tqcheckbox.h>
|
|
#include <tqlayout.h>
|
|
#include <tqstring.h>
|
|
#include <tqsocket.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tqgroupbox.h>
|
|
#include <tqbuttongroup.h>
|
|
#include <tqradiobutton.h>
|
|
#include <tdemainwindow.h>
|
|
#include <klineeditdlg.h>
|
|
#include <tdemessagebox.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqwhatsthis.h>
|
|
#include <kaudioplayer.h>
|
|
#include <kstandarddirs.h>
|
|
#include <tqvbox.h>
|
|
#include <kiconloader.h>
|
|
#include <ktabctl.h>
|
|
#include <kpassdlg.h>
|
|
#include <tqcstring.h>
|
|
#include <knotifyclient.h>
|
|
#include <tdeaction.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <iostream>
|
|
#include "kbgboard.h"
|
|
#include "kbgstatus.h"
|
|
|
|
#include "clip.h"
|
|
#include "version.h"
|
|
|
|
|
|
void KBgEngineFIBS::start()
|
|
{
|
|
// FIXME: open the child windows here and not in the constructor
|
|
}
|
|
|
|
// == configuration handling ===================================================
|
|
|
|
/*
|
|
* Restore settings and ask children to do the same
|
|
*/
|
|
void KBgEngineFIBS::readConfig()
|
|
{
|
|
TDEConfig *config = kapp->config();
|
|
config->setGroup("fibs engine");
|
|
|
|
// history variables
|
|
lastAway = config->readEntry("away_hist", "");
|
|
|
|
// various options
|
|
showMsg = config->readBoolEntry("pers_msg", false);
|
|
whoisInvite = config->readBoolEntry("whois_invite", false);
|
|
|
|
// connection information
|
|
infoFIBS[FIBSHost] = config->readEntry("server", "fibs.com");
|
|
infoFIBS[FIBSPort] = config->readEntry("port", "4321");
|
|
infoFIBS[FIBSUser] = config->readEntry("user", "");
|
|
infoFIBS[FIBSPswd] = config->readEntry("password", "");
|
|
|
|
// automatic messages
|
|
useAutoMsg[MsgBeg] = config->readBoolEntry("auto-beg", false);
|
|
useAutoMsg[MsgLos] = config->readBoolEntry("auto-los", false);
|
|
useAutoMsg[MsgWin] = config->readBoolEntry("auto-win", false);
|
|
|
|
autoMsg[MsgBeg] = config->readEntry("msg-beg", "");
|
|
autoMsg[MsgLos] = config->readEntry("msg-los", "");
|
|
autoMsg[MsgWin] = config->readEntry("msg-win", "");
|
|
|
|
// ask the children to read their config options
|
|
playerlist->readConfig();
|
|
chatWindow->readConfig();
|
|
}
|
|
|
|
/*
|
|
* Save the engine specific settings and tell all clients
|
|
*/
|
|
void KBgEngineFIBS::saveConfig()
|
|
{
|
|
TDEConfig *config = kapp->config();
|
|
config->setGroup("fibs engine");
|
|
|
|
// history variables
|
|
config->writeEntry("away_hist", lastAway);
|
|
|
|
// various options
|
|
config->writeEntry("pers_msg", showMsg);
|
|
config->writeEntry("whois_invite", whoisInvite);
|
|
|
|
// connection information
|
|
config->writeEntry("server", infoFIBS[FIBSHost]);
|
|
config->writeEntry("port", infoFIBS[FIBSPort]);
|
|
config->writeEntry("user", infoFIBS[FIBSUser]);
|
|
config->writeEntry("password", infoFIBS[FIBSPswd]);
|
|
|
|
// automatic messages
|
|
config->writeEntry("auto-beg", useAutoMsg[MsgBeg]);
|
|
config->writeEntry("auto-los", useAutoMsg[MsgLos]);
|
|
config->writeEntry("auto-win", useAutoMsg[MsgWin]);
|
|
|
|
config->writeEntry("msg-beg", autoMsg[MsgBeg]);
|
|
config->writeEntry("msg-los", autoMsg[MsgLos]);
|
|
config->writeEntry("msg-win", autoMsg[MsgWin]);
|
|
|
|
// ask the children to read their config options
|
|
playerlist->saveConfig();
|
|
chatWindow->saveConfig();
|
|
}
|
|
|
|
void KBgEngineFIBS::setupDefault()
|
|
{
|
|
|
|
cbp->setChecked(false);
|
|
cbi->setChecked(false);
|
|
|
|
lec[FIBSHost]->setText("fibs.com");
|
|
lec[FIBSPort]->setText("4321");
|
|
|
|
lec[FIBSUser]->clear();
|
|
lec[FIBSPswd]->clear();
|
|
|
|
|
|
chatWindow->setupDefault();
|
|
playerlist->setupDefault();
|
|
}
|
|
|
|
void KBgEngineFIBS::setupCancel()
|
|
{
|
|
chatWindow->setupCancel();
|
|
playerlist->setupCancel();
|
|
}
|
|
|
|
/*
|
|
* Called when the setup dialog is positively closed
|
|
*/
|
|
void KBgEngineFIBS::setupOk()
|
|
{
|
|
// various options
|
|
showMsg = cbp->isChecked();
|
|
whoisInvite = cbi->isChecked();
|
|
|
|
// connection information
|
|
for (int i = 0; i < NumFIBS; i++)
|
|
infoFIBS[i] = lec[i]->text();
|
|
|
|
// automatic messages
|
|
for (int i = 0; i < NumMsg; i++) {
|
|
useAutoMsg[i] = cbm[i]->isChecked();
|
|
autoMsg[i] = lem[i]->text();
|
|
}
|
|
|
|
chatWindow->setupOk();
|
|
playerlist->setupOk();
|
|
|
|
// save settings
|
|
saveConfig();
|
|
}
|
|
|
|
/*
|
|
* Puts the FIBS specific setup into the dialog nb
|
|
*/
|
|
void KBgEngineFIBS::getSetupPages(KDialogBase *nb)
|
|
{
|
|
/*
|
|
* Main Widget
|
|
*/
|
|
TQVBox *vbp = nb->addVBoxPage(i18n("FIBS Engine"), i18n("Here you can configure the FIBS backgammon engine"),
|
|
kapp->iconLoader()->loadIcon(PROG_NAME "_engine", TDEIcon::Desktop));
|
|
|
|
/*
|
|
* Get a multi page work space
|
|
*/
|
|
KTabCtl *tc = new KTabCtl(vbp, "fibs tabs");
|
|
|
|
/*
|
|
* FIBS, local options
|
|
*/
|
|
TQWidget *w = new TQWidget(tc);
|
|
TQGridLayout *gl = new TQGridLayout(w, 3, 1, nb->spacingHint());
|
|
|
|
/*
|
|
* Group boxes
|
|
*/
|
|
TQGroupBox *gbo = new TQGroupBox(i18n("Options"), w);
|
|
TQGroupBox *gbm = new TQGroupBox(i18n("Automatic Messages"), w);
|
|
|
|
gl->addWidget(gbo, 0, 0);
|
|
gl->addWidget(gbm, 1, 0);
|
|
|
|
/*
|
|
* Options
|
|
*/
|
|
cbp = new TQCheckBox(i18n("Show copy of personal messages in main window"), gbo);
|
|
cbi = new TQCheckBox(i18n("Automatically request player info on invitation"), gbo);
|
|
|
|
TQWhatsThis::add(cbp, i18n("Usually, all messages sent directly to you by other players "
|
|
"are displayed only in the chat window. Check this box if you "
|
|
"would like to get a copy of these messages in the main window."));
|
|
TQWhatsThis::add(cbi, i18n("Check this box if you would like to receive information on "
|
|
"players that invite you to games."));
|
|
|
|
cbp->setChecked(showMsg);
|
|
cbi->setChecked(whoisInvite);
|
|
|
|
gl = new TQGridLayout(gbo, 2, 1, 20);
|
|
gl->addWidget(cbp, 0, 0);
|
|
gl->addWidget(cbi, 1, 0);
|
|
|
|
/*
|
|
* Automatic messages
|
|
*/
|
|
gl = new TQGridLayout(gbm, NumMsg, 2, 20);
|
|
|
|
cbm[MsgBeg] = new TQCheckBox(i18n("Start match:"), gbm);
|
|
cbm[MsgWin] = new TQCheckBox(i18n("Win match:"), gbm);
|
|
cbm[MsgLos] = new TQCheckBox(i18n("Lose match:"), gbm);
|
|
|
|
TQWhatsThis::add(cbm[MsgBeg], i18n("If you want to send a standard greeting to your "
|
|
"opponent whenever you start a new match, check "
|
|
"this box and write the message into the entry "
|
|
"field."));
|
|
TQWhatsThis::add(cbm[MsgWin], i18n("If you want to send a standard message to your "
|
|
"opponent whenever you won a match, check this box "
|
|
"and write the message into the entry field."));
|
|
TQWhatsThis::add(cbm[MsgLos], i18n("If you want to send a standard message to your "
|
|
"opponent whenever you lost a match, check this box "
|
|
"and write the message into the entry field."));
|
|
|
|
for (int i = 0; i < NumMsg; i++) {
|
|
lem[i] = new TQLineEdit(autoMsg[i], gbm);
|
|
gl->addWidget(cbm[i], i, 0);
|
|
gl->addWidget(lem[i], i, 1);
|
|
connect(cbm[i], TQT_SIGNAL(toggled(bool)), lem[i], TQT_SLOT(setEnabled(bool)));
|
|
cbm[i]->setChecked(useAutoMsg[i]);
|
|
lem[i]->setEnabled(useAutoMsg[i]);
|
|
TQWhatsThis::add(lem[i], TQWhatsThis::textFor(cbm[i]));
|
|
}
|
|
|
|
/*
|
|
* Put the page into the notebook
|
|
*/
|
|
gl->activate();
|
|
tc->addTab(w, i18n("&Local"));
|
|
|
|
|
|
/*
|
|
* FIBS, connection setup
|
|
*/
|
|
w = new TQWidget(tc);
|
|
gl = new TQGridLayout(w, 3, 1, nb->spacingHint());
|
|
|
|
TQGroupBox *gbc = new TQGroupBox(i18n("Server"), w);
|
|
TQGroupBox *gbk = new TQGroupBox(i18n("Other"), w);
|
|
|
|
gl->addWidget(gbc, 0, 0);
|
|
gl->addWidget(gbk, 1, 0);
|
|
|
|
/*
|
|
* Server box
|
|
*/
|
|
gl = new TQGridLayout(gbc, 4, 2, 20);
|
|
|
|
TQLabel *lbc[NumFIBS];
|
|
|
|
lbc[FIBSHost] = new TQLabel(i18n("Server name:"), gbc);
|
|
lbc[FIBSPort] = new TQLabel(i18n("Server port:"), gbc);
|
|
lbc[FIBSUser] = new TQLabel(i18n("User name:"), gbc);
|
|
lbc[FIBSPswd] = new TQLabel(i18n("Password:"), gbc);
|
|
|
|
for (int i = 0; i < NumFIBS; i++) {
|
|
lec[i] = new TQLineEdit(infoFIBS[i], gbc);
|
|
gl->addWidget(lbc[i], i, 0);
|
|
gl->addWidget(lec[i], i, 1);
|
|
}
|
|
lec[FIBSPswd]->setEchoMode(TQLineEdit::Password);
|
|
|
|
TQWhatsThis::add(lec[FIBSHost], i18n("Enter here the host name of FIBS. With almost "
|
|
"absolute certainty this should be \"fibs.com\". "
|
|
"If you leave this blank, you will be asked again "
|
|
"at connection time."));
|
|
TQWhatsThis::add(lec[FIBSPort], i18n("Enter here the port number of FIBS. With almost "
|
|
"absolute certainty this should be \"4321\". "
|
|
"If you leave this blank, you will be asked again "
|
|
"at connection time."));
|
|
TQWhatsThis::add(lec[FIBSUser], i18n("Enter your login on FIBS here. If you do not have a "
|
|
"login yet, you should first create an account using "
|
|
"the corresponding menu entry. If you leave this blank, "
|
|
"you will be asked again at connection time."));
|
|
TQWhatsThis::add(lec[FIBSPswd], i18n("Enter your password on FIBS here. If you do not have a "
|
|
"login yet, you should first create an account using "
|
|
"the corresponding menu entry. If you leave this blank, "
|
|
"you will be asked again at connection time. The password "
|
|
"will not be visible."));
|
|
|
|
/*
|
|
* Connection keepalive
|
|
*/
|
|
cbk = new TQCheckBox(i18n("Keep connections alive"), gbk);
|
|
|
|
TQWhatsThis::add(cbk, i18n("Usually, FIBS drops the connection after one hour of inactivity. When "
|
|
"you check this box, %1 will try to keep the connection alive, even "
|
|
"if you are not actually playing or chatting. Use this with caution "
|
|
"if you do not have flat-rate Internet access.").arg(PROG_NAME));
|
|
|
|
cbk->setChecked(keepalive);
|
|
|
|
gl = new TQGridLayout(gbk, 1, 1, nb->spacingHint());
|
|
gl->addWidget(cbk, 0, 0);
|
|
|
|
/*
|
|
* Done with the page, put it in
|
|
*/
|
|
gl->activate();
|
|
tc->addTab(w, i18n("&Connection"));
|
|
|
|
/*
|
|
* Ask children for settings
|
|
*/
|
|
chatWindow->getSetupPages(tc, nb->spacingHint());
|
|
playerlist->getSetupPages(tc, nb->spacingHint());
|
|
|
|
/*
|
|
* TODO: future extensions
|
|
*/
|
|
w = new TQWidget(tc);
|
|
tc->addTab(w, i18n("&Buddy List"));
|
|
}
|
|
|
|
|
|
// == functions related to the invitation menu =================================
|
|
|
|
/*
|
|
* Remove a player from the invitation list in the join menu
|
|
*/
|
|
void KBgEngineFIBS::cancelJoin(const TQString &info)
|
|
{
|
|
TQRegExp patt = TQRegExp("^" + info + " ");
|
|
|
|
for (int i = 0; i <= numJoin; i++) {
|
|
if (actJoin[i]->text().contains(patt)) {
|
|
// move all entries starting at i+1 up by one...
|
|
for (int j = i; j < numJoin; j++)
|
|
actJoin[j]->setText(actJoin[j+1]->text());
|
|
actJoin[numJoin--]->unplug(joinMenu);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Parse the information in info for the purposes of the invitation
|
|
* submenu
|
|
*/
|
|
void KBgEngineFIBS::changeJoin(const TQString &info)
|
|
{
|
|
char name_p[100], name_o[100];
|
|
float rate;
|
|
int expi;
|
|
|
|
/*
|
|
* Extract the name of the player, her opponent, rating and experience.
|
|
* It is okay to use latin1(), since the string is coming from FIBS.
|
|
*/
|
|
sscanf(info.latin1(), "%99s %99s %*s %*s %*s %f %i %*s %*s %*s %*s %*s",
|
|
name_p, name_o, &rate, &expi);
|
|
|
|
TQString name = name_p;
|
|
TQString oppo = name_o;
|
|
|
|
TQString rate_s; rate_s.setNum(rate);
|
|
TQString expi_s; expi_s.setNum(expi);
|
|
|
|
TQRegExp patt = TQRegExp("^" + name + " ");
|
|
|
|
/*
|
|
* We have essentially two lists of names to check against: the ones
|
|
* that have invited us and are not yet in the menu and the ones that
|
|
* are already in the menu.
|
|
*/
|
|
|
|
if (numJoin > -1 && oppo != "-")
|
|
cancelJoin(name);
|
|
|
|
for (TQStringList::Iterator it = invitations.begin(); it != invitations.end(); ++it) {
|
|
|
|
if ((*it).contains(patt)) {
|
|
|
|
TQString text, menu;
|
|
|
|
if ((*it).contains(TQRegExp(" r$"))) {
|
|
menu = i18n("R means resume", "%1 (R)").arg(name);
|
|
text = i18n("%1 (experience %2, rating %3) wants to resume a saved match with you. "
|
|
"If you want to play, use the corresponding menu entry to join (or type "
|
|
"'join %4').").arg(name).arg(expi_s).arg(rate_s).arg(name);
|
|
KNotifyClient::event("invitation", i18n("%1 wants to resume a saved match with you").
|
|
arg(name));
|
|
} else if ((*it).contains(TQRegExp(" u$"))) {
|
|
menu = i18n("U means unlimited", "%1 (U)").arg(name);
|
|
text = i18n("%1 (experience %2, rating %3) wants to play an unlimited match with you. "
|
|
"If you want to play, use the corresponding menu entry to join (or type "
|
|
"'join %4').").arg(name).arg(expi_s).arg(rate_s).arg(name);
|
|
KNotifyClient::event("invitation", i18n("%1 has invited you to an unlimited match").
|
|
arg(name));
|
|
} else {
|
|
TQString len = (*it).right((*it).length() - name.length() - 1);
|
|
menu = i18n("If the format of the (U) and (R) strings is changed, it should also be changed here",
|
|
"%1 (%2)").arg(name).arg(len);
|
|
text = i18n("%1 (experience %2, rating %3) wants to play a %4 point match with you. "
|
|
"If you want to play, use the corresponding menu entry to join (or type "
|
|
"'join %5').").arg(name).arg(expi_s).arg(rate_s).arg(len).arg(name);
|
|
KNotifyClient::event("invitation", i18n("%1 has invited you for a %2 point match").
|
|
arg(name).arg(len));
|
|
}
|
|
emit serverString("rawwho " + name); // this avoids a race
|
|
if (whoisInvite) {
|
|
emit serverString("whois " + name);
|
|
emit infoText("<font color=\"red\">" + text + "</font>");
|
|
} else
|
|
emit infoText("<font color=\"red\">" + text + "</font><br>");
|
|
|
|
for (int i = 0; i <=numJoin; i++)
|
|
actJoin[i]->unplug(joinMenu);
|
|
|
|
if (++numJoin > 7) numJoin = 7;
|
|
|
|
for (int i = numJoin; i > 0; i--)
|
|
actJoin[i]->setText(actJoin[i-1]->text());
|
|
|
|
actJoin[0]->setText(menu);
|
|
|
|
for (int i = 0; i <= numJoin; i++)
|
|
actJoin[i]->plug(joinMenu);
|
|
|
|
invitations.remove(it);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If there are entries in the menu, enable it
|
|
*/
|
|
menu->setItemEnabled(joinMenuID, numJoin > -1);
|
|
}
|
|
|
|
|
|
// == various slots and functions ==============================================
|
|
|
|
/*
|
|
* Keep the connection alive.
|
|
*/
|
|
void KBgEngineFIBS::keepAlive()
|
|
{
|
|
emit serverString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
}
|
|
|
|
/*
|
|
* Several bookkeeping operations that have to be done at the
|
|
* end of every game. Some of these may or may not be necessary
|
|
* at a particular time, but they don't hurt either.
|
|
*/
|
|
void KBgEngineFIBS::endGame()
|
|
{
|
|
playing = false;
|
|
|
|
emit serverString("rawwho " + infoFIBS[FIBSUser]);
|
|
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
|
|
emit allowCommand(Load, false);
|
|
emit allowCommand(Undo, false);
|
|
emit allowCommand(Done, false);
|
|
emit allowCommand(Cube, false);
|
|
emit allowCommand(Roll, false);
|
|
}
|
|
|
|
/*
|
|
* Toggle visibility of the player list
|
|
*/
|
|
void KBgEngineFIBS::showList()
|
|
{
|
|
playerlist->isVisible() ? playerlist->hide() : playerlist->show();
|
|
}
|
|
|
|
/*
|
|
* Toggle visibility of the chat window
|
|
*/
|
|
void KBgEngineFIBS::showChat()
|
|
{
|
|
chatWindow->isVisible() ? chatWindow->hide() : chatWindow->show();
|
|
}
|
|
|
|
/*
|
|
* Process the last move coming from the board
|
|
*/
|
|
void KBgEngineFIBS::handleMove(TQString *s)
|
|
{
|
|
lastMove = *s;
|
|
TQString t = lastMove.left(1);
|
|
int moves = t.toInt();
|
|
|
|
emit allowCommand(Done, moves == toMove);
|
|
emit allowCommand(Undo, moves > 0);
|
|
|
|
/*
|
|
* Allow undo and possibly start the commit timer
|
|
*/
|
|
redoPossible &= ((moves < toMove) && (undoCounter > 0));
|
|
emit allowCommand(Redo, redoPossible);
|
|
if (moves == toMove && cl >= 0) {
|
|
emit allowMoving(false);
|
|
ct->start(cl, true);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Done with the move
|
|
*/
|
|
void KBgEngineFIBS::done()
|
|
{
|
|
// prevent the timer from expiring again
|
|
ct->stop();
|
|
|
|
// no more moves
|
|
emit allowMoving(false);
|
|
|
|
// no more commands until it's our turn
|
|
emit allowCommand(Load, false);
|
|
emit allowCommand(Undo, false);
|
|
emit allowCommand(Done, false);
|
|
emit allowCommand(Cube, false);
|
|
emit allowCommand(Roll, false);
|
|
|
|
// Transform the string to FIBS cormat
|
|
lastMove.replace(0, 2, "move ");
|
|
lastMove.replace(pat[PlsChar], "-");
|
|
|
|
// sent it to the server
|
|
emit serverString(lastMove);
|
|
}
|
|
|
|
/*
|
|
* Undo the last move
|
|
*/
|
|
void KBgEngineFIBS::undo()
|
|
{
|
|
ct->stop();
|
|
|
|
redoPossible = true;
|
|
++undoCounter;
|
|
|
|
emit allowMoving(true);
|
|
emit allowCommand(Done, false);
|
|
emit allowCommand(Redo, true);
|
|
emit undoMove();
|
|
}
|
|
|
|
/*
|
|
* Redo the last undone move
|
|
*/
|
|
void KBgEngineFIBS::redo()
|
|
{
|
|
--undoCounter;
|
|
emit redoMove();
|
|
}
|
|
|
|
/*
|
|
* Double the cube - coming from the board
|
|
*/
|
|
void KBgEngineFIBS::doubleCube(const int w)
|
|
{
|
|
if (playing && w == US) cube();
|
|
}
|
|
|
|
/*
|
|
* Roll the dice - coming from the board
|
|
*/
|
|
void KBgEngineFIBS::rollDice(const int w)
|
|
{
|
|
if (playing && w == US) roll();
|
|
}
|
|
|
|
/*
|
|
* This engine passes all commands unmodified to the server
|
|
*/
|
|
void KBgEngineFIBS::handleCommand(TQString const &cmd)
|
|
{
|
|
emit serverString(cmd);
|
|
}
|
|
|
|
/*
|
|
* If we have a connection, we don't quit right away
|
|
*/
|
|
bool KBgEngineFIBS::queryClose()
|
|
{
|
|
if (connection->state() == TQSocket::Idle)
|
|
return true;
|
|
|
|
switch (KMessageBox::warningYesNoCancel((TQWidget *)parent(),i18n("Still connected. Log out first?"),TQString(),i18n("Log Out"), i18n("Stay Connected"))) {
|
|
case KMessageBox::Yes :
|
|
disconnectFIBS();
|
|
return true;
|
|
case KMessageBox::No :
|
|
return true;
|
|
default: // cancel
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If we have a connection, we don't quit right away
|
|
*/
|
|
bool KBgEngineFIBS::queryExit()
|
|
{
|
|
if( kapp->sessionSaving())
|
|
return true;
|
|
if (connection->state() != TQSocket::Idle)
|
|
disconnectFIBS();
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* This displays a copy of personal messages in the main window.
|
|
* Normally, these only get displayed in the chat window.
|
|
*/
|
|
void KBgEngineFIBS::personalMessage(const TQString &msg)
|
|
{
|
|
if (showMsg)
|
|
emit infoText(msg);
|
|
}
|
|
|
|
|
|
// == slots and functions for FIBS commands ====================================
|
|
|
|
/*
|
|
* Accept the offer
|
|
*/
|
|
void KBgEngineFIBS::accept()
|
|
{
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
|
|
emit serverString("accept");
|
|
}
|
|
|
|
/*
|
|
* Reject the offer
|
|
*/
|
|
void KBgEngineFIBS::reject()
|
|
{
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
|
|
emit serverString("reject");
|
|
}
|
|
|
|
/*
|
|
* Continue a multi game match
|
|
*/
|
|
void KBgEngineFIBS::match_conti()
|
|
{
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
|
|
emit serverString("join");
|
|
}
|
|
|
|
/*
|
|
* Leave a multi game match
|
|
*/
|
|
void KBgEngineFIBS::match_leave()
|
|
{
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
|
|
emit serverString("leave");
|
|
}
|
|
|
|
/*
|
|
* Go away from the server for a little while. Offer the last know away
|
|
* message as a default to the user.
|
|
*/
|
|
void KBgEngineFIBS::away()
|
|
{
|
|
bool ret;
|
|
TQString msg = KLineEditDlg::getText(i18n("Please type the message that should be displayed to other\n"
|
|
"users while you are away."),
|
|
lastAway, &ret, (TQWidget *)parent());
|
|
if (ret) {
|
|
lastAway = msg;
|
|
emit serverString("away " + msg);
|
|
actAway->setEnabled(false);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Toggle being ready for games
|
|
*/
|
|
void KBgEngineFIBS::toggle_ready()
|
|
{
|
|
emit serverString("toggle ready");
|
|
}
|
|
|
|
/*
|
|
* Toggle the use of greedy bearoffs
|
|
*/
|
|
void KBgEngineFIBS::toggle_greedy()
|
|
{
|
|
emit serverString("toggle greedy");
|
|
}
|
|
|
|
/*
|
|
* Toggle whether we will be asked to double/roll or not
|
|
*/
|
|
void KBgEngineFIBS::toggle_double()
|
|
{
|
|
emit serverString("toggle double");
|
|
}
|
|
|
|
/*
|
|
* Toggle whether we want to see details on rating computations
|
|
*/
|
|
void KBgEngineFIBS::toggle_ratings()
|
|
{
|
|
emit serverString("toggle ratings");
|
|
}
|
|
|
|
/*
|
|
* Come back after being away.
|
|
*/
|
|
void KBgEngineFIBS::back()
|
|
{
|
|
emit serverString("back");
|
|
}
|
|
|
|
/*
|
|
* Double the cube
|
|
*/
|
|
void KBgEngineFIBS::cube()
|
|
{
|
|
emit serverString("double");
|
|
}
|
|
|
|
/*
|
|
* Roll the dice
|
|
*/
|
|
void KBgEngineFIBS::roll()
|
|
{
|
|
emit serverString("roll");
|
|
}
|
|
|
|
/*
|
|
* Reload the board
|
|
*/
|
|
void KBgEngineFIBS::load()
|
|
{
|
|
emit serverString("board");
|
|
}
|
|
|
|
/*
|
|
* Handle the menu short cuts for joining. This is not as pretty as it
|
|
* could or should be, but it works and is easy to understand.
|
|
*/
|
|
void KBgEngineFIBS::join(const TQString &msg)
|
|
{
|
|
emit serverString("join " + msg.left(msg.find('(')));
|
|
}
|
|
void KBgEngineFIBS::join_0() { join(actJoin[0]->text()); }
|
|
void KBgEngineFIBS::join_1() { join(actJoin[1]->text()); }
|
|
void KBgEngineFIBS::join_2() { join(actJoin[2]->text()); }
|
|
void KBgEngineFIBS::join_3() { join(actJoin[3]->text()); }
|
|
void KBgEngineFIBS::join_4() { join(actJoin[4]->text()); }
|
|
void KBgEngineFIBS::join_5() { join(actJoin[5]->text()); }
|
|
void KBgEngineFIBS::join_6() { join(actJoin[6]->text()); }
|
|
void KBgEngineFIBS::join_7() { join(actJoin[7]->text()); }
|
|
|
|
|
|
// == invitation handling ======================================================
|
|
|
|
/*
|
|
* Show the invitation dialog and set the name to player
|
|
*/
|
|
void KBgEngineFIBS::inviteDialog()
|
|
{
|
|
fibsRequestInvitation("");
|
|
}
|
|
|
|
/*
|
|
* Show the invitation dialog and set the name to player
|
|
*/
|
|
void KBgEngineFIBS::fibsRequestInvitation(const TQString &player)
|
|
{
|
|
if (!invitationDlg) {
|
|
TQString p = player;
|
|
invitationDlg = new KBgInvite("invite");
|
|
connect(invitationDlg, TQT_SIGNAL(inviteCommand(const TQString &)), this, TQT_SLOT(handleCommand(const TQString &)));
|
|
connect(invitationDlg, TQT_SIGNAL(dialogDone()), this, TQT_SLOT(invitationDone()));
|
|
}
|
|
invitationDlg->setPlayer(player);
|
|
invitationDlg->show();
|
|
}
|
|
|
|
/*
|
|
* Finish off the invitation dialog
|
|
*/
|
|
void KBgEngineFIBS::invitationDone()
|
|
{
|
|
delete invitationDlg;
|
|
invitationDlg = 0;
|
|
}
|
|
|
|
|
|
// == connection handling ======================================================
|
|
|
|
/*
|
|
* Establish a connection to the server and log in if the parameter login
|
|
* is true.
|
|
*/
|
|
void KBgEngineFIBS::connectFIBS()
|
|
{
|
|
/*
|
|
* Make sure the connection parameter are properly set.
|
|
*/
|
|
if (!queryConnection(false))
|
|
return;
|
|
|
|
conAction->setEnabled(false);
|
|
newAction->setEnabled(false);
|
|
disAction->setEnabled(false);
|
|
|
|
/*
|
|
* Connect
|
|
*/
|
|
emit infoText(i18n("Looking up %1").arg(infoFIBS[FIBSHost]));
|
|
connection->connectToHost(infoFIBS[FIBSHost], infoFIBS[FIBSPort].toUShort());
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Hostname has been resolved.
|
|
*/
|
|
void KBgEngineFIBS::hostFound()
|
|
{
|
|
emit infoText(i18n("Connecting to %1").arg(infoFIBS[FIBSHost]));
|
|
}
|
|
|
|
/*
|
|
* An error has occurred. Reset and inform the user.
|
|
*/
|
|
void KBgEngineFIBS::connError(int f)
|
|
{
|
|
switch (f) {
|
|
case TQSocket::ErrConnectionRefused:
|
|
emit infoText(i18n("Error, connection has been refused"));
|
|
break;
|
|
case TQSocket::ErrHostNotFound:
|
|
emit infoText(i18n("Error, nonexistent host or name server down."));
|
|
break;
|
|
case TQSocket::ErrSocketRead:
|
|
emit infoText(i18n("Error, reading data from socket"));
|
|
break;
|
|
}
|
|
connectionClosed();
|
|
return;
|
|
}
|
|
|
|
void KBgEngineFIBS::readData()
|
|
{
|
|
TQString line;
|
|
while(connection->canReadLine()) {
|
|
line = connection->readLine();
|
|
if (line.length() > 2) {
|
|
line.truncate(line.length()-2);
|
|
handleServerData(line);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Transmit the string s to the server
|
|
*/
|
|
void KBgEngineFIBS::sendData(const TQString &s)
|
|
{
|
|
connection->writeBlock((s+"\r\n").latin1(),2+s.length());
|
|
}
|
|
|
|
/*
|
|
* Connection has been established. Log in and update the menus & actions.
|
|
*/
|
|
void KBgEngineFIBS::connected()
|
|
{
|
|
conAction->setEnabled(false);
|
|
newAction->setEnabled(false);
|
|
disAction->setEnabled(true);
|
|
|
|
menu->setItemEnabled( cmdMenuID, true);
|
|
menu->setItemEnabled(respMenuID, true);
|
|
menu->setItemEnabled(optsMenuID, true);
|
|
|
|
/*
|
|
* Initialize the rx state machine
|
|
*/
|
|
rxStatus = RxConnect;
|
|
rxCollect = "";
|
|
|
|
/*
|
|
* Depending on whether somebody else wants to handle the login or not
|
|
*/
|
|
if (login) {
|
|
|
|
/*
|
|
* Make sure the player list is empty when the whole list comes
|
|
* right after login
|
|
*/
|
|
playerlist->clear();
|
|
|
|
/*
|
|
* Login, using the autologin feature of FIBS, before we even receive anything.
|
|
*/
|
|
TQString entry;
|
|
entry.setNum(CLIP_VERSION);
|
|
emit serverString(TQString("login ") + PROG_NAME + "-" + PROG_VERSION + " " + entry + " "
|
|
+ infoFIBS[FIBSUser] + " " + infoFIBS[FIBSPswd]);
|
|
|
|
} else {
|
|
|
|
emit serverString("guest");
|
|
login = true;
|
|
|
|
}
|
|
|
|
/*
|
|
* Some visual feedback and done
|
|
*/
|
|
emit infoText(i18n("Connected") + "<br>");
|
|
}
|
|
|
|
/*
|
|
* Create a new account on FIBS. Obviously, this will also create
|
|
* a connection. The actual login is handled in the message parsing
|
|
* state machine.
|
|
*/
|
|
void KBgEngineFIBS::newAccount()
|
|
{
|
|
if (!queryConnection(true))
|
|
return;
|
|
|
|
rxStatus = RxNewLogin;
|
|
rxCollect = "";
|
|
login = false;
|
|
connectFIBS();
|
|
}
|
|
|
|
/*
|
|
* Send a disconnection request to the server. The server will disconnect
|
|
* and we will receive a connectionClosed() signal.
|
|
*/
|
|
void KBgEngineFIBS::disconnectFIBS()
|
|
{
|
|
// send two lines in case we are stuck in the login phase
|
|
emit serverString("quit");
|
|
emit serverString("quit");
|
|
}
|
|
|
|
/*
|
|
* Connection to the server is closed for some (unknown) reason. Delete
|
|
* the connection object and get the actions into a proper state.
|
|
*/
|
|
void KBgEngineFIBS::connectionClosed()
|
|
{
|
|
/*
|
|
* Read remaining input
|
|
*/
|
|
readData();
|
|
|
|
/*
|
|
* Flush whatever is left in the rxBuffer and send a note
|
|
*/
|
|
emit infoText(rxCollect + "<br><hr>");
|
|
emit infoText(i18n("Disconnected.") + "<br>");
|
|
|
|
conAction->setEnabled(true);
|
|
newAction->setEnabled(true);
|
|
disAction->setEnabled(false);
|
|
|
|
menu->setItemEnabled(joinMenuID, false);
|
|
menu->setItemEnabled( cmdMenuID, false);
|
|
menu->setItemEnabled(respMenuID, false);
|
|
menu->setItemEnabled(optsMenuID, false);
|
|
}
|
|
|
|
/*
|
|
* To establish a connection, we need to query the server name, the port
|
|
* number, the login and the password.
|
|
*/
|
|
bool KBgEngineFIBS::queryConnection(const bool newlogin)
|
|
{
|
|
TQString text, msg;
|
|
bool first, ret = true;
|
|
|
|
/*
|
|
* query the connection parameter
|
|
*/
|
|
if (newlogin || infoFIBS[FIBSHost].isEmpty()) {
|
|
|
|
msg = KLineEditDlg::getText(i18n("Enter the name of the server you want to connect to.\n"
|
|
"This should almost always be \"fibs.com\"."),
|
|
infoFIBS[FIBSHost], &ret, (TQWidget *)parent());
|
|
|
|
if (ret)
|
|
infoFIBS[FIBSHost] = msg;
|
|
else
|
|
return false;
|
|
|
|
}
|
|
if (newlogin || infoFIBS[FIBSPort].isEmpty()) {
|
|
|
|
msg = KLineEditDlg::getText(i18n("Enter the port number on the server. "
|
|
"It should almost always be \"4321\"."),
|
|
infoFIBS[FIBSPort], &ret, (TQWidget *)parent());
|
|
|
|
if (ret)
|
|
infoFIBS[FIBSPort] = msg;
|
|
else
|
|
return false;
|
|
}
|
|
if (newlogin || infoFIBS[FIBSUser].isEmpty()) {
|
|
|
|
if (newlogin)
|
|
|
|
text = i18n("Enter the login you would like to use on the server %1. The login may not\n"
|
|
"contain spaces or colons. If the login you choose is not available, you'll later be\n"
|
|
"given the opportunity to pick another one.\n\n").arg(infoFIBS[FIBSHost]);
|
|
|
|
else
|
|
|
|
text = i18n("Enter your login on the server %1. If you don't have a login, you\n"
|
|
"should create one using the corresponding menu option.\n\n").arg(infoFIBS[FIBSHost]);
|
|
|
|
|
|
first = true;
|
|
do {
|
|
msg = (KLineEditDlg::getText(text, infoFIBS[FIBSUser], &ret,
|
|
(TQWidget *)parent())).stripWhiteSpace();
|
|
if (first) {
|
|
text += i18n("The login may not contain spaces or colons!");
|
|
first = false;
|
|
}
|
|
|
|
} while (ret && (msg.isEmpty() || msg.contains(' ') || msg.contains(':')));
|
|
|
|
if (ret)
|
|
infoFIBS[FIBSUser] = msg;
|
|
else
|
|
return false;
|
|
}
|
|
if (newlogin || infoFIBS[FIBSPswd].isEmpty()) {
|
|
|
|
if (newlogin)
|
|
|
|
text = i18n("Enter the password you would like to use with the login %1\n"
|
|
"on the server %2. It may not contain colons.\n\n").
|
|
arg(infoFIBS[FIBSUser]).arg(infoFIBS[FIBSHost]);
|
|
|
|
else
|
|
|
|
text = i18n("Enter the password for the login %1 on the server %2.\n\n").
|
|
arg(infoFIBS[FIBSUser]).arg(infoFIBS[FIBSHost]);
|
|
|
|
first = true;
|
|
do {
|
|
TQCString password;
|
|
if (newlogin)
|
|
ret = (KPasswordDialog::getNewPassword(password, text) == KPasswordDialog::Accepted);
|
|
else
|
|
ret = (KPasswordDialog::getPassword(password, text) == KPasswordDialog::Accepted);
|
|
|
|
password.stripWhiteSpace();
|
|
msg = password;
|
|
|
|
if (first) {
|
|
text += i18n("The password may not contain colons or spaces!");
|
|
first = false;
|
|
}
|
|
|
|
} while (ret && (msg.isEmpty() || msg.contains(' ') || msg.contains(':')));
|
|
|
|
if (ret)
|
|
infoFIBS[FIBSPswd] = msg;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
* Made it here, all parameters acquired
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
|
|
// == message parsing ==========================================================
|
|
|
|
/*
|
|
* Pattern setup - rather long and boring
|
|
*/
|
|
void KBgEngineFIBS::initPattern()
|
|
{
|
|
TQString pattern;
|
|
|
|
/*
|
|
* Initialize the search pattern array
|
|
*/
|
|
pat[Welcome] = TQRegExp(pattern.sprintf("^%d ", CLIP_WELCOME));
|
|
pat[OwnInfo] = TQRegExp(pattern.sprintf("^%d ", CLIP_OWN_INFO));
|
|
pat[WhoInfo] = TQRegExp(pattern.sprintf("^%d ", CLIP_WHO_INFO));
|
|
pat[WhoEnde] = TQRegExp(pattern.sprintf("^%d$", CLIP_WHO_END));
|
|
pat[MotdBeg] = TQRegExp(pattern.sprintf("^%d" , CLIP_MOTD_BEGIN));
|
|
pat[MotdEnd] = TQRegExp(pattern.sprintf("^%d" , CLIP_MOTD_END));
|
|
pat[MsgPers] = TQRegExp(pattern.sprintf("^%d ", CLIP_MESSAGE));
|
|
pat[MsgDeli] = TQRegExp(pattern.sprintf("^%d ", CLIP_MESSAGE_DELIVERED));
|
|
pat[MsgSave] = TQRegExp(pattern.sprintf("^%d ", CLIP_MESSAGE_SAVED));
|
|
pat[ChatSay] = TQRegExp(pattern.sprintf("^%d ", CLIP_SAYS));
|
|
pat[ChatSht] = TQRegExp(pattern.sprintf("^%d ", CLIP_SHOUTS));
|
|
pat[ChatWis] = TQRegExp(pattern.sprintf("^%d ", CLIP_WHISPERS));
|
|
pat[ChatKib] = TQRegExp(pattern.sprintf("^%d ", CLIP_KIBITZES));
|
|
pat[SelfSay] = TQRegExp(pattern.sprintf("^%d ", CLIP_YOU_SAY));
|
|
pat[SelfSht] = TQRegExp(pattern.sprintf("^%d ", CLIP_YOU_SHOUT));
|
|
pat[SelfWis] = TQRegExp(pattern.sprintf("^%d ", CLIP_YOU_WHISPER));
|
|
pat[SelfKib] = TQRegExp(pattern.sprintf("^%d ", CLIP_YOU_KIBITZ));
|
|
pat[UserLin] = TQRegExp(pattern.sprintf("^%d ", CLIP_LOGIN));
|
|
pat[UserLot] = TQRegExp(pattern.sprintf("^%d ", CLIP_LOGOUT));
|
|
|
|
pat[NoLogin] = TQRegExp("\\*\\* Unknown command: 'login'");
|
|
pat[BegRate] = TQRegExp("^rating calculation:$");
|
|
pat[EndRate] = TQRegExp("^change for ");
|
|
pat[HTML_lt] = TQRegExp("<");
|
|
pat[HTML_gt] = TQRegExp(">");
|
|
pat[BoardSY] = TQRegExp("^Value of 'boardstyle' set to 3");
|
|
pat[BoardSN] = TQRegExp("^Value of 'boardstyle' set to [^3]");
|
|
pat[WhoisBG] = TQRegExp("^Information about ");
|
|
pat[WhoisE1] = TQRegExp("^ No email address\\.$");
|
|
pat[WhoisE2] = TQRegExp("^ Email address: ");
|
|
pat[SelfSlf] = TQRegExp("^You say to yourself:");
|
|
pat[Goodbye] = TQRegExp("^ Goodbye\\.");
|
|
pat[GameSav] = TQRegExp("The game was saved\\.$");
|
|
pat[RawBord] = TQRegExp("^board:");
|
|
pat[YouTurn] = TQRegExp("^It's your turn\\. Please roll or double");
|
|
pat[PlsMove] = TQRegExp("^Please move [1-6]+ pie");
|
|
pat[EndWtch] = TQRegExp("^You stop watching ");
|
|
pat[BegWtch] = TQRegExp("^You're now watching ");
|
|
pat[BegGame] = TQRegExp("^Starting a new game with ");
|
|
pat[Reload1] = TQRegExp("^You are now playing with ");
|
|
pat[Reload2] = TQRegExp(" has joined you. Your running match was loaded\\.$");
|
|
pat[OneWave] = TQRegExp(" waves goodbye.$");
|
|
pat[TwoWave] = TQRegExp(" waves goodbye again.$");
|
|
pat[YouWave] = TQRegExp("^You wave goodbye.$");
|
|
pat[GameBG1] = TQRegExp("start a [0-9]+ point match");
|
|
pat[GameBG2] = TQRegExp("start an unlimited match");
|
|
pat[GameRE1] = TQRegExp("are resuming their [0-9]+-point match");
|
|
pat[GameRE2] = TQRegExp("are resuming their unlimited match");
|
|
pat[GameEnd] = TQRegExp("point match against");
|
|
pat[TabChar] = TQRegExp("\\t");
|
|
pat[PlsChar] = TQRegExp("\\+");
|
|
pat[Invite0] = TQRegExp(" wants to play a [0-9]+ point match with you\\.$");
|
|
pat[Invite1] = TQRegExp("^.+ wants to play a ");
|
|
pat[Invite2] = TQRegExp(" wants to resume a saved match with you\\.$");
|
|
pat[Invite3] = TQRegExp(" wants to play an unlimited match with you\\.$");
|
|
pat[TypJoin] = TQRegExp("^Type 'join ");
|
|
pat[OneName] = TQRegExp("^ONE USERNAME PER PERSON ONLY!!!");
|
|
pat[YouAway] = TQRegExp("^You're away. Please type 'back'");
|
|
pat[YouBack] = TQRegExp("^Welcome back\\.$");
|
|
pat[YouMove] = TQRegExp("^It's your turn to move\\.");
|
|
pat[YouRoll] = TQRegExp("^It's your turn to roll or double\\.");
|
|
pat[TwoStar] = TQRegExp("^\\*\\* ");
|
|
pat[OthrNam] = TQRegExp("^\\*\\* Please use another name\\. ");
|
|
pat[BoxHori] = TQRegExp("^ *\\+-*\\+ *$");
|
|
pat[BoxVer1] = TQRegExp("^ *\\|");
|
|
pat[BoxVer2] = TQRegExp("\\| *$");
|
|
pat[YourNam] = TQRegExp("Your name will be ");
|
|
pat[GivePwd] = TQRegExp("Please give your password:");
|
|
pat[RetypeP] = TQRegExp("Please retype your password:");
|
|
pat[HelpTxt] = TQRegExp("^NAME$");
|
|
pat[MatchB1] = TQRegExp(" has joined you for a [0-9]+ point match\\.$");
|
|
pat[MatchB2] = TQRegExp(" has joined you for an unlimited match\\.$");
|
|
pat[EndLose] = TQRegExp(" wins the [0-9]+ point match [0-9]+-[0-9]+");
|
|
pat[EndVict] = TQRegExp(" win the [0-9]+ point match [0-9]+-[0-9]+");
|
|
pat[RejAcpt] = TQRegExp("Type 'accept' or 'reject'\\.$");
|
|
pat[YouAcpt] = TQRegExp("^You accept the double\\. The cube shows [0-9]+\\.");
|
|
|
|
pat[KeepAlv] = TQRegExp("^\\*\\* Unknown command: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'");
|
|
pat[RatingY] = TQRegExp("You'll see how the rating changes are calculated\\.$");
|
|
pat[RatingN] = TQRegExp("You won't see how the rating changes are calculated\\.$");
|
|
|
|
// FIXME same problem as in previous line
|
|
// mpgnu accepts the double.5 arthur_tn - gnu 1 0 1243.32 365 6 983722411 adsl-61-168-141.bna.bellsouth.net - -
|
|
|
|
// FIXME: <PLAYER> can't move. -- needs board reload...
|
|
|
|
/*
|
|
|
|
opponent matchlength score (your points first)
|
|
**gnu 1 0 - 0
|
|
*blah 1 0 - 0
|
|
kraut 1 0 - 0
|
|
|
|
logged in and ready **
|
|
logged in *
|
|
otherwise " "
|
|
|
|
*/
|
|
|
|
pat[ConLeav] = TQRegExp("^Type 'join' if you want to play the next game, type 'leave' if you don't\\.$");
|
|
pat[GreedyY] = TQRegExp("^\\*\\* Will use automatic greedy bearoffs\\.");
|
|
pat[GreedyN] = TQRegExp("^\\*\\* Won't use automatic greedy bearoffs\\.");
|
|
pat[BegBlnd] = TQRegExp("^\\*\\* You blind ");
|
|
pat[EndBlnd] = TQRegExp("^\\*\\* You unblind ");
|
|
pat[MatchB3] = TQRegExp("^\\*\\* You are now playing a [0-9]+ point match with ");
|
|
pat[MatchB4] = TQRegExp("^\\*\\* You are now playing an unlimited match with ");
|
|
pat[RejCont] = TQRegExp("^You reject\\. The game continues\\.");
|
|
pat[AcptWin] = TQRegExp("^You accept and win ");
|
|
pat[YouGive] = TQRegExp("^You give up\\.");
|
|
pat[DoubleY] = TQRegExp("^\\*\\* You will be asked if you want to double\\.");
|
|
pat[DoubleN] = TQRegExp("^\\*\\* You won't be asked if you want to double\\.");
|
|
}
|
|
|
|
/*
|
|
* Parse an incoming line and notify all interested parties - first match
|
|
* decides.
|
|
*/
|
|
void KBgEngineFIBS::handleServerData(TQString &line)
|
|
{
|
|
TQString rawline = line; // contains the line before it is HTML'fied
|
|
|
|
/*
|
|
* Fix-up any HTML-like tags in the line
|
|
*/
|
|
line.replace(pat[HTML_lt], "<");
|
|
line.replace(pat[HTML_gt], ">");
|
|
|
|
/*
|
|
* FIBS sometimes sends tabs, where it should send 8 spaces...
|
|
*/
|
|
line.replace(pat[TabChar], " ");
|
|
|
|
switch (rxStatus) {
|
|
|
|
case RxConnect:
|
|
handleMessageConnect(line, rawline);
|
|
break;
|
|
|
|
case RxMotd:
|
|
handleMessageMotd(line);
|
|
return;
|
|
|
|
case RxWhois:
|
|
handleMessageWhois(line);
|
|
break;
|
|
|
|
case RxRating:
|
|
handleMessageRating(line);
|
|
break;
|
|
|
|
case RxNewLogin:
|
|
handleMessageNewLogin(line);
|
|
break;
|
|
|
|
case RxIgnore:
|
|
/*
|
|
* Ignore _ALL_ incoming strings - this is needed during the
|
|
* login phase, when the message box is open.
|
|
*/
|
|
break;
|
|
|
|
case RxGoodbye:
|
|
/*
|
|
* Receive the logout sequence. The string will be flushed by the
|
|
* disconnectFIBS() callback
|
|
*/
|
|
rxCollect += TQString("<font color=\"blue\"><pre>") + line + "</pre></font><br>";
|
|
break;
|
|
|
|
case RxNormal:
|
|
handleMessageNormal(line, rawline);
|
|
break;
|
|
|
|
default:
|
|
/*
|
|
* This is a serious problem - latin1() is fine since the line comes from FIBS.
|
|
*/
|
|
std::cerr << "PROBLEM in KBgEngineFIBS::handleServerData: " << line.latin1() << std::endl;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle messages during the RxWhois state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageWhois(const TQString &line)
|
|
{
|
|
rxCollect += "<br> " + line;
|
|
if (line.contains(pat[WhoisE1]) || line.contains(pat[WhoisE2])) {
|
|
rxStatus = RxNormal;
|
|
emit infoText("<font color=\"darkgreen\">" + rxCollect + "<br></font>");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle messages during the RxRating state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageRating(const TQString &line)
|
|
{
|
|
rxCollect += "<br>" + line;
|
|
if (line.contains(pat[EndRate]) && ++rxCount == 2) {
|
|
emit infoText("<font color=\"blue\">" + rxCollect + "<br></font>");
|
|
rxStatus = RxNormal;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle messages during the RxMotd state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageMotd(const TQString &line)
|
|
{
|
|
if (line.contains(pat[MotdEnd])) {
|
|
rxStatus = RxNormal;
|
|
emit infoText("<font color=\"blue\"><pre>" + rxCollect + "</pre></font>");
|
|
/*
|
|
* just to be on the safe side, we set the value of boardstyle.
|
|
* we do it here, since this is reasonably late in the login
|
|
* procedure
|
|
*/
|
|
emit serverString("set boardstyle 3");
|
|
} else {
|
|
TQString tline = line;
|
|
tline.replace(pat[BoxHori], "<br><hr>");
|
|
tline.replace(pat[BoxVer1], "");
|
|
tline.replace(pat[BoxVer2], "");
|
|
rxCollect += "<br>" + tline;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle messages during the RxConnect state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageConnect(const TQString &line, const TQString &rawline)
|
|
{
|
|
/*
|
|
* Two possibilities: either we are logged in or we sent bad password/login
|
|
*/
|
|
if (line.contains("login:")) {
|
|
/*
|
|
* This can only happen if the password/login is wrong.
|
|
*/
|
|
if (rxCollect.isEmpty()) {
|
|
rxStatus = RxIgnore;
|
|
int ret = KMessageBox::warningContinueCancel
|
|
((TQWidget *)parent(), i18n("There was a problem with "
|
|
"your login and password. "
|
|
"You can reenter\n"
|
|
"your login and password and "
|
|
"try to reconnect."),
|
|
i18n("Wrong Login/Password"),
|
|
i18n("Reconnect"));
|
|
if (ret == KMessageBox::Continue) {
|
|
infoFIBS[FIBSUser] = "";
|
|
infoFIBS[FIBSPswd] = "";
|
|
login = true;
|
|
connectFIBS(); // will reset the rxStatus
|
|
} else {
|
|
rxStatus = RxConnect;
|
|
emit serverString("");
|
|
emit serverString("");
|
|
}
|
|
return;
|
|
}
|
|
emit infoText("<hr><pre>" + rxCollect + "</pre><br>");
|
|
rxCollect = "";
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Ok, we are logged in! Now receive personal information. These
|
|
* are completely useless but what the heck.
|
|
*/
|
|
if (line.contains(pat[Welcome])) {
|
|
char p[3][256];
|
|
time_t tmp;
|
|
// Using latin1() is okay, since the string comes from FIBS.
|
|
int words = sscanf (line.latin1(), "%255s%255s%li%255s", p[0], p[1], &tmp, p[2]);
|
|
if (words >= 4) {
|
|
TQDateTime d; d.setTime_t(tmp);
|
|
TQString text = i18n("%1, last logged in from %2 at %3.").arg(p[1]).arg(p[2]).arg(d.toString());
|
|
emit infoText("<hr><br>" + text);
|
|
playerlist->setName(p[1]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Initial parsing of user options and making sure that settings needed
|
|
* by us are at the correct value. We use and ignore values according
|
|
* to the following list:
|
|
*
|
|
* p[ 0] - CLIP_OWN_INFO
|
|
* p[ 1] - name -- IGNORE
|
|
* OptAllowPip
|
|
* n[ 0] - autoboard -- IGNORE
|
|
* OptAutoDouble
|
|
* OptAutoMove
|
|
* n[ 1] - away -- IGNORE
|
|
* n[ 2] - bell -- IGNORE
|
|
* OptCrawford
|
|
* n[ 3] - double -- IGNORE
|
|
* n[ 4] - expierience -- IGNORE
|
|
* OptGreedy
|
|
* n[ 6] - moreboards -- IGNORE and set to YES
|
|
* OptMoves
|
|
* n[ 8] - notify -- IGNORE and set to YES
|
|
* rating - rating -- IGNORE
|
|
* OptRatings
|
|
* OptReady
|
|
* n[10] - redoubles -- IGNORE
|
|
* n[11] - report -- IGNORE and set to YES
|
|
* OptSilent
|
|
* p[3] - timezone
|
|
*
|
|
*/
|
|
if (line.contains(pat[OwnInfo])) {
|
|
|
|
rxStatus = RxNormal;
|
|
|
|
int fibsOptions[NumFIBSOpt];
|
|
|
|
char p[3][256];
|
|
int n[12];
|
|
double rating;
|
|
|
|
// Using latin1() is okay, since the string comes from FIBS.
|
|
int words = sscanf (line.latin1(), "%255s%255s%i%i%i%i%i%i%i%i%i%i%i%i%i%lf%i%i%i%i%i%255s",
|
|
p[0], p[1],
|
|
&fibsOptions[OptAllowPip],
|
|
&n[0],
|
|
&fibsOptions[OptDouble],
|
|
&fibsOptions[OptAutoMove], // equivalent to OptDouble, can be ignored
|
|
&n[1], &n[2],
|
|
&fibsOptions[OptCrawford],
|
|
&n[3], &n[4],
|
|
&fibsOptions[OptGreedy],
|
|
&n[6],
|
|
&fibsOptions[OptMoves],
|
|
&n[8],
|
|
&rating,
|
|
&fibsOptions[OptRatings],
|
|
&fibsOptions[OptReady],
|
|
&n[10], &n[11],
|
|
&fibsOptions[OptSilent],
|
|
p[2]);
|
|
|
|
if (words >= 22 && n[6] != 1) {
|
|
/*
|
|
* need to get boards after new dice have arrived
|
|
*/
|
|
emit infoText("<font color=\"red\">" + i18n("The moreboards toggle has been set.") + "</font>");
|
|
emit serverString("toggle moreboards");
|
|
}
|
|
if (words >= 22 && n[8] != 1) {
|
|
/*
|
|
* need to know who logs out
|
|
*/
|
|
emit infoText("<font color=\"red\">" + i18n("The notify toggle has been set.") + "</font>");
|
|
emit serverString("toggle notify");
|
|
}
|
|
if (words >= 22 && n[11] != 1) {
|
|
/*
|
|
* want to know who starts playing games
|
|
*/
|
|
emit infoText("<font color=\"red\">" + i18n("The report toggle has been set.") + "</font>");
|
|
emit serverString("toggle report");
|
|
}
|
|
|
|
/*
|
|
* Set the correct toggles in the options menu
|
|
*/
|
|
fibsOpt[OptReady]->setChecked(fibsOptions[OptReady]);
|
|
fibsOpt[OptDouble]->setChecked(!fibsOptions[OptDouble]);
|
|
fibsOpt[OptRatings]->setChecked(fibsOptions[OptRatings]);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* The beginning of a new login procedure starts starts here
|
|
*/
|
|
if (line.contains(pat[OneName])) {
|
|
rxStatus = RxNewLogin;
|
|
emit infoText(TQString("<font color=\"red\">") + rxCollect + "</font>");
|
|
rxCollect = "";
|
|
TQString tmp = rawline;
|
|
handleServerData(tmp);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Still in the middle of the login sequence, still collecting information
|
|
*/
|
|
rxCollect += "<br>" + line;
|
|
}
|
|
|
|
/*
|
|
* Handle messages during the RxNewLogin state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageNewLogin(const TQString &line)
|
|
{
|
|
/*
|
|
* Request the new login
|
|
*/
|
|
if (line.contains(pat[OneName])) {
|
|
emit serverString(TQString("name ") + infoFIBS[FIBSUser]);
|
|
return;
|
|
}
|
|
/*
|
|
* Ooops, user name already exists
|
|
*/
|
|
if (line.contains(pat[OthrNam])) {
|
|
TQString text = i18n("The selected login is alreay in use! Please select another one.");
|
|
bool ret, first = true;
|
|
TQString msg;
|
|
|
|
do {
|
|
msg = (KLineEditDlg::getText(text, infoFIBS[FIBSUser], &ret,
|
|
(TQWidget *)parent())).stripWhiteSpace();
|
|
if (first) {
|
|
text += i18n("\n\nThe login may not contain spaces or colons!");
|
|
first = false;
|
|
}
|
|
} while (msg.contains(' ') || msg.contains(':'));
|
|
|
|
if (ret) {
|
|
infoFIBS[FIBSUser] = msg;
|
|
emit serverString("name " + msg);
|
|
} else
|
|
emit serverString("bye");
|
|
|
|
return;
|
|
}
|
|
/*
|
|
* first time we send the password
|
|
*/
|
|
if (line.contains(pat[YourNam])) {
|
|
emit serverString(infoFIBS[FIBSPswd]);
|
|
return;
|
|
}
|
|
/*
|
|
* second time we send the password
|
|
*/
|
|
if (line.contains(pat[GivePwd])) {
|
|
emit serverString(infoFIBS[FIBSPswd]);
|
|
return;
|
|
}
|
|
/*
|
|
* at this point we are done creating the account
|
|
*/
|
|
if (line.contains(pat[RetypeP])) {
|
|
|
|
TQString text = i18n("Your account has been created. Your new login is <u>%1</u>. To fully activate "
|
|
"this account, I will now close the connection. Once you reconnect, you can start "
|
|
"playing backgammon on FIBS.").arg(infoFIBS[FIBSUser]);
|
|
emit infoText("<br><hr><font color=\"blue\">" + text + "</font><br><hr>");
|
|
emit serverString("bye");
|
|
rxStatus = RxNormal;
|
|
rxCollect = "";
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Handle all normal messages - during the RxNormal state
|
|
*/
|
|
void KBgEngineFIBS::handleMessageNormal(TQString &line, TQString &rawline)
|
|
{
|
|
|
|
// - ignored ----------------------------------------------------------------------
|
|
|
|
/*
|
|
* For now, the waves are ignored. They should probably go into
|
|
* the chat window -- but only optional
|
|
*/
|
|
if (line.contains(pat[OneWave]) || line.contains(pat[TwoWave]) || line.contains(pat[YouWave])) {
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* These messages used to go into the games window. If KBackgammon
|
|
* ever gets a games window, they should be in there. For now, they
|
|
* are ignored.
|
|
*/
|
|
else if (line.contains(pat[GameBG1]) || line.contains(pat[GameBG2]) || line.contains(pat[GameRE1]) ||
|
|
line.contains(pat[GameRE2]) || line.contains(pat[GameEnd])) {
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Artefact caused by the login test procedure utilized.
|
|
*/
|
|
else if (line.contains(pat[NoLogin])) {
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* Connection keep-alive response
|
|
*/
|
|
else if (line.contains(pat[KeepAlv])) {
|
|
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Chat and personal messages - note that the chat window sends these messages
|
|
* back to us so we can display them if the user wants that.
|
|
*/
|
|
else if (line.contains(pat[ChatSay]) || line.contains(pat[ChatSht]) || line.contains(pat[ChatWis]) ||
|
|
line.contains(pat[ChatKib]) || line.contains(pat[SelfSay]) || line.contains(pat[SelfSht]) ||
|
|
line.contains(pat[SelfWis]) || line.contains(pat[SelfKib]) || line.contains(pat[SelfSlf]) ||
|
|
line.contains(pat[MsgPers]) || line.contains(pat[MsgDeli]) || line.contains(pat[MsgSave])) {
|
|
|
|
emit chatMessage(line);
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Beginning of games. In all these cases we are playing and not watching.
|
|
*/
|
|
else if (line.contains(pat[MatchB1]) || line.contains(pat[MatchB2])) {
|
|
|
|
if (useAutoMsg[MsgBeg] && !autoMsg[MsgBeg].stripWhiteSpace().isEmpty())
|
|
emit serverString("kibitz " + autoMsg[MsgBeg]);
|
|
}
|
|
else if (line.contains(pat[MatchB3]) || line.contains(pat[MatchB4])) {
|
|
|
|
if (useAutoMsg[MsgBeg] && !autoMsg[MsgBeg].stripWhiteSpace().isEmpty())
|
|
emit serverString("kibitz " + autoMsg[MsgBeg]);
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* The help should be handled separately. A fairly complete implementation of a
|
|
* help parsing can be found in KFibs.
|
|
*/
|
|
else if (line.contains(pat[HelpTxt])) {
|
|
|
|
// do nothing
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Simple cases without the need for many comments...
|
|
*/
|
|
else if (line.contains(pat[RawBord])) {
|
|
|
|
/*
|
|
* Save the board string and create a new game state
|
|
*/
|
|
KBgStatus *st = new KBgStatus(currBoard = rawline);
|
|
|
|
/*
|
|
* Save important state data and stop the timeout
|
|
*/
|
|
ct->stop();
|
|
undoCounter = 0;
|
|
|
|
pname[US ] = st->player(US);
|
|
pname[THEM] = st->player(THEM);
|
|
|
|
playing = (TQString("You") == pname[US]);
|
|
|
|
toMove = st->moves();
|
|
|
|
/*
|
|
* Update the caption string
|
|
*/
|
|
if (st->turn() < 0)
|
|
caption = i18n("%1 (%2) vs. %3 (%4) - game over").arg(pname[US]).
|
|
arg(st->points(US)).arg(pname[THEM]).arg(st->points(THEM));
|
|
else if (st->length() < 0)
|
|
caption = i18n("%1 (%2) vs. %3 (%4) - unlimited match").arg(pname[US]).
|
|
arg(st->points(US)).arg(pname[THEM]).arg(st->points(THEM));
|
|
else
|
|
caption = i18n("%1 (%2) vs. %3 (%4) - %5 point match").arg(pname[US]).
|
|
arg(st->points(US)).arg(pname[THEM]).arg(st->points(THEM)).
|
|
arg(st->length());
|
|
|
|
emit statText(caption);
|
|
|
|
/*
|
|
* Emit information and drop the state object
|
|
*/
|
|
emit allowMoving(playing && (st->turn() == US));
|
|
emit newState(*st);
|
|
|
|
delete st;
|
|
|
|
/*
|
|
* Set the actions correctly
|
|
*/
|
|
emit allowCommand(Load, true );
|
|
emit allowCommand(Undo, false);
|
|
emit allowCommand(Redo, false);
|
|
emit allowCommand(Done, false);
|
|
|
|
return;
|
|
}
|
|
else if (line.contains(pat[PlsMove]) || line.contains(pat[YouMove])) {
|
|
|
|
KNotifyClient::event("move", i18n("Please make your move"));
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Being away and coming back
|
|
*/
|
|
else if (line.contains(pat[YouAway])) {
|
|
|
|
emit changePlayerStatus(infoFIBS[FIBSUser], KFibsPlayerList::Away, true);
|
|
actBack->setEnabled(true);
|
|
line += "<br><pre> </pre>" + i18n("(or use the corresponding menu entry to join the match)");
|
|
}
|
|
else if (line.contains(pat[YouBack])) {
|
|
|
|
emit changePlayerStatus(infoFIBS[FIBSUser], KFibsPlayerList::Away, false);
|
|
actBack->setEnabled(false);
|
|
actAway->setEnabled(true);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Catch the response of the user responding to double or resign
|
|
*/
|
|
else if (line.contains(pat[YouGive]) || line.contains(pat[RejCont]) || line.contains(pat[AcptWin])) {
|
|
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Catch the responses to newly set toggles
|
|
*/
|
|
else if (line.contains(pat[GreedyY]) || line.contains(pat[GreedyN])) {
|
|
|
|
fibsOpt[OptGreedy]->setChecked(line.contains(pat[GreedyY]));
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
else if (line.contains(pat[DoubleY]) || line.contains(pat[DoubleN])) {
|
|
|
|
fibsOpt[OptDouble]->setChecked(line.contains(pat[DoubleY]));
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
|
|
else if (line.contains(pat[RatingY]) || line.contains(pat[RatingN])) {
|
|
|
|
fibsOpt[OptRatings]->setChecked(line.contains(pat[RatingY]));
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* It's our turn to roll or double
|
|
*/
|
|
else if (line.contains(pat[YouTurn]) || line.contains(pat[YouRoll])) {
|
|
|
|
emit allowCommand(Cube, playing);
|
|
emit allowCommand(Roll, playing);
|
|
|
|
emit statText(caption); // force a pip count recomputation by the board
|
|
|
|
KNotifyClient::event("roll or double", i18n("It's your turn to roll the dice or double the cube"));
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Got an invitation for a match
|
|
*/
|
|
else if (line.contains(pat[Invite0]) || line.contains(pat[Invite2]) || line.contains(pat[Invite3])) {
|
|
|
|
rxCollect = rawline.left(rawline.find(' '));
|
|
emit serverString("rawwho " + rxCollect);
|
|
|
|
if (line.contains(pat[Invite0])) {
|
|
rawline.replace(pat[Invite1], "");
|
|
rawline = rxCollect + " "+ rawline.left(rawline.find(' '));
|
|
} else if (line.contains(pat[Invite2])) {
|
|
rawline = rxCollect + " r";
|
|
} else if (line.contains(pat[Invite3])) {
|
|
invitations += rxCollect + " u";
|
|
}
|
|
invitations += rawline;
|
|
return; // will be printed once the rawwho is received
|
|
}
|
|
|
|
// - rx status changes ------------------------------------------------------------
|
|
|
|
else if (line.contains(pat[WhoisBG])) {
|
|
rxStatus = RxWhois;
|
|
rxCollect = TQString("<br><u>") + line + "</u>";
|
|
return;
|
|
}
|
|
else if (line.contains(pat[MotdBeg])) {
|
|
rxStatus = RxMotd;
|
|
rxCollect = "";
|
|
return;
|
|
}
|
|
else if (line.contains(pat[BegRate])) {
|
|
rxStatus = RxRating;
|
|
rxCount = 0;
|
|
rxCollect = "<br>" + line;
|
|
return;
|
|
}
|
|
else if (line.contains(pat[Goodbye])) {
|
|
rxStatus = RxGoodbye;
|
|
rxCollect = "<br><hr><br>";
|
|
handleServerData(rawline); // danger: recursion!
|
|
return;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Continue a mutli game match? We have to either leave or continue
|
|
*/
|
|
else if (line.contains(pat[ConLeav])) {
|
|
actConti->setEnabled(true);
|
|
actLeave->setEnabled(true);
|
|
line.append("<br><pre> </pre>" + i18n("(or use the corresponding menu "
|
|
"entry to leave or continue the match)"));
|
|
}
|
|
/*
|
|
* Beginning and end of user updates
|
|
*/
|
|
else if (line.contains(pat[WhoInfo])) {
|
|
rawline.replace(pat[WhoInfo], "");
|
|
if (rawline.contains(TQRegExp("^" + infoFIBS[FIBSUser] + " "))) {
|
|
int ready;
|
|
// Using latin1() is fine, since the string is coming from FIBS.
|
|
sscanf(rawline.latin1(), "%*s %*s %*s %i %*s %*s %*s %*s %*s %*s %*s %*s", &ready);
|
|
fibsOpt[OptReady]->setChecked(ready);
|
|
}
|
|
emit fibsWhoInfo(rawline);
|
|
return;
|
|
}
|
|
else if (line.contains(pat[WhoEnde])) {
|
|
emit fibsWhoEnd();
|
|
return;
|
|
}
|
|
/*
|
|
* This message is ignored. The instruction is given elsewhere (and slightly
|
|
* delayed in the flow of time).
|
|
*/
|
|
if (line.contains(pat[TypJoin])) {
|
|
return;
|
|
}
|
|
/*
|
|
* Watching other players
|
|
*/
|
|
else if (line.contains(pat[BegWtch])) {
|
|
emit allowCommand(Load, true);
|
|
rawline.replace(pat[BegWtch], "");
|
|
rawline.truncate(rawline.length()-1);
|
|
emit fibsStartNewGame(rawline);
|
|
load();
|
|
}
|
|
else if (line.contains(pat[EndWtch])) {
|
|
emit gameOver();
|
|
}
|
|
/*
|
|
* Blinding of players, the actual blind is handled by
|
|
* the player list
|
|
*/
|
|
else if (line.contains(pat[BegBlnd])) {
|
|
rawline.replace(pat[BegBlnd], "");
|
|
rawline.truncate(rawline.length()-1);
|
|
emit changePlayerStatus(rawline, KFibsPlayerList::Blind, true);
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
else if (line.contains(pat[EndBlnd])) {
|
|
rawline.replace(pat[EndBlnd], "");
|
|
rawline.truncate(rawline.length()-1);
|
|
emit changePlayerStatus(rawline, KFibsPlayerList::Blind, false);
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
/*
|
|
* Starting or reloading games or matches
|
|
*/
|
|
else if (line.contains(pat[BegGame])) {
|
|
rawline.replace(pat[BegGame], "");
|
|
rawline.truncate(rawline.length()-1);
|
|
emit fibsStartNewGame(rawline);
|
|
fibsOpt[OptDouble]->setChecked(true);
|
|
fibsOpt[OptGreedy]->setChecked(false);
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
}
|
|
else if (line.contains(pat[Reload1])) {
|
|
rawline.replace(pat[Reload1], "");
|
|
rawline = rawline.left(rawline.find(' '));
|
|
rawline.truncate(rawline.length()-1);
|
|
emit fibsStartNewGame(rawline);
|
|
fibsOpt[OptDouble]->setChecked(true);
|
|
fibsOpt[OptGreedy]->setChecked(false);
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
load();
|
|
}
|
|
else if (line.contains(pat[Reload2])) {
|
|
rawline.replace(pat[Reload2], "");
|
|
emit fibsStartNewGame(rawline);
|
|
fibsOpt[OptDouble]->setChecked(true);
|
|
fibsOpt[OptGreedy]->setChecked(false);
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
load();
|
|
}
|
|
/*
|
|
* Opponent offered resignation or the cube. We have to accept
|
|
* or reject the offer.
|
|
*/
|
|
else if (line.contains(pat[RejAcpt])) {
|
|
actAccept->setEnabled(true);
|
|
actReject->setEnabled(true);
|
|
line += "<br><pre> </pre>" + i18n("(or use the corresponding menu "
|
|
"entry to accept or reject the offer)");
|
|
}
|
|
/*
|
|
* This is strange: FIBS seems to not send a newline at the
|
|
* end of this pattern. So we work around that.
|
|
*/
|
|
else if (line.contains(pat[YouAcpt])) {
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
rawline.replace(pat[YouAcpt], "");
|
|
line.truncate(line.length()-rawline.length());
|
|
if (!rawline.stripWhiteSpace().isEmpty()) {
|
|
handleServerData(rawline);
|
|
}
|
|
}
|
|
/*
|
|
* Ending of games
|
|
*/
|
|
else if (line.contains(pat[EndLose])) {
|
|
if (playing) {
|
|
KNotifyClient::event("game over l", i18n("Sorry, you lost the game."));
|
|
if (useAutoMsg[MsgLos] && !autoMsg[MsgLos].stripWhiteSpace().isEmpty())
|
|
emit serverString(TQString("tell ") + pname[THEM] + " " + autoMsg[MsgLos]);
|
|
}
|
|
emit gameOver();
|
|
}
|
|
else if (line.contains(pat[EndVict])) {
|
|
if (playing) {
|
|
KNotifyClient::event("game over w", i18n("Congratulations, you won the game!"));
|
|
if (useAutoMsg[MsgWin] && !autoMsg[MsgWin].stripWhiteSpace().isEmpty())
|
|
emit serverString(TQString("tell ") + pname[THEM] + " " + autoMsg[MsgWin]);
|
|
}
|
|
emit gameOver();
|
|
}
|
|
else if (line.contains(pat[GameSav])) {
|
|
emit gameOver();
|
|
}
|
|
/*
|
|
* User logs out. This has to be signalled to the player
|
|
* list. Get the true user names by working on the rawline.
|
|
*/
|
|
else if (line.contains(pat[UserLot])) {
|
|
rawline.replace(pat[UserLot], "");
|
|
emit fibsLogout(rawline.left(rawline.find(' ')));
|
|
return;
|
|
}
|
|
/*
|
|
* Emit the name of the newly logged in user.
|
|
*/
|
|
else if (line.contains(pat[UserLin])) {
|
|
rawline.replace(pat[UserLin], "");
|
|
emit fibsLogin(rawline.left(rawline.find(' ')));
|
|
return;
|
|
}
|
|
/*
|
|
* Special attention has to be paid to the proper setting of
|
|
* the 'boardstyle' variable, since we will not be able to display
|
|
* the board properly without it.
|
|
*/
|
|
else if (line.contains(pat[BoardSY])) {
|
|
// ignored
|
|
return;
|
|
}
|
|
else if (line.contains(pat[BoardSN])) {
|
|
emit serverString("set boardstyle 3");
|
|
emit infoText(TQString("<font color=\"red\"><br>")
|
|
+ i18n("You should never set the 'boardstyle' variable "
|
|
"by hand! It is vital for proper functioning of "
|
|
"this program that it remains set to 3. It has "
|
|
"been reset for you.")
|
|
+ "<br></font>");
|
|
return;
|
|
}
|
|
/*
|
|
* This is the final fall through: if the line started with ** and
|
|
* hasn't been processed, make it red, since it is a server resp.
|
|
* to something we just did.
|
|
*/
|
|
else if (line.contains(pat[TwoStar])) {
|
|
line = "<font color=\"red\">" + line + "</font>";
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
|
|
/*
|
|
* Print whatever part of the line made it here
|
|
*/
|
|
emit infoText(line);
|
|
}
|
|
|
|
// EOF
|
|
|
|
|
|
// == constructor, destructor and setup ========================================
|
|
|
|
/*
|
|
* Constructor
|
|
*/
|
|
KBgEngineFIBS::KBgEngineFIBS(TQWidget *parent, TQString *name, TQPopupMenu *pmenu)
|
|
: KBgEngine(parent, name, pmenu)
|
|
{
|
|
/*
|
|
* No connection, not playing, ready for login
|
|
*/
|
|
connection = new TQSocket(TQT_TQOBJECT(parent), "fibs connection");
|
|
playing = false;
|
|
login = true;
|
|
|
|
connect(connection, TQT_SIGNAL(hostFound()), this, TQT_SLOT(hostFound()));
|
|
connect(connection, TQT_SIGNAL(connected()), this, TQT_SLOT(connected()));
|
|
connect(connection, TQT_SIGNAL(error(int)), this, TQT_SLOT(connError(int)));
|
|
connect(connection, TQT_SIGNAL(connectionClosed()), this, TQT_SLOT(connectionClosed()));
|
|
connect(connection, TQT_SIGNAL(delayedCloseFinished()), this, TQT_SLOT(connectionClosed()));
|
|
connect(connection, TQT_SIGNAL(readyRead()), this, TQT_SLOT(readData()));
|
|
|
|
connect(this, TQT_SIGNAL(serverString(const TQString &)), this, TQT_SLOT(sendData(const TQString &)));
|
|
|
|
/*
|
|
* No invitation dialog
|
|
*/
|
|
invitationDlg = 0;
|
|
|
|
connect(this, TQT_SIGNAL(fibsWhoInfo(const TQString &)), this, TQT_SLOT(changeJoin(const TQString &)));
|
|
connect(this, TQT_SIGNAL(fibsLogout (const TQString &)), this, TQT_SLOT(cancelJoin(const TQString &)));
|
|
connect(this, TQT_SIGNAL(gameOver()), this, TQT_SLOT(endGame()));
|
|
|
|
/*
|
|
* Creating, initializing and connecting the player list
|
|
*/
|
|
playerlist = new KFibsPlayerList(0, "fibs player list");
|
|
|
|
connect(this, TQT_SIGNAL(fibsWhoInfo(const TQString &)), playerlist, TQT_SLOT(changePlayer(const TQString &)));
|
|
connect(this, TQT_SIGNAL(fibsLogout (const TQString &)), playerlist, TQT_SLOT(deletePlayer(const TQString &)));
|
|
connect(this, TQT_SIGNAL(fibsWhoEnd()), playerlist, TQT_SLOT(stopUpdate()));
|
|
connect(this, TQT_SIGNAL(fibsConnectionClosed()), playerlist, TQT_SLOT(stopUpdate()));
|
|
connect(this, TQT_SIGNAL(changePlayerStatus(const TQString &, int, bool)),
|
|
playerlist, TQT_SLOT(changePlayerStatus(const TQString &, int, bool)));
|
|
connect(playerlist, TQT_SIGNAL(fibsCommand(const TQString &)), this, TQT_SLOT(handleCommand(const TQString &)));
|
|
connect(playerlist, TQT_SIGNAL(fibsInvite(const TQString &)), this, TQT_SLOT(fibsRequestInvitation(const TQString &)));
|
|
|
|
/*
|
|
* Create, initialize and connect the chat window
|
|
*/
|
|
chatWindow = new KBgChat(0, "chat window");
|
|
|
|
connect(this, TQT_SIGNAL(chatMessage(const TQString &)), chatWindow, TQT_SLOT(handleData(const TQString &)));
|
|
connect(this, TQT_SIGNAL(fibsStartNewGame(const TQString &)), chatWindow, TQT_SLOT(startGame(const TQString &)));
|
|
connect(this, TQT_SIGNAL(gameOver()), chatWindow, TQT_SLOT(endGame()));
|
|
connect(this, TQT_SIGNAL(fibsLogout (const TQString &)), chatWindow, TQT_SLOT(deletePlayer(const TQString &)));
|
|
connect(chatWindow, TQT_SIGNAL(fibsCommand(const TQString &)), this, TQT_SLOT(handleCommand(const TQString &)));
|
|
connect(chatWindow, TQT_SIGNAL(fibsRequestInvitation(const TQString &)), this, TQT_SLOT(fibsRequestInvitation(const TQString &)));
|
|
connect(chatWindow, TQT_SIGNAL(personalMessage(const TQString &)), this, TQT_SLOT(personalMessage(const TQString &)));
|
|
connect(playerlist, TQT_SIGNAL(fibsTalk(const TQString &)), chatWindow, TQT_SLOT(fibsTalk(const TQString &)));
|
|
|
|
/*
|
|
* Creating, initializing and connecting the menu
|
|
* ----------------------------------------------
|
|
*/
|
|
respMenu = new TQPopupMenu();
|
|
joinMenu = new TQPopupMenu();
|
|
cmdMenu = new TQPopupMenu();
|
|
optsMenu = new TQPopupMenu();
|
|
|
|
/*
|
|
* Initialize the FIBS submenu - this is also put in the play menu
|
|
*/
|
|
conAction = new TDEAction(i18n("&Connect"), 0, this, TQT_SLOT( connectFIBS()), this);
|
|
newAction = new TDEAction(i18n("New Account"), 0, this, TQT_SLOT( newAccount()), this);
|
|
disAction = new TDEAction(i18n("&Disconnect"), 0, this, TQT_SLOT(disconnectFIBS()), this);
|
|
|
|
conAction->setEnabled(true ); conAction->plug(menu);
|
|
disAction->setEnabled(false); disAction->plug(menu);
|
|
newAction->setEnabled(true ); newAction->plug(menu);
|
|
|
|
menu->insertSeparator();
|
|
|
|
(invAction = new TDEAction(i18n("&Invite..."), 0, this, TQT_SLOT(inviteDialog()), this))->plug(menu);
|
|
|
|
/*
|
|
* Create and fill the response menu. This is for all these: type this or
|
|
* that messages from FIBS.
|
|
*/
|
|
cmdMenuID = menu->insertItem(i18n("&Commands"), cmdMenu); {
|
|
|
|
(actAway = new TDEAction(i18n("Away"), 0, this, TQT_SLOT(away()), this))->plug(cmdMenu);
|
|
(actBack = new TDEAction(i18n("Back"), 0, this, TQT_SLOT(back()), this))->plug(cmdMenu);
|
|
|
|
actAway->setEnabled(true);
|
|
actBack->setEnabled(false);
|
|
}
|
|
|
|
/*
|
|
* Create the server side options. This is preliminary and needs more work.
|
|
* The available options are skewed, since they refelect the needs of the
|
|
* author. Contact jens@hoefkens.com if your favorite option is missing.
|
|
*/
|
|
optsMenuID = menu->insertItem(i18n("&Options"), optsMenu); {
|
|
|
|
for (int i = 0; i < NumFIBSOpt; i++)
|
|
fibsOpt[i] = 0;
|
|
|
|
fibsOpt[OptReady] = new TDEToggleAction(i18n("Ready to Play"),
|
|
0, this, TQT_SLOT(toggle_ready()), this);
|
|
fibsOpt[OptRatings] = new TDEToggleAction(i18n("Show Rating Computations"),
|
|
0, this, TQT_SLOT(toggle_ratings()), this);
|
|
fibsOpt[OptRatings]->setCheckedState(i18n("Hide Rating Computations"));
|
|
fibsOpt[OptGreedy] = new TDEToggleAction(i18n("Greedy Bearoffs"),
|
|
0, this, TQT_SLOT(toggle_greedy()), this);
|
|
fibsOpt[OptDouble] = new TDEToggleAction(i18n("Ask for Doubles"),
|
|
0, this, TQT_SLOT(toggle_double()), this);
|
|
|
|
for (int i = 0; i < NumFIBSOpt; i++)
|
|
if (fibsOpt[i])
|
|
fibsOpt[i]->plug(optsMenu);
|
|
|
|
}
|
|
|
|
/*
|
|
* Create and fill the response menu. This is for all these: type this or
|
|
* that messages from FIBS.
|
|
*/
|
|
respMenuID = menu->insertItem(i18n("&Response"), respMenu); {
|
|
|
|
(actAccept = new TDEAction(i18n("Accept"), 0, this, TQT_SLOT(accept()), this))->plug(respMenu);
|
|
(actReject = new TDEAction(i18n("Reject"), 0, this, TQT_SLOT(reject()), this))->plug(respMenu);
|
|
|
|
actAccept->setEnabled(false);
|
|
actReject->setEnabled(false);
|
|
|
|
respMenu->insertSeparator();
|
|
|
|
(actConti = new TDEAction(i18n("Join"), 0, this, TQT_SLOT(match_conti()), this))->plug(respMenu);
|
|
(actLeave = new TDEAction(i18n("Leave"), 0, this, TQT_SLOT(match_leave()), this))->plug(respMenu);
|
|
|
|
actConti->setEnabled(false);
|
|
actLeave->setEnabled(false);
|
|
}
|
|
|
|
/*
|
|
* Create the join menu and do not fill it (this happens at first
|
|
* action setup.
|
|
*/
|
|
joinMenuID = menu->insertItem(i18n("&Join"), joinMenu); {
|
|
numJoin = -1;
|
|
|
|
actJoin[0] = new TDEAction("", 0, this, TQT_SLOT(join_0()), this);
|
|
actJoin[1] = new TDEAction("", 0, this, TQT_SLOT(join_1()), this);
|
|
actJoin[2] = new TDEAction("", 0, this, TQT_SLOT(join_2()), this);
|
|
actJoin[3] = new TDEAction("", 0, this, TQT_SLOT(join_3()), this);
|
|
actJoin[4] = new TDEAction("", 0, this, TQT_SLOT(join_4()), this);
|
|
actJoin[5] = new TDEAction("", 0, this, TQT_SLOT(join_5()), this);
|
|
actJoin[6] = new TDEAction("", 0, this, TQT_SLOT(join_6()), this);
|
|
actJoin[7] = new TDEAction("", 0, this, TQT_SLOT(join_7()), this);
|
|
}
|
|
|
|
menu->setItemEnabled(joinMenuID, false);
|
|
menu->setItemEnabled( cmdMenuID, false);
|
|
menu->setItemEnabled(respMenuID, false);
|
|
menu->setItemEnabled(optsMenuID, false);
|
|
|
|
/*
|
|
* Continue with the FIBS menu
|
|
*/
|
|
menu->insertSeparator();
|
|
|
|
(listAct = new TDEToggleAction(i18n("&Player List"), 0, this, TQT_SLOT(showList()), this))->plug(menu);
|
|
(chatAct = new TDEToggleAction(i18n("&Chat"), 0, this, TQT_SLOT(showChat()), this))->plug(menu);
|
|
|
|
connect(playerlist, TQT_SIGNAL(windowVisible(bool)), listAct, TQT_SLOT(setChecked(bool)));
|
|
connect(chatWindow, TQT_SIGNAL(windowVisible(bool)), chatAct, TQT_SLOT(setChecked(bool)));
|
|
|
|
/*
|
|
* Create message IDs. This sets up a lot of regular expressions.
|
|
*/
|
|
initPattern();
|
|
|
|
/*
|
|
* Restore old settings
|
|
*/
|
|
readConfig();
|
|
|
|
// FIXME: open the child windows in start() and not here
|
|
|
|
/*
|
|
* Update the menu actions
|
|
*/
|
|
listAct->setChecked(playerlist->isVisible());
|
|
chatAct->setChecked(chatWindow->isVisible());
|
|
|
|
/*
|
|
* Initialize the keepalive timer FIXME: make this a setting
|
|
*/
|
|
keepalive = true;
|
|
|
|
// FIXME: move the start to connect...
|
|
|
|
keepaliveTimer = new TQTimer(this);
|
|
connect(keepaliveTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(keepAlive()));
|
|
keepaliveTimer->start(1200000);
|
|
}
|
|
|
|
/*
|
|
* Destructor deletes child objects if necessary
|
|
*/
|
|
KBgEngineFIBS::~KBgEngineFIBS()
|
|
{
|
|
delete joinMenu;
|
|
delete respMenu;
|
|
delete cmdMenu;
|
|
delete optsMenu;
|
|
|
|
delete connection;
|
|
delete invitationDlg;
|
|
|
|
delete playerlist;
|
|
delete chatWindow;
|
|
}
|
|
|
|
|