anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
m_xmlrpc.cpp (5724B)
1 /* 2 * 3 * (C) 2010-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 */ 8 9 #include "module.h" 10 #include "modules/xmlrpc.h" 11 #include "modules/httpd.h" 12 13 static struct special_chars 14 { 15 Anope::string character; 16 Anope::string replace; 17 18 special_chars(const Anope::string &c, const Anope::string &r) : character(c), replace(r) { } 19 } 20 special[] = { 21 special_chars("&", "&"), 22 special_chars("\"", """), 23 special_chars("<", "<"), 24 special_chars(">", "&qt;"), 25 special_chars("'", "'"), 26 special_chars("\n", "
"), 27 special_chars("\002", ""), // bold 28 special_chars("\003", ""), // color 29 special_chars("\035", ""), // italics 30 special_chars("\037", ""), // underline 31 special_chars("\026", ""), // reverses 32 special_chars("", "") 33 }; 34 35 class MyXMLRPCServiceInterface : public XMLRPCServiceInterface, public HTTPPage 36 { 37 std::deque<XMLRPCEvent *> events; 38 39 public: 40 MyXMLRPCServiceInterface(Module *creator, const Anope::string &sname) : XMLRPCServiceInterface(creator, sname), HTTPPage("/xmlrpc", "text/xml") { } 41 42 void Register(XMLRPCEvent *event) anope_override 43 { 44 this->events.push_back(event); 45 } 46 47 void Unregister(XMLRPCEvent *event) anope_override 48 { 49 std::deque<XMLRPCEvent *>::iterator it = std::find(this->events.begin(), this->events.end(), event); 50 51 if (it != this->events.end()) 52 this->events.erase(it); 53 } 54 55 Anope::string Sanitize(const Anope::string &string) anope_override 56 { 57 Anope::string ret = string; 58 for (int i = 0; special[i].character.empty() == false; ++i) 59 ret = ret.replace_all_cs(special[i].character, special[i].replace); 60 return ret; 61 } 62 63 static Anope::string Unescape(const Anope::string &string) 64 { 65 Anope::string ret = string; 66 for (int i = 0; special[i].character.empty() == false; ++i) 67 if (!special[i].replace.empty()) 68 ret = ret.replace_all_cs(special[i].replace, special[i].character); 69 70 for (size_t i, last = 0; (i = string.find("&#", last)) != Anope::string::npos;) 71 { 72 last = i + 1; 73 74 size_t end = string.find(';', i); 75 if (end == Anope::string::npos) 76 break; 77 78 Anope::string ch = string.substr(i + 2, end - (i + 2)); 79 80 if (ch.empty()) 81 continue; 82 83 long l; 84 if (!ch.empty() && ch[0] == 'x') 85 l = strtol(ch.substr(1).c_str(), NULL, 16); 86 else 87 l = strtol(ch.c_str(), NULL, 10); 88 89 if (l > 0 && l < 256) 90 ret = ret.replace_all_cs("&#" + ch + ";", Anope::string(l)); 91 } 92 93 return ret; 94 } 95 96 private: 97 static bool GetData(Anope::string &content, Anope::string &tag, Anope::string &data) 98 { 99 if (content.empty()) 100 return false; 101 102 Anope::string prev, cur; 103 bool istag; 104 105 do 106 { 107 prev = cur; 108 cur.clear(); 109 110 size_t len = 0; 111 istag = false; 112 113 if (content[0] == '<') 114 { 115 len = content.find_first_of('>'); 116 istag = true; 117 } 118 else if (content[0] != '>') 119 { 120 len = content.find_first_of('<'); 121 } 122 123 // len must advance 124 if (len == Anope::string::npos || len == 0) 125 break; 126 127 if (istag) 128 { 129 cur = content.substr(1, len - 1); 130 content.erase(0, len + 1); 131 while (!content.empty() && content[0] == ' ') 132 content.erase(content.begin()); 133 } 134 else 135 { 136 cur = content.substr(0, len); 137 content.erase(0, len); 138 } 139 } 140 while (istag && !content.empty()); 141 142 tag = Unescape(prev); 143 data = Unescape(cur); 144 return !istag && !data.empty(); 145 } 146 147 public: 148 bool OnRequest(HTTPProvider *provider, const Anope::string &page_name, HTTPClient *client, HTTPMessage &message, HTTPReply &reply) anope_override 149 { 150 Anope::string content = message.content, tname, data; 151 XMLRPCRequest request(reply); 152 153 while (GetData(content, tname, data)) 154 { 155 Log(LOG_DEBUG) << "m_xmlrpc: Tag name: " << tname << ", data: " << data; 156 if (tname == "methodName") 157 request.name = data; 158 else if (tname == "name" && data == "id") 159 { 160 GetData(content, tname, data); 161 request.id = data; 162 } 163 else if (tname == "string") 164 request.data.push_back(data); 165 } 166 167 for (unsigned i = 0; i < this->events.size(); ++i) 168 { 169 XMLRPCEvent *e = this->events[i]; 170 171 if (!e->Run(this, client, request)) 172 return false; 173 else if (!request.get_replies().empty()) 174 { 175 this->Reply(request); 176 return true; 177 } 178 } 179 180 reply.error = HTTP_PAGE_NOT_FOUND; 181 reply.Write("Unrecognized query"); 182 return true; 183 } 184 185 void Reply(XMLRPCRequest &request) anope_override 186 { 187 if (!request.id.empty()) 188 request.reply("id", request.id); 189 190 Anope::string r = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<methodResponse>\n<params>\n<param>\n<value>\n<struct>\n"; 191 for (std::map<Anope::string, Anope::string>::const_iterator it = request.get_replies().begin(); it != request.get_replies().end(); ++it) 192 r += "<member>\n<name>" + it->first + "</name>\n<value>\n<string>" + this->Sanitize(it->second) + "</string>\n</value>\n</member>\n"; 193 r += "</struct>\n</value>\n</param>\n</params>\n</methodResponse>"; 194 195 request.r.Write(r); 196 } 197 }; 198 199 class ModuleXMLRPC : public Module 200 { 201 ServiceReference<HTTPProvider> httpref; 202 public: 203 MyXMLRPCServiceInterface xmlrpcinterface; 204 205 ModuleXMLRPC(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, EXTRA | VENDOR), 206 xmlrpcinterface(this, "xmlrpc") 207 { 208 209 } 210 211 ~ModuleXMLRPC() 212 { 213 if (httpref) 214 httpref->UnregisterPage(&xmlrpcinterface); 215 } 216 217 void OnReload(Configuration::Conf *conf) anope_override 218 { 219 if (httpref) 220 httpref->UnregisterPage(&xmlrpcinterface); 221 this->httpref = ServiceReference<HTTPProvider>("HTTPProvider", conf->GetModule(this)->Get<const Anope::string>("server", "httpd/main")); 222 if (!httpref) 223 throw ConfigException("Unable to find http reference, is m_httpd loaded?"); 224 httpref->RegisterPage(&xmlrpcinterface); 225 } 226 }; 227 228 MODULE_INIT(ModuleXMLRPC)