// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "yubo_chat.h" using namespace std; using namespace NLMISC; using namespace NLNET; // *************************************************************************** CYuboChat::CYuboChat() { _Connected= false; _CommandState= None; _AutoLoginState= UserUnknown; } // *************************************************************************** void CYuboChat::connect(const string &url, const std::string &login, const std::string &pwd) { if(_Connected) return; _URL= url; _Login= login; _Password= pwd; // mark as connected even if the connection failed (to allow display of error message) _Connected= true; // Connect the socket try { // connect in non blocking mode _Sock.connect(CInetAddress(_URL)); _Sock.setNonBlockingMode(true); if (!_Sock.connected()) { // Add an error string addStringReceived(toString("ERROR: Cannot connect to the url: %s", _URL.c_str())); return; } } catch(Exception &e) { addStringReceived(toString("ERROR: exception with server %s: %s", _URL.c_str(), e.what())); } } // *************************************************************************** void CYuboChat::disconnect() { if(!_Connected) return; // verify if the actual connection was not broken first if(_Sock.connected()) { try { _Sock.disconnect(); } catch(Exception &e) { addStringReceived(toString("ERROR: exception with server %s: %s", _URL.c_str(), e.what())); } } // must reset the sock, else block at next connect (due to nonblocking stuff i think) contReset(_Sock); // flush _CurrentReceivedString.clear(); _CommandState= None; _AutoLoginState= UserUnknown; _Connected= false; } // *************************************************************************** void CYuboChat::send(const ucstring &msg) { if(!_Connected) return; // verify also that the socket was not disconnected by peer if(_Sock.connected()) { // append to the queue of user string to send _StringsToSend.push_back(msg); // flush string only when the user is logued // Allow also the user to enter his login if autologin has failed if(_AutoLoginState!=UserUnknown) { while(!_StringsToSend.empty()) { sendInternal(_StringsToSend.front()); _StringsToSend.pop_front(); } } } } // *************************************************************************** void CYuboChat::receive(std::list &msgList) { // verify also that the socket was not disconnected by peer if(_Connected && _Sock.connected()) { // **** Receive chars from chat bool receiving= true; while(receiving) { uint32 size = 1; char c; if (_Sock.receive((uint8*)&c, size, false) == CSock::Ok && size==1) { // the char is a command id? if(_CommandState==WaitCommandId) { // if the command is an option negociation if((uint8)c>=251 && (uint8)c<=254) // next char is the option id _CommandState= WaitOptionId; else // back to normal state _CommandState= None; } // the char is an option id? else if(_CommandState==WaitOptionId) { // just ignore and back to normal mode _CommandState= None; } // end of line? else if(c==0 || c=='\n') { if(!_CurrentReceivedString.empty()) { addStringReceived(_CurrentReceivedString); // clear the received string _CurrentReceivedString.clear(); } } // special telnet code? else if((uint8)c==255) { // next char is the command id _CommandState=WaitCommandId; } // normal char else { if(c=='\r') { if(_CurrentReceivedString.empty()) _CurrentReceivedString=" "; } else _CurrentReceivedString += c; } // test if must send login/pwd if(toLower(_CurrentReceivedString)==" login: ") { // flush display addStringReceived(_CurrentReceivedString); _CurrentReceivedString.clear(); // autolog if(_AutoLoginState==UserUnknown) { _AutoLoginState=LoginEntered; // if autologin valid if(!_Login.empty()) sendInternal(_Login); } } else if(toLower(_CurrentReceivedString)==" password: ") { // flush display addStringReceived(_CurrentReceivedString); _CurrentReceivedString.clear(); // autolog if(_AutoLoginState==LoginEntered) { _AutoLoginState=Logged; // if autologin valid if(!_Password.empty()) { sendInternal(_Password); // cool stuff sendInternal(string(".emote is in game")); sendInternal(string(".set client Ryzom")); } } } } else { receiving= false; } } } // return the list of received string (NB: even if not connected, can contains conection errors) msgList= _ReceivedStrings; _ReceivedStrings.clear(); } // *************************************************************************** void CYuboChat::addStringReceived(const std::string &str) { _ReceivedStrings.push_back(str); } // *************************************************************************** void CYuboChat::sendInternal(const ucstring &msg) { try { string toSend= msg.toString(); // replace any 255 char (eg: y trema) with '?' for(uint i=0;i