/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set et sw=2 ts=2: */ /*************************************************************************** * msgparser.cc * * Fri Feb 24 14:59:34 CET 2012 * Copyright 2012 Jonas Suhr Christensen * jsc@umbraculum.org ****************************************************************************/ /* * This file is part of Munia. * * Munia 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. * * Munia 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 Munia; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "messageparser.h" #include "nodemanager.h" #include #include #include #include #include #include "hugin.hpp" typedef std::vector TokenVector; typedef std::list MsgTokensList; inline static void parse_into_msg_tokens(std::string& data, MsgTokensList& msgTokensList) { TokenVector tokenVector; std::string token; bool inside_quote = false; char prev_ch = '0'; for(size_t i = 0; i < data.length(); i++) { char ch = data[i]; switch(ch) { case '\"': if(prev_ch != '\\') { inside_quote = !inside_quote; } else { token += ch; } break; case ' ': if(inside_quote) { DEBUG(msgparser, "Appending %c\n", ch); token += ch; } else { if(token.empty()) { continue; // skip multiple white spaces and pre white space } DEBUG(msgparser, "Adding token %s\n", token.c_str()); tokenVector.push_back(token); token.clear(); } break; case ';': if(inside_quote) { token += ch; } else { tokenVector.push_back(token); msgTokensList.push_back(tokenVector); tokenVector.clear(); token.clear(); } break; default: token += ch; break; } prev_ch = ch; } if(token != "") { tokenVector.push_back(token); token.clear(); } if(!tokenVector.empty()) { msgTokensList.push_back(tokenVector); tokenVector.clear(); } //// WARNING: Enabling this will print passwords in plaintext... //// Debug: print tokens //DEBUG(parser, "tokenlists: %d\n", msgTokensList.size()); //MsgTokensList::iterator j = msgTokensList.begin(); //while(j != msgTokensList.end()) //{ // DEBUG(parser, " tokens: %d\n", j->size()); // int idx = 0; // TokenVector::iterator i = j->begin(); // while(i != j->end()) // { // DEBUG(parser, " token[%d]: '%s'\n", idx++, i->c_str()); // i++; // } // j++; //} } static nodeid_t getId(std::map &sym, std::string token) { bool isnumeric = true; for(size_t i = 0; i < token.size(); i++) { isnumeric &= (token[i] >= '0' && token[i] <= '9'); } DEBUG(getid, "======= %d %s\n", isnumeric, token.c_str()); if(isnumeric) { nodeid_t id = atoi(token.c_str()); DEBUG(getid, "======= id: %d\n", id); return id; } if(sym.find(token) == sym.end()) { sym[token] = node_manager.createId(); } return sym[token]; } inline static void create_msg_list(MsgTokensList& msgTokensList, MessageList& msgList, bool clientmode) { size_t origin = 0; if(clientmode) { origin = 1; } std::map sym; MsgTokensList::iterator it_msg; for(it_msg = msgTokensList.begin(); it_msg != msgTokensList.end(); it_msg++) { TokenVector t = *it_msg; //malformed msg if(t.size() < origin+1) { continue; } message_t m; DEBUG(msgparser, "t[%d] : %s, running in clientmode: %d\n", (int)origin, t[origin].c_str(), clientmode); // DEBUG(msgparser, "%d\n", t.size()); if(t[origin] == "subscribe") m.cmd = cmd::subscribe; else if(t[origin] == "unsubscribe") m.cmd = cmd::unsubscribe; else if(t[origin] == "login") m.cmd = cmd::login; else if(t[origin] == "logout") m.cmd = cmd::logout; else if(t[origin] == "create") m.cmd = cmd::create; else if(t[origin] == "remove") m.cmd = cmd::remove; else if(t[origin] == "move") m.cmd = cmd::move; else if(t[origin] == "update") m.cmd = cmd::update; else m.cmd = cmd::error; switch(m.cmd) { case cmd::subscribe: { if(t.size() != origin+1+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.subscribe.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); } break; case cmd::unsubscribe: { if(t.size() != origin+1+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.unsubscribe.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); DEBUG(msgparser, "unsubscribe @ %d\n", m.unsubscribe.id); } break; case cmd::login: { if(t.size() != origin+1+2) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.login.user = t[origin+1]; m.login.password = t[origin+2]; DEBUG(msgparser, "login %s\n", m.login.user.c_str()); } break; case cmd::logout: if(t.size() != origin+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } break; case cmd::create: { if(!clientmode && t.size() != origin+1+2) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } if(clientmode && t.size() != origin+1+2) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } if(clientmode) { m.create.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.create.parentid = getId(sym, t[origin+2]);// atoi(t[origin+2].c_str()); } else { m.create.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.create.parentid = getId(sym, t[origin+2]);//atoi(t[origin+1].c_str()); } break; } case cmd::remove: { if(t.size() != origin+1+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.remove.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); } break; case cmd::move: { if(t.size() != origin+2+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.move.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.move.parentid = getId(sym, t[origin+2]);//atoi(t[origin+2].c_str()); } break; case cmd::update: { if(t.size() != origin+3+1) { DEBUG(msgparser, "Wrong number of parameters\n"); continue; } m.update.id = getId(sym, t[origin+1]);//atoi(t[origin+1].c_str()); m.update.attribute = t[origin+2]; m.update.value = t[origin+3]; } break; default: break; }; msgList.push_back(m); } } MessageList parse_msg(std::string data) { DEBUG(msgparser, "Parsing: '%s'\n", data.c_str()); MsgTokensList msgTokensList; parse_into_msg_tokens(data, msgTokensList); MessageList msgList; create_msg_list(msgTokensList, msgList, false); return msgList; } MessageList parse_msg_client(std::string data) { DEBUG(msgparser, "Parsing: '%s'\n", data.c_str()); MsgTokensList msgTokensList; parse_into_msg_tokens(data, msgTokensList); MessageList msgList; create_msg_list(msgTokensList, msgList, true); return msgList; } std::string msg_tostring(message_t m) { char* buf = NULL; switch(m.cmd) { case cmd::create: asprintf(&buf, "create %d %d;", m.create.id, m.create.parentid); break; case cmd::remove: asprintf(&buf, "remove %d;", m.remove.id); break; case cmd::move: asprintf(&buf, "move %d %d;", m.move.id, m.move.parentid); break; case cmd::update: asprintf(&buf, "update %d \"%s\" \"%s\";", m.update.id, m.update.attribute.c_str(), m.update.value.c_str()); break; default: break; } std::string r; if(buf) { r = buf; free(buf); } return r; } message_t create_msg_create(node_t t) { message_t m; m.cmd = cmd::create; m.create.id = t.id; m.create.parentid = t.parentid; return m; } message_t create_msg_update(node_t t, const std::string &attr) { message_t m; m.cmd = cmd::update; m.update.id = t.id; m.update.attribute = attr; m.update.value = t.attributes[attr]; return m; } message_t create_msg_remove(node_t t) { message_t m; m.cmd = cmd::remove; m.remove.id = t.id; return m; } message_t create_msg_move(nodeid_t id, nodeid_t to) { message_t m; m.cmd = cmd::move; m.move.id = id; m.move.parentid = to; return m; }