diff options
-rw-r--r-- | libpiano/main.c | 14 | ||||
-rw-r--r-- | libpiano/piano.h | 7 | ||||
-rw-r--r-- | libpiano/xml.c | 130 | ||||
-rw-r--r-- | libpiano/xml.h | 6 | ||||
-rw-r--r-- | src/main.c | 11 |
5 files changed, 135 insertions, 33 deletions
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 ("<?xml version=\"1.0\"?>" "<methodCall><methodName>misc.sync</methodName>" "<params></params></methodCall>"); 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), "<?xml version=\"1.0\"?>" "<methodCall><methodName>station.getStations</methodName>" @@ -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: * <struct> * <member> @@ -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; } /* <methodResponse> <params> <param> <value> <struct> */ @@ -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; } /* <methodResponse> <params> <param> <value> <array> <data> */ @@ -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 <struct> 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; } /* <methodResponse> <params> <param> <value> <array> <data> */ @@ -322,6 +400,8 @@ void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) { } xmlFreeDoc (doc); + + return PIANO_RET_OK; } /* parse simple answers like this: <?xml version="1.0" encoding="UTF-8"?> @@ -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); @@ -302,9 +302,16 @@ int main (int argc, char **argv) { termSetBuffer (0); printf ("Login...\n"); - PianoConnect (&ph, bsettings.username, bsettings.password); + if (PianoConnect (&ph, bsettings.username, bsettings.password) != + PIANO_RET_OK) { + printf ("Login failed. Check your username and password\n"); + return 0; + } printf ("Get stations...\n"); - PianoGetStations (&ph); + if (PianoGetStations (&ph) != PIANO_RET_OK) { + printf ("Error while fetching your stations.\n"); + return 0; + } /* select station */ curStation = selectStation (&ph); |