1 /*
2  * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #pragma once
20 
21 #include "typedefs.h"
22 #include "Exception.h"
23 #include "Util.h"
24 
25 namespace dcpp {
26 
27 STANDARD_EXCEPTION(ParseException);
28 
29 class CID;
30 
31 class AdcCommand {
32 public:
33     template<uint32_t T>
34     struct Type {
35         enum { CMD = T };
36     };
37 
38     enum Error {
39         SUCCESS = 0,
40         ERROR_GENERIC = 0,
41         ERROR_HUB_GENERIC = 10,
42         ERROR_HUB_FULL = 11,
43         ERROR_HUB_DISABLED = 12,
44         ERROR_LOGIN_GENERIC = 20,
45         ERROR_NICK_INVALID = 21,
46         ERROR_NICK_TAKEN = 22,
47         ERROR_BAD_PASSWORD = 23,
48         ERROR_CID_TAKEN = 24,
49         ERROR_COMMAND_ACCESS = 25,
50         ERROR_REGGED_ONLY = 26,
51         ERROR_INVALID_PID = 27,
52         ERROR_BANNED_GENERIC = 30,
53         ERROR_PERM_BANNED = 31,
54         ERROR_TEMP_BANNED = 32,
55         ERROR_PROTOCOL_GENERIC = 40,
56         ERROR_PROTOCOL_UNSUPPORTED = 41,
57         ERROR_CONNECT_FAILED = 42,
58         ERROR_INF_MISSING = 43,
59         ERROR_BAD_STATE = 44,
60         ERROR_FEATURE_MISSING = 45,
61         ERROR_BAD_IP = 46,
62         ERROR_NO_HUB_HASH = 47,
63         ERROR_TRANSFER_GENERIC = 50,
64         ERROR_FILE_NOT_AVAILABLE = 51,
65         ERROR_FILE_PART_NOT_AVAILABLE = 52,
66         ERROR_SLOTS_FULL = 53,
67         ERROR_NO_CLIENT_HASH = 54
68     };
69 
70     enum Severity {
71         SEV_SUCCESS = 0,
72         SEV_RECOVERABLE = 1,
73         SEV_FATAL = 2
74     };
75 
76     static const char TYPE_BROADCAST = 'B';
77     static const char TYPE_CLIENT = 'C';
78     static const char TYPE_DIRECT = 'D';
79     static const char TYPE_ECHO = 'E';
80     static const char TYPE_FEATURE = 'F';
81     static const char TYPE_INFO = 'I';
82     static const char TYPE_HUB = 'H';
83     static const char TYPE_UDP = 'U';
84 
85 #if defined(_WIN32) || defined(__i386__) || defined(__x86_64__) || defined(__alpha) || defined(__arm__)
86 #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<CMD_##n> n
87 #else
88 #define C(n, a, b, c) static const uint32_t CMD_##n = ((((uint32_t)a)<<24) | (((uint32_t)b)<<16) | (((uint32_t)c)<<8)); typedef Type<CMD_##n> n
89 #endif
90     // Base commands
91     C(SUP, 'S','U','P');
92     C(STA, 'S','T','A');
93     C(INF, 'I','N','F');
94     C(MSG, 'M','S','G');
95     C(SCH, 'S','C','H');
96     C(RES, 'R','E','S');
97     C(CTM, 'C','T','M');
98     C(RCM, 'R','C','M');
99     C(GPA, 'G','P','A');
100     C(PAS, 'P','A','S');
101     C(QUI, 'Q','U','I');
102     C(GET, 'G','E','T');
103     C(GFI, 'G','F','I');
104     C(SND, 'S','N','D');
105     C(SID, 'S','I','D');
106     // Extensions
107     C(CMD, 'C','M','D');
108     C(PSR, 'P','S','R');
109     C(PUB, 'P','U','B');
110     C(NAT, 'N','A','T');
111     C(RNT, 'R','N','T');
112     C(ZON, 'Z','O','N');
113     C(ZOF, 'Z','O','F');
114 #undef C
115 
116     static const uint32_t HUB_SID = 0xffffffff;     // No client will have this sid
toFourCC(const char * x)117     static uint32_t toFourCC(const char* x) { return *reinterpret_cast<const uint32_t*>(x); }
fromFourCC(uint32_t x)118     static std::string fromFourCC(uint32_t x) { return std::string(reinterpret_cast<const char*>(&x), sizeof(x)); }
119     explicit AdcCommand(uint32_t aCmd, char aType = TYPE_CLIENT);
120     explicit AdcCommand(uint32_t aCmd, const uint32_t aTarget, char aType);
121     explicit AdcCommand(Severity sev, Error err, const string& desc, char aType = TYPE_CLIENT);
122     explicit AdcCommand(const string& aLine, bool nmdc = false);
123     void parse(const string& aLine, bool nmdc = false);
124 
getCommand()125     uint32_t getCommand() const { return cmdInt; }
getType()126     char getType() const { return type; }
setType(char t)127     void setType(char t) { type = t; }
getFourCC()128     string getFourCC() const { string tmp(4, 0); tmp[0] = type; tmp[1] = cmd[0]; tmp[2] = cmd[1]; tmp[3] = cmd[2]; return tmp; }
129 
getFeatures()130     const string& getFeatures() const { return features; }
setFeatures(const string & feat)131     AdcCommand& setFeatures(const string& feat) { features = feat; return *this; }
132 
getParameters()133     StringList& getParameters() { return parameters; }
getParameters()134     const StringList& getParameters() const { return parameters; }
135 
136     string toString(const CID& aCID) const;
137     string toString(uint32_t sid, bool nmdc = false) const;
138 
addParam(const string & name,const string & value)139     AdcCommand& addParam(const string& name, const string& value) {
140         parameters.push_back(name);
141         parameters.back() += value;
142         return *this;
143     }
addParam(const string & str)144     AdcCommand& addParam(const string& str) {
145         parameters.push_back(str);
146         return *this;
147     }
148     const string& getParam(size_t n) const;
149     /** Return a named parameter where the name is a two-letter code */
150     bool getParam(const char* name, size_t start, string& ret) const;
151     bool hasFlag(const char* name, size_t start) const;
toCode(const char * x)152     static uint16_t toCode(const char* x) { return *((uint16_t*)x); }
153 
154     bool operator==(uint32_t aCmd) { return cmdInt == aCmd; }
155 
156     static string escape(const string& str, bool old);
getTo()157     uint32_t getTo() const { return to; }
setTo(const uint32_t sid)158     AdcCommand& setTo(const uint32_t sid) { to = sid; return *this; }
getFrom()159     uint32_t getFrom() const { return from; }
160 
toSID(const string & aSID)161     static uint32_t toSID(const string& aSID) { return *reinterpret_cast<const uint32_t*>(aSID.data()); }
fromSID(const uint32_t aSID)162     static string fromSID(const uint32_t aSID) { return string(reinterpret_cast<const char*>(&aSID), sizeof(aSID)); }
163 private:
164     string getHeaderString(const CID& cid) const;
165     string getHeaderString(uint32_t sid, bool nmdc) const;
166     string getParamString(bool nmdc) const;
167     StringList parameters;
168     string features;
169     union {
170         char cmdChar[4];
171         uint8_t cmd[4];
172         uint32_t cmdInt;
173     };
174     uint32_t from;
175     uint32_t to;
176     char type;
177 
178 };
179 
180 template<class T>
181 class CommandHandler {
182 public:
183     void dispatch(const string& aLine, bool nmdc = false) {
184         try {
185             AdcCommand c(aLine, nmdc);
186 
187 #define C(n) case AdcCommand::CMD_##n: ((T*)this)->handle(AdcCommand::n(), c); break;
188             switch(c.getCommand()) {
189                 C(SUP);
190                 C(STA);
191                 C(INF);
192                 C(MSG);
193                 C(SCH);
194                 C(RES);
195                 C(CTM);
196                 C(RCM);
197                 C(GPA);
198                 C(PAS);
199                 C(QUI);
200                 C(GET);
201                 C(GFI);
202                 C(SND);
203                 C(SID);
204                 C(CMD);
205                 C(PSR);
206                 C(NAT);
207                 C(RNT);
208                 C(ZON);
209                 C(ZOF);
210             default:
211                 dcdebug("Unknown ADC command: %.50s\n", aLine.c_str());
212                 break;
213 #undef C
214 
215             }
catch(const ParseException &)216         } catch(const ParseException&) {
217             dcdebug("Invalid ADC command: %.50s\n", aLine.c_str());
218             return;
219         }
220     }
221 };
222 
223 } // namespace dcpp
224