From 56432d661e34de9aa0d1727fb7b06f19aa18723e Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Tue, 17 Jun 2008 12:13:56 +0200 Subject: More error handling. Now we can parse and handle pandora's messages and abort the parsing process. Some more fault type should be added, as well as more client support for those errors. --- libpiano/main.c | 14 ++++-- libpiano/piano.h | 7 +-- libpiano/xml.c | 130 +++++++++++++++++++++++++++++++++++++++++++++---------- libpiano/xml.h | 6 ++- 4 files changed, 126 insertions(+), 31 deletions(-) (limited to 'libpiano') diff --git a/libpiano/main.c b/libpiano/main.c index faf5317..be97737 100644 --- a/libpiano/main.c +++ b/libpiano/main.c @@ -166,12 +166,13 @@ void PianoDestroy (PianoHandle_t *ph) { * @param password (plaintext, utf-8 encoded) * @return nothing */ -void PianoConnect (PianoHandle_t *ph, char *user, char *password) { +PianoReturn_t PianoConnect (PianoHandle_t *ph, char *user, char *password) { char url[PIANO_URL_BUFFER_SIZE]; char *requestStr = PianoEncryptString ("" "misc.sync" ""); char *retStr, requestStrPlain[10000]; + PianoReturn_t ret; /* sync (is the return value used by pandora? for now: ignore result) */ snprintf (url, sizeof (url), PIANO_RPC_URL "rid=%s&method=sync", @@ -192,10 +193,12 @@ void PianoConnect (PianoHandle_t *ph, char *user, char *password) { snprintf (url, sizeof (url), PIANO_SECURE_RPC_URL "rid=%s" "&method=authenticateListener", ph->routeId); PianoHttpPost (ph->curlHandle, url, requestStr, &retStr); - PianoXmlParseUserinfo (ph, retStr); + ret = PianoXmlParseUserinfo (ph, retStr); free (requestStr); free (retStr); + + return ret; } /* get all stations for authenticated user (so: PianoConnect needs to @@ -205,9 +208,10 @@ void PianoConnect (PianoHandle_t *ph, char *user, char *password) { * @param piano handle filled with some authentication data by PianoConnect * @return nothing */ -void PianoGetStations (PianoHandle_t *ph) { +PianoReturn_t PianoGetStations (PianoHandle_t *ph) { char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE]; char *requestStr, *retStr; + PianoReturn_t ret; snprintf (xmlSendBuf, sizeof (xmlSendBuf), "" "station.getStations" @@ -219,9 +223,11 @@ void PianoGetStations (PianoHandle_t *ph) { "rid=%s&lid=%s&method=getStations", ph->routeId, ph->user.listenerId); PianoHttpPost (ph->curlHandle, url, requestStr, &retStr); - PianoXmlParseStations (ph, retStr); + ret = PianoXmlParseStations (ph, retStr); free (retStr); free (requestStr); + + return ret; } /* get next songs for station (usually four tracks) diff --git a/libpiano/piano.h b/libpiano/piano.h index bad8401..b832b69 100644 --- a/libpiano/piano.h +++ b/libpiano/piano.h @@ -139,7 +139,8 @@ struct PianoSearchResult { typedef struct PianoSearchResult PianoSearchResult_t; /* FIXME: more error types (http failed, e.g.) later */ -enum PianoReturn {PIANO_RET_OK, PIANO_RET_ERR}; +enum PianoReturn {PIANO_RET_OK, PIANO_RET_ERR, PIANO_RET_XML_INVALID, + PIANO_RET_AUTH_TOKEN_INVALID, PIANO_RET_AUTH_USER_PASSWORD_INVALID}; typedef enum PianoReturn PianoReturn_t; void PianoInit (PianoHandle_t *); @@ -148,9 +149,9 @@ void PianoDestroyPlaylist (PianoHandle_t *ph); void PianoDestroySearchResult (PianoSearchResult_t *searchResult); void PianoDestroyStation (PianoStation_t *station); void PianoDestroyStations (PianoHandle_t *ph); -void PianoConnect (PianoHandle_t *, char *, char *); +PianoReturn_t PianoConnect (PianoHandle_t *, char *, char *); -void PianoGetStations (PianoHandle_t *ph); +PianoReturn_t PianoGetStations (PianoHandle_t *ph); void PianoGetPlaylist (PianoHandle_t *ph, char *stationId); PianoReturn_t PianoRateTrack (PianoHandle_t *ph, PianoStation_t *station, diff --git a/libpiano/xml.c b/libpiano/xml.c index 4d4b4b1..f6e21f8 100644 --- a/libpiano/xml.c +++ b/libpiano/xml.c @@ -29,6 +29,71 @@ THE SOFTWARE. #include "piano.h" #include "crypt.h" +void PianoXmlStructParser (xmlNode *structRoot, + void (*callback) (char *, xmlNode *, void *), void *data); +char *PianoXmlGetNodeText (xmlNode *node); + +/* parse fault and get fault type + */ +void PianoXmlIsFaultCb (char *key, xmlNode *value, void *data) { + PianoReturn_t *ret = data; + char *valueStr = PianoXmlGetNodeText (value); + char *matchStart, *matchEnd, *matchStr; + + if (strcmp ("faultString", key) == 0) { + *ret = PIANO_RET_ERR; + /* find fault identifier in a string like this: + * com.savagebeast.radio.api.protocol.xmlrpc.RadioXmlRpcException: + * 192.168.160.78|1213101717317|AUTH_INVALID_TOKEN| + * Invalid auth token */ + if ((matchStart = strchr (valueStr, '|')) != NULL) { + if ((matchStart = strchr (matchStart+1, '|')) != NULL) { + if ((matchEnd = strchr (matchStart+1, '|')) != NULL) { + matchStr = calloc (matchEnd - (matchStart+1)+1, + sizeof (*matchStr)); + memcpy (matchStr, matchStart+1, matchEnd - + (matchStart+1)); + /* translate to our error message system */ + if (strcmp ("AUTH_INVALID_TOKEN", matchStr) == 0) { + *ret = PIANO_RET_AUTH_TOKEN_INVALID; + } else if (strcmp ("AUTH_INVALID_USERNAME_PASSWORD", + matchStr) == 0) { + *ret = PIANO_RET_AUTH_USER_PASSWORD_INVALID; + } else { + *ret = PIANO_RET_ERR; + printf (PACKAGE ": Unknown error %s in %s\n", + matchStr, valueStr); + } + free (matchStr); + } + } + } + } +} + +/* check whether pandora returned an error or not + * @author PromyLOPh + * @added 2008-06-16 + * @param document root of xml doc + * @return _RET_OK or fault code (_RET_*) + */ +PianoReturn_t PianoXmlIsFault (xmlNode *docRoot) { + xmlNode *faultStruct; + PianoReturn_t ret; + + /* FIXME: we could get into troubles when fault is not the first child + * (pandora yould add whitespace e.g.) */ + if (docRoot->children != NULL && + docRoot->children->type == XML_ELEMENT_NODE && + xmlStrEqual (docRoot->children->name, (xmlChar *) "fault")) { + /* FIXME: detect fault type */ + faultStruct = docRoot->children->children->children; + PianoXmlStructParser (faultStruct, PianoXmlIsFaultCb, &ret); + return ret; + } + return PIANO_RET_OK; +} + /* parses things like this: * * @@ -89,14 +154,19 @@ void PianoXmlStructParser (xmlNode *structRoot, */ PianoReturn_t PianoXmlInitDoc (char *xml, xmlDocPtr *doc, xmlNode **docRoot) { *doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, 0); + PianoReturn_t ret; if (*doc == NULL) { printf (PACKAGE ": error while parsing this xml document\n%s\n", xml); - return PIANO_RET_ERR; + return PIANO_RET_XML_INVALID; } *docRoot = xmlDocGetRootElement (*doc); + if ((ret = PianoXmlIsFault (*docRoot)) != PIANO_RET_OK) { + return ret; + } + return PIANO_RET_OK; } @@ -190,19 +260,20 @@ void PianoXmlParsePlaylistCb (char *key, xmlNode *value, void *data) { } } -/* parses server response and updates handle +/* parses userinfos sent by pandora as login response * @author PromyLOPh * @added 2008-06-03 * @param piano handle * @param utf-8 string - * @return nothing + * @return _RET_OK or error */ -void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { +PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { xmlNode *docRoot; xmlDocPtr doc; + PianoReturn_t ret; - if (PianoXmlInitDoc (xml, &doc, &docRoot) != PIANO_RET_OK) { - return; + if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } /* */ @@ -210,6 +281,7 @@ void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { PianoXmlStructParser (structRoot, PianoXmlParseUserinfoCb, &ph->user); xmlFreeDoc (doc); + return PIANO_RET_OK; } /* parse stations returned by pandora @@ -217,14 +289,15 @@ void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { * @added 2008-06-04 * @param piano handle * @param xml returned by pandora - * @return nothing + * @return _RET_OK or error */ -void PianoXmlParseStations (PianoHandle_t *ph, char *xml) { +PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, char *xml) { xmlNode *docRoot, *curNode; xmlDocPtr doc; + PianoReturn_t ret; - if (PianoXmlInitDoc (xml, &doc, &docRoot) != PIANO_RET_OK) { - return; + if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } /* */ @@ -249,6 +322,7 @@ void PianoXmlParseStations (PianoHandle_t *ph, char *xml) { } xmlFreeDoc (doc); + return PIANO_RET_OK; } /* parse "create station" answer (it returns a new station structure) @@ -258,13 +332,14 @@ void PianoXmlParseStations (PianoHandle_t *ph, char *xml) { * @param xml document * @return nothing yet */ -void PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { +PianoReturn_t PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { xmlNode *docRoot; xmlDocPtr doc; PianoStation_t *tmpStation; + PianoReturn_t ret; - if (PianoXmlInitDoc (xml, &doc, &docRoot) != PIANO_RET_OK) { - return; + if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } /* get node */ @@ -284,6 +359,8 @@ void PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { } xmlFreeDoc (doc); + + return PIANO_RET_OK; } /* parses playlist; used when searching too @@ -292,12 +369,13 @@ void PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { * @param piano handle * @param xml document */ -void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { +PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { xmlNode *docRoot, *curNode; xmlDocPtr doc; + PianoReturn_t ret; - if (PianoXmlInitDoc (xml, &doc, &docRoot) != PIANO_RET_OK) { - return; + if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } /* */ @@ -322,6 +400,8 @@ void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { } xmlFreeDoc (doc); + + return PIANO_RET_OK; } /* parse simple answers like this: @@ -335,15 +415,17 @@ void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { PianoReturn_t PianoXmlParseSimple (char *xml) { xmlNode *docRoot; xmlDocPtr doc; - PianoReturn_t ret = PIANO_RET_ERR; + PianoReturn_t ret; - if (PianoXmlInitDoc (xml, &doc, &docRoot) != PIANO_RET_OK) { - return PIANO_RET_ERR; + if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } xmlNode *val = docRoot->children->children->children->children; if (xmlStrEqual (val->content, (xmlChar *) "1")) { ret = PIANO_RET_OK; + } else { + ret = PIANO_RET_ERR; } xmlFreeDoc (doc); @@ -434,12 +516,14 @@ void PianoXmlParseSearchCb (char *key, xmlNode *value, void *data) { * @param returns search result * @return nothing yet */ -void PianoXmlParseSearch (char *searchXml, PianoSearchResult_t *searchResult) { +PianoReturn_t PianoXmlParseSearch (char *searchXml, + PianoSearchResult_t *searchResult) { xmlNode *docRoot, *curNode; xmlDocPtr doc; + PianoReturn_t ret; - if (PianoXmlInitDoc (searchXml, &doc, &docRoot) != PIANO_RET_OK) { - return; + if ((ret = PianoXmlInitDoc (searchXml, &doc, &docRoot)) != PIANO_RET_OK) { + return ret; } xmlNode *structRoot = docRoot->children->children->children->children; @@ -448,6 +532,8 @@ void PianoXmlParseSearch (char *searchXml, PianoSearchResult_t *searchResult) { PianoXmlStructParser (structRoot, PianoXmlParseSearchCb, searchResult); xmlFreeDoc (doc); + + return PIANO_RET_OK; } /* encode reserved xml chars diff --git a/libpiano/xml.h b/libpiano/xml.h index f8c9106..54deb6e 100644 --- a/libpiano/xml.h +++ b/libpiano/xml.h @@ -23,8 +23,10 @@ THE SOFTWARE. #ifndef _XML_H #define _XML_H -void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml); -void PianoXmlParseStations (PianoHandle_t *ph, char *xml); +#include "piano.h" + +PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml); +PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, char *xml); void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml); void PianoXmlParseSearch (char *searchXml, PianoSearchResult_t *searchResult); -- cgit v1.2.3