File indexing completed on 2024-05-12 04:04:15
0001 /* 0002 This file is part of Knights, a chess board for KDE SC 4. 0003 SPDX-FileCopyrightText: 2009, 2010, 2011 Miha Čančula <miha@noughmad.eu> 0004 0005 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0006 */ 0007 0008 #include "proto/ficsprotocol.h" 0009 #include "proto/ficsdialog.h" 0010 #include "proto/chatwidget.h" 0011 #include "settings.h" 0012 #include "knightsdebug.h" 0013 0014 #include <KLocalizedString> 0015 0016 #include <QDialog> 0017 #include <QDialogButtonBox> 0018 #include <QVBoxLayout> 0019 #include <QPushButton> 0020 #include <QAbstractSocket> 0021 #include <QTcpSocket> 0022 #include <QApplication> 0023 0024 using namespace Knights; 0025 0026 // TODO: Include optional [white]/[black], m, f in RegEx check 0027 0028 const char* boolPattern = "([tf])"; 0029 const char* ratedPattern = "([ru])"; 0030 const char* namePattern = "([a-zA-Z\\(\\)]+)"; 0031 const char* ratingPattern = "([0-9\\+\\-\\s]+)"; 0032 const char* timePattern = "(\\d+)\\s+(\\d+)"; 0033 const char* variantPattern = "([a-z]+)\\s+([a-z]+)"; 0034 const char* argsPattern = "(.*)"; //TODO better 0035 const char* idPattern = "(\\d+)"; 0036 const char* pieces = "PRNBQKprnbqk"; 0037 const char* coordinate = "[abdcdefgh][12345678]"; 0038 const char* remainingTime = "\\d+ \\d+ (\\d+) \\d+ \\d+ (\\d+) (\\d+) (\\d+)"; 0039 const char* currentPlayerPattern = "([WB]) \\-?\\d+ \\d+ \\d+ \\d+ \\d+ \\d+ \\d+"; 0040 const char* offerPattern = "<pf> (\\d+) w=([a-zA-Z\\(\\)]+) t=([a-z]+) p=(.+)"; 0041 0042 FicsProtocol::FicsProtocol ( QObject* parent ) : TextProtocol ( parent ), 0043 movePattern(QStringLiteral("[%1]\\/(%2)\\-(%3)(=[%4])?") 0044 .arg ( QLatin1String(pieces) ) 0045 .arg ( QLatin1String(coordinate) ) 0046 .arg ( QLatin1String(coordinate) ) 0047 .arg ( QLatin1String(pieces) ) ), 0048 seekExp ( QString ( QLatin1String("%1 w=%2 ti=%3 rt=%4[PE\\s] t=%5 i=%6 r=%7 tp=%8 c=%9 rr=%10 a=%11 f=%12") ) 0049 .arg ( QLatin1String(idPattern) ) // %1 = index 0050 .arg ( QLatin1String(namePattern) ) // %2 = name 0051 .arg ( QLatin1String("([0-9a-f]{2,2})") ) // %3 = titles 0052 .arg ( QLatin1String("(\\d+)") ) // %4 = rating 0053 .arg ( QLatin1String("(\\d+)") ) // %5 = time 0054 .arg ( QLatin1String("(\\d+)") ) // %6 = increment 0055 .arg ( QLatin1String(ratedPattern) ) // %7 = rated ('r' or 'u') 0056 .arg ( QLatin1String("([a-z]+)") ) // %8 = type (standard, blitz, lightning, etc.) 0057 .arg ( QLatin1String("([?WB])") ) // %9 = color ('?', 'W' or 'B') 0058 .arg ( QLatin1String("(\\d+)\\-(\\d+)") ) // %10 = rating range (x-y) 0059 .arg ( QLatin1String(boolPattern) ) // %11 = automatic ( 't' or 'f' ) 0060 .arg ( QLatin1String(boolPattern) )), // %12 = formula ( 't' or 'f' ) 0061 challengeExp(QString ( QLatin1String("%1 w=%2 t=match p=%2 \\(%3\\) %2 \\(%3\\)")) 0062 .arg ( QLatin1String( idPattern ) ) // %1 = index 0063 .arg ( QLatin1String( namePattern ) ) // %2 = name 0064 .arg ( QLatin1String( ratingPattern ) ) ), // %3 = rating 0065 moveStringExp ( movePattern ), 0066 moveRegExp ( QString ( QLatin1String("<12>.*%1.*%2 (none|o-o|o-o-o|%3)") ) 0067 .arg ( QLatin1String( currentPlayerPattern ) ) 0068 .arg ( QLatin1String( remainingTime ) ) 0069 .arg ( movePattern ) ), 0070 gameStartedExp ( QString ( QLatin1String("Creating: %1 \\(%2\\) %3 \\(%4\\) %5 %6") ) 0071 .arg ( QLatin1String( namePattern ) ) 0072 .arg ( QLatin1String( ratingPattern ) ) 0073 .arg ( QLatin1String( namePattern ) ) 0074 .arg ( QLatin1String( ratingPattern ) ) 0075 .arg ( QLatin1String( variantPattern ) ) 0076 .arg ( QLatin1String( timePattern ) ) ), 0077 offerExp ( QLatin1String( offerPattern ) ), 0078 m_stage(ConnectStage), 0079 sendPassword(false), 0080 m_widget(nullptr), 0081 m_seeking(false), 0082 m_chat(nullptr) 0083 { 0084 // FICS games are always time-limited 0085 setAttribute ( QStringLiteral("TimeLimitEnabled"), true ); 0086 0087 //TODO: this initialization is obsolete since the time control _should_ be set 0088 //when a new game is started and the values provided in the game dialog are used. 0089 if ( !Manager::self()->timeControlEnabled(color()) ) { 0090 TimeControl tc; 0091 tc.moves = 100; 0092 tc.baseTime = QTime().addSecs( 10 * 60 ); // A default time of 10 minutes with no increment 0093 tc.increment = 0; 0094 Manager::self()->setTimeControl(color(), tc); 0095 } 0096 } 0097 0098 FicsProtocol::~FicsProtocol() = default; 0099 0100 Protocol::Features FicsProtocol::supportedFeatures() { 0101 return TimeLimit | SetTimeLimit | UpdateTime | Pause | Adjourn | Resign | Abort; 0102 } 0103 0104 void FicsProtocol::startGame() { 0105 0106 } 0107 0108 void FicsProtocol::move ( const Move& m ) { 0109 write(m.string(false)); 0110 } 0111 0112 void FicsProtocol::init ( ) { 0113 m_stage = ConnectStage; 0114 0115 ChatWidget* console = createConsoleWidget(); 0116 console->addExtraButton ( QStringLiteral("seek"), i18nc("Start searching for opponents", "Seek"), QStringLiteral("edit-find") ); 0117 console->addExtraButton ( QStringLiteral("unseek"), i18nc("Stop searching for opponents", "Unseek"), QStringLiteral("edit-clear") ); 0118 console->addExtraButton ( QStringLiteral("accept"), i18n("Accept"), QStringLiteral("dialog-ok-accept") ); 0119 console->addExtraButton ( QStringLiteral("help"), i18n("Help"), QStringLiteral("help-contents") ); 0120 connect ( console, &ChatWidget::sendText, this, &FicsProtocol::writeCheckMoves ); 0121 setConsole ( console ); 0122 0123 QTcpSocket* socket = new QTcpSocket ( this ); 0124 setDevice ( socket ); 0125 QString address = attribute("server").toString(); 0126 int port = attribute("port").toInt(); 0127 if ( port == 0 ) 0128 port = 5000; 0129 connect ( socket, &QTcpSocket::errorOccurred, this, &FicsProtocol::socketError ); 0130 0131 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0132 socket->connectToHost(address, port); 0133 if (socket->waitForConnected(5000)) 0134 QApplication::restoreOverrideCursor(); 0135 } 0136 0137 QList< Protocol::ToolWidgetData > FicsProtocol::toolWidgets() { 0138 ToolWidgetData consoleData; 0139 consoleData.widget = console(); 0140 consoleData.title = i18n("Server Console"); 0141 consoleData.name = QStringLiteral("console"); 0142 consoleData.type = ConsoleToolWidget; 0143 consoleData.owner = color(); 0144 0145 if ( !m_chat ) { 0146 m_chat = createChatWidget(); 0147 connect ( m_chat, &ChatWidget::sendText, this, &FicsProtocol::sendChat ); 0148 } 0149 0150 ToolWidgetData chatData; 0151 chatData.widget = m_chat; 0152 chatData.title = i18n("Chat with %1", playerName()); 0153 chatData.name = QStringLiteral("chat"); 0154 chatData.type = ChatToolWidget; 0155 0156 return { 0157 consoleData, 0158 chatData, 0159 }; 0160 } 0161 0162 void FicsProtocol::socketError() { 0163 QApplication::restoreOverrideCursor(); 0164 Q_EMIT error( NetworkError, device()->errorString() ); 0165 } 0166 0167 void FicsProtocol::login ( const QString& username, const QString& password ) { 0168 otherPlayerName = username; 0169 write(username); 0170 sendPassword = true; 0171 this->password = password; 0172 } 0173 0174 void FicsProtocol::setupOptions() { 0175 write("set style 12"); 0176 write("iset seekremove 1"); 0177 write("iset seekinfo 1"); 0178 write("iset pendinfo 1"); 0179 write("set seek 1"); 0180 } 0181 0182 void FicsProtocol::openGameDialog() { 0183 if ( m_widget ) { 0184 m_widget->setStatus(i18n("Login failed"), true); 0185 Settings::setAutoLogin(false); 0186 m_widget->setLoginEnabled(true); 0187 return; 0188 } 0189 QDialog* dialog = new QDialog ( qApp->activeWindow() ); 0190 dialog->setWindowTitle(i18nc("@title:window", "Chess server")); 0191 auto mainLayout = new QVBoxLayout(dialog); 0192 dialog->setLayout(mainLayout); 0193 auto bBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel ); 0194 0195 bBox->button(QDialogButtonBox::Ok)->setText(i18n("Accept")); 0196 bBox->button(QDialogButtonBox::Ok)->setVisible(false); 0197 bBox->button(QDialogButtonBox::Ok)->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok-accept"))); 0198 0199 bBox->button(QDialogButtonBox::Cancel)->setText(i18n("Decline")); 0200 bBox->button(QDialogButtonBox::Cancel)->setVisible(false); 0201 bBox->button(QDialogButtonBox::Cancel)->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); 0202 0203 m_widget = new FicsDialog (); 0204 m_widget->setServerName ( attribute( "server" ).toString()); 0205 m_widget->setConsoleWidget ( console() ); 0206 mainLayout->addWidget(m_widget); 0207 mainLayout->addWidget(bBox); 0208 0209 connect ( bBox, &QDialogButtonBox::rejected, m_widget, &FicsDialog::decline ); 0210 connect ( bBox, &QDialogButtonBox::accepted, m_widget, &FicsDialog::accept ); 0211 connect ( m_widget, &FicsDialog::acceptButtonNeeded, bBox->button(QDialogButtonBox::Ok), &QPushButton::setVisible ); 0212 connect ( m_widget, &FicsDialog::declineButtonNeeded, bBox->button(QDialogButtonBox::Cancel), &QPushButton::setVisible ); 0213 0214 connect ( m_widget, &FicsDialog::login, this, &FicsProtocol::login ); 0215 connect ( m_widget, &FicsDialog::acceptSeek, this, &FicsProtocol::acceptSeek ); 0216 connect ( m_widget, &FicsDialog::acceptChallenge, this, &FicsProtocol::acceptChallenge ); 0217 connect ( m_widget, &FicsDialog::declineChallenge, this, &FicsProtocol::declineChallenge ); 0218 0219 connect ( this, &FicsProtocol::sessionStarted, m_widget, &FicsDialog::slotSessionStarted ); 0220 connect ( this, &FicsProtocol::gameOfferReceived, m_widget, &FicsDialog::addGameOffer ); 0221 connect ( this, &FicsProtocol::gameOfferRemoved, m_widget, &FicsDialog::removeGameOffer ); 0222 connect ( this, &FicsProtocol::challengeReceived, m_widget, &FicsDialog::addChallenge ); 0223 connect ( this, &FicsProtocol::gameOfferRemoved, m_widget, &FicsDialog::removeChallenge ); 0224 connect ( m_widget, &FicsDialog::seekingChanged, this, &FicsProtocol::setSeeking ); 0225 0226 // connect ( dialog, &QDialog::accepted, this, &FicsProtocol::dialogAccepted ); 0227 connect ( dialog, &QDialog::rejected, this, &FicsProtocol::dialogRejected ); 0228 0229 connect ( this, &FicsProtocol::initSuccesful, dialog, &QDialog::accept ); 0230 /* TODO: The SLOT slotDialogAccepted() is not implemented. Need to recheck the intention */ 0231 //connect ( this, &FicsProtocol::initSuccesful, m_widget, &FicsDialog::slotDialogAccepted ); 0232 connect ( this, &FicsProtocol::error, dialog, &QDialog::deleteLater ); 0233 if ( Settings::autoLogin() ) 0234 m_widget->slotLogin(); 0235 dialog->show(); 0236 } 0237 0238 bool FicsProtocol::parseStub(const QString& line) { 0239 Q_UNUSED(line); 0240 return false; 0241 } 0242 0243 bool FicsProtocol::parseLine(const QString& line) { 0244 if ( line.isEmpty() || line.startsWith( QLatin1String("fics%") ) ) 0245 return true; 0246 bool display = true; 0247 ChatWidget::MessageType type = ChatWidget::GeneralMessage; 0248 switch ( m_stage ) { 0249 case ConnectStage: 0250 if ( line.contains ( QLatin1String("login:") ) ) { 0251 type = ChatWidget::AccountMessage; 0252 openGameDialog(); 0253 } else if ( line.contains ( QLatin1String("password:") ) ) { 0254 type = ChatWidget::AccountMessage; 0255 if ( sendPassword ) 0256 write(password); 0257 else 0258 console()->setPasswordMode(true); 0259 } else if ( line.contains ( QLatin1String("Press return to enter the server") ) ) { 0260 type = ChatWidget::AccountMessage; 0261 write(QString()); 0262 } 0263 // TODO: Check for incorrect logins 0264 else if ( line.contains ( QLatin1String("Starting FICS session") ) ) { 0265 type = ChatWidget::StatusMessage; 0266 m_stage = SeekStage; 0267 console()->setPasswordMode(false); 0268 setupOptions(); 0269 QString name = line; 0270 name.remove ( 0, name.indexOf ( QLatin1String("session as ") ) + 11 ); 0271 if ( name.contains ( QLatin1String("(U)") ) ) 0272 name.truncate ( name.indexOf ( QLatin1String("(U)") ) ); 0273 else 0274 name.truncate ( name.indexOf ( QLatin1Char ( ' ' ) ) ); 0275 qCDebug(LOG_KNIGHTS) << QLatin1String("Your name is") << name; 0276 otherPlayerName = name; 0277 Q_EMIT sessionStarted(); 0278 } else if ( line.contains ( QLatin1String("Invalid password") ) ) { 0279 m_widget->setLoginEnabled ( true ); 0280 type = ChatWidget::AccountMessage; 0281 m_widget->setStatus(i18n("Invalid Password"), true); 0282 } 0283 break; 0284 case SeekStage: 0285 if ( line.startsWith( QLatin1String("<sc>") ) ) { 0286 display = false; 0287 Q_EMIT clearSeeks(); 0288 } else if ( line.startsWith( QLatin1String("<sr>") ) ) { 0289 display = false; 0290 for ( const QString& str : line.split(QLatin1Char(' ') ) ) { 0291 bool ok; 0292 int id = str.toInt(&ok); 0293 if ( ok ) 0294 Q_EMIT gameOfferRemoved(id); 0295 } 0296 } else if ( line.startsWith( QLatin1String("<s>") ) && seekExp.indexIn(line) > -1 ) { 0297 display = false; 0298 FicsGameOffer offer; 0299 int n = 1; 0300 offer.gameId = seekExp.cap(n++).toInt(); 0301 offer.player.first = seekExp.cap(n++); 0302 n++; // Ignore titles for now, TODO 0303 offer.player.second = seekExp.cap(n++).toInt(); 0304 offer.baseTime = seekExp.cap(n++).toInt(); 0305 offer.timeIncrement = seekExp.cap(n++).toInt(); 0306 offer.rated = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('r') ); 0307 offer.variant = seekExp.cap(n++); 0308 offer.color = parseColor(seekExp.cap(n++)); 0309 offer.ratingRange.first = seekExp.cap(n++).toInt(); 0310 offer.ratingRange.second = seekExp.cap(n++).toInt(); 0311 offer.automatic = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('t') ); 0312 offer.formula = ( !seekExp.cap(n).isEmpty() && seekExp.cap(n++)[0] == QLatin1Char('t') ); 0313 Q_EMIT gameOfferReceived ( offer ); 0314 } else if ( line.startsWith( QLatin1String("<pf>") ) && challengeExp.indexIn ( line ) > -1 ) { 0315 display = false; 0316 FicsChallenge challenge; 0317 challenge.gameId = challengeExp.cap ( 1 ).toInt(); 0318 challenge.player.first = challengeExp.cap ( 2 ); 0319 int ratingPos = ( challengeExp.cap(2) == challengeExp.cap(3) ) ? 4 : 6; 0320 challenge.player.second = challengeExp.cap ( ratingPos ).toInt(); 0321 Q_EMIT challengeReceived ( challenge ); 0322 } else if ( line.startsWith( QLatin1String("<pr>") ) ) { 0323 display = false; 0324 for ( const QString& str : line.split( QLatin1Char(' ') ) ) { 0325 bool ok; 0326 int id = str.toInt(&ok); 0327 if ( ok ) 0328 Q_EMIT challengeRemoved(id); 0329 } 0330 } else if ( gameStartedExp.indexIn ( line ) > -1 ) { 0331 qCDebug(LOG_KNIGHTS) << "Game Started" << line; 0332 type = ChatWidget::StatusMessage; 0333 QString player1 = gameStartedExp.cap ( 1 ); 0334 QString player2 = gameStartedExp.cap ( 3 ); 0335 Color color = NoColor; 0336 if ( player1 == otherPlayerName ) { 0337 color = Black; 0338 setPlayerName ( player2 ); 0339 } else { 0340 color = White; 0341 setPlayerName ( player1 ); 0342 } 0343 if ( byColor(color) != this ) { 0344 qCDebug(LOG_KNIGHTS) << "Switching protocols"; 0345 // The color is different than was assigned at first 0346 // We have to switch the protocols 0347 Protocol* t = white(); 0348 setWhiteProtocol(black()); 0349 setBlackProtocol(t); 0350 } 0351 Protocol* opp = Protocol::byColor ( oppositeColor ( color ) ); 0352 if ( opp->isLocal() ) 0353 opp->setPlayerName ( otherPlayerName ); 0354 0355 m_stage = PlayStage; 0356 initComplete(); 0357 } 0358 break; 0359 case PlayStage: 0360 if ( moveRegExp.indexIn ( line ) > -1 ) { 0361 display = false; 0362 qCDebug(LOG_KNIGHTS) << moveRegExp.cap(1) << colorName(color()); 0363 bool validMove = !( moveRegExp.cap ( 1 ) == QLatin1Char('W') && color() == White ) 0364 && !( moveRegExp.cap ( 1 ) == QLatin1Char('B') && color() == Black ); 0365 0366 const int whiteTimeLimit = moveRegExp.cap ( 3 ).toInt(); 0367 const int blackTimeLimit = moveRegExp.cap ( 4 ).toInt(); 0368 const QString moveString = moveRegExp.cap ( 6 ); 0369 0370 qCDebug(LOG_KNIGHTS) << "Move:" << moveString; 0371 0372 if ( moveString == QLatin1String("none") ) { 0373 TimeControl tc; 0374 tc.moves = 0; 0375 tc.baseTime = QTime().addSecs(whiteTimeLimit); 0376 tc.increment = moveRegExp.cap(2).toInt(); 0377 Manager::self()->setTimeControl(NoColor, tc); 0378 break; 0379 } 0380 0381 if ( validMove ) { 0382 Move m; 0383 if ( moveString == QLatin1String("o-o") ) { 0384 // Short (king's rook) castling 0385 m = Move::castling ( Move::KingSide, color() ); 0386 } else if ( moveString == QLatin1String("o-o-o") ) { 0387 // Long (Queen's rock) castling 0388 m = Move::castling ( Move::QueenSide, color() ); 0389 } else if ( moveStringExp.indexIn ( moveString ) > -1 ) { 0390 m.setFrom( Pos(moveStringExp.cap(1)) ); 0391 m.setTo( Pos(moveStringExp.cap(2)) ); 0392 if ( !moveStringExp.cap(3).isEmpty() ) { 0393 m.setFlag ( Move::Promote, true ); 0394 QChar typeChar = moveRegExp.cap ( 3 ).mid ( 1, 1 ) [0]; 0395 m.setPromotedType ( Piece::typeFromChar ( typeChar ) ); 0396 } 0397 } 0398 qCDebug(LOG_KNIGHTS) << "Valid move" << m; 0399 Q_EMIT pieceMoved ( m ); 0400 } 0401 Manager::self()->setCurrentTime ( White, QTime().addSecs ( whiteTimeLimit ) ); 0402 Manager::self()->setCurrentTime ( Black, QTime().addSecs ( blackTimeLimit ) ); 0403 0404 if ( moveRegExp.cap(5).toInt() == 2 ) { 0405 // TODO: Notify the manager that time is starting now 0406 } 0407 } else if ( offerExp.indexIn(line) > -1 ) { 0408 Offer offer; 0409 offer.id = offerExp.cap(1).toInt(); 0410 offer.player = color(); 0411 QString type = offerExp.cap(3); 0412 if ( type == QLatin1String("abort") ) 0413 offer.action = ActionAbort; 0414 else if ( type == QLatin1String("adjourn") ) 0415 offer.action = ActionAdjourn; 0416 else if ( type == QLatin1String("draw") ) 0417 offer.action = ActionDraw; 0418 else if ( type == QLatin1String("takeback") ) { 0419 offer.action = ActionUndo; 0420 offer.numberOfMoves = offerExp.cap(4).toInt(); 0421 } 0422 m_offers.insert ( offer.id, offer ); 0423 Manager::self()->sendOffer ( offer ); 0424 } else if ( line.contains ( QLatin1String(" says:") ) ) { 0425 type = ChatWidget::ChatMessage; 0426 m_chat->addText ( line, type ); 0427 } else if ( line.contains ( QLatin1String("lost contact or quit") ) ) 0428 type = ChatWidget::AccountMessage; 0429 else if ( line.startsWith(QLatin1Char('{')) && line.contains(QLatin1Char('}'))) { 0430 if ( line.endsWith ( QLatin1String("1-0") ) ) { 0431 type = ChatWidget::AccountMessage; 0432 Q_EMIT gameOver ( White ); 0433 } else if ( line.endsWith ( QLatin1String("1/2-1/2") ) || line.endsWith ( QLatin1Char('*') ) ) { 0434 // Knights has no way of reporting aborted or unfinished games 0435 // so we report aborted games as draws 0436 type = ChatWidget::AccountMessage; 0437 Q_EMIT gameOver ( NoColor ); 0438 } else if ( line.endsWith ( QLatin1String("0-1") ) ) { 0439 type = ChatWidget::AccountMessage; 0440 Q_EMIT gameOver ( Black ); 0441 } 0442 } 0443 } 0444 0445 if ( display ) 0446 writeToConsole ( line, type ); 0447 return true; 0448 } 0449 0450 Color FicsProtocol::parseColor ( QString str ) { 0451 if ( str.isEmpty() || str[0] == QLatin1Char('?') ) 0452 return NoColor; 0453 if ( str[0] == QLatin1Char('W') ) 0454 return White; 0455 if ( str[0] == QLatin1Char('B') ) 0456 return Black; 0457 return NoColor; 0458 } 0459 0460 void FicsProtocol::acceptSeek ( int id ) { 0461 write ( QLatin1String("play ") + QString::number(id) ); 0462 m_seeking = false; 0463 } 0464 0465 void FicsProtocol::acceptChallenge ( int id ) { 0466 write ( QLatin1String("accept ") + QString::number(id) ); 0467 m_seeking = true; 0468 } 0469 0470 void FicsProtocol::declineChallenge ( int id ) { 0471 write ( QLatin1String("decline ") + QString::number(id) ); 0472 } 0473 0474 void FicsProtocol::dialogRejected() { 0475 Q_EMIT error ( UserCancelled ); 0476 } 0477 0478 void FicsProtocol::setSeeking ( bool seek ) { 0479 m_seeking = seek; 0480 if ( seek ) { 0481 QByteArray seekText = "seek"; 0482 0483 TimeControl tc = Manager::self()->timeControl(color()); 0484 seekText += ' '; 0485 seekText += QString::number ( 60 * tc.baseTime.hour() + tc.baseTime.minute() ).toLatin1(); 0486 seekText += ' '; 0487 seekText += QString::number ( tc.increment ).toLatin1(); 0488 0489 seekText += m_widget->rated() ? " rated" : " unrated"; 0490 /* 0491 * Commented out until I figure out a simple way to determine if a color should be forced. 0492 switch ( color() ) 0493 { 0494 case White: 0495 seekText += " white"; 0496 break; 0497 case Black: 0498 seekText += " black"; 0499 break; 0500 default: 0501 break; 0502 } 0503 */ 0504 seekText += m_widget->autoAcceptChallenge() ? " auto" : " manual"; 0505 qCDebug(LOG_KNIGHTS) << seekText; 0506 write(QLatin1String(seekText)); 0507 } else 0508 write("unseek"); 0509 } 0510 0511 void FicsProtocol::resign() { 0512 write("resign"); 0513 } 0514 0515 void FicsProtocol::sendChat ( QString text ) { 0516 write ( QLatin1String("say ") + text ); 0517 } 0518 0519 void FicsProtocol::acceptOffer(const Offer& offer) { 0520 write ( QLatin1String("accept ") + QString::number(offer.id) ); 0521 } 0522 0523 void FicsProtocol::declineOffer(const Offer& offer) { 0524 write ( QLatin1String("decline ") + QString::number(offer.id) ); 0525 } 0526 0527 void FicsProtocol::makeOffer(const Offer& offer) { 0528 switch (offer.action) { 0529 case ActionDraw: 0530 write ( "draw" ); 0531 break; 0532 0533 case ActionPause: 0534 write ( "pause" ); 0535 break; 0536 0537 case ActionUndo: 0538 write ( QLatin1String("takeback ") + QString::number ( offer.numberOfMoves ) ); 0539 break; 0540 0541 case ActionResume: 0542 write ( "unpause" ); 0543 break; 0544 0545 case ActionAdjourn: 0546 write ( "adjourn" ); 0547 break; 0548 0549 case ActionAbort: 0550 write ( "abort" ); 0551 break; 0552 0553 default: 0554 break; 0555 } 0556 } 0557 0558 #include "moc_ficsprotocol.cpp"