/* * Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ADCHPP_ADC_COMMAND_H #define ADCHPP_ADC_COMMAND_H #include "common.h" #include "Exception.h" #include "Util.h" #include "Buffer.h" namespace adchpp { STANDARD_EXCEPTION(ParseException); class AdcCommand : private boost::noncopyable { public: template struct Type { enum { CMD = T }; }; enum Error { ERROR_GENERIC = 0, ERROR_HUB_GENERIC = 10, ERROR_HUB_FULL = 11, ERROR_HUB_DISABLED = 12, ERROR_LOGIN_GENERIC = 20, ERROR_NICK_INVALID = 21, ERROR_NICK_TAKEN = 22, ERROR_BAD_PASSWORD = 23, ERROR_CID_TAKEN = 24, ERROR_COMMAND_ACCESS = 25, ERROR_REGGED_ONLY = 26, ERROR_INVALID_PID = 27, ERROR_BANNED_GENERIC = 30, ERROR_PERM_BANNED = 31, ERROR_TEMP_BANNED = 32, ERROR_PROTOCOL_GENERIC = 40, ERROR_PROTOCOL_UNSUPPORTED = 41, ERROR_CONNECT_FAILED = 42, ERROR_INF_MISSING = 43, ERROR_BAD_STATE = 44, ERROR_FEATURE_MISSING = 45, ERROR_BAD_IP = 46, ERROR_NO_HUB_HASH = 47, ERROR_TRANSFER_GENERIC = 50, ERROR_FILE_NOT_AVAILABLE = 51, ERROR_FILE_PART_NOT_AVAILABLE = 52, ERROR_SLOTS_FULL = 53, ERROR_NO_CLIENT_HASH = 54 }; enum Severity { SEV_SUCCESS = 0, SEV_RECOVERABLE = 1, SEV_FATAL = 2 }; enum Priority { PRIORITY_NORMAL, ///< Default priority, command will be sent out normally PRIORITY_LOW, ///< Low priority, command will only be sent if connection isn't saturated PRIORITY_IGNORE ///< Ignore, command will not be put in send queue }; static const char TYPE_BROADCAST = 'B'; static const char TYPE_CLIENT = 'C'; static const char TYPE_DIRECT = 'D'; static const char TYPE_ECHO = 'E'; static const char TYPE_FEATURE = 'F'; static const char TYPE_INFO = 'I'; static const char TYPE_HUB = 'H'; static const char TYPE_UDP = 'U'; // Known commands... #define C(n, a, b, c) static const uint32_t CMD_##n = (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); typedef Type n // Base commands C(SUP, 'S','U','P'); C(STA, 'S','T','A'); C(INF, 'I','N','F'); C(MSG, 'M','S','G'); C(SCH, 'S','C','H'); C(RES, 'R','E','S'); C(CTM, 'C','T','M'); C(RCM, 'R','C','M'); C(GPA, 'G','P','A'); C(PAS, 'P','A','S'); C(QUI, 'Q','U','I'); C(GET, 'G','E','T'); C(GFI, 'G','F','I'); C(SND, 'S','N','D'); C(SID, 'S','I','D'); // Extensions C(CMD, 'C','M','D'); C(NAT, 'N','A','T'); C(RNT, 'R','N','T'); #undef C static const uint32_t HUB_SID = static_cast(-1); static const uint32_t INVALID_SID = static_cast(-2); static uint32_t toSID(const std::string& aSID) { return *reinterpret_cast(aSID.data()); } static std::string fromSID(const uint32_t aSID) { return std::string(reinterpret_cast(&aSID), sizeof(aSID)); } static void appendSID(std::string& str, uint32_t aSID) { str.append(reinterpret_cast(&aSID), sizeof(aSID)); } static uint32_t toCMD(uint8_t a, uint8_t b, uint8_t c) { return (((uint32_t)a) | (((uint32_t)b)<<8) | (((uint32_t)c)<<16)); } static uint32_t toCMD(const char* str) { return toCMD(str[0], str[1], str[2]); } static uint16_t toField(const char* x) { return *((uint16_t*)x); } static std::string fromField(const uint16_t aField) { return std::string(reinterpret_cast(&aField), sizeof(aField)); } static uint32_t toFourCC(const char* x) { return *reinterpret_cast(x); } static std::string fromFourCC(uint32_t x) { return std::string(reinterpret_cast(&x), sizeof(x)); } ADCHPP_DLL AdcCommand(); ADCHPP_DLL explicit AdcCommand(Severity sev, Error err, const std::string& desc, char aType = TYPE_INFO); explicit AdcCommand(uint32_t cmd, char aType = TYPE_INFO, uint32_t aFrom = HUB_SID) : cmdInt(cmd), priority(PRIORITY_NORMAL), from(aFrom), to(INVALID_SID), type(aType) { } explicit AdcCommand(const std::string& aLine) throw(ParseException) : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse(aLine); } explicit AdcCommand(const BufferPtr& buffer_) throw(ParseException) : buffer(buffer_), cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(0) { parse((const char*)buffer->data(), buffer->size()); } void parse(const std::string& str) throw(ParseException) { parse(str.data(), str.size()); } ADCHPP_DLL void parse(const char* buf, size_t len) throw(ParseException); uint32_t getCommand() const { return cmdInt; } char getType() const { return type; } std::string getFourCC() const { std::string tmp(4, 0); tmp[0] = type; tmp[1] = cmd[0]; tmp[2] = cmd[1]; tmp[3] = cmd[2]; return tmp; } StringList& getParameters() { return parameters; } const StringList& getParameters() const { return parameters; } ADCHPP_DLL std::string toString() const; AdcCommand& addParam(const std::string& param) { parameters.push_back(param); resetBuffer(); return *this; } AdcCommand& addParam(const std::string& name, const std::string& value) { return addParam(name + value); } const std::string& getParam(size_t n) const { return getParameters().size() > n ? getParameters()[n] : Util::emptyString; } void resetBuffer() { buffer.reset(); } const std::string& getFeatures() const { return features; } /** Return a named parameter where the name is a two-letter code */ ADCHPP_DLL bool getParam(const char* name, size_t start, std::string& ret) const; ADCHPP_DLL bool delParam(const char* name, size_t start); ADCHPP_DLL bool hasFlag(const char* name, size_t start) const; bool operator==(uint32_t aCmd) const { return cmdInt == aCmd; } ADCHPP_DLL static void escape(const std::string& s, std::string& out); ADCHPP_DLL const BufferPtr& getBuffer() const; uint32_t getTo() const { return to; } void setTo(uint32_t aTo) { to = aTo; } uint32_t getFrom() const { return from; } void setFrom(uint32_t aFrom) { from = aFrom; } Priority getPriority() const { return priority; } void setPriority(Priority priority_) { priority = priority_; } private: StringList parameters; std::string features; mutable BufferPtr buffer; union { char cmdChar[4]; uint8_t cmd[4]; uint32_t cmdInt; }; Priority priority; uint32_t from; uint32_t to; char type; }; class Client; class Entity; template class CommandHandler { public: bool dispatch(Entity& c, AdcCommand& cmd) { #define C(n) case AdcCommand::CMD_##n: return ((T*)this)->handle(AdcCommand::n(), c, cmd); break; switch(cmd.getCommand()) { C(SUP); C(STA); C(INF); C(MSG); C(SCH); C(RES); C(CTM); C(RCM); C(GPA); C(PAS); C(QUI); C(GET); C(GFI); C(SND); C(SID); C(CMD); C(NAT); C(RNT); default: dcdebug("Unknown ADC command: %.50s\n", cmd.toString().c_str()); return true; #undef C } } }; } #endif // ADC_COMMAND_H