#include #include #include #include #include #include #include #include #include "rapidxml.hpp" using namespace std; bool VERBOSE_CURL = false; bool DEBUG = false; string host = "fritz.box"; string user = "dslf-config"; string pass = "GEHEIM"; CURL *curl_handle; string securePort = ""; struct MemoryStruct { char *memory; size_t size; }; struct Number { string type; string quickdial; string vanity; int prio; string number; Number() { type = ""; quickdial = ""; vanity = ""; prio = 0; number = ""; } }; struct Email { string classifier; string email; Email() { classifier = ""; email = ""; } }; struct Contact { int uniqueid; int category; string realName; string imageURL; vector emails; vector numbers; Contact() { uniqueid = -1; category = 0; realName = ""; imageURL = ""; emails = vector(); numbers = vector(); } }; struct Phonebook { int id; string name; long timestamp; vector contacts; Phonebook() { id = -1; name = ""; timestamp = 0; } }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *) userp; mem->memory = (char*) realloc(mem->memory, mem->size + realsize + 1); if (mem->memory == NULL) { cerr << "Kein Speicher mehr." << endl; throw exception(); } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } vector split(const string &s, char delim) { vector elems; stringstream ss; ss.str(s); string item; while (getline(ss, item, delim)) { elems.push_back(item); } return elems; } void getValueFromXML(MemoryStruct &chunk, map ¶ms) { rapidxml::xml_document<> doc; doc.parse<0>(chunk.memory); rapidxml::xml_node<> *node = doc.first_node("s:Envelope"); if (node) { node = node->first_node("s:Body"); if (node) { node = node->first_node(); if (node) { string nodeName = node->name(); string endsWith = "Response"; if (nodeName.size() >= endsWith.size() && nodeName.compare(nodeName.size() - endsWith.size(), endsWith.size(), endsWith) == 0) { for(map::iterator it = params.begin(); it != params.end(); it++) { rapidxml::xml_node<> *paramNode = node->first_node(it->first.c_str()); if (paramNode) { params[it->first] = paramNode->value(); } } } } } } } string getTR064URL(const string& url, bool secure = true) { return (secure ? "https" : "http") + string("://") + host + ":" + string(secure ? securePort : "49000") + string("/upnp/control/") + url; } MemoryStruct callTR064(const string& url, const string& service, const string& action, map params = map(), bool secure = true) { if (secure && securePort.empty()) { struct MemoryStruct chunk = callTR064("deviceinfo", "DeviceInfo:1", "GetSecurityPort", map(), false); map result = map(); result["NewSecurityPort"] = ""; getValueFromXML(chunk, result); if (!result["NewSecurityPort"].empty()) { securePort = result["NewSecurityPort"]; } else { cerr << "SecurityPort konnte nicht ausgelesen werden."; throw exception(); } free(chunk.memory); } struct MemoryStruct chunk; chunk.memory = (char*) malloc(1); chunk.size = 0; string param = ""; for(map::iterator it = params.begin(); it != params.end(); it++) { param.append("<") .append(it->first) .append(">") .append(it->second) .append("first) .append(">"); } const string boxUrl = getTR064URL(url, secure); const string post = "" "" "" "" + param + "" "" ""; if (DEBUG) { cout << "Query:" << endl << boxUrl << endl << post << endl; } curl_easy_reset(curl_handle); if (VERBOSE_CURL) { curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); } if (secure) { curl_easy_setopt(curl_handle, CURLOPT_USERNAME, user.c_str()); curl_easy_setopt(curl_handle, CURLOPT_PASSWORD, pass.c_str()); curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANYSAFE); curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); } struct curl_slist *list = NULL; list = curl_slist_append(list, "Content-Type: text/xml; charset=\"utf-8\""); list = curl_slist_append(list, ("SoapAction: urn:dslforum-org:service:" + service + "#" + action).c_str()); curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, list); curl_easy_setopt(curl_handle, CURLOPT_URL, boxUrl.c_str()); curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, post.c_str()); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void * )&chunk); CURLcode res = curl_easy_perform(curl_handle); if (res != CURLE_OK) { cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << endl; throw exception(); } else if (DEBUG) { cout << "Antwort:" << endl << chunk.size << " Bytes empfangen." << endl << chunk.memory << endl; } curl_slist_free_all(list); return chunk; } string getPhoneBook(string &url) { CURL *curl_handle = curl_easy_init(); struct MemoryStruct chunk; chunk.memory = (char*) malloc(1); chunk.size = 0; curl_easy_reset(curl_handle); if (VERBOSE_CURL) { curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L); } curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, false); curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); curl_easy_setopt(curl_handle, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void * )&chunk); CURLcode res = curl_easy_perform(curl_handle); if (res != CURLE_OK) { cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << endl; throw exception(); } else if (DEBUG) { cout << "Antwort:" << endl << chunk.size << " Bytes empfangen." << endl << chunk.memory << endl; } string ret = string(chunk.memory); free(chunk.memory); curl_easy_cleanup(curl_handle); return ret; } Phonebook parsePhoneBook(string xml) { Phonebook pb = Phonebook(); rapidxml::xml_document<> doc; char* cstr = new char[xml.size() + 1]; strcpy(cstr, xml.c_str()); doc.parse<0>(cstr); rapidxml::xml_node<> *phonebooks = doc.first_node("phonebooks"); rapidxml::xml_node<> *node; rapidxml::xml_attribute<> *attr; if (phonebooks) { rapidxml::xml_node<> *phonebook = phonebooks->first_node("phonebook"); if (phonebook) { attr = phonebook->first_attribute("owner"); if (attr) { pb.id = atoi(attr->value()); } attr = phonebook->first_attribute("name"); if (attr) { pb.name = attr->value(); } node = phonebook->first_node("timestamp"); if (node) { pb.timestamp = atol(node->value()); } rapidxml::xml_node<> *contact = phonebook->first_node("contact"); while (contact) { Contact c = Contact(); node = contact->first_node("uniqueid"); if (node) { c.uniqueid = atoi(node->value()); } node = contact->first_node("category"); if (node) { c.category = atoi(node->value()); } rapidxml::xml_node<> *person = contact->first_node("person"); if (person) { node = person->first_node("realName"); if (node) { c.realName = node->value(); } node = person->first_node("imageURL"); if (node) { c.imageURL = node->value(); } } rapidxml::xml_node<> *telephony = contact->first_node("telephony"); if (telephony) { rapidxml::xml_node<> *services = telephony->first_node("services"); if (services) { node = services->first_node("email"); while (node) { Email email = Email(); email.email = node->value(); attr = node->first_attribute("classifier"); if (attr) { email.classifier = attr->value(); } c.emails.push_back(email); node = node->next_sibling("email"); } } node = telephony->first_node("number"); while (node) { Number number = Number(); number.number = node->value(); attr = node->first_attribute("type"); if (attr) { number.type = attr->value(); } attr = node->first_attribute("quickdial"); if (attr) { number.quickdial = attr->value(); } attr = node->first_attribute("vanity"); if (attr) { number.vanity = attr->value(); } attr = node->first_attribute("prio"); if (attr) { char *val = attr->value(); if (strlen(val) > 0) { number.prio = atoi(attr->value()); } } c.numbers.push_back(number); node = node->next_sibling("number"); } } pb.contacts.push_back(c); contact = contact->next_sibling("contact"); } } } delete [] cstr; return pb; } int main(void) { curl_global_init(CURL_GLOBAL_ALL); curl_handle = curl_easy_init(); map params = map(); struct MemoryStruct chunk = callTR064("x_contact", "X_AVM-DE_OnTel:1", "GetPhonebookList"); params["NewPhonebookList"] = ""; getValueFromXML(chunk, params); free(chunk.memory); vector pbIDs = split(params["NewPhonebookList"], ','); for(vector::iterator it = pbIDs.begin(); it != pbIDs.end(); ++it) { cout << "Telefonbuch ID: " << *it << endl; params.clear(); params["NewPhonebookID"] = *it; chunk = callTR064("x_contact", "X_AVM-DE_OnTel:1", "GetPhoneBook", params); params.clear(); params["NewPhonebookName"] = ""; params["NewPhonebookExtraID"] = ""; params["NewPhonebookURL"] = ""; getValueFromXML(chunk, params); free(chunk.memory); string xml = getPhoneBook(params["NewPhonebookURL"]); Phonebook pb = parsePhoneBook(xml); cout << "Telefonbuch mit " << pb.contacts.size() << " Einträgen gefunden." << endl; for(vector::iterator itCon = pb.contacts.begin(); itCon != pb.contacts.end(); ++itCon) { cout << itCon->realName << " hat " << itCon->numbers.size() << " Nummern und " << itCon->emails.size() << " Emails." << endl; } } curl_easy_cleanup(curl_handle); curl_global_cleanup(); return 0; }