summaryrefslogtreecommitdiff
path: root/libpiano/src
diff options
context:
space:
mode:
authorLars-Dominik Braun <PromyLOPh@gmail.com>2008-06-17 12:36:33 +0200
committerLars-Dominik Braun <PromyLOPh@gmail.com>2008-06-17 12:36:33 +0200
commit22f765b7b3abb4b0553b285b42bf81b24fefa224 (patch)
treeb63436b0867ebf5c1c7e885ca0d75f5be6efd1d9 /libpiano/src
parent1351a0cbebcd01fd5e659d3aa9306c31ddbdc6a3 (diff)
downloadpianobar-22f765b7b3abb4b0553b285b42bf81b24fefa224.tar.gz
pianobar-22f765b7b3abb4b0553b285b42bf81b24fefa224.tar.bz2
pianobar-22f765b7b3abb4b0553b285b42bf81b24fefa224.zip
lib: Move sources to src
Diffstat (limited to 'libpiano/src')
-rw-r--r--libpiano/src/Makefile.am6
-rw-r--r--libpiano/src/const.h35
-rw-r--r--libpiano/src/crypt.c265
-rw-r--r--libpiano/src/crypt.h29
-rw-r--r--libpiano/src/crypt_key_input.h1071
-rw-r--r--libpiano/src/crypt_key_output.h1076
-rw-r--r--libpiano/src/http.c83
-rw-r--r--libpiano/src/http.h28
-rw-r--r--libpiano/src/main.c465
-rw-r--r--libpiano/src/main.h27
-rw-r--r--libpiano/src/piano.h166
-rw-r--r--libpiano/src/xml.c547
-rw-r--r--libpiano/src/xml.h38
13 files changed, 3836 insertions, 0 deletions
diff --git a/libpiano/src/Makefile.am b/libpiano/src/Makefile.am
new file mode 100644
index 0000000..e74d442
--- /dev/null
+++ b/libpiano/src/Makefile.am
@@ -0,0 +1,6 @@
+lib_LTLIBRARIES = libpiano.la
+
+libpiano_la_SOURCES = crypt.c http.c main.c xml.c const.h crypt.h crypt_key_input.h crypt_key_output.h http.h main.h xml.h
+include_HEADERS = piano.h
+libpiano_la_CPPFLAGS = ${LIBCURL_CFLAGS} ${LIBXML_CFLAGS}
+libpiano_la_LIBADD = ${LIBCURL_LIBS} ${LIBXML_LIBS}
diff --git a/libpiano/src/const.h b/libpiano/src/const.h
new file mode 100644
index 0000000..dfaca1f
--- /dev/null
+++ b/libpiano/src/const.h
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _CONST_H
+#define _CONST_H
+
+/* constants */
+
+
+#define PIANO_USERAGENT "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008051115 Firefox/3.0pre"
+#define PIANO_RPC_URL "http://www.pandora.com/radio/xmlrpc/v19?"
+#define PIANO_SECURE_RPC_URL "https://www.pandora.com/radio/xmlrpc/v19?"
+#define PIANO_URL_BUFFER_SIZE 1024
+#define PIANO_HTTP_BUFFER_SIZE 100000
+
+#endif /* _CONST_H */
diff --git a/libpiano/src/crypt.c b/libpiano/src/crypt.c
new file mode 100644
index 0000000..10744e0
--- /dev/null
+++ b/libpiano/src/crypt.c
@@ -0,0 +1,265 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "crypt_key_output.h"
+#include "crypt_key_input.h"
+
+/* hex string to array of unsigned int values
+ * @param hex string
+ * @param return array
+ * @param return size of array
+ * @return nothing, yet
+ */
+void PianoHexToInts (char *strHex, unsigned int **retInts, size_t *retIntsN) {
+ size_t i;
+ char hexInt[9];
+ unsigned int *arrInts = calloc (strlen (strHex) / 8, sizeof (*arrInts));
+
+ /* FIXME: error handling: string too short, e.g. */
+ /* unsigned int = 4 bytes, 8 chars in hex */
+ for (i = 0; i < strlen (strHex); i += 8) {
+ memset (hexInt, 0, sizeof (hexInt));
+ memcpy (hexInt, strHex+i, sizeof (hexInt)-1);
+ sscanf (hexInt, "%x", &arrInts[i/8]);
+ }
+ *retInts = arrInts;
+ /* FIXME: copy & waste */
+ *retIntsN = strlen (strHex) / 8, sizeof (*arrInts);
+}
+
+/* decipher int array; reverse engineered from pandora source
+ * @param decrypt-me
+ * @param decrypt-me-length
+ * @param return plain ints array
+ * @return nothing, yet
+ */
+void PianoDecipherInts (unsigned int *cipherInts, size_t cipherIntsN,
+ unsigned int **retPlainInts) {
+ unsigned int *plainInts = calloc (cipherIntsN, sizeof (*plainInts));
+
+ size_t i;
+
+ for (i = 0; i < cipherIntsN; i += 2) {
+ unsigned int _loc2 = cipherInts [i];
+ unsigned int _loc3 = cipherInts [i+1];
+ unsigned int _loc6;
+ size_t n_count;
+
+ for (n_count = in_key_n + 1; n_count > 1; --n_count) {
+ _loc2 = _loc2 ^ in_key_p [n_count];
+
+ unsigned int _loc4 = _loc2;
+ #if 0
+ unsigned short _loc8 = _loc4 & 0xff;
+ _loc4 = _loc4 >> 8;
+ unsigned short _loc9 = _loc4 & 0xff;
+ _loc4 = _loc4 >> 8;
+ unsigned short _loc10 = _loc4 & 0xff;
+ _loc4 = _loc4 >> 8;
+ unsigned short _loc11 = _loc4 & 0xff;
+ #endif
+ unsigned short _loc8 = _loc4 & 0xff;
+ unsigned short _loc9 = (_loc4 >> 8) & 0xff;
+ unsigned short _loc10 = (_loc4 >> 16) & 0xff;
+ unsigned short _loc11 = (_loc4 >> 24) & 0xff;
+ unsigned int _loc5 = in_key_s [0][_loc11] +
+ in_key_s [1][_loc10];
+ _loc5 = _loc5 ^ in_key_s [2][_loc9];
+ _loc5 = _loc5 + in_key_s [3][_loc8];
+ _loc3 = _loc3 ^ _loc5;
+ _loc6 = _loc2;
+ _loc2 = _loc3;
+ _loc3 = _loc6;
+ }
+ _loc6 = _loc2;
+ _loc2 = _loc3;
+ _loc3 = _loc6;
+ _loc3 = _loc3 ^ in_key_p [1];
+ _loc2 = _loc2 ^ in_key_p [0];
+ plainInts [i] = _loc2;
+ plainInts [i+1] = _loc3;
+ }
+ *retPlainInts = plainInts;
+}
+
+/* int array to string
+ * @param int array
+ * @param length of array
+ * @return the string
+ */
+char *PianoIntsToString (unsigned int *arrInts, size_t arrIntsN) {
+ char *strDecoded = calloc (arrIntsN * 4 + 1, sizeof (*strDecoded));
+ size_t i;
+
+ for (i = 0; i < arrIntsN; i++) {
+ snprintf (&strDecoded[i*4], arrIntsN * 4, "%c%c%c%c", ((arrInts[i] >> 24) & 0xff), ((arrInts[i] >> 16) & 0xff), ((arrInts[i] >> 8) & 0xff), ((arrInts[i] >> 0) & 0xff));
+ }
+ return strDecoded;
+}
+
+/* decrypt hex-encoded string
+ * @param hex string
+ * @return decrypted string
+ */
+char *PianoDecryptString (char *strInput) {
+ unsigned int *cipherInts, *plainInts;
+ size_t cipherIntsN;
+ char *strDecrypted;
+
+ PianoHexToInts (strInput, &cipherInts, &cipherIntsN);
+ PianoDecipherInts (cipherInts, cipherIntsN, &plainInts);
+ strDecrypted = PianoIntsToString (plainInts, cipherIntsN);
+
+ free (cipherInts);
+ free (plainInts);
+
+ return strDecrypted;
+}
+
+/* string to int array
+ * @param the string, length % 8 needs to be 0
+ * @param returns int array
+ * @param returns size of int array
+ * @return nothing
+ */
+void PianoBytesToInts (char *strInput, unsigned int **retArrInts,
+ size_t *retArrIntsN) {
+ size_t i, j, neededStrLen = strlen (strInput);
+ unsigned int *arrInts;
+ char shift;
+
+ /* blowfish encrypts two 4 byte blocks */
+ neededStrLen = strlen (strInput);
+ if (neededStrLen % 8 != 0) {
+ /* substract overhead and add full 8 byte block */
+ neededStrLen = neededStrLen - (neededStrLen % 8) + 8;
+ }
+ arrInts = calloc (neededStrLen / 4, sizeof (*arrInts));
+
+ /* we must not read beyond the end of the string, so be a bit
+ * paranoid */
+ shift = 24;
+ i = 0;
+ j = 0;
+ while (i < strlen (strInput)) {
+ shift = 24;
+ while (shift >= 0 && i < strlen (strInput)) {
+ arrInts[i/4] |= strInput[i] << shift;
+ shift -= 8;
+ i++;
+ }
+ }
+ *retArrInts = arrInts;
+ *retArrIntsN = neededStrLen / 4;
+}
+
+/* decipher ints; reverse engineered from pandora flash client
+ * @param encipher this
+ * @param how many ints
+ * @param returns crypted ints; memory is allocated by this function
+ * @return nothing yet
+ */
+void PianoEncipherInts (unsigned int *plainInts, size_t plainIntsN,
+ unsigned int **retCipherInts) {
+ unsigned int *cipherInts = calloc (plainIntsN, sizeof (*cipherInts));
+ size_t i, _loc7;
+
+ for (i = 0; i < plainIntsN; i+=2) {
+ /* ++ encipher */
+ unsigned int _loc2 = plainInts [i];
+ unsigned int _loc3 = plainInts [i+1];
+ unsigned int _loc6;
+
+ for (_loc7 = 0; _loc7 < out_key_n; _loc7++) {
+ _loc2 = _loc2 ^ out_key_p[_loc7];
+ unsigned int _loc4 = _loc2;
+ #if 0
+ unsigned int _loc8 = _loc4 & 0xff;
+ _loc4 >>= 8;
+ unsigned int _loc9 = _loc4 & 0xff;
+ _loc4 >>= 8;
+ unsigned int _loc10 = _loc4 & 0xff;
+ _loc4 >>= 8;
+ unsigned _loc11 = _loc4 & 0xff;
+ #endif
+ unsigned int _loc8 = _loc4 & 0xff;
+ unsigned int _loc9 = (_loc4 >> 8) & 0xff;
+ unsigned int _loc10 = (_loc4 >> 16) & 0xff;
+ unsigned _loc11 = (_loc4 >> 24) & 0xff;
+ unsigned int _loc5 = out_key_s[0][_loc11] +
+ out_key_s [1][_loc10];
+ _loc5 ^= out_key_s [2][_loc9];
+ _loc5 += out_key_s [3][_loc8];
+ _loc3 ^= _loc5;
+ _loc6 = _loc2;
+ _loc2 = _loc3;
+ _loc3 = _loc6;
+ }
+ _loc6 = _loc2;
+ _loc2 = _loc3;
+ _loc3 = _loc6;
+ _loc3 ^= out_key_p [out_key_n];
+ _loc2 ^= out_key_p [out_key_n+1];
+ cipherInts [i] = _loc2;
+ cipherInts [i+1] = _loc3;
+ }
+ *retCipherInts = cipherInts;
+}
+
+/* int array to hex-encoded string
+ * @param int array
+ * @param size of array
+ * @return string; memory is allocated here, don't forget to free it
+ */
+char *PianoIntsToHexString (unsigned int *arrInts, size_t arrIntsN) {
+ /* 4 bytes as hex (= 8 chars) */
+ char *hexStr = calloc (arrIntsN * 4 * 2 + 1, sizeof (*hexStr));
+ size_t i;
+
+ for (i = 0; i < arrIntsN; i++) {
+ snprintf (hexStr+i*4*2, arrIntsN * 4 * 2 + 1, "%08x", arrInts[i]);
+ }
+ return hexStr;
+}
+
+/* blowfish-encrypt string; used before sending xml to server
+ * @param encrypt this
+ * @return encrypted, hex-encoded string
+ */
+char *PianoEncryptString (char *strInput) {
+ unsigned int *plainInts, *cipherInts;
+ size_t plainIntsN;
+ char *strHex;
+
+ PianoBytesToInts (strInput, &plainInts, &plainIntsN);
+ PianoEncipherInts (plainInts, plainIntsN, &cipherInts);
+ strHex = PianoIntsToHexString (cipherInts, plainIntsN);
+
+ free (plainInts);
+ free (cipherInts);
+
+ return strHex;
+}
diff --git a/libpiano/src/crypt.h b/libpiano/src/crypt.h
new file mode 100644
index 0000000..5b097f1
--- /dev/null
+++ b/libpiano/src/crypt.h
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _CRYPH_H
+#define _CRYPT_H
+
+char *PianoDecryptString (char *strInput);
+char *PianoEncryptString (char *strInput);
+
+#endif /* _CRYPT_H */
diff --git a/libpiano/src/crypt_key_input.h b/libpiano/src/crypt_key_input.h
new file mode 100644
index 0000000..101d382
--- /dev/null
+++ b/libpiano/src/crypt_key_input.h
@@ -0,0 +1,1071 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* decryption key for audio urls; maybe a bit (is) wrong? */
+
+const unsigned int in_key_n = 16;
+
+static const unsigned long in_key_p [16 + 2] = {
+2296512344,
+484947285,
+143549968,
+244631162,
+2837862836,
+4220619567,
+3243088304,
+3951650136,
+2299087613,
+1520074566,
+158025345,
+411178977,
+2673524149,
+2453762392,
+3332626847,
+495515519,
+3311155458,
+682696847};
+
+static const unsigned long in_key_s [4][256] = {{
+2128658832,
+3697692759,
+569211301,
+3742887157,
+3467885802,
+2147119513,
+4192337968,
+3437898897,
+4016418030,
+2157619138,
+583117442,
+401727980,
+3072617582,
+4077876221,
+3671778389,
+2649329515,
+2640655243,
+2071373660,
+4085571303,
+3553863527,
+1133039616,
+3437126533,
+2490500932,
+3370401494,
+1573762703,
+2175142928,
+2392296103,
+3236551751,
+5067846,
+165858937,
+3228665328,
+743820206,
+3002649133,
+59643220,
+2417792365,
+3142818654,
+3427635772,
+933884315,
+3613996694,
+3618979812,
+2360591210,
+1682801625,
+1453625472,
+3456164020,
+879269100,
+328554126,
+2275316178,
+1272030676,
+2500712587,
+749073271,
+3896454727,
+4088023553,
+687999959,
+2469782053,
+3766986318,
+3451556060,
+1754326800,
+2344570827,
+1225379552,
+2644890178,
+4208616430,
+27004362,
+2596728114,
+3890571680,
+2829628313,
+2146575973,
+2604179370,
+875685754,
+3789988084,
+3710311422,
+429817720,
+2489171178,
+2417320237,
+2057030818,
+513667518,
+2609637543,
+3883646020,
+812728312,
+2465864861,
+3479050491,
+3739187534,
+702439720,
+1035737271,
+4260354581,
+3936608854,
+4227404962,
+3051622786,
+2736574401,
+3016354133,
+2400405798,
+2156979612,
+3314004968,
+2051685990,
+19000029,
+2263979164,
+3289285288,
+2054307889,
+3734311294,
+491634325,
+2190156983,
+2148046895,
+3704963939,
+3127900644,
+2980448167,
+1614044505,
+3660721912,
+980501804,
+3968515521,
+3295860462,
+148000610,
+243717540,
+1863084385,
+1451686518,
+1937128161,
+1288731877,
+2328067692,
+2439034247,
+4197306741,
+1938401619,
+2555038861,
+15219513,
+3628919040,
+3510915315,
+1489139789,
+1991410177,
+4187354845,
+225137599,
+2062447135,
+2501882488,
+2480492692,
+567737617,
+1036415794,
+3981376799,
+913768078,
+3065006006,
+1820394782,
+254348814,
+1325117948,
+2909116826,
+2511990395,
+1715211232,
+3189554177,
+3567373216,
+3556507372,
+2262599526,
+693598649,
+1099914476,
+3672117902,
+2638339847,
+3299432663,
+1538274707,
+1268479177,
+201923410,
+3061278922,
+592173100,
+3679063927,
+1977344805,
+213188203,
+1473160814,
+655738293,
+2307755395,
+1102800598,
+1224966405,
+2974183441,
+2587452770,
+3896724147,
+2477674660,
+3932777844,
+2839523899,
+2303064094,
+2319028970,
+3994938371,
+2531716662,
+1149932666,
+2122231008,
+3430946183,
+1123953689,
+3918797176,
+3113636643,
+569397975,
+873251573,
+1006744943,
+2358488303,
+1706139356,
+3748979395,
+2868106633,
+3327350140,
+965732034,
+4203817156,
+1154349457,
+4176400058,
+2506261162,
+3522349991,
+2825760889,
+2975958252,
+3380371122,
+4191046999,
+3067498012,
+2000197545,
+1596105051,
+43102264,
+3960878063,
+2991269966,
+2651508977,
+503441229,
+3370966567,
+4126958357,
+3479998414,
+1663772473,
+4055833092,
+3058057733,
+1519395627,
+4081731088,
+3498430713,
+4087687311,
+1900626065,
+1479961327,
+754122244,
+2327746245,
+22675233,
+927443873,
+2073499140,
+1474870579,
+2638639189,
+1805139553,
+953981772,
+3390679038,
+1167912887,
+95410946,
+648812050,
+3545853366,
+4257643329,
+3476212461,
+4247642195,
+1702876451,
+2551474845,
+4015716228,
+2857099433,
+731476059,
+1034709055,
+189485318,
+706939940,
+2448745741,
+3738990808,
+2158196067,
+272411170,
+2036216135,
+3989855351,
+849465627,
+2117968867,
+4237903689,
+1146595723,
+4164488914,
+3196930194,
+3197964737,
+931629632},
+{3548148628,
+2211365680,
+2089986676,
+1655452034,
+2053784589,
+1508902489,
+1547502091,
+444611061,
+1464377684,
+1323694999,
+2081672378,
+2096063287,
+1954615531,
+2547897755,
+51446746,
+3545549320,
+3792454069,
+2011748624,
+603352473,
+4082037335,
+3248566449,
+1996054105,
+367955388,
+45294088,
+4191310435,
+3560573315,
+2208097136,
+317000604,
+973063857,
+1901052476,
+3594901368,
+2372855512,
+3754787831,
+1249648311,
+1236196835,
+1003906284,
+1584089589,
+1911913406,
+4148522202,
+4117131048,
+464855281,
+57312436,
+4033903816,
+3327693898,
+328640972,
+2473759010,
+656272857,
+3330556738,
+1461007611,
+4149032611,
+389760877,
+167691223,
+465324772,
+3366565279,
+1394746618,
+3064354168,
+587646460,
+1027350944,
+1109309161,
+1888507858,
+2555943894,
+1275409665,
+3956869818,
+2047644060,
+3068621980,
+2124508377,
+1890051703,
+78829997,
+531871861,
+864999736,
+3976110411,
+550237492,
+3644799421,
+963672361,
+2733945391,
+2843027788,
+3240585992,
+329717593,
+2367858037,
+520750960,
+4141805924,
+918099938,
+3102520697,
+2717021903,
+600629173,
+2513538841,
+2432383934,
+1222912227,
+2250136015,
+1948713135,
+3303451350,
+4045419046,
+3737856603,
+1818504227,
+1009479111,
+3646248578,
+3257619203,
+1147482990,
+4107385262,
+2863997375,
+339020927,
+1396395445,
+122111967,
+1785723989,
+1749970671,
+35631032,
+229501423,
+1725806672,
+3827732449,
+2328758187,
+1666770172,
+2201735539,
+2116234489,
+2696008844,
+2750826860,
+2456856093,
+2196939312,
+3967735672,
+3306243803,
+1276372623,
+2299710358,
+2465827193,
+267327425,
+4294932395,
+578153752,
+2087579097,
+848263718,
+1627539853,
+366252371,
+4134377219,
+2567776591,
+1116309489,
+1592683734,
+1135214447,
+4078309104,
+883503540,
+1924140744,
+688979784,
+825732389,
+3771827534,
+181267738,
+3001917334,
+3164692624,
+3534114336,
+774568626,
+1184890620,
+1267945932,
+437602121,
+3742699662,
+2050213757,
+1614127546,
+163079514,
+1753969382,
+119415495,
+1663983235,
+1291217790,
+1366095958,
+1281385911,
+534413482,
+2423430219,
+766473010,
+1036107689,
+3882538353,
+4072983665,
+2120880908,
+2578509329,
+3528269059,
+3019425823,
+2507098354,
+2754316745,
+1302297579,
+3471472873,
+3481343609,
+1110986617,
+3582075135,
+3938075187,
+1835529863,
+114194332,
+780559136,
+1585511111,
+2709377510,
+4663784,
+1983420553,
+1741851203,
+3571748766,
+4159418382,
+2298273138,
+3444544863,
+1646590981,
+4150277106,
+2922217812,
+1591569840,
+2501244910,
+2307277202,
+2486747582,
+4137585745,
+3264322649,
+617810905,
+592289569,
+2957603935,
+1720250393,
+1282606586,
+3978699383,
+3209807216,
+3518166905,
+1471743803,
+3699500250,
+3010910150,
+1141653188,
+3125105165,
+1708028061,
+91863804,
+3079950642,
+1336661688,
+585800731,
+1074729853,
+3353177727,
+2984823139,
+3539233959,
+2168918504,
+3793136000,
+2920883668,
+963999784,
+859512981,
+1285863374,
+1626228743,
+1196896976,
+3246829424,
+2086049373,
+1817626830,
+1917959116,
+1920789886,
+256350158,
+780762582,
+213624274,
+3580963146,
+1783941209,
+3588539293,
+4013209723,
+1482977330,
+74981631,
+559033976,
+2469748467,
+2880298757,
+1099765558,
+981518101,
+3991034119,
+758521765,
+2537136421,
+2024757999,
+1200463233,
+1909122492,
+1302732640,
+1250260811,
+1659083864,
+1287777740},
+{3554236288,
+810416052,
+158802161,
+131289115,
+2593446892,
+990921853,
+88040369,
+3223991913,
+3314506608,
+978106573,
+164800071,
+1122917831,
+3948723682,
+884979134,
+954240927,
+1937491233,
+3177479616,
+3510454307,
+2556095171,
+2095156345,
+2078654475,
+2247021842,
+3261581243,
+3126392505,
+2156995676,
+3163839338,
+2870938297,
+793620229,
+1688422899,
+512503459,
+2068937319,
+1069519665,
+2140042310,
+3631453050,
+4119336486,
+3936344495,
+1966578659,
+3270436351,
+1287213770,
+2499138104,
+1312726036,
+821755190,
+2864942520,
+2022246070,
+1346794584,
+3958680043,
+2898351670,
+2292291399,
+440681239,
+1464442920,
+2295074635,
+2252760328,
+490755791,
+301606609,
+1139180458,
+2816955463,
+1563942872,
+36955748,
+3471174646,
+4103015072,
+2739976564,
+1133336123,
+824381589,
+315115904,
+3583285615,
+1598273833,
+2548883769,
+618878114,
+4030191589,
+925875053,
+4125012162,
+1453444251,
+3684935211,
+4170815349,
+4112292800,
+3897892094,
+3514815579,
+3146810609,
+693096477,
+1806637049,
+1659631547,
+2330028127,
+4286685584,
+4168728225,
+3735359230,
+1236064845,
+1245391878,
+2346463708,
+609365761,
+253579419,
+3740453275,
+3206055112,
+1763220332,
+1154782396,
+1635249739,
+106454628,
+1237878011,
+3960679739,
+1259117609,
+1325699946,
+390092277,
+2014447649,
+1310659372,
+2776516651,
+2445505501,
+1354818074,
+1167516370,
+2429917704,
+3779915141,
+1893127422,
+2330145579,
+1193157505,
+1509056626,
+3153125681,
+1404909737,
+4176954964,
+2943369187,
+3147767230,
+3349110054,
+943888967,
+2421425468,
+865909068,
+3907763794,
+1570630418,
+1473683708,
+1023355763,
+725783349,
+3425397802,
+2607056779,
+2248801744,
+739959172,
+1925660432,
+3214198318,
+1841031619,
+4141680013,
+4210070222,
+3152438583,
+3667048743,
+4281076589,
+3634719715,
+945809397,
+2561946849,
+1225545006,
+3306764442,
+3409589233,
+1598008340,
+3831187310,
+1733352819,
+932119442,
+3082624907,
+1422551176,
+2766356888,
+819609813,
+3288351621,
+1230545957,
+680725051,
+977757332,
+2721303922,
+440647377,
+3207512234,
+1130262272,
+2587644460,
+2563067841,
+681411150,
+4115404362,
+1110175982,
+3158946095,
+643581087,
+110203798,
+2836680784,
+1488118585,
+4070154931,
+2991733788,
+4119545618,
+948002949,
+3109157700,
+897958133,
+169664173,
+733813972,
+1982075210,
+1205004562,
+375168004,
+2810680328,
+2246661195,
+2809488804,
+1054033161,
+3346180847,
+3943569363,
+2728441744,
+844689912,
+2821295363,
+907982464,
+2715150073,
+3800824232,
+1719926814,
+2155188792,
+2709493441,
+1938625885,
+2114268368,
+466087366,
+2409883443,
+2025557853,
+1344441334,
+3617674189,
+817973227,
+1955080900,
+2845524782,
+3745246674,
+2632253171,
+1257730466,
+2040723666,
+2708337140,
+543947183,
+1488485060,
+292373701,
+491952464,
+2057755552,
+3400090358,
+1900715831,
+3612192944,
+1987004224,
+3567497054,
+878496315,
+1604053755,
+1176518849,
+2279327360,
+1748284085,
+303657754,
+2782089490,
+506128051,
+1614889427,
+2801053043,
+1202125863,
+1360990060,
+3802296025,
+879327051,
+2871259251,
+2348346866,
+3233806136,
+3311161207,
+1838180420,
+544662648,
+1972132486,
+3765637101,
+3464671957,
+2834850978,
+4022703989,
+3719086717,
+3051662122,
+1658462487,
+3404201395,
+2558383819,
+401622436,
+4158099338,
+3191926275,
+3900648207},
+{2906980109,
+3244040462,
+3842009756,
+4177586565,
+3128780359,
+389257510,
+1433826605,
+3239482476,
+2804682224,
+1095312530,
+4264552109,
+500527977,
+320084931,
+3448532078,
+87643447,
+1233852435,
+3799263706,
+849541286,
+3654913140,
+1720613777,
+1204288368,
+3558012178,
+1852713204,
+2991301237,
+712827210,
+512347544,
+2209552811,
+2380728472,
+2061298391,
+1187415824,
+4154911301,
+4057990159,
+2349469378,
+2545159130,
+1775747174,
+2591410713,
+2229519704,
+4057763051,
+34983877,
+2018348659,
+3051995695,
+2099457161,
+122176200,
+3614959731,
+1011099307,
+2707461689,
+2710657949,
+1519288114,
+297037952,
+350201262,
+511044781,
+1108019973,
+3101610154,
+3969643310,
+997019662,
+1683546324,
+1465743109,
+358651173,
+4222805613,
+268914497,
+652780242,
+3508590503,
+414591203,
+3313257121,
+2605462681,
+1291711251,
+2142143497,
+2733700582,
+3268848903,
+1669040160,
+3061666233,
+2897555767,
+3277977602,
+218193538,
+551879950,
+2651413813,
+1304346475,
+1672107670,
+1251053219,
+57431126,
+1608803694,
+1191480742,
+904537817,
+645123498,
+3097150410,
+2924217906,
+611983353,
+2293480932,
+2034270664,
+986691666,
+741722320,
+3726624549,
+1403284782,
+616727866,
+3292944289,
+1733282574,
+3943960954,
+892568249,
+1602920243,
+2055039837,
+1121174416,
+1554530122,
+1969210884,
+1627002077,
+255323245,
+659290392,
+413679961,
+3355601324,
+853401555,
+1923886853,
+1911568009,
+275978186,
+4110789833,
+3785826431,
+1880789664,
+1834557896,
+3185455839,
+4112428490,
+1909962454,
+901840141,
+1702581561,
+930703993,
+544235727,
+1917462098,
+3576405067,
+2313599093,
+3209909484,
+1078722592,
+2300716722,
+488195978,
+843151466,
+1885259855,
+2660301574,
+2493041758,
+3885484332,
+3596373427,
+4091285124,
+18165664,
+2851846839,
+2066994388,
+3779380391,
+1638886162,
+1203036700,
+3207436785,
+3839055612,
+992380467,
+1617890949,
+3271283843,
+1985171789,
+1589586926,
+59295131,
+2201447571,
+1802886001,
+1524685393,
+1619130887,
+4277411271,
+1632946657,
+916420718,
+1988186984,
+1087584352,
+328546419,
+699568195,
+752262087,
+2593455512,
+2054325461,
+224511444,
+1937218889,
+4177808215,
+3674484078,
+2202083318,
+1662921402,
+431990019,
+3263118914,
+1513147185,
+3599292635,
+1667827679,
+4194190277,
+2902980642,
+1527280030,
+2323092096,
+3686881320,
+1844238265,
+234981319,
+3601863066,
+3591054018,
+1245988708,
+1982786555,
+3217502413,
+2338410264,
+1184032842,
+686321676,
+2833157096,
+3648900116,
+3352580660,
+2473019798,
+2877120488,
+4117315385,
+105188436,
+3682865154,
+923331766,
+858955270,
+2848822230,
+1157150450,
+2597825900,
+3704699325,
+1687529016,
+2601511833,
+3714180651,
+788566728,
+3803114264,
+2289638900,
+931304621,
+2478429664,
+942053111,
+2072299200,
+1527540710,
+1639028869,
+4075126463,
+2520412384,
+2832409251,
+2538838994,
+523574607,
+99984740,
+1238458557,
+566420211,
+1326154395,
+3447105210,
+4266037523,
+2847987284,
+3693440980,
+1764601394,
+4086197753,
+3561101407,
+1750462971,
+3195538424,
+962192249,
+232305254,
+4054331716,
+2477415058,
+3576429591,
+2979101766,
+2766793053,
+3112000711,
+3423119961,
+357902640,
+1320412483,
+2720212787,
+1427733989,
+99871163,
+1794019431,
+1332239274,
+653929270,
+3402307422,
+1010543326,
+3438754380,
+3221207255}};
diff --git a/libpiano/src/crypt_key_output.h b/libpiano/src/crypt_key_output.h
new file mode 100644
index 0000000..5bafaf5
--- /dev/null
+++ b/libpiano/src/crypt_key_output.h
@@ -0,0 +1,1076 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* encryption key for xmlrpc */
+
+#ifndef _CRYPT_H
+#define _CRYPT_H
+
+const unsigned int out_key_n = 16;
+
+static const unsigned long out_key_p [16 + 2] = {
+1655854977,
+919004318,
+2043595880,
+23762164,
+-1305147675,
+-215967440,
+835493487, /* ! */
+261889135, /* ! */
+987405585,
+-122581809,
+8882411,
+875817828, /* ! */
+466417059,
+-544099275,
+-1525766406,
+-1945723444,
+536361814,
+-1487225158};
+
+static const unsigned long out_key_s [4][256] = {{
+-513813079,
+-765782257,
+183159219,
+-1365669178,
+1047088991,
+222171688,
+-2090853737,
+-765179426,
+997050138,
+-2057228390,
+-1628206499,
+-1408898308, /* ! */
+-588637121,
+1846207300,
+2065654413,
+-412282565, /* ! */
+-1421690766,
+1839083055,
+1892832522,
+-1919151611,
+-1767698857,
+1341672799,
+-255927541,
+726598137,
+1990634699,
+464663677,
+-904351607, /* ! */
+1970163162,
+-792713214,
+-475806450, /* 47 */
+1950400144,
+-262078895,
+-761022537,
+-667642993,
+312735385,
+-34426203,
+1832569587,
+-1684213010, /* ! */
+634837297,
+-1948396026,
+-604405134,
+-691056861,
+988289742,
+-1839385794,
+2062571691,
+297518815,
+-888607360,
+-511051809,
+701070684,
+-1998977035, /* ! */
+1553720912,
+-1604313120,
+-1754421883,
+1603596992, /* ! */
+1928276512,
+-943968281,
+1944528438,
+589172448,
+1447396119,
+694763397, /* ! */
+2082830654, /* ! */
+553534140,
+1553843344, /* ! */
+-1667538856,
+-2018018024,
+1501396120,
+1234751004,
+1067889147,
+-1123200064, /* ! */
+-2044106955,
+2086877862,
+1976886420,
+38662426,
+-104788291,
+-2117573866,
+663013564,
+-996232851, /* ! */
+1102290631, /* 95 */
+-740244768,
+-1151084003, /* ! */
+1942342365,
+-21446148,
+593950808, /* ! */
+-704678316,
+882519192,
+-1705861753,
+1535663280,
+-955682427,
+490241188,
+-2045390075,
+-1740044623, /* ! */
+-560660930, /* ! */
+-397891080,
+-646170301, /* ! */
+486316357,
+1043377519,
+-1352836022, /* ! */
+963270259,
+1208484782,
+-1946438033,
+-1672860695,
+-2047609127,
+-2066653853,
+882790375,
+-1651671083,
+-1390467297,
+947685781,
+943582655, /* ! */
+993804347,
+-669445900, /* ! */
+1033242534,
+1947027902,
+2123227639,
+-1374249331, /* ! */
+559160429,
+802992266,
+-443557517,
+-1689158322,
+1902902596,
+1955321636,
+75631,
+-1420670840,
+-2016287362,
+-1445425632,
+-420570310, /* ! */
+-354654912, /* 143 */
+-1972668301,
+653997721, /* ! */
+452795541,
+-66510820,
+-1862128475,
+-1327921414,
+1708518909,
+15711562, /* ! */
+1721321276,
+-1394169533,
+373602900,
+2099511181, /* ! */
+2078960031, /* ! */
+-1504406862,
+-1849228115, /* ! */
+-1767469541,
+-1599186379,
+772444871,
+918597368, /* ! */
+-937045004,
+-712386722,
+-904126536,
+-1318252653,
+-450264842, /* ! */
+1826831532, /* ! */
+-958506776,
+2050742404,
+2050686251,
+-154637178,
+481081149,
+1114171521,
+-1904274054,
+1419437721,
+693681474,
+1890059780,
+-1575700716,
+-656873177,
+490233525,
+-526894138,
+1682076343,
+-781336395,
+816523260,
+2048253734,
+1527924261,
+-1254019825,
+-1450610880,
+1819678767,
+1741799953, /* 191 */
+812933538, /* ! */
+250020223,
+-588621470,
+-586042668, /* ! */
+303595274,
+-736731322,
+-1042514938,
+2056265092,
+590811071,
+-2076239761,
+1536040004,
+526821270,
+-809199490,
+826044521,
+-639982281,
+575323029,
+-370506263, /* ! */
+-749572018,
+2087094581,
+587374721,
+552065397, /* ! */
+149358673,
+786310855,
+-167069507,
+-1875132152,
+1022462681,
+129236467,
+-1087026086,
+1856839244, /* ! */
+1328124015,
+1731045631, /* ! */
+-1648761702,
+-2049695288,
+-701165592,
+-329506427, /* ! */
+-925003291,
+-721052514,
+1651606994, /* ! */
+-1211116030,
+1210824470, /* ! */
+1625998108, /* ! */
+173453468,
+-558787357, /* ! */
+-1398935598,
+1207642912,
+-1044964430,
+1054695311,
+-532066592, /* 239 */
+-261141564,
+-1493815133, /* ! */
+-161866707,
+-1721246338,
+-477625609,
+133205312,
+1987497710,
+-1339095630,
+1043463425,
+-1843491306, /* ! */
+543431533,
+-257519406, /* ! */
+1302076883,
+127797200,
+-1975436180,
+1034932095, /* ! */
+-1868206592, /* ! */
+-1696244482,
+1998241908,
+1099342102,
+900741619, /* ! */
+1370202513, /* ! */
+-627586602,
+1075779902,
+-800694166,
+2047880971, /* ! */
+757977382,
+-737442507,
+763877853,
+837154760, /* ! */
+-1361839879,
+1697214753,
+-1169239768,
+-2088855814},
+{1629020117,
+922095353,
+504197536, /* ! */
+954775243,
+120145635, /* ! */
+-579060756,
+-519454323,
+73872886,
+-557968095,
+410158880,
+-67682390, /* ! */
+2136179483,
+113474032,
+936282950, /* 287 */
+1835643417, /* ! */
+-425487382,
+2010519404,
+-837248632,
+-1592374918,
+-1308567382,
+-768768095,
+-935042502,
+-1467653241,
+101884394,
+1185880783,
+-2128586097,
+2058885475,
+-296250734,
+2137323390,
+1125638684,
+1529361514,
+-1107789882,
+-782194686,
+1311102644,
+-19347165, /* ! */
+1295250024,
+627682341,
+1409475839,
+1718747575,
+1534390947,
+1253718782, /* ! */
+1169937313,
+1521291895,
+1265721067,
+563973947,
+-1270523181,
+1493641800,
+422652537,
+153943244,
+491686725,
+53879678, /* ! */
+-403818722,
+-501153969,
+411423572,
+964839170,
+-798731292,
+191704494, /* ! */
+-1942882791, /* ! */
+247351225,
+-1147871801,
+991063408,
+2078916385, /* 335 */
+-409571302, /* ! */
+-1940714758,
+-1635967463,
+380126381,
+-1480405811,
+-111862091,
+798808002,
+1846690607,
+1161223894,
+-840749709,
+1757844636,
+1919227953,
+1396721207,
+-841099775, /* ! */
+1457173961,
+269317440, /* ! */
+2076729104,
+1669595361,
+-406583178,
+1213054918,
+2137223591,
+-408202097,
+-1602785642,
+-1642508502,
+2059883563,
+963377666,
+-1730998307,
+990959345, /* ! */
+-1662041039,
+1184415790,
+-1800589468, /* ! */
+1191574841,
+2066827079,
+1565744467, /* ! */
+-1982705060,
+1003114192,
+431969651,
+2118380916,
+1762711765, /* ! */
+-1288938317,
+-1853007890, /* ! */
+1365304189,
+-1249405781,
+-843409397,
+-2121756142, /* ! */
+1763447208,
+1707589958,
+2025386815, /* 383 */
+1264619878,
+1975513356,
+-506432955,
+-339393069,
+-715206660,
+-1014927581,
+-2017612850,
+1645137307,
+1335624819, /* ! */
+-1383696066,
+-216010255,
+-937606920,
+1953828927, /* ! */
+1100215538,
+-1844619416,
+975828407,
+1987251605,
+1299855611,
+755596177, /* ! */
+-926025603, /* ! */
+307698060,
+-819390822,
+138444246, /* ! */
+-1330460178, /* ! */
+-295935330,
+-668410217,
+216808357,
+-192442834, /* ! */
+1944707886,
+683076481,
+-1879751421,
+1560771135,
+886165615,
+-971369067,
+-179874281,
+-1780972412, /* ! */
+1551477128,
+124161839,
+638318309,
+-793030002,
+-303257131, /* ! */
+913110130,
+-1563131354,
+-1152927828,
+58544864,
+-666588206, /* ! */
+-2025777247,
+1410656413, /* 431 */
+1133449775,
+1776814160,
+-1202000308,
+-1587468692,
+764233611,
+-404082071,
+1418515926,
+-250996474,
+1606154972,
+-1042368908,
+-960300962,
+163193207,
+2109826396,
+310314579, /* ! */
+-656998654,
+-2120731499,
+398720860,
+1102716052,
+-1232677915,
+513056809, /* ! */
+-1517523318,
+-1907107147,
+5008204,
+-388009951, /* ! */
+145362986,
+2001293342,
+-313996635,
+1696291650,
+-468561025,
+-620682907,
+-487614562,
+185707581,
+542653640,
+1843380185,
+1071686700,
+-278346004,
+-1874035140,
+1769296035, /* ! */
+823654751,
+-1141322049,
+770471852,
+-1174632118,
+-1380529665,
+-356118263,
+369984285,
+-993721262,
+2078447917,
+-1905514517, /* 479 */
+438882915,
+-1866080467,
+-1965418802,
+785895483,
+856543611,
+2115038375,
+1562771728,
+158744776,
+740212411, /* ! */
+-1753064584,
+-347114853,
+-679343665,
+-1677363466,
+-776711069,
+146507865,
+1433561752,
+1484718853, /* ! */
+2068007340,
+1673669650,
+2034888177,
+-1427667267,
+1725314550,
+-745227351,
+-510153416,
+1812096408,
+-769448952,
+724796919,
+-1641705060, /* ! */
+-187715871,
+-1993150269,
+-1951578846,
+-1566737172, /* ! */
+-695189052,
+-1557626854,
+278291124,
+-207619058,
+892260834,
+-217735893,
+1437921610, /* ! */
+-1331483695,
+1629715297,
+1609637755,
+-1299672728, /* ! */
+2024824922,
+1141063060, /* ! */
+-1593362831,
+-406554816,
+-2065662630, /* 527 */
+-224474689,
+1957733334},
+{530839846,
+-1871368488,
+722209002, /* ! */
+-1494427347,
+283456798,
+-1991074430,
+-1437368661, /* ! */
+1393643393,
+1884233053, /* ! */
+316592593, /* ! */
+-1633634175,
+67711552,
+-1532028936, /* ! */
+-28150029,
+204892734,
+-626897753,
+-1702641288,
+1473684453, /* ! */
+847362557,
+-1079059160,
+-19386413,
+-1492891500,
+-1231328909,
+-1172519719,
+733310353,
+1030660013,
+562154443,
+1484588979,
+413427779,
+-1254045512,
+1581815858,
+1647037953, /* ! */
+-1864688004, /* ! */
+-594840704,
+1714355138,
+1910977695, /* ! */
+-869823320,
+-1594092636,
+-949905272,
+1872451812,
+1724295091,
+1473849446,
+-467809334,
+-872003011,
+957920643,
+-1658925668, /* ! */ /* 575 */
+-1014830365,
+2041534498,
+-1289170570,
+-314708652,
+-14928717, /* ! */
+594597886,
+606588791,
+-294691293,
+-1652089121, /* ! */
+1353100923,
+-376999554, /* ! */
+-1606083711,
+1964831987, /* ! */
+1284324098,
+946571071,
+-236835181, /* ! */
+1826868670, /* ! */
+-628576385,
+353949044,
+-1383415207,
+-442241461,
+1210088326,
+-1861213995,
+2026802836,
+-775203988,
+213100962,
+1303937343,
+1886697286,
+-853503936,
+22916867,
+347578369,
+458151896, /* ! */
+893076939,
+752142338,
+-51154144,
+698477494,
+2085285200,
+-1415936037,
+-1477954736,
+238866470, /* ! */
+364867055, /* ! */
+1969690005,
+1464856701,
+-221777765, /* ! */
+1766279956,
+926079829,
+-2128722228,
+1464323667, /* 623 */
+-468389908,
+-1102371895,
+-626360488,
+1493866378,
+1382411426,
+1373259629, /* ! */
+-1516263679,
+-2036634017, /* ! */
+-454735742,
+-461817920,
+1678767014,
+682280596,
+-1933839848,
+1867889900, /* ! */
+1536263691,
+1512429242,
+1233608153,
+1055317390,
+1481821303,
+-1545547500,
+-474961387,
+-1325240485,
+727223122, /* ! */
+666049219,
+1466147771,
+-978190400,
+-984951028,
+137279631,
+828970652,
+1470706108,
+1240031461,
+339800793, /* ! */
+-1772684179,
+1005013651, /* ! */
+-893710369,
+2713655,
+-831673471, /* ! */
+560401867,
+1193286576,
+2012625949,
+-1385481301,
+690693520,
+450434938, /* ! */
+6859662,
+-1695312035,
+-470768530,
+-1735583840,
+1551947458, /* 671 */
+-23903826, /* ! */
+-272927289,
+1457836440,
+-549340909,
+340129861,
+1448426993, /* ! */
+1720095155, /* ! */
+289970191,
+609452121,
+-1134964683, /* ! */
+2130731381,
+661512363,
+1034545082,
+1645695279, /* ! */
+-592416413,
+1464654292,
+314520845,
+-1293877797,
+-943133768,
+2135092525,
+-339166461,
+-1468607841,
+2119446364,
+-1873255440,
+-372270913,
+287916301,
+-55366124,
+-1194267973,
+1116182918,
+1905595606, /* ! */
+-1948425343,
+-1664638428,
+-818329511,
+469058705,
+-2055526656, /* ! */
+-251951159,
+463740098,
+-1736727888, /* ! */
+893359773, /* ! */
+-932042121,
+342343504,
+-29499057,
+1590216069,
+1274735907,
+-1960711099,
+-1127741069,
+122033645,
+2128542502, /* 719 */
+-81160273,
+519927763, /* ! */
+-1307524253,
+-482965142,
+-1875812682,
+-288813376,
+1790354532,
+-1951270944,
+-524755692, /* ! */
+1014821076,
+-786978547,
+-1503715841,
+-2119099811,
+-178066143,
+-328007828,
+-1411219934,
+1027907211,
+1561637548,
+-1472328906,
+110611707,
+1896384984,
+-1646981054, /* ! */
+-1588084855,
+-2134248380,
+-905796293,
+-56029556,
+-2117775674,
+-1582683057,
+615719466,
+384957578,
+1188945602,
+-1184220203,
+-6033762,
+2003966672,
+1510414055, /* ! */
+-2049998746,
+386408271,
+1961250254,
+1424350579,
+-858634167,
+213880883,
+-1007779050,
+2026561215,
+259490021,
+-797084108,
+1460692963,
+1525331451,
+1370262182, /* ! */ /* 767 */
+293318673,
+544808302,
+920263177,
+103655446, /* ! */
+-1431460277,
+-1803600980, /* ! */
+-1505376616,
+257291575,
+1208290601,
+1859852686,
+69613997,
+-1234549782,
+-1423238393, /* ! */
+711158442,
+218702758,
+48671031,
+1561531785,
+549682762},
+{1722841024, /* ! */
+1678073353,
+-614334879,
+-1261051299,
+778307565,
+1683919416,
+-606372214,
+890910445,
+-1519602957,
+422817018,
+-985731497,
+-399348512, /* ! */
+-1730647324,
+-1099955160,
+-1930459907,
+-2018277684,
+-1196489861,
+1513840148,
+1886456409,
+838084158,
+1913826009,
+-142146436, /* ! */
+-413218814,
+565709772,
+204821326,
+-1548350062,
+1881270649,
+-1176661609,
+655405327,
+1449467372, /* ! */ /* 815 */
+1721788626,
+-854013850,
+-899192508,
+-360793273,
+867045638,
+-1591438706,
+-1195082927,
+2094926826,
+1928537063, /* ! */
+792539387, /* ! */
+1767255387,
+1983283598,
+-358435631,
+-779393177,
+-1086267881,
+-1549436626,
+-1582534409,
+1051799914,
+-245143042,
+-1918223607,
+-11193281,
+1001934263, /* ! */
+-73506240, /* ! */
+1279486962,
+-937898593,
+265050536,
+-2052831146,
+-2116298214,
+676055329,
+1320971350,
+60112790, /* ! */
+-1111508310, /* ! */
+691496339,
+-1289734630,
+1672957635,
+1828477688,
+2055454618,
+-497831808,
+-1032041626,
+1974291279,
+146836556,
+-367217667,
+-719016930,
+-894795368,
+400656073,
+-551206802,
+71329459, /* ! */
+955057240, /* ! */ /* 863 */
+-842425766,
+-938155869,
+-461082201,
+-89628848,
+-719614551, /* ! */
+851389605,
+1710650519,
+1929871027,
+2138521733,
+1395635780,
+1378055652, /* ! */
+234386875,
+230019956,
+-2105283931,
+-418953863,
+556294611,
+1790257504,
+-11582813,
+-795597470,
+907791823, /* ! */
+-36926894,
+-1078349178,
+1632571284,
+1085203308, /* ! */
+-2102060924,
+-353799919, /* ! */
+-511810872,
+1217595593,
+315762222,
+664567993,
+-620935514,
+1760697749,
+-150531764,
+-906315733, /* ! */
+966756585,
+2143511316,
+829751318,
+-645111024,
+-750227043,
+914171901, /* ! */
+-326094853,
+-4718658,
+176409364, /* ! */
+-453628962,
+1015428453,
+-950961455, /* ! */
+-1929004703,
+-1979218629, /* 911 */
+-386687514,
+-809528953,
+-1315642451,
+519041810,
+1296778479,
+-1396513598,
+338706908,
+1972031445,
+-479710299, /* ! */
+-514326614,
+-95378821,
+1012441438,
+-1770114023,
+1966997515,
+-431195712,
+-195630652,
+-1805137610,
+-878196189,
+1305117064,
+-201378838,
+45814250,
+1582855393, /* ! */
+1051694644,
+-118080464,
+842639867, /* ! */
+964643756, /* ! */
+-810650327,
+2103445589,
+-1435798060,
+1611948935,
+-2013661703,
+1773966623,
+1264748971,
+-53913554,
+-1910238305,
+59625376, /* ! */
+129956518,
+1806897494,
+1746354391,
+765642861,
+945168608,
+-1084123694,
+470467004,
+-285404973,
+-273067374,
+-379320221,
+469476951,
+891590085, /* 959 */
+484100235,
+-1507959076, /* ! */
+1604199464,
+423268838,
+488586602,
+930867807,
+-242676590, /* ! */
+-54340460,
+1075848084,
+-1939665362,
+589512753,
+205813722,
+-46146582, /* ! */
+-797260050, /* ! */
+224571541,
+-1212320744,
+1738238306,
+-444589,
+2005858805,
+2003218491,
+638371325,
+256246972,
+1793131025, /* ! */
+-707291882,
+-1151592902,
+363764911, /* ! */
+1777326955,
+-757008613,
+-2006058918, /* ! */
+-946044045,
+-1781443141,
+-1007568595,
+-661476356,
+203874992,
+663304469,
+-563792643,
+1058896789,
+-1700207594,
+-1838678505,
+816281610,
+783051130,
+244431728,
+26999557,
+-400433464,
+2036402176, /* ! */
+1461934271,
+1431750752, /* ! */
+557152328, /* 1007 */
+336682025,
+-188192101, /* ! */
+-1029579530,
+1537018210, /* ! */
+355741330,
+-913772271,
+-573111973,
+1332856894, /* ! */
+-463998480,
+1095506380,
+-1372153732,
+-1070918314,
+1176314092,
+-1513258489,
+2134865852,
+-1080957377,
+-1538012438,
+-238348645,
+730779314,
+1576034869,
+638655973,
+-1293620774,
+-1041456218,
+-1532623621,
+-360700565,
+2018940370,
+-706509096,
+-1761858993, /* ! */
+566171489, /* ! */
+-2101362137,
+548160877,
+1587887228, /* ! */
+1708148227,
+-928571626}};
+
+#endif /* _CRYPT_H */
diff --git a/libpiano/src/http.c b/libpiano/src/http.c
new file mode 100644
index 0000000..ee63fef
--- /dev/null
+++ b/libpiano/src/http.c
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "const.h"
+#include "http.h"
+
+
+/* FIXME: curl has a receive limit, use it! */
+/* callback for curl, writes data to buffer
+ * @param received data
+ * @param block size
+ * @param blocks received
+ * @param write data into this buffer
+ * @return written bytes
+ */
+size_t PianoCurlRetToVar (void *ptr, size_t size, size_t nmemb, void *stream) {
+ char *charPtr = ptr;
+ char *streamPtr = stream;
+
+ if (strlen (streamPtr) + nmemb > PIANO_HTTP_BUFFER_SIZE) {
+ printf ("buffer overflow...\n");
+ return 0;
+ } else {
+ memcpy (streamPtr+strlen(streamPtr), charPtr, size*nmemb);
+ return size*nmemb;
+ }
+}
+
+/* FIXME: we may use a callback given by the library client here. would be
+ * more flexible... */
+/* post data to url and receive answer as string
+ * @param initialized curl handle
+ * @param call this url
+ * @param post this data
+ * @param put received data here, memory is allocated by this function
+ * @return nothing yet
+ */
+void PianoHttpPost (CURL *ch, char *url, char *postData, char **retData) {
+ struct curl_slist *headers = NULL;
+ /* Let's hope nothing will be bigger than this... */
+ char curlRet[PIANO_HTTP_BUFFER_SIZE];
+
+ headers = curl_slist_append (headers, "Content-Type: text/xml");
+
+ curl_easy_setopt (ch, CURLOPT_URL, url);
+ curl_easy_setopt (ch, CURLOPT_POSTFIELDS, postData);
+ curl_easy_setopt (ch, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt (ch, CURLOPT_WRITEFUNCTION, PianoCurlRetToVar);
+ /* don't verify certificate for now, it's easier ;) */
+ curl_easy_setopt (ch, CURLOPT_SSL_VERIFYPEER, 0);
+ memset (curlRet, 0, sizeof (curlRet));
+ curl_easy_setopt (ch, CURLOPT_WRITEDATA, curlRet);
+
+ curl_easy_perform (ch);
+
+ curl_slist_free_all (headers);
+
+ *retData = calloc (strlen (curlRet) + 1, sizeof (char));
+ strcpy (*retData, curlRet);
+}
diff --git a/libpiano/src/http.h b/libpiano/src/http.h
new file mode 100644
index 0000000..87dc49c
--- /dev/null
+++ b/libpiano/src/http.h
@@ -0,0 +1,28 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+void PianoHttpPost (CURL *ch, char *url, char *postData, char **retData);
+
+#endif /* _HTTP_H */
diff --git a/libpiano/src/main.c b/libpiano/src/main.c
new file mode 100644
index 0000000..95adc48
--- /dev/null
+++ b/libpiano/src/main.c
@@ -0,0 +1,465 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <curl/curl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "const.h"
+#include "main.h"
+#include "piano.h"
+#include "http.h"
+#include "xml.h"
+#include "crypt.h"
+
+/* initialize piano handle, set up curl handle and settings; note: you
+ * _must_ init curl and libxml2 using curl_global_init (CURL_GLOBAL_SSL)
+ * and xmlInitParser (), you also _must_ cleanup their garbage on your own!
+ * @param piano handle
+ * @return nothing
+ */
+void PianoInit (PianoHandle_t *ph) {
+ memset (ph, 0, sizeof (*ph));
+ ph->curlHandle = curl_easy_init ();
+ /* FIXME: 64-bit may make this hack useless */
+ snprintf (ph->routeId, sizeof (ph->routeId), "%07liP", time (NULL)>>8);
+ /* at the moment we don't need publicity */
+ curl_easy_setopt (ph->curlHandle, CURLOPT_USERAGENT, PIANO_USERAGENT);
+}
+
+/* free complete search result
+ * @public yes
+ * @param search result
+ */
+void PianoDestroySearchResult (PianoSearchResult_t *searchResult) {
+ PianoArtist_t *curArtist, *lastArtist;
+ PianoSong_t *curSong, *lastSong;
+
+ curArtist = searchResult->artists;
+ while (curArtist != NULL) {
+ free (curArtist->name);
+ free (curArtist->musicId);
+ lastArtist = curArtist;
+ curArtist = curArtist->next;
+ memset (lastArtist, 0, sizeof (*lastArtist));
+ free (lastArtist);
+ }
+
+ curSong = searchResult->songs;
+ while (curSong != NULL) {
+ free (curSong->title);
+ free (curSong->artist);
+ free (curSong->musicId);
+ lastSong = curSong;
+ curSong = curSong->next;
+ memset (lastSong, 0, sizeof (*lastSong));
+ free (lastSong);
+ }
+}
+
+/* free single station
+ * @public yes
+ * @param station
+ */
+void PianoDestroyStation (PianoStation_t *station) {
+ free (station->name);
+ free (station->id);
+ memset (station, 0, sizeof (station));
+}
+
+/* free complete station list
+ * @param piano handle
+ */
+void PianoDestroyStations (PianoHandle_t *ph) {
+ PianoStation_t *curStation, *lastStation;
+
+ curStation = ph->stations;
+ while (curStation != NULL) {
+ lastStation = curStation;
+ curStation = curStation->next;
+ PianoDestroyStation (lastStation);
+ free (lastStation);
+ }
+ ph->stations = NULL;
+}
+
+/* FIXME: copy & waste */
+/* free _all_ elements of playlist
+ * @param piano handle
+ * @return nothing
+ */
+void PianoDestroyPlaylist (PianoHandle_t *ph) {
+ PianoSong_t *curSong, *lastSong;
+
+ curSong = ph->playlist;
+ while (curSong != NULL) {
+ free (curSong->audioUrl);
+ free (curSong->artist);
+ free (curSong->focusTraitId);
+ free (curSong->matchingSeed);
+ free (curSong->musicId);
+ free (curSong->title);
+ free (curSong->userSeed);
+ lastSong = curSong;
+ curSong = curSong->next;
+ memset (lastSong, 0, sizeof (*lastSong));
+ free (lastSong);
+ }
+ ph->playlist = NULL;
+}
+
+/* frees the whole piano handle structure; this will _not_ cleanup curl's
+ * internal garbage, you have to call curl_global_cleanup () and
+ * xmlCleanupParser () for libxml2
+ * @param piano handle
+ * @return nothing
+ */
+void PianoDestroy (PianoHandle_t *ph) {
+ curl_easy_cleanup (ph->curlHandle);
+ /* FIXME: only free if pointer != NULL */
+ free (ph->user.webAuthToken);
+ free (ph->user.authToken);
+ free (ph->user.listenerId);
+
+ PianoDestroyStations (ph);
+ PianoDestroyPlaylist (ph);
+ memset (ph, 0, sizeof (*ph));
+}
+
+/* authenticates user
+ * @param piano handle
+ * @param username (utf-8 encoded)
+ * @param password (plaintext, utf-8 encoded)
+ * @return nothing
+ */
+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",
+ ph->routeId);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ free (requestStr);
+ free (retStr);
+
+ /* authenticate */
+ snprintf (requestStrPlain, sizeof (requestStrPlain),
+ "<?xml version=\"1.0\"?><methodCall>"
+ "<methodName>listener.authenticateListener</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "</params></methodCall>", time (NULL), user, password);
+ requestStr = PianoEncryptString (requestStrPlain);
+ snprintf (url, sizeof (url), PIANO_SECURE_RPC_URL "rid=%s"
+ "&method=authenticateListener", ph->routeId);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ ret = PianoXmlParseUserinfo (ph, retStr);
+
+ free (requestStr);
+ free (retStr);
+
+ return ret;
+}
+
+/* get all stations for authenticated user (so: PianoConnect needs to
+ * be run before)
+ * @param piano handle filled with some authentication data by PianoConnect
+ * @return nothing
+ */
+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>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken);
+ requestStr = PianoEncryptString (xmlSendBuf);
+ snprintf (url, sizeof (url), PIANO_RPC_URL
+ "rid=%s&lid=%s&method=getStations", ph->routeId,
+ ph->user.listenerId);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ ret = PianoXmlParseStations (ph, retStr);
+ free (retStr);
+ free (requestStr);
+
+ return ret;
+}
+
+/* get next songs for station (usually four tracks)
+ * @param piano handle
+ * @param station id
+ * @return nothing yet
+ */
+void PianoGetPlaylist (PianoHandle_t *ph, char *stationId) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+
+ /* FIXME: remove static numbers */
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>playlist.getFragment</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>15941546</string></value></param>"
+ "<param><value><string>181840822</string></value></param>"
+ "<param><value><string></string></value></param>"
+ "<param><value><string></string></value></param>"
+ "<param><value><string>aacplus</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ stationId);
+ requestStr = PianoEncryptString (xmlSendBuf);
+ snprintf (url, sizeof (url), PIANO_RPC_URL
+ "rid=%s&lid=%s&method=getFragment&arg1=%s&arg2=15941546"
+ "&arg3=181840822&arg4=&arg5=&arg6=aacplus", ph->routeId,
+ ph->user.listenerId, stationId);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ PianoXmlParsePlaylist (ph, retStr);
+ free (retStr);
+ free (requestStr);
+}
+
+/* love or ban track (you cannot remove your rating, so PIANO_RATE_NONE is
+ * not allowed)
+ * @public yes
+ * @param piano handle
+ * @param track will be added to this stations loved tracks list
+ * @param rate this track
+ * @param your rating
+ * @return value from return enum
+ */
+PianoReturn_t PianoRateTrack (PianoHandle_t *ph, PianoStation_t *station,
+ PianoSong_t *song, PianoSongRating_t rating) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+ PianoReturn_t ret = PIANO_RET_ERR;
+
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>station.addFeedback</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><boolean>%i</boolean></value></param>"
+ "<param><value><boolean>0</boolean></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ station->id, song->musicId, song->matchingSeed, song->userSeed,
+ /* sometimes focusTraitId is not set, dunno why yet */
+ (song->focusTraitId == NULL) ? "" : song->focusTraitId,
+ (rating == PIANO_RATE_LOVE) ? 1 : 0);
+ requestStr = PianoEncryptString (xmlSendBuf);
+ snprintf (url, sizeof (url), PIANO_RPC_URL
+ "rid=%s&lid=%s&method=addFeedback&arg1=%s&arg2=%s"
+ "&arg3=%s&arg4=%s&arg5=%s&arg6=%s&arg7=false", ph->routeId,
+ ph->user.listenerId, station->id, song->musicId,
+ song->matchingSeed, song->userSeed,
+ (song->focusTraitId == NULL) ? "" : song->focusTraitId,
+ (rating == PIANO_RATE_LOVE) ? "true" : "false");
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ ret = PianoXmlParseSimple (retStr);
+
+ if (ret == PIANO_RET_OK) {
+ song->rating = rating;
+ }
+
+ free (requestStr);
+ free (retStr);
+
+ return ret;
+}
+
+/* rename station (on the server and local)
+ * @public yes
+ * @param piano handle
+ * @param change this stations name
+ * @param new name
+ * @return
+ */
+PianoReturn_t PianoRenameStation (PianoHandle_t *ph, PianoStation_t *station,
+ char *newName) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr, *urlencodedNewName, *xmlencodedNewName;
+ PianoReturn_t ret = PIANO_RET_ERR;
+
+ xmlencodedNewName = PianoXmlEncodeString (newName);
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>station.setStationName</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ station->id, xmlencodedNewName);
+ requestStr = PianoEncryptString (xmlSendBuf);
+
+ urlencodedNewName = curl_easy_escape (ph->curlHandle, newName, 0);
+ snprintf (url, sizeof (url), PIANO_RPC_URL "rid=%s&lid=%s"
+ "&method=setStationName&arg1=%s&arg2=%s", ph->routeId,
+ ph->user.listenerId, station->id, urlencodedNewName);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ ret = PianoXmlParseSimple (retStr);
+
+ if (ret == PIANO_RET_OK) {
+ free (station->name);
+ station->name = strdup (newName);
+ }
+
+ curl_free (urlencodedNewName);
+ free (xmlencodedNewName);
+ free (requestStr);
+ free (retStr);
+
+ return ret;
+}
+
+/* delete station
+ * @public yes
+ * @param piano handle
+ * @param station you want to delete
+ * @return
+ */
+PianoReturn_t PianoDeleteStation (PianoHandle_t *ph, PianoStation_t *station) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+ PianoReturn_t ret = PIANO_RET_ERR;
+
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>station.removeStation</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ station->id);
+ requestStr = PianoEncryptString (xmlSendBuf);
+
+ snprintf (url, sizeof (url), PIANO_RPC_URL "rid=%s&lid=%s"
+ "&method=removeStation&arg1=%s", ph->routeId, ph->user.listenerId,
+ station->id);
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ ret = PianoXmlParseSimple (retStr);
+
+ if (ret == PIANO_RET_OK) {
+ /* delete station from local station list */
+ PianoStation_t *curStation = ph->stations, *lastStation = NULL;
+ while (curStation != NULL) {
+ if (curStation == station) {
+ printf ("deleting station\n");
+ if (lastStation != NULL) {
+ lastStation->next = curStation->next;
+ } else {
+ /* first station in list */
+ ph->stations = curStation->next;
+ }
+ PianoDestroyStation (curStation);
+ free (curStation);
+ }
+ lastStation = curStation;
+ curStation = curStation->next;
+ }
+ }
+
+ free (requestStr);
+ free (retStr);
+
+ return ret;
+}
+
+/* search for music (artist or track), needed to create new station; don't
+ * forget to free the search result; beware! searchResult will be nulled
+ * by PianoXmlParseSearch
+ * @public yes
+ * @param piano handle
+ * @param utf-8 search string
+ * @param return search result
+ * @return nothing yet
+ */
+void PianoSearchMusic (PianoHandle_t *ph, char *searchStr,
+ PianoSearchResult_t *searchResult) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr, *xmlencodedSearchStr, *urlencodedSearchStr;
+
+ xmlencodedSearchStr = PianoXmlEncodeString (searchStr);
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>music.search</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ xmlencodedSearchStr);
+ requestStr = PianoEncryptString (xmlSendBuf);
+
+ urlencodedSearchStr = curl_easy_escape (ph->curlHandle, searchStr, 0);
+ snprintf (url, sizeof (url), PIANO_RPC_URL "rid=%s&lid=%s&"
+ "method=search&arg1=%s", ph->routeId, ph->user.listenerId,
+ urlencodedSearchStr);
+
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ PianoXmlParseSearch (retStr, searchResult);
+
+ curl_free (urlencodedSearchStr);
+ free (xmlencodedSearchStr);
+ free (retStr);
+ free (requestStr);
+}
+
+/* create new station on server
+ * @public yes
+ * @param piano handle
+ * @param music id from artist or track, you may obtain one by calling
+ * PianoSearchMusic
+ * @return nothing, yet
+ */
+void PianoCreateStation (PianoHandle_t *ph, char *musicId) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+
+ snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
+ "<methodCall><methodName>station.createStation</methodName>"
+ "<params><param><value><int>%li</int></value></param>"
+ "<param><value><string>%s</string></value></param>"
+ "<param><value><string>mi%s</string></value></param>"
+ "</params></methodCall>", time (NULL), ph->user.authToken,
+ musicId);
+ requestStr = PianoEncryptString (xmlSendBuf);
+
+ snprintf (url, sizeof (url), PIANO_RPC_URL "rid=%s&lid=%s"
+ "&method=createStation&arg1=mi%s", ph->routeId,
+ ph->user.listenerId, musicId);
+
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ PianoXmlParseCreateStation (ph, retStr);
+
+ free (requestStr);
+ free (retStr);
+}
diff --git a/libpiano/src/main.h b/libpiano/src/main.h
new file mode 100644
index 0000000..1746e53
--- /dev/null
+++ b/libpiano/src/main.h
@@ -0,0 +1,27 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+
+#endif /* _MAIN_H */
diff --git a/libpiano/src/piano.h b/libpiano/src/piano.h
new file mode 100644
index 0000000..b832b69
--- /dev/null
+++ b/libpiano/src/piano.h
@@ -0,0 +1,166 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _PIANO_H
+#define _PIANO_H
+
+/* this is our public API; don't expect this api to be stable, as long
+ * pandora does not provide a stable api
+ * all strings _must_ be utf-8 encoded. i won't care, but pandora does. so
+ * be nice and check the encoding of your strings. thanks :) */
+
+#include <curl/curl.h>
+
+struct PianoUserInfo {
+ unsigned int zipcode;
+ /* disabled: billingFrequency */
+ signed hasExplicitContentFilter;
+ char *webAuthToken;
+ /* disabled: alertCode */
+ /* disabled: seenQuickMixPanel */
+ unsigned short birthYear;
+ char *bookmarkUrl;
+ char *listenerState; /* FIXME: use enum? */
+ /* disabled: adCookieValue */
+ /* disabled: gender */
+ /* disabled: emailOptIn */
+ /* disabled: autoRenew */
+ char *username;
+ char *listenerId;
+ char *authToken;
+ char *webName;
+};
+
+typedef struct PianoUserInfo PianoUserInfo_t;
+
+struct PianoStation {
+ signed isCreator;
+ /* disabled: originalStationId */
+ char **genre;
+ unsigned int originalCreatorId;
+ /* disabled: initialSeed */
+ /* disabled: isNew */
+ /* disabled: transformType */
+ char *idToken;
+ signed isQuickMix;
+ char *name;
+ char *id;
+ struct PianoStation *next;
+};
+typedef struct PianoStation PianoStation_t;
+
+enum PianoSongRating {PIANO_RATE_BAN, PIANO_RATE_LOVE, PIANO_RATE_NONE};
+typedef enum PianoSongRating PianoSongRating_t;
+
+struct PianoSong {
+ char *artist;
+ char **genre;
+ char *matchingSeed;
+ /* disabled: composerName */
+ /* disabled: isSeed */
+ /* disabled: artistFansURL */
+ /* disabled: songExplorerUrl */
+ float fileGain;
+ /* disabled: songDetailURL */
+ /* disabled: albumDetailURL */
+ char *webId;
+ /* disabled: musicComUrl */
+ /* disabled: fanExplorerUrl */
+ PianoSongRating_t rating;
+ /* disabled: artistExplorerUrl */
+ /* disabled: artRadio */
+ char *audioEncoding; /* FIXME: should be enum: mp3 or aacplus */
+ char *stationId;
+ char *album;
+ char *artistMusicId;
+ char *userSeed;
+ /* disabled: albumExplorerUrl */
+ /* disabled: amazonUrl */
+ char *audioUrl;
+ signed onTour;
+ /* disabled: itunesUrl */
+ char *musicId;
+ char *title;
+ char *focusTraitId;
+ char *identity;
+ int score; /* only used for search results */
+ struct PianoSong *next;
+};
+
+typedef struct PianoSong PianoSong_t;
+
+/* currently only used for search results */
+struct PianoArtist {
+ /* disabled: iscomposer */
+ /* disabled: likelymatch */
+ char *name;
+ char *musicId;
+ int score;
+ struct PianoArtist *next;
+};
+
+typedef struct PianoArtist PianoArtist_t;
+
+struct PianoHandle {
+ CURL *curlHandle;
+ char routeId[9];
+ PianoUserInfo_t user;
+ /* linked lists */
+ PianoStation_t *stations;
+ PianoSong_t *playlist;
+};
+
+typedef struct PianoHandle PianoHandle_t;
+
+struct PianoSearchResult {
+ PianoSong_t *songs;
+ PianoArtist_t *artists;
+};
+
+typedef struct PianoSearchResult PianoSearchResult_t;
+
+/* FIXME: more error types (http failed, e.g.) later */
+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 *);
+void PianoDestroy (PianoHandle_t *);
+void PianoDestroyPlaylist (PianoHandle_t *ph);
+void PianoDestroySearchResult (PianoSearchResult_t *searchResult);
+void PianoDestroyStation (PianoStation_t *station);
+void PianoDestroyStations (PianoHandle_t *ph);
+PianoReturn_t PianoConnect (PianoHandle_t *, char *, char *);
+
+PianoReturn_t PianoGetStations (PianoHandle_t *ph);
+void PianoGetPlaylist (PianoHandle_t *ph, char *stationId);
+
+PianoReturn_t PianoRateTrack (PianoHandle_t *ph, PianoStation_t *station,
+ PianoSong_t *song, PianoSongRating_t rating);
+PianoReturn_t PianoRenameStation (PianoHandle_t *ph, PianoStation_t *station,
+ char *newName);
+PianoReturn_t PianoDeleteStation (PianoHandle_t *ph, PianoStation_t *station);
+void PianoSearchMusic (PianoHandle_t *ph, char *searchStr,
+ PianoSearchResult_t *searchResult);
+void PianoCreateStation (PianoHandle_t *ph, char *musicId);
+
+#endif /* _PIANO_H */
diff --git a/libpiano/src/xml.c b/libpiano/src/xml.c
new file mode 100644
index 0000000..3369074
--- /dev/null
+++ b/libpiano/src/xml.c
@@ -0,0 +1,547 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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
+ * @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>
+ * <name />
+ * <value />
+ * </member>
+ * <!-- ... -->
+ * </struct>
+ * @param xml node named "struct" (or containing a similar structure)
+ * @param who wants to use this data? callback: content of <name> as
+ * string, content of <value> as xmlNode (may contain other nodes
+ * or text), additional data used by callback(); don't forget
+ * to *copy* data taken from <name> or <value> as they will be
+ * freed soon
+ * @param extra data for callback
+ */
+void PianoXmlStructParser (xmlNode *structRoot,
+ void (*callback) (char *, xmlNode *, void *), void *data) {
+
+ xmlNode *curNode, *memberNode, *valueNode;
+ xmlChar *key;
+
+ /* get all <member> nodes */
+ for (curNode = structRoot->children; curNode; curNode = curNode->next) {
+ if (curNode->type == XML_ELEMENT_NODE &&
+ xmlStrEqual ((xmlChar *) "member", curNode->name)) {
+ key = NULL;
+ valueNode = NULL;
+ /* check children for <name> or <value> */
+ for (memberNode = curNode->children; memberNode;
+ memberNode = memberNode->next) {
+ if (memberNode->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual ((xmlChar *) "name", memberNode->name)) {
+ key = memberNode->children->content;
+ } else if (xmlStrEqual ((xmlChar *) "value",
+ memberNode->name)) {
+ valueNode = memberNode->children;
+ }
+ }
+ }
+ /* this will ignore empty <value /> nodes, but well... */
+ if (key != NULL && valueNode != NULL) {
+ (*callback) ((char *) key, valueNode, data);
+ }
+ }
+ }
+}
+
+/* create xml parser from string
+ * @param xml document
+ * @param returns document pointer (needed to free memory later)
+ * @param returns document root
+ * @return _RET_ERR or _RET_OK
+ */
+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_XML_INVALID;
+ }
+
+ *docRoot = xmlDocGetRootElement (*doc);
+
+ if ((ret = PianoXmlIsFault (*docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ return PIANO_RET_OK;
+}
+
+/* get text from <value> nodes; some of them have <boolean>, <string>
+ * or <int> subnodes, just ignore them
+ * @param xml node <value>
+ */
+char *PianoXmlGetNodeText (xmlNode *node) {
+ /* FIXME: this is not the correct way; we should check the node type
+ * as well */
+ if (node->content != NULL) {
+ return (char *) node->content;
+ } else if (node->children != NULL &&
+ node->children->content != NULL) {
+ return (char *) node->children->content;
+ }
+ return NULL;
+}
+
+/* structParser callback; writes userinfo to PianoUserInfo structure
+ * @param value identifier
+ * @param value node
+ * @param pointer to userinfo structure
+ * @return nothing
+ */
+void PianoXmlParseUserinfoCb (char *key, xmlNode *value, void *data) {
+ PianoUserInfo_t *user = data;
+ char *valueStr = PianoXmlGetNodeText (value);
+
+ /* FIXME: should be continued later */
+ if (strcmp ("webAuthToken", key) == 0) {
+ user->webAuthToken = strdup (valueStr);
+ } else if (strcmp ("authToken", key) == 0) {
+ user->authToken = strdup (valueStr);
+ } else if (strcmp ("listenerId", key) == 0) {
+ user->listenerId = strdup (valueStr);
+ }
+}
+
+void PianoXmlParseStationsCb (char *key, xmlNode *value, void *data) {
+ PianoStation_t *station = data;
+ char *valueStr = PianoXmlGetNodeText (value);
+
+ if (strcmp ("stationName", key) == 0) {
+ station->name = strdup (valueStr);
+ } else if (strcmp ("stationId", key) == 0) {
+ station->id = strdup (valueStr);
+ }
+}
+
+/* FIXME: copy & waste */
+void PianoXmlParsePlaylistCb (char *key, xmlNode *value, void *data) {
+ PianoSong_t *song = data;
+ char *valueStr = PianoXmlGetNodeText (value);
+
+ if (strcmp ("audioURL", key) == 0) {
+ /* last 48 chars of audioUrl are encrypted, but they put the key
+ * into the door's lock; dumb pandora... */
+ const char urlTailN = 48;
+ char *urlTail, *urlTailCrypted = valueStr + (strlen (valueStr) - urlTailN);
+ urlTail = PianoDecryptString (urlTailCrypted);
+ song->audioUrl = calloc (strlen (valueStr) + 1, sizeof (char));
+ strncpy (song->audioUrl, valueStr, strlen (valueStr) - urlTailN);
+ /* FIXME: the key seems to be broken... so ignore 8 x 0x08 postfix;
+ * urlTailN/2 because the encrypted hex string is now decoded */
+ strncat (song->audioUrl, urlTail, (urlTailN/2)-8);
+ free (urlTail);
+
+ } else if (strcmp ("artistSummary", key) == 0) {
+ song->artist = strdup (valueStr);
+ } else if (strcmp ("musicId", key) == 0) {
+ song->musicId = strdup (valueStr);
+ } else if (strcmp ("matchingSeed", key) == 0) {
+ song->matchingSeed = strdup (valueStr);
+ } else if (strcmp ("userSeed", key) == 0) {
+ song->userSeed = strdup (valueStr);
+ } else if (strcmp ("focusTraitId", key) == 0) {
+ song->focusTraitId = strdup (valueStr);
+ } else if (strcmp ("songTitle", key) == 0) {
+ song->title = strdup (valueStr);
+ } else if (strcmp ("rating", key) == 0) {
+ if (strcmp (valueStr, "1") == 0) {
+ song->rating = PIANO_RATE_LOVE;
+ } else {
+ song->rating = PIANO_RATE_NONE;
+ }
+ }
+}
+
+/* parses userinfos sent by pandora as login response
+ * @param piano handle
+ * @param utf-8 string
+ * @return _RET_OK or error
+ */
+PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) {
+ xmlNode *docRoot;
+ xmlDocPtr doc;
+ PianoReturn_t ret;
+
+ if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ /* <methodResponse> <params> <param> <value> <struct> */
+ xmlNode *structRoot = docRoot->children->children->children->children;
+ PianoXmlStructParser (structRoot, PianoXmlParseUserinfoCb, &ph->user);
+
+ xmlFreeDoc (doc);
+ return PIANO_RET_OK;
+}
+
+/* parse stations returned by pandora
+ * @param piano handle
+ * @param xml returned by pandora
+ * @return _RET_OK or error
+ */
+PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, char *xml) {
+ xmlNode *docRoot, *curNode;
+ xmlDocPtr doc;
+ PianoReturn_t ret;
+
+ if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ /* <methodResponse> <params> <param> <value> <array> <data> */
+ xmlNode *dataRoot = docRoot->children->children->children->children->children;
+ for (curNode = dataRoot->children; curNode; curNode = curNode->next) {
+ if (curNode->type == XML_ELEMENT_NODE &&
+ xmlStrEqual ((xmlChar *) "value", curNode->name)) {
+ PianoStation_t *tmpStation = calloc (1, sizeof (*tmpStation));
+ PianoXmlStructParser (curNode->children,
+ PianoXmlParseStationsCb, tmpStation);
+ /* start new linked list or append */
+ if (ph->stations == NULL) {
+ ph->stations = tmpStation;
+ } else {
+ PianoStation_t *curStation = ph->stations;
+ while (curStation->next != NULL) {
+ curStation = curStation->next;
+ }
+ curStation->next = tmpStation;
+ }
+ }
+ }
+
+ xmlFreeDoc (doc);
+ return PIANO_RET_OK;
+}
+
+/* parse "create station" answer (it returns a new station structure)
+ * @param piano handle
+ * @param xml document
+ * @return nothing yet
+ */
+PianoReturn_t PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) {
+ xmlNode *docRoot;
+ xmlDocPtr doc;
+ PianoStation_t *tmpStation;
+ PianoReturn_t ret;
+
+ if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ /* get <struct> node */
+ xmlNode *dataRoot = docRoot->children->children->children->children;
+ tmpStation = calloc (1, sizeof (*tmpStation));
+ PianoXmlStructParser (dataRoot, PianoXmlParseStationsCb, tmpStation);
+ /* FIXME: copy & waste */
+ /* start new linked list or append */
+ if (ph->stations == NULL) {
+ ph->stations = tmpStation;
+ } else {
+ PianoStation_t *curStation = ph->stations;
+ while (curStation->next != NULL) {
+ curStation = curStation->next;
+ }
+ curStation->next = tmpStation;
+ }
+
+ xmlFreeDoc (doc);
+
+ return PIANO_RET_OK;
+}
+
+/* parses playlist; used when searching too
+ * @param piano handle
+ * @param xml document
+ */
+PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) {
+ xmlNode *docRoot, *curNode;
+ xmlDocPtr doc;
+ PianoReturn_t ret;
+
+ if ((ret = PianoXmlInitDoc (xml, &doc, &docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ /* <methodResponse> <params> <param> <value> <array> <data> */
+ xmlNode *dataRoot = docRoot->children->children->children->children->children;
+ for (curNode = dataRoot->children; curNode; curNode = curNode->next) {
+ if (curNode->type == XML_ELEMENT_NODE &&
+ xmlStrEqual ((xmlChar *) "value", curNode->name)) {
+ PianoSong_t *tmpSong = calloc (1, sizeof (*tmpSong));
+ PianoXmlStructParser (curNode->children,
+ PianoXmlParsePlaylistCb, tmpSong);
+ /* begin linked list or append */
+ if (ph->playlist == NULL) {
+ ph->playlist = tmpSong;
+ } else {
+ PianoSong_t *curSong = ph->playlist;
+ while (curSong->next != NULL) {
+ curSong = curSong->next;
+ }
+ curSong->next = tmpSong;
+ }
+ }
+ }
+
+ xmlFreeDoc (doc);
+
+ return PIANO_RET_OK;
+}
+
+/* parse simple answers like this: <?xml version="1.0" encoding="UTF-8"?>
+ * <methodResponse><params><param><value>1</value></param></params>
+ * </methodResponse>
+ * @param xml string
+ * @return
+ */
+PianoReturn_t PianoXmlParseSimple (char *xml) {
+ xmlNode *docRoot;
+ xmlDocPtr doc;
+ PianoReturn_t ret;
+
+ 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);
+
+ return ret;
+}
+
+/* xml struct parser callback, used in PianoXmlParseSearchCb
+ */
+void PianoXmlParseSearchArtistCb (char *key, xmlNode *value, void *data) {
+ PianoArtist_t *artist = data;
+ char *valueStr = PianoXmlGetNodeText (value);
+
+ if (strcmp ("artistName", key) == 0) {
+ artist->name = strdup (valueStr);
+ } else if (strcmp ("musicId", key) == 0) {
+ artist->musicId = strdup (valueStr);
+ }
+}
+
+/* callback for xml struct parser used in PianoXmlParseSearch, "switch" for
+ * PianoXmlParseSearchArtistCb and PianoXmlParsePlaylistCb
+ */
+void PianoXmlParseSearchCb (char *key, xmlNode *value, void *data) {
+ PianoSearchResult_t *searchResult = data;
+
+ if (strcmp ("artists", key) == 0) {
+ xmlNode *curNode;
+
+ /* skip <value><array><data> */
+ for (curNode = value->children->children; curNode;
+ curNode = curNode->next) {
+ if (curNode->type == XML_ELEMENT_NODE &&
+ xmlStrEqual ((xmlChar *) "value", curNode->name)) {
+
+ PianoArtist_t *artist = calloc (1, sizeof (*artist));
+ memset (artist, 0, sizeof (*artist));
+
+ PianoXmlStructParser (curNode->children,
+ PianoXmlParseSearchArtistCb, artist);
+
+ /* add result to linked list */
+ if (searchResult->artists == NULL) {
+ searchResult->artists = artist;
+ } else {
+ PianoArtist_t *curArtist = searchResult->artists;
+ while (curArtist->next != NULL) {
+ curArtist = curArtist->next;
+ }
+ curArtist->next = artist;
+ }
+ }
+ }
+ } else if (strcmp ("songs", key) == 0) {
+ xmlNode *curNode;
+
+ for (curNode = value->children->children; curNode;
+ curNode = curNode->next) {
+ if (curNode->type == XML_ELEMENT_NODE &&
+ xmlStrEqual ((xmlChar *) "value", curNode->name)) {
+ /* FIXME: copy & waste */
+ PianoSong_t *tmpSong = calloc (1, sizeof (*tmpSong));
+ PianoXmlStructParser (curNode->children,
+ PianoXmlParsePlaylistCb, tmpSong);
+ /* begin linked list or append */
+ if (searchResult->songs == NULL) {
+ searchResult->songs = tmpSong;
+ } else {
+ PianoSong_t *curSong = searchResult->songs;
+ while (curSong->next != NULL) {
+ curSong = curSong->next;
+ }
+ curSong->next = tmpSong;
+ }
+ }
+ }
+ }
+}
+
+/* parse search result; searchResult is nulled before use
+ * @param xml document
+ * @param returns search result
+ * @return nothing yet
+ */
+PianoReturn_t PianoXmlParseSearch (char *searchXml,
+ PianoSearchResult_t *searchResult) {
+ xmlNode *docRoot;
+ xmlDocPtr doc;
+ PianoReturn_t ret;
+
+ if ((ret = PianoXmlInitDoc (searchXml, &doc, &docRoot)) != PIANO_RET_OK) {
+ return ret;
+ }
+
+ xmlNode *structRoot = docRoot->children->children->children->children;
+ /* we need a "clean" search result (with null pointers) */
+ memset (searchResult, 0, sizeof (*searchResult));
+ PianoXmlStructParser (structRoot, PianoXmlParseSearchCb, searchResult);
+
+ xmlFreeDoc (doc);
+
+ return PIANO_RET_OK;
+}
+
+/* encode reserved xml chars
+ * @param encode this
+ * @return encoded string
+ */
+char *PianoXmlEncodeString (const char *s) {
+ char *replacements[] = {"&&amp;", "'&apos;", "\"&quot;", "<&lt;", ">&gt;"};
+ char *s_new = NULL;
+ unsigned int s_new_n = 0;
+ unsigned int i;
+ char found = 0;
+
+ s_new_n = strlen (s) + 1;
+ s_new = calloc (s_new_n, 1);
+
+ while (*s) {
+ found = 0;
+ for (i = 0; i < sizeof (replacements) / sizeof (*replacements); i++) {
+ if (*s == replacements[i][0]) {
+ /* replacements[i]+1 is our replacement, and -1 'cause we
+ * "overwrite" one byte */
+ s_new_n += strlen (replacements[i]+1)-1;
+ s_new = realloc (s_new, s_new_n);
+ strncat (s_new, replacements[i]+1, strlen (replacements[i]+1));
+ found = 1;
+ /* no need to look for other entities */
+ break;
+ }
+ }
+ if (!found) {
+ strncat (s_new, s, 1);
+ }
+ s++;
+ }
+ return s_new;
+}
diff --git a/libpiano/src/xml.h b/libpiano/src/xml.h
new file mode 100644
index 0000000..54deb6e
--- /dev/null
+++ b/libpiano/src/xml.h
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2008 Lars-Dominik Braun
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef _XML_H
+#define _XML_H
+
+#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);
+PianoReturn_t PianoXmlParseSimple (char *xml);
+void PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml);
+
+char *PianoXmlEncodeString (const char *s);
+
+#endif /* _XML_H */