AdcCommand.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "adchpp.h"
00020
00021 #include "AdcCommand.h"
00022
00023 #include "Text.h"
00024
00025 namespace adchpp {
00026
00027 #ifdef __GNUC__ /// @todo go figure why some GCCs need these...
00028 const char AdcCommand::TYPE_BROADCAST;
00029 const char AdcCommand::TYPE_CLIENT;
00030 const char AdcCommand::TYPE_DIRECT;
00031 const char AdcCommand::TYPE_ECHO;
00032 const char AdcCommand::TYPE_FEATURE;
00033 const char AdcCommand::TYPE_INFO;
00034 const char AdcCommand::TYPE_HUB;
00035 const char AdcCommand::TYPE_UDP;
00036 #endif
00037
00038 using namespace std;
00039
00040 AdcCommand::AdcCommand() : cmdInt(0), priority(PRIORITY_NORMAL), from(INVALID_SID), to(INVALID_SID), type(TYPE_INFO) { }
00041
00042 AdcCommand::AdcCommand(Severity sev, Error err, const string& desc, char aType ) : cmdInt(CMD_STA), priority(PRIORITY_NORMAL), from(HUB_SID), type(aType) {
00043 addParam(Util::toString(sev * 100 + err));
00044 addParam(desc);
00045 }
00046
00047 void AdcCommand::escape(const string& s, string& out) {
00048 out.reserve(out.length() + static_cast<size_t>(s.length() * 1.1));
00049
00050 for(string::const_iterator i = s.begin(), iend = s.end(); i != iend; ++i) {
00051 switch(*i) {
00052 case ' ': out += '\\'; out += 's'; break;
00053 case '\n': out += '\\'; out += 'n'; break;
00054 case '\\': out += '\\'; out += '\\'; break;
00055 default: out += *i;
00056 }
00057 }
00058 }
00059
00060 void AdcCommand::parse(const char* buf, size_t len) throw(ParseException) {
00061 if(len < 5) {
00062 throw ParseException("Command too short");
00063 }
00064
00065 type = buf[0];
00066
00067 if(type != TYPE_BROADCAST && type != TYPE_CLIENT && type != TYPE_DIRECT && type != TYPE_ECHO && type != TYPE_FEATURE && type != TYPE_INFO && type != TYPE_HUB && type != TYPE_UDP) {
00068 throw ParseException("Invalid type");
00069 }
00070
00071 if(type == TYPE_HUB) {
00072 to = HUB_SID;
00073 }
00074
00075 cmd[0] = buf[1];
00076 cmd[1] = buf[2];
00077 cmd[2] = buf[3];
00078
00079 if(buf[4] != ' ') {
00080 throw ParseException("Missing space after command");
00081 }
00082
00083
00084 len--;
00085
00086 parameters.reserve(8);
00087
00088 string cur;
00089 cur.reserve(64);
00090
00091 bool toSet = false;
00092 bool featureSet = false;
00093 bool fromSet = false;
00094
00095 string::size_type i = 5;
00096 while(i < len) {
00097 switch(buf[i]) {
00098 case '\\':
00099 ++i;
00100 if(i == len)
00101 throw ParseException("Escape at eol");
00102 if(buf[i] == 's')
00103 cur += ' ';
00104 else if(buf[i] == 'n')
00105 cur += '\n';
00106 else if(buf[i] == '\\')
00107 cur += '\\';
00108 else
00109 throw ParseException("Unknown escape");
00110 break;
00111 case ' ':
00112
00113 {
00114 if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
00115 if(cur.length() != 4) {
00116 throw ParseException("Invalid SID length");
00117 }
00118 from = toSID(cur);
00119 fromSet = true;
00120 } else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
00121 if(cur.length() != 4) {
00122 throw ParseException("Invalid SID length");
00123 }
00124 to = toSID(cur);
00125 toSet = true;
00126 } else if(type == TYPE_FEATURE && !featureSet) {
00127 if(cur.length() % 5 != 0) {
00128 throw ParseException("Invalid feature length");
00129 }
00130 features = cur;
00131 featureSet = true;
00132 } else {
00133 if(!Text::validateUtf8(cur)) {
00134 throw ParseException("Invalid UTF-8 sequence");
00135 }
00136 parameters.push_back(cur);
00137 }
00138 cur.clear();
00139 }
00140 break;
00141 default:
00142 cur += buf[i];
00143 }
00144 ++i;
00145 }
00146
00147 if(!cur.empty()) {
00148 if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
00149 if(cur.length() != 4) {
00150 throw ParseException("Invalid SID length");
00151 }
00152 from = toSID(cur);
00153 fromSet = true;
00154 } else if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
00155 if(cur.length() != 4) {
00156 throw ParseException("Invalid SID length");
00157 }
00158 to = toSID(cur);
00159 toSet = true;
00160 } else if(type == TYPE_FEATURE && !featureSet) {
00161 if(cur.length() % 5 != 0) {
00162 throw ParseException("Invalid feature length");
00163 }
00164 features = cur;
00165 featureSet = true;
00166 } else {
00167 if(!Text::validateUtf8(cur)) {
00168 throw ParseException("Invalid UTF-8 sequence");
00169 }
00170 parameters.push_back(cur);
00171 }
00172 }
00173
00174 if((type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) && !fromSet) {
00175 throw ParseException("Missing from_sid");
00176 }
00177
00178 if(type == TYPE_FEATURE && !featureSet) {
00179 throw ParseException("Missing feature");
00180 }
00181
00182 if((type == TYPE_DIRECT || type == TYPE_ECHO) && !toSet) {
00183 throw ParseException("Missing to_sid");
00184 }
00185 }
00186
00187 const BufferPtr& AdcCommand::getBuffer() const {
00188 if(!buffer) {
00189 buffer = make_shared<Buffer>(toString());
00190 }
00191 return buffer;
00192 }
00193
00194 string AdcCommand::toString() const {
00195 if(buffer) {
00196 return string((char*)buffer->data(), buffer->size());
00197 }
00198 string tmp;
00199
00200 tmp.reserve(128);
00201
00202 tmp += type;
00203 tmp += cmdChar;
00204
00205 if(type == TYPE_BROADCAST || type == TYPE_DIRECT || type == TYPE_ECHO || type == TYPE_FEATURE) {
00206 tmp += ' ';
00207 appendSID(tmp, from);
00208 }
00209
00210 if(type == TYPE_DIRECT || type == TYPE_ECHO) {
00211 tmp += ' ';
00212 appendSID(tmp, to);
00213 }
00214
00215 if(type == TYPE_FEATURE) {
00216 tmp += ' ';
00217 tmp += features;
00218 }
00219
00220 for(StringIterC i = getParameters().begin(); i != getParameters().end(); ++i) {
00221 tmp += ' ';
00222 escape(*i, tmp);
00223 }
00224
00225 tmp += '\n';
00226
00227 return tmp;
00228 }
00229
00230 bool AdcCommand::getParam(const char* name, size_t start, string& ret) const {
00231 for(string::size_type i = start; i < getParameters().size(); ++i) {
00232 if(toField(name) == toField(getParameters()[i].c_str())) {
00233 ret = getParameters()[i].substr(2);
00234 return true;
00235 }
00236 }
00237 return false;
00238 }
00239
00240 bool AdcCommand::delParam(const char* name, size_t start) {
00241 for(string::size_type i = start; i < getParameters().size(); ++i) {
00242 if(toField(name) == toField(getParameters()[i].c_str())) {
00243 getParameters().erase(getParameters().begin() + i);
00244 resetBuffer();
00245 return true;
00246 }
00247 }
00248 return false;
00249 }
00250
00251 bool AdcCommand::hasFlag(const char* name, size_t start) const {
00252 for(string::size_type i = start; i < getParameters().size(); ++i) {
00253 if(toField(name) == toField(getParameters()[i].c_str()) &&
00254 getParameters()[i].size() == 3 &&
00255 getParameters()[i][2] == '1')
00256 {
00257 return true;
00258 }
00259 }
00260 return false;
00261 }
00262
00263 }