summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS2
-rw-r--r--BUGS6
-rw-r--r--COPYING19
-rw-r--r--ChangeLog15
-rw-r--r--INSTALL25
-rw-r--r--Makefile.am3
-rw-r--r--NEWS4
-rw-r--r--RoadMap18
-rwxr-xr-xautogen.sh7
-rw-r--r--configure.in37
-rw-r--r--libpiano/Makefile.am6
-rw-r--r--libpiano/const.h35
-rw-r--r--libpiano/crypt.c283
-rw-r--r--libpiano/crypt.h29
-rw-r--r--libpiano/crypt_key_input.h1071
-rw-r--r--libpiano/crypt_key_output.h1076
-rw-r--r--libpiano/http.c87
-rw-r--r--libpiano/http.h28
-rw-r--r--libpiano/main.c249
-rw-r--r--libpiano/main.h27
-rw-r--r--libpiano/piano.h132
-rw-r--r--libpiano/xml.c278
-rw-r--r--libpiano/xml.h30
-rw-r--r--src/Makefile.am6
-rw-r--r--src/main.c339
25 files changed, 3812 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..84f6677
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Reverse engineering, main code:
+ Lars-Dominik Braun <PromyLOPh@gmail.com>
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..20034c6
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,6 @@
+Bugs
+====
+
+A lot, I think. But none of them are found yet...
+
+Report them to: PromyLOPh@gmail.com
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..ce56cec
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,19 @@
+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.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..beca2c0
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,15 @@
+2008-06-09
+ * replaced calloc & strcpy by strdup in xml.c
+ * rating implemented
+ * skip, change station, quit implemented
+ * now using thread for audio playback
+
+2008-06-07
+ * updated readme
+ * documented some more functions
+ * fixed autotools
+ * added primitive playback of first song using libao and faad2
+
+2008-06-05
+ * url creation now uses less buffers
+ * first public release
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d6458ab
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,25 @@
+Install
+=======
+
+Do not install this application yet!
+
+Dependencies
+------------
+
+Versions may vary :) Just get the newest one:
+
+libao http://www.xiph.org/ao/ (pianobar)
+libcurl http://curl.haxx.se/ (libpiano, pianobar)
+libfaad2 http://www.audiocoding.com/downloads.html (pianobar)
+libxml2 http://xmlsoft.org/ (libpiano)
+
+Build
+-----
+
+./autogen.sh
+./configure
+make
+
+Just run the client from this source directory
+
+./src/pianobar
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..b0a409e
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = libpiano src
+
+EXTRA_DIST = autogen.sh RoadMap BUGS
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..c8aa439
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,4 @@
+News
+====
+
+Nothing happened yet...
diff --git a/RoadMap b/RoadMap
new file mode 100644
index 0000000..6b83d8c
--- /dev/null
+++ b/RoadMap
@@ -0,0 +1,18 @@
+Roadmap
+=======
+
+Ordered by importance:
+
+Must-have:
+----------
+
+* implement all pandora commands like ban/love/...
+* buffer songs (works without too, but would be a huge improvement)
+* fixes, fixes, fixes (look for memory leaks or implement error handling, e.g.)
+
+Wishes:
+-------
+
+* replaygain
+* cache for authtoken (how long are they valid?) and other userdata
+* last.fm scrobbling
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..12d2f9b
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+libtoolize --force \
+&& aclocal \
+&& automake --add-missing \
+&& autoconf \
+&& ./configure
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..2206af2
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,37 @@
+AC_INIT([pianobar], [20080609], [PromyLOPh@gmail.com])
+AC_CONFIG_SRCDIR([src/main.c])
+AM_INIT_AUTOMAKE([-Wall])
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AM_SANITY_CHECK
+AM_PROG_LIBTOOL
+
+PKG_PROG_PKG_CONFIG
+
+PKG_CHECK_MODULES(LIBCURL, libcurl >= 7.18.0)
+AC_SUBST(LIBCURL_CFLAGS)
+AC_SUBST(LIBCURL_LIBS)
+
+PKG_CHECK_MODULES(LIBXML, libxml-2.0 >= 2.6.31)
+AC_SUBST(LIBXML_CFLAGS)
+AC_SUBST(LIBXML_LIBS)
+
+PKG_CHECK_MODULES(LIBAO, ao >= 0.8.8)
+AC_SUBST(LIBAO_CFLAGS)
+AC_SUBST(LIBAO_LIBS)
+
+AC_CHECK_LIB([faad], [NeAACDecOpen], [LIBFAAD_LIBS=-lfaad], AC_MSG_ERROR([libfaad2 is required. See INSTALL]))
+AC_SUBST(LIBFAAD_LIBS)
+
+# FIXME: check for pthread
+
+AC_CHECK_HEADERS([stdlib.h string.h])
+
+AC_CHECK_FUNCS([memset])
+
+AC_TYPE_SIZE_T
+
+AC_CONFIG_FILES(Makefile src/Makefile libpiano/Makefile)
+
+AC_OUTPUT
diff --git a/libpiano/Makefile.am b/libpiano/Makefile.am
new file mode 100644
index 0000000..e74d442
--- /dev/null
+++ b/libpiano/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/const.h b/libpiano/const.h
new file mode 100644
index 0000000..dfaca1f
--- /dev/null
+++ b/libpiano/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/crypt.c b/libpiano/crypt.c
new file mode 100644
index 0000000..396f61d
--- /dev/null
+++ b/libpiano/crypt.c
@@ -0,0 +1,283 @@
+/*
+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
+ * @author PromyLOPh
+ * @added 2008-06-01
+ * @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
+ * @author PromyLOPh
+ * @author probably pandora?
+ * @added 2008-06-01
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-01
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-01
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-02
+ * @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
+ * @author PromyLOPh
+ * @author probably pandora?
+ * @added 2008-06-07
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-07
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-07
+ * @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/crypt.h b/libpiano/crypt.h
new file mode 100644
index 0000000..5b097f1
--- /dev/null
+++ b/libpiano/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/crypt_key_input.h b/libpiano/crypt_key_input.h
new file mode 100644
index 0000000..101d382
--- /dev/null
+++ b/libpiano/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/crypt_key_output.h b/libpiano/crypt_key_output.h
new file mode 100644
index 0000000..5bafaf5
--- /dev/null
+++ b/libpiano/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/http.c b/libpiano/http.c
new file mode 100644
index 0000000..31c93cf
--- /dev/null
+++ b/libpiano/http.c
@@ -0,0 +1,87 @@
+/*
+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
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @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/http.h b/libpiano/http.h
new file mode 100644
index 0000000..87dc49c
--- /dev/null
+++ b/libpiano/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/main.c b/libpiano/main.c
new file mode 100644
index 0000000..185d94c
--- /dev/null
+++ b/libpiano/main.c
@@ -0,0 +1,249 @@
+/*
+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"
+
+char *PianoEncryptString (char *strInput);
+
+/* initialize piano handle, set up curl handle and settings
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @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);
+ /* set tor as control connection proxy */
+ curl_easy_setopt (ph->curlHandle, CURLOPT_PROXY, "localhost:9050");
+ curl_easy_setopt (ph->curlHandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
+}
+
+/* free complete station list
+ * @author PromyLOPh
+ * @added 2008-06-09
+ * @param piano handle
+ */
+void PianoDestroyStations (PianoHandle_t *ph) {
+ PianoStation_t *curStation, *lastStation;
+
+ curStation = ph->stations;
+ while (curStation != NULL) {
+ free (curStation->name);
+ free (curStation->id);
+ lastStation = curStation;
+ curStation = curStation->next;
+ memset (lastStation, 0, sizeof (*lastStation));
+ free (lastStation);
+ }
+}
+
+/* FIXME: copy & waste */
+/* free _all_ elements of playlist
+ * @author PromyLOPh
+ * @added 2008-06-09
+ * @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);
+ }
+}
+
+/* frees the whole piano handle structure
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @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
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @param piano handle
+ * @param username (utf-8 encoded)
+ * @param password (plaintext, utf-8 encoded)
+ * @return nothing
+ */
+void PianoConnect (PianoHandle_t *ph, char *user, char *password) {
+ /* sync */
+ 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];
+
+ /* 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);
+ PianoXmlParseUserinfo (ph, retStr);
+
+ free (requestStr);
+ free (retStr);
+}
+
+/* get all stations for authenticated user (so: PianoConnect needs to
+ * be run before)
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @param piano handle filled with some authentication data by PianoConnect
+ * @return nothing
+ */
+void PianoGetStations (PianoHandle_t *ph) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+
+ 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);
+ PianoXmlParseStations (ph, retStr);
+ free (retStr);
+ free (requestStr);
+}
+
+/* get next songs for station (usually four tracks)
+ * @author PromyLOPh
+ * @added 2008-06-05
+ * @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);
+}
+
+void PianoRateTrack (PianoHandle_t *ph, PianoStation_t *station,
+ PianoSong_t *song, PianoSongRating_t rating) {
+ char xmlSendBuf[10000], url[PIANO_URL_BUFFER_SIZE];
+ char *requestStr, *retStr;
+
+ 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,
+ 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,
+ (rating == PIANO_RATE_LOVE) ? "true" : "false");
+ PianoHttpPost (ph->curlHandle, url, requestStr, &retStr);
+ /* FIXME: check answer (success = <?xml version="1.0" encoding="UTF-8"?><methodResponse><params><param><value>1</value></param></params></methodResponse> ) */
+ free (requestStr);
+ free (retStr);
+}
diff --git a/libpiano/main.h b/libpiano/main.h
new file mode 100644
index 0000000..1746e53
--- /dev/null
+++ b/libpiano/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/piano.h b/libpiano/piano.h
new file mode 100644
index 0000000..ac64cd1
--- /dev/null
+++ b/libpiano/piano.h
@@ -0,0 +1,132 @@
+/*
+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
+ * 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;
+
+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 */
+ int 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;
+ struct PianoSong *next;
+};
+
+typedef struct PianoSong PianoSong_t;
+
+struct PianoHandle {
+ CURL *curlHandle;
+ char routeId[9];
+ PianoUserInfo_t user;
+ /* linked lists */
+ PianoStation_t *stations;
+ PianoSong_t *playlist;
+};
+
+typedef struct PianoHandle PianoHandle_t;
+
+enum PianoSongRating {PIANO_RATE_BAN, PIANO_RATE_LOVE};
+typedef enum PianoSongRating PianoSongRating_t;
+
+void PianoInit (PianoHandle_t *);
+void PianoDestroy (PianoHandle_t *);
+void PianoDestroyPlaylist (PianoHandle_t *ph);
+void PianoConnect (PianoHandle_t *, char *, char *);
+
+void PianoGetStations (PianoHandle_t *ph);
+void PianoGetPlaylist (PianoHandle_t *ph, char *stationId);
+
+void PianoRateTrack (PianoHandle_t *ph, PianoStation_t *station,
+ PianoSong_t *song, PianoSongRating_t rating);
+
+#endif /* _PIANO_H */
diff --git a/libpiano/xml.c b/libpiano/xml.c
new file mode 100644
index 0000000..370d236
--- /dev/null
+++ b/libpiano/xml.c
@@ -0,0 +1,278 @@
+/*
+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 "piano.h"
+#include "crypt.h"
+
+/* parses things like this:
+ * <struct>
+ * <member>
+ * <name />
+ * <value />
+ * </member>
+ * <!-- ... -->
+ * </struct>
+ * @author PromyLOPh
+ * @added 2008-06-03
+ * @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
+ */
+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);
+ }
+ }
+ }
+}
+
+/* structParser callback; writes userinfo to PianoUserInfo structure
+ * @author PromyLOPh
+ * @added 2008-06-03
+ * @param value identifier
+ * @param value node
+ * @param pointer to userinfo structure
+ * @return nothing
+ */
+void PianoXmlParseUserinfoCb (char *key, xmlNode *value, void *data) {
+ char *valueStr = NULL;
+ PianoUserInfo_t *user = data;
+
+ /* some values have subnodes like <boolean> or <string>, just
+ * ignore them... */
+ if (value->content != NULL) {
+ valueStr = (char *) value->content;
+ } else if (value->children != NULL &&
+ value->children->content != NULL) {
+ valueStr = (char *) value->children->content;
+ }
+ /* 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 = NULL;
+
+ /* FIXME: copy & waste */
+ /* some values have subnodes like <boolean> or <string>, just
+ * ignore them... */
+ if (value->content != NULL) {
+ valueStr = (char *) value->content;
+ } else if (value->children != NULL &&
+ value->children->content != NULL) {
+ valueStr = (char *) value->children->content;
+ }
+ 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 = NULL;
+
+ /* some values have subnodes like <boolean> or <string>, just
+ * ignore them... */
+ if (value->content != NULL) {
+ valueStr = (char *) value->content;
+ } else if (value->children != NULL &&
+ value->children->content != NULL) {
+ valueStr = (char *) value->children->content;
+ }
+ 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);
+ //printf ("tail is:\t%s\nwas:\t\t%s (%i)\nurl was:\t %s (%i)\n", urlTail, urlTailCrypted, strlen (urlTailCrypted), valueStr, strlen (valueStr));
+ 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);
+ }
+}
+
+/* parses server response and updates handle
+ * @author PromyLOPh
+ * @added 2008-06-03
+ * @param piano handle
+ * @param utf-8 string
+ * @return nothing
+ */
+void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) {
+ xmlNode *docRoot = NULL;
+ xmlDocPtr doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, 0);
+
+ if (doc == NULL) {
+ printf ("whoops... xml parser error\n");
+ return;
+ }
+
+ docRoot = xmlDocGetRootElement (doc);
+
+ /* <methodResponse> <params> <param> <value> <struct> */
+ xmlNode *structRoot = docRoot->children->children->children->children;
+ PianoXmlStructParser (structRoot, PianoXmlParseUserinfoCb, &ph->user);
+
+ xmlFreeDoc (doc);
+ xmlCleanupParser();
+}
+
+/* parse stations returned by pandora
+ * @author PromyLOPh
+ * @added 2008-06-04
+ * @param piano handle
+ * @param xml returned by pandora
+ * @return nothing
+ */
+void PianoXmlParseStations (PianoHandle_t *ph, char *xml) {
+ /* FIXME: copy & waste */
+ xmlNode *docRoot = NULL, *curNode = NULL;
+ xmlDocPtr doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, 0);
+
+ if (doc == NULL) {
+ printf ("whoops... xml parser error\n");
+ return;
+ }
+
+ docRoot = xmlDocGetRootElement (doc);
+
+ /* <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);
+ xmlCleanupParser();
+}
+
+void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml) {
+ /* FIXME: copy & waste */
+ xmlNode *docRoot = NULL, *curNode = NULL;
+ xmlDocPtr doc = xmlReadDoc ((xmlChar *) xml, NULL, NULL, 0);
+
+ if (doc == NULL) {
+ printf ("whoops... xml parser error\n");
+ return;
+ }
+
+ docRoot = xmlDocGetRootElement (doc);
+
+ /* <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);
+ xmlCleanupParser();
+}
diff --git a/libpiano/xml.h b/libpiano/xml.h
new file mode 100644
index 0000000..c4eede8
--- /dev/null
+++ b/libpiano/xml.h
@@ -0,0 +1,30 @@
+/*
+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
+
+void PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml);
+void PianoXmlParseStations (PianoHandle_t *ph, char *xml);
+void PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml);
+
+#endif /* _XML_H */
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..8f88440
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,6 @@
+bin_PROGRAMS = pianobar
+
+pianobar_SOURCES = main.c
+pianobar_CPPFLAGS = ${LIBCURL_CFLAGS} ${LIBAO_CFLAGS} -I../libpiano
+pianobar_LDADD = ${LIBCURL_LIBS} ${LIBAO_LIBS} ${LIBFAAD_LIBS} -lpthread ../libpiano/libpiano.la
+
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..d125122
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,339 @@
+/*
+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 <piano.h>
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ao/ao.h>
+#include <neaacdec.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <termios.h>
+#include <poll.h>
+
+struct aacPlayer {
+ /* buffer */
+ char *buffer;
+ size_t bufferFilled;
+ char lastBytes[4];
+ /* got mdat atom */
+ char dataMode;
+ char foundEsdsAtom;
+ char audioInitialized;
+ /* aac */
+ NeAACDecHandle aacHandle;
+ unsigned long samplerate;
+ unsigned char channels;
+ /* audio out */
+ ao_device *audioOutDevice;
+ char *url;
+ char finishedPlayback;
+ char doQuit;
+};
+
+void dumpBuffer (char *buf, size_t len) {
+ int i;
+ for (i = 0; i < len; i++) {
+ printf ("%02x ", buf[i] & 0xff);
+ }
+ printf ("\n");
+}
+
+/* FIXME: this is a huge block of _bad_ and buggy code */
+int playCurlCb (void *ptr, size_t size, size_t nmemb, void *stream) {
+ char *data = ptr;
+ struct aacPlayer *player = stream;
+
+ if (player->doQuit) {
+ return -1;
+ }
+
+ if (player->dataMode == 1) {
+ size_t bufferOffset = 0, aacBufferN;
+ char *aacDecoded, *aacBuffer;
+ NeAACDecFrameInfo frameInfo;
+
+ aacBufferN = player->bufferFilled + nmemb;
+ aacBuffer = calloc (aacBufferN, sizeof (char));
+ memcpy (aacBuffer, player->buffer, player->bufferFilled);
+ memcpy (aacBuffer + player->bufferFilled, data, nmemb * size);
+
+ free (player->buffer);
+
+ /* keep some bytes in buffer */
+ while (bufferOffset < aacBufferN-500) {
+ //printf ("play buffer at %i/%i: ", bufferOffset, aacBufferN);
+ //dumpBuffer (aacBuffer+bufferOffset, 50);
+ /* FIXME: well, i think we need this block length table */
+ aacDecoded = NeAACDecDecode(player->aacHandle, &frameInfo,
+ (unsigned char *) aacBuffer+bufferOffset,
+ aacBufferN-bufferOffset);
+ //printf ("bytesconsumed: %li\nerror: %i\nsamples: %lu\nsamplerate: %lu\n\n", frameInfo.bytesconsumed, frameInfo.error, frameInfo.samples, frameInfo.samplerate);
+ if (frameInfo.error != 0) {
+ printf ("error: %s\n\n", NeAACDecGetErrorMessage (frameInfo.error));
+ break;
+ }
+ ao_play (player->audioOutDevice, aacDecoded,
+ frameInfo.samples*frameInfo.channels);
+ bufferOffset += frameInfo.bytesconsumed;
+ }
+ /* copy remaining bytes */
+ player->buffer = calloc (aacBufferN - bufferOffset, sizeof (char));
+ memcpy (player->buffer, aacBuffer+bufferOffset,
+ aacBufferN - bufferOffset);
+ player->bufferFilled = aacBufferN - bufferOffset;
+ //printf ("player->buffer (%i) = ", aacBufferN - bufferOffset);
+ //dumpBuffer (player->buffer, 50);
+ free (aacBuffer);
+ } else {
+ player->buffer = calloc (nmemb + sizeof (player->lastBytes), size);
+ /* we are going to find a 4-byte string, but curl sends fragments and
+ * if the identifier is cut into two pieces, we will get into big
+ * trouble... */
+ memcpy (player->buffer, player->lastBytes, sizeof (player->lastBytes));
+ memcpy (player->buffer+sizeof (player->lastBytes), data, size*nmemb);
+
+ char *searchBegin = player->buffer;
+
+ if (!player->foundEsdsAtom) {
+ while (searchBegin < player->buffer + nmemb) {
+ if (memcmp (searchBegin, "esds", 4) == 0) {
+ player->foundEsdsAtom = 1;
+ break;
+ }
+ searchBegin++;
+ }
+ }
+ if (player->foundEsdsAtom && !player->audioInitialized) {
+ /* FIXME: is this the correct way? */
+ while (searchBegin < player->buffer + nmemb) {
+ if (memcmp (searchBegin, "\x05\x80\x80\x80", 4) == 0) {
+ ao_sample_format format;
+ int audioOutDriver;
+
+ char err = NeAACDecInit2 (player->aacHandle,
+ (unsigned char *) searchBegin+1+4, 5,
+ &player->samplerate, &player->channels);
+ if (err != 0) {
+ printf ("whoops... %i\n", err);
+ return 1;
+ }
+ //printf ("samplerate: %li\nchannels: %i\n\n",
+ // player->samplerate, player->channels);
+ audioOutDriver = ao_default_driver_id();
+ format.bits = 16;
+ format.channels = player->channels;
+ format.rate = player->samplerate;
+ format.byte_format = AO_FMT_LITTLE;
+ player->audioOutDevice = ao_open_live (audioOutDriver, &format, NULL);
+ player->audioInitialized = 1;
+ break;
+ }
+ searchBegin++;
+ }
+ }
+ if (player->audioInitialized) {
+ while (searchBegin < player->buffer + nmemb) {
+ if (memcmp (searchBegin, "mdat", 4) == 0) {
+ player->dataMode = 1;
+ memmove (player->buffer, searchBegin+4, nmemb - (searchBegin-player->buffer));
+ player->bufferFilled = nmemb - (searchBegin-player->buffer);
+ //printf ("copied %i bytes: ", nmemb - (searchBegin-player->buffer));
+ //dumpBuffer (player->buffer, 50);
+ break;
+ }
+ searchBegin++;
+ }
+ }
+ if (!player->dataMode) {
+ memcpy (player->lastBytes, data + (size * nmemb - sizeof (player->lastBytes)),
+ sizeof (player->lastBytes));
+ //printf ("last bytes: ");
+ //dumpBuffer (player->lastBytes, 4);
+ free (player->buffer);
+ }
+ }
+
+ return size*nmemb;
+}
+
+void *threadPlayUrl (void *data) {
+ struct aacPlayer *player = data;
+ NeAACDecConfigurationPtr conf;
+ CURL *audioFd;
+
+ audioFd = curl_easy_init ();
+ player->aacHandle = NeAACDecOpen();
+
+ conf = NeAACDecGetCurrentConfiguration(player->aacHandle);
+ conf->outputFormat = FAAD_FMT_16BIT;
+ conf->downMatrix = 1;
+ NeAACDecSetConfiguration(player->aacHandle, conf);
+
+ curl_easy_setopt (audioFd, CURLOPT_URL, player->url);
+ curl_easy_setopt (audioFd, CURLOPT_WRITEFUNCTION, playCurlCb);
+ curl_easy_setopt (audioFd, CURLOPT_WRITEDATA, player);
+ /* at the moment we don't need publicity */
+ curl_easy_setopt (audioFd, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9pre) Gecko/2008051115 Firefox/3.0pre");
+ curl_easy_perform (audioFd);
+
+ free (player->buffer);
+ NeAACDecClose(player->aacHandle);
+ ao_close(player->audioOutDevice);
+ curl_easy_cleanup (audioFd);
+
+ player->finishedPlayback = 1;
+
+ return NULL;
+}
+
+PianoStation_t *selectStation (PianoHandle_t *ph) {
+ PianoStation_t *curStation;
+ size_t i;
+
+ printf ("which station do you want to listen to?\n");
+ i = 0;
+ curStation = ph->stations;
+ while (curStation != NULL) {
+ printf ("%2i) %s\n", i, curStation->name);
+ curStation = curStation->next;
+ i++;
+ }
+ scanf ("%i", &i);
+ curStation = ph->stations;
+ while (curStation != NULL && i > 0) {
+ curStation = curStation->next;
+ i--;
+ }
+ return curStation;
+}
+
+int main (int argc, char **argv) {
+ PianoHandle_t ph;
+ struct aacPlayer player;
+ char doQuit = 0;
+ PianoSong_t *curSong = NULL;
+ PianoStation_t *curStation;
+ struct termios termopts;
+
+ /* init some things */
+ curl_global_init (CURL_GLOBAL_SSL);
+ ao_initialize();
+ PianoInit (&ph);
+
+ /* no buffering for stdin */
+ tcgetattr (fileno (stdin), &termopts);
+ termopts.c_lflag &= ~ICANON;
+ tcsetattr(fileno (stdin), TCSANOW, &termopts);
+ setvbuf (stdin, NULL, _IONBF, 1);
+
+ PianoConnect (&ph, argv[1], argv[2]);
+ PianoGetStations (&ph);
+ printf ("webAuthToken: %s\nauthToken: %s\nlistenerId: %s\n", ph.user.webAuthToken, ph.user.authToken, ph.user.listenerId);
+
+ /* select station */
+ curStation = selectStation (&ph);
+ printf ("playing station %s\n", curStation->name);
+ PianoGetPlaylist (&ph, curStation->id);
+
+ curSong = ph.playlist;
+ /* play first track */
+ while (!doQuit) {
+ PianoSong_t *lastSong = NULL;
+ pthread_t playerThread;
+ printf ("%s by %s\n", curSong->title, curSong->artist);
+ memset (&player, 0, sizeof (player));
+ player.url = strdup (curSong->audioUrl);
+
+ /* start player */
+ pthread_create (&playerThread, NULL, threadPlayUrl, &player);
+
+ /* in the meantime: wait for user actions */
+ while (!player.finishedPlayback) {
+ struct pollfd polls = {fileno (stdin), POLLIN, POLLIN};
+ char buf;
+
+ if (poll (&polls, 1, 1000) > 0) {
+ read (fileno (stdin), &buf, sizeof (buf));
+ switch (buf) {
+ case '?':
+ printf ("n\tnext track\nq\tquit\ns\tchange station\n");
+ break;
+
+ case 'b':
+ player.doQuit = 1;
+ PianoRateTrack (&ph, curStation, curSong,
+ PIANO_RATE_BAN);
+ PianoDestroyPlaylist (&ph);
+ break;
+
+ case 'l':
+ PianoRateTrack (&ph, curStation, curSong,
+ PIANO_RATE_LOVE);
+ break;
+
+ case 'n':
+ player.doQuit = 1;
+ break;
+
+ case 'q':
+ doQuit = 1;
+ player.doQuit = 1;
+ break;
+
+ case 's':
+ /* FIXME: does not work, segfault... */
+ player.doQuit = 1;
+ PianoDestroyPlaylist (&ph);
+ curStation = selectStation (&ph);
+ printf ("changed station to %s\n", curStation->name);
+ break;
+
+ }
+ }
+ }
+ pthread_join (playerThread, NULL);
+
+ free (player.url);
+ /* what's next? */
+ lastSong = curSong;
+ curSong = lastSong->next;
+ if (curSong == NULL && !doQuit) {
+ printf ("receiving new playlist\n");
+ PianoGetPlaylist (&ph, curStation->id);
+ curSong = lastSong->next;
+ if (curSong == NULL) {
+ /* no tracks left */
+ doQuit = 1;
+ }
+ }
+ }
+
+ /* destroy everything (including the world...) */
+ PianoDestroy (&ph);
+ curl_global_cleanup ();
+ ao_shutdown();
+
+ return 0;
+}