diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..84f66775 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Reverse engineering, main code: + Lars-Dominik Braun diff --git a/BUGS b/BUGS new file mode 100644 index 00000000..20034c65 --- /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 00000000..ce56cec5 --- /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 00000000..beca2c0f --- /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 00000000..d6458ab8 --- /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 00000000..b0a409ea --- /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 00000000..c8aa4393 --- /dev/null +++ b/NEWS @@ -0,0 +1,4 @@ +News +==== + +Nothing happened yet... diff --git a/RoadMap b/RoadMap new file mode 100644 index 00000000..6b83d8c7 --- /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 00000000..12d2f9b1 --- /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 00000000..2206af2f --- /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 00000000..e74d442b --- /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 00000000..dfaca1fe --- /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 00000000..396f61db --- /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 +#include +#include + +#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 00000000..5b097f1b --- /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 00000000..101d3824 --- /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 00000000..5bafaf53 --- /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 00000000..31c93cfc --- /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 +#include +#include + +#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 00000000..87dc49cb --- /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 00000000..185d94c8 --- /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 +#include +#include +#include + +#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 ("" + "misc.sync" + ""); + 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), + "" + "listener.authenticateListener" + "%li" + "%s" + "%s" + "", 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), "" + "station.getStations" + "%li" + "%s" + "", 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), "" + "playlist.getFragment" + "%li" + "%s" + "%s" + "15941546" + "181840822" + "" + "" + "aacplus" + "", 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), "" + "station.addFeedback" + "%li" + "%s" + "%s" + "%s" + "%s" + "%s" + "%s" + "%i" + "0" + "", 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 = 1 ) */ + free (requestStr); + free (retStr); +} diff --git a/libpiano/main.h b/libpiano/main.h new file mode 100644 index 00000000..1746e530 --- /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 00000000..ac64cd1b --- /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 + +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 00000000..370d2366 --- /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 +#include +#include +#include + +#include "piano.h" +#include "crypt.h" + +/* parses things like this: + * + * + * + * + * + * + * + * @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 as + * string, content of as xmlNode (may contain other nodes + * or text), additional data used by callback(); don't forget + * to *copy* data taken from or 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 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 or */ + 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 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 or , 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 or , 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 or , 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); + + /* */ + 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); + + /* */ + 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); + + /* */ + 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 00000000..c4eede8b --- /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 00000000..8f884401 --- /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 00000000..d125122d --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +}