AdcCommand.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2010 Jacek Sieka, arnetheduck on gmail point com
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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 /* = TYPE_INFO */) : 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     // Skip trailing LF
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             // New parameter...
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 }
Generated on Sat Nov 27 23:37:53 2010 for adchpp by  doxygen 1.6.3