diff options
| author | Lars-Dominik Braun <PromyLOPh@lavabit.com> | 2010-11-23 21:59:31 +0100 | 
|---|---|---|
| committer | Lars-Dominik Braun <lars@6xq.net> | 2010-12-26 15:47:42 +0100 | 
| commit | 13106ac8bb95e325cf522817f91ad1f3b0fcecb0 (patch) | |
| tree | 5488d884b5fac8bf5f1946cae92e536fa2d0d345 /src/libpiano | |
| parent | d074480b9159a53fc4e6bdb40463289c69c2f6a7 (diff) | |
| download | pianobar-13106ac8bb95e325cf522817f91ad1f3b0fcecb0.tar.gz pianobar-13106ac8bb95e325cf522817f91ad1f3b0fcecb0.tar.bz2 pianobar-13106ac8bb95e325cf522817f91ad1f3b0fcecb0.zip | |
Better directory layout
Removed useless AUTHORS, COPYING and README files. Move manpage to
contrib (it's not exactly source code).
Diffstat (limited to 'src/libpiano')
| -rw-r--r-- | src/libpiano/config.h | 1 | ||||
| -rw-r--r-- | src/libpiano/crypt.c | 197 | ||||
| -rw-r--r-- | src/libpiano/crypt.h | 30 | ||||
| -rw-r--r-- | src/libpiano/crypt_key_input.h | 305 | ||||
| -rw-r--r-- | src/libpiano/crypt_key_output.h | 303 | ||||
| -rw-r--r-- | src/libpiano/piano.c | 1114 | ||||
| -rw-r--r-- | src/libpiano/piano.h | 244 | ||||
| -rw-r--r-- | src/libpiano/piano_private.h | 31 | ||||
| -rw-r--r-- | src/libpiano/xml.c | 826 | ||||
| -rw-r--r-- | src/libpiano/xml.h | 48 | 
10 files changed, 3099 insertions, 0 deletions
| diff --git a/src/libpiano/config.h b/src/libpiano/config.h new file mode 100644 index 0000000..febad25 --- /dev/null +++ b/src/libpiano/config.h @@ -0,0 +1 @@ +#define PACKAGE "libpiano" diff --git a/src/libpiano/crypt.c b/src/libpiano/crypt.c new file mode 100644 index 0000000..8a8ad01 --- /dev/null +++ b/src/libpiano/crypt.c @@ -0,0 +1,197 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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 <stdint.h> +#include <arpa/inet.h> + +#include "crypt_key_output.h" +#include "crypt_key_input.h" +#include "piano_private.h" + +#define byteswap32(x) ((((x) >> 24) & 0x000000ff) | \ +		(((x) >> 8) & 0x0000ff00) | \ +		(((x) << 8) & 0x00ff0000) | \ +		(((x) << 24) & 0xff000000)) + +#define hostToBigEndian32(x) htonl(x) +#define bigToHostEndian32(x) ntohl(x) + +/*	decrypt hex-encoded, blowfish-crypted string: decode 2 hex-encoded blocks, + *	decrypt, byteswap + *	@param hex string + *	@return decrypted string or NULL + */ +#define INITIAL_SHIFT 28 +#define SHIFT_DEC 4 +unsigned char *PianoDecryptString (const unsigned char *strInput) { +	/* hex-decode => strlen/2 + null-byte */ +	uint32_t *iDecrypt; +	unsigned char *strDecrypted; +	unsigned char shift = INITIAL_SHIFT, intsDecoded = 0, j; +	/* blowfish blocks, 32-bit */ +	uint32_t f, l, r, lrExchange; + +	if ((iDecrypt = calloc (strlen ((char *) strInput)/2/sizeof (*iDecrypt)+1, +			sizeof (*iDecrypt))) == NULL) { +		return NULL; +	} +	strDecrypted = (unsigned char *) iDecrypt; + +	while (*strInput != '\0') { +		/* hex-decode string */ +		if (*strInput >= '0' && *strInput <= '9') { +			*iDecrypt |= (*strInput & 0x0f) << shift; +		} else if (*strInput >= 'a' && *strInput <= 'f') { +			/* 0xa (hex) = 10 (decimal), 'a' & 0x0f == 1 => +9 */ +			*iDecrypt |= ((*strInput+9) & 0x0f) << shift; +		} +		if (shift > 0) { +			shift -= SHIFT_DEC; +		} else { +			shift = INITIAL_SHIFT; +			/* initialize next dword */ +			*(++iDecrypt) = 0; +			++intsDecoded; +		} + +		/* two 32-bit hex-decoded boxes available => blowfish decrypt */ +		if (intsDecoded == 2) { +			l = *(iDecrypt-2); +			r = *(iDecrypt-1); + +			for (j = in_key_n + 1; j > 1; --j) { +				l ^= in_key_p [j]; +				 +				f = in_key_s [0][(l >> 24) & 0xff] + +						in_key_s [1][(l >> 16) & 0xff]; +				f ^= in_key_s [2][(l >> 8) & 0xff]; +				f += in_key_s [3][l & 0xff]; +				r ^= f; +				/* exchange l & r */ +				lrExchange = l; +				l = r; +				r = lrExchange; +			} +			/* exchange l & r */ +			lrExchange = l; +			l = r; +			r = lrExchange; +			r ^= in_key_p [1]; +			l ^= in_key_p [0]; + +			*(iDecrypt-2) = bigToHostEndian32 (l); +			*(iDecrypt-1) = bigToHostEndian32 (r); + +			intsDecoded = 0; +		} +		++strInput; +	} + +	return strDecrypted; +} +#undef INITIAL_SHIFT +#undef SHIFT_DEC + +/*	blowfish-encrypt/hex-encode string + *	@param encrypt this + *	@return encrypted, hex-encoded string + */ +unsigned char *PianoEncryptString (const unsigned char *strInput) { +	const size_t strInputN = strlen ((char *) strInput); +	/* num of 64-bit blocks, rounded to next block */ +	size_t blockN = strInputN / 8 + 1; +	uint32_t *blockInput, *blockPtr; +	/* output string */ +	unsigned char *strHex, *hexPtr; +	const char *hexmap = "0123456789abcdef"; + +	if ((blockInput = calloc (blockN*2, sizeof (*blockInput))) == NULL) { +		return NULL; +	} +	blockPtr = blockInput; + +	if ((strHex = calloc (blockN*8*2 + 1, sizeof (*strHex))) == NULL) { +		return NULL; +	} +	hexPtr = strHex; + +	memcpy (blockInput, strInput, strInputN); + +	while (blockN > 0) { +		/* encryption blocks */ +		uint32_t f, lrExchange; +		register uint32_t l, r; +		int i; + +		l = hostToBigEndian32 (*blockPtr); +		r = hostToBigEndian32 (*(blockPtr+1)); +		 +		/* encrypt blocks */ +		for (i = 0; i < out_key_n; i++) { +			l ^= out_key_p[i]; + +			f = out_key_s[0][(l >> 24) & 0xff] + +					out_key_s[1][(l >> 16) & 0xff]; +			f ^= out_key_s[2][(l >> 8) & 0xff]; +			f += out_key_s[3][l & 0xff]; +			r ^= f; +			/* exchange l & r */ +			lrExchange = l; +			l = r; +			r = lrExchange; +		} +		/* exchange l & r again */ +		lrExchange = l; +		l = r; +		r = lrExchange; +		r ^= out_key_p [out_key_n]; +		l ^= out_key_p [out_key_n+1]; + +		/* swap bytes again... */ +		l = byteswap32 (l); +		r = byteswap32 (r); + +		/* hex-encode encrypted blocks */ +		for (i = 0; i < 4; i++) { +			*hexPtr++ = hexmap[(l & 0xf0) >> 4]; +			*hexPtr++ = hexmap[l & 0x0f]; +			l >>= 8; +		} +		for (i = 0; i < 4; i++) { +			*hexPtr++ = hexmap[(r & 0xf0) >> 4]; +			*hexPtr++ = hexmap[r & 0x0f]; +			r >>= 8; +		} + +		/* two! 32-bit blocks encrypted (l & r) */ +		blockPtr += 2; +		--blockN; +	} + +	free (blockInput); + +	return strHex; +} diff --git a/src/libpiano/crypt.h b/src/libpiano/crypt.h new file mode 100644 index 0000000..e20847c --- /dev/null +++ b/src/libpiano/crypt.h @@ -0,0 +1,30 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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 (const char *strInput); +char *PianoEncryptString (const char *strInput); + +#endif /* _CRYPT_H */ diff --git a/src/libpiano/crypt_key_input.h b/src/libpiano/crypt_key_input.h new file mode 100644 index 0000000..a02e668 --- /dev/null +++ b/src/libpiano/crypt_key_input.h @@ -0,0 +1,305 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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 _CRYPT_KEY_INPUT_H +#define _CRYPT_KEY_INPUT_H + +#include <stdint.h> + +/* decryption key for last 48 bytes of audio urls + * search for rpc.input in the decompiled pandora actionscript + */ + +const unsigned int in_key_n = 16; + +static const uint32_t in_key_p [16 + 2] = { +		0xCB42446BL, 0x84C9ADD7L, 0x58BB40B6L, 0x67309C28L, +		0x847AE93FL, 0x634B08FAL, 0x7B41B0E7L, 0x6CA77EA8L, +		0x680A3F07L, 0x32C26224L, 0x15F68F8FL, 0x84983ECEL, +		0xE88938C0L, 0xFB2F1633L, 0x172C14BDL, 0xEDD40F8CL, +		0xFF10C4FBL, 0x22B7AB11L, +		}; + +static const uint32_t in_key_s [4][256] = {{ +		0x44B440E2L, 0xE99DBE06L, 0xB9F1A081L, 0x0933FCA1L, +		0x6B412E99L, 0xB30F4B41L, 0xE32063E6L, 0xF9C0101EL, +		0x5265F727L, 0x678F8106L, 0xACF39C5CL, 0x28F2868FL, +		0x5475BE2FL, 0x404DE0BCL, 0x23468728L, 0x184A1488L, +		0xEA971385L, 0x2F886887L, 0x5E95611CL, 0x239508CCL, +		0x88355159L, 0x5E7E789FL, 0x9A805DAFL, 0xEC5AB7E0L, +		0x4A3E4C9FL, 0xA2BE130CL, 0xEE7E0076L, 0x05B9A2F8L, +		0x6D7AD1C3L, 0x3CAA426EL, 0x2879FC42L, 0x29BB3A22L, +		0x62AE8B5DL, 0xC561999BL, 0x98D278B1L, 0x0373DDA7L, +		0x3CED65D5L, 0x4540C197L, 0x8AE57D79L, 0x24F37705L, +		0x54E2BF0CL, 0xCAF2D2C8L, 0xAB85D018L, 0xBBD96449L, +		0xB36A13B9L, 0x3C44EB0AL, 0xD820C26BL, 0xF90B784DL, +		0xAB672603L, 0xD532CF15L, 0x7FFB6686L, 0x7BE27118L, +		0x793DDA02L, 0xE73107DDL, 0x2632F764L, 0x6FBE7A13L, +		0x65982C19L, 0xAFF729A3L, 0x69B5BBF7L, 0x2864B0FAL, +		0x8AED80D3L, 0x0AEB3597L, 0x13689958L, 0x80B40D77L, +		0x3D9641A8L, 0xF24E7E40L, 0xB9E7A890L, 0xDC02983DL, +		0xD9050DA9L, 0xFB874500L, 0xB2C64291L, 0xDC12F8F5L, +		0x128A5CD2L, 0x527F82D3L, 0xCD7C1081L, 0xC5EBDB5FL, +		0xF968BDD0L, 0xF3E427A3L, 0xBCF76022L, 0xA94CA0BBL, +		0x28884495L, 0x8214C39CL, 0x6851B166L, 0xEBA17650L, +		0x95729279L, 0xCE1666C5L, 0x6A57605DL, 0x1BD16C4BL, +		0x59EF9ECCL, 0xE7C09A6AL, 0x24673702L, 0x0E7CE01EL, +		0x3636E13AL, 0x40F429BAL, 0x9FBA277EL, 0x9AE49DD0L, +		0x300E6BABL, 0x201ADB58L, 0xC029E2D9L, 0xE5C74ED7L, +		0x5C143553L, 0x8E747F2CL, 0x159043C5L, 0x379614D4L, +		0x9075D06FL, 0x585C1BC2L, 0xE9D22CC1L, 0x0914AEC0L, +		0xB3B46C73L, 0xC96D2F00L, 0xB14BB0D9L, 0x46A5C5B6L, +		0x0E3516F4L, 0xEB9AB01EL, 0x5C04E434L, 0x284AAFB4L, +		0x1BCAF462L, 0xF1A5542AL, 0xBBD03E4AL, 0x4BDC3DA7L, +		0x6BD0FCC9L, 0x40D21E00L, 0x32E2AEF1L, 0xEF62B668L, +		0x344EA1BAL, 0x46B1BD02L, 0xCAFE4DC6L, 0x15BE27F0L, +		0xBFF5A998L, 0x3B0D9B30L, 0x27CA9A40L, 0x84C597FFL, +		0xD6859FE3L, 0x5D045192L, 0x2A002659L, 0xCC8B3052L, +		0xFAEFE7C2L, 0xEB9F883EL, 0x69772177L, 0x5FA05797L, +		0x69DF2134L, 0xDACC373BL, 0x3C035B9EL, 0x977A58DCL, +		0x84D49E26L, 0x912CFF20L, 0xDFA2D5A6L, 0x0CA8AA62L, +		0x53CC93D9L, 0x3DD8536AL, 0xF40CF797L, 0xC6EF5FA5L, +		0xDDBF6EA2L, 0xFF79AD8BL, 0x9CC8F9B6L, 0x9070482EL, +		0xB6779612L, 0x0A7C86DFL, 0x968E17A3L, 0x28CA9EF1L, +		0x86DB025BL, 0xF2A80541L, 0x2631C384L, 0x5750F7E3L, +		0x78191CBFL, 0x4025BF50L, 0x1E032A2BL, 0xC3B4DE8DL, +		0xAC98A492L, 0xCD90D98FL, 0x92B02F24L, 0xFC462ECFL, +		0x435695A9L, 0xEDECDDA4L, 0x297B6304L, 0xD973A25AL, +		0x65A7991DL, 0x8B727303L, 0xC8F89BD7L, 0xCF18B1D7L, +		0x60A234FFL, 0x13E68F78L, 0xF919D31AL, 0x5249D0A5L, +		0x117B11AAL, 0xEF6D0783L, 0x2128D583L, 0xA7A24FEAL, +		0xD9C379ECL, 0x86A4C5ADL, 0xF3CDAA1CL, 0x04A8A51FL, +		0xE19C74E7L, 0x578622A0L, 0xFD70277DL, 0xEDD3226AL, +		0x503434D8L, 0x31A8EBB5L, 0x9122632EL, 0x7EF237DAL, +		0xA59DEF47L, 0xDD87BA93L, 0x7965AB65L, 0x26790F7CL, +		0xDFDF407BL, 0xAF80CDF0L, 0xA9E55C4FL, 0x54B77138L, +		0x39B26324L, 0xBE3FD4CDL, 0xDEB06C51L, 0xEEB11B71L, +		0x90B974D4L, 0xE125702EL, 0x9F6E26EAL, 0x6E4574E1L, +		0x0ABC33CAL, 0x3F51A4B0L, 0x225E548AL, 0x7D275103L, +		0x3849134BL, 0xE32DC3B0L, 0x08297936L, 0x788C457BL, +		0x17F9219EL, 0xE7E6FE7DL, 0xD79DB0B0L, 0xD3F8FEF0L, +		0x8B0D4DBFL, 0x210883B0L, 0xEACAC580L, 0xAEC1E03EL, +		0xF2A7678AL, 0x76457B5BL, 0xB518F841L, 0x31E3B067L, +		0x4E972C3BL, 0x19E5A9BCL, 0xB7438C21L, 0x4C5B5F28L, +		0xFBB2E5BDL, 0x7734BB35L, 0x705A9013L, 0xD132FAC5L, +		0x99F8BC98L, 0x8E6B0A9DL, 0xB287744FL, 0x4CBC0613L, +		0xF094CEB8L, 0xF93137B0L, 0x9242EE26L, 0xC25D9AEBL, +		0xD517C2F2L, 0xEC2F7F38L, 0xE18380AFL, 0x22C2678AL, +		}, { +		0xDE0A562AL, 0x596C7989L, 0x2E99CBDEL, 0x5CC946AFL, +		0x2DA232BFL, 0x64145592L, 0x7885E518L, 0x85B53628L, +		0xFB83003EL, 0x5F643977L, 0x193D31BFL, 0x0FDB8849L, +		0x2BA77CF5L, 0x86D0A1A5L, 0x48803977L, 0xB670B7DDL, +		0x2924E754L, 0x333CAA9FL, 0x994FF797L, 0x9858B8BEL, +		0x22BFD9ADL, 0x1A51D7DCL, 0x372CD282L, 0xB38A5CA4L, +		0xB0B6858DL, 0x4F5CAD72L, 0x3C0DC2D6L, 0xEB090786L, +		0xC45E17FCL, 0xF0C37D9CL, 0x8315CA42L, 0x336E14D8L, +		0xE4DA980CL, 0x14EEBD73L, 0xA82E556CL, 0x4ABA084AL, +		0x9EEC5155L, 0x0CA47152L, 0x03BE2A25L, 0x874F8618L, +		0xC3C31219L, 0x8554B382L, 0x26FFF693L, 0xD9FE05D6L, +		0xC69BB513L, 0xC547ED34L, 0x44F66E01L, 0x58B32FD0L, +		0xF9F7FA8AL, 0xFEF4A493L, 0x2999E20BL, 0x6D23743FL, +		0x97E2A9DCL, 0x1916908AL, 0x905CBF0DL, 0xE0290BDBL, +		0xC06B65EFL, 0xE5A45154L, 0x45ABB6ECL, 0xDD329C85L, +		0xEDF93835L, 0xE5D485D5L, 0x248B2CD5L, 0x60CC627BL, +		0x2B3224F1L, 0xD7DFA43DL, 0xD5D6DA9AL, 0x7A3F9A29L, +		0x26605F98L, 0x435FB927L, 0xED9A7CD7L, 0x6020C2EFL, +		0x43AC15D0L, 0x05FE8353L, 0x74AF1FB8L, 0xADFDC949L, +		0x3BA09A14L, 0x2BC91C0DL, 0x7D681AD5L, 0xA08CA21CL, +		0x208C85ADL, 0x0F3DE514L, 0xB4C87BE1L, 0x455233DCL, +		0xFF35FDF1L, 0xCE93E7E9L, 0x409BA175L, 0x817C4198L, +		0x749B8E5AL, 0xBA599286L, 0x44E40068L, 0x7FA013C6L, +		0x9D62E731L, 0x453F48E4L, 0x375CADBEL, 0xC3D661D5L, +		0xA96A5BF9L, 0x9D2B321AL, 0x0A144AFBL, 0x01590B67L, +		0x9887312FL, 0x7592FB46L, 0x99AC6DD8L, 0xAA347510L, +		0x0F3DC8A9L, 0x9BE58B17L, 0x49C674FCL, 0x3D1F5303L, +		0x138E2052L, 0x1B7CA3EBL, 0xB3C8BE68L, 0xB5C6CB1DL, +		0xBA62EA1CL, 0x269241DBL, 0xA0EE1AB3L, 0x8EB3E79CL, +		0x94EA0E9FL, 0xB86FFB54L, 0x56DCBF7FL, 0x3404FD03L, +		0x8076B757L, 0xB05A9529L, 0x8CC7B224L, 0x4F29804CL, +		0x6CD2C621L, 0x99424188L, 0xF89E7F5DL, 0xFDF62C52L, +		0x94D264B1L, 0x9AE26508L, 0xE7C1DF25L, 0xFCE03375L, +		0x4111F745L, 0x46978B8AL, 0x6D3DEBE0L, 0xA8C9A4A1L, +		0xBF9ADEE2L, 0x651A9A66L, 0x37EBEFEDL, 0x6BAC6274L, +		0xED007BFAL, 0x8B00DB5DL, 0x8EB88E4FL, 0x7247626BL, +		0xC70E0D71L, 0xB06D9EC3L, 0x777CBB67L, 0x9812CC56L, +		0x12ACE7D0L, 0xEE395981L, 0xFE39A6EFL, 0xC1F592CDL, +		0xB8C0866DL, 0xC0D8526EL, 0xC6AA7A35L, 0x91113015L, +		0x36CC0A0DL, 0xD1E8DBA0L, 0x074756C8L, 0xFC272600L, +		0x6C33093EL, 0x44D5C245L, 0xCA27B4C7L, 0x5A794CFAL, +		0x459D3DD0L, 0x0F7D4917L, 0x139A3245L, 0x9B2E5E3CL, +		0x31018582L, 0x759B9D72L, 0x8BDD1D9BL, 0xA16CB7FCL, +		0x3BBE42B1L, 0x87E40683L, 0x9BE04779L, 0xE9DDE72BL, +		0x0BE9A89AL, 0x1CB85941L, 0x96134FD9L, 0xFB347B02L, +		0xD908504AL, 0x71F33096L, 0x705269F0L, 0x3EF468FDL, +		0xC97983DAL, 0x71277190L, 0x8C2B030FL, 0x8CAE4554L, +		0x2E643F45L, 0xE16A9CE9L, 0x2C06928EL, 0xC7E0F46AL, +		0xBDDCEB74L, 0x74985EDBL, 0xBC223E1DL, 0x7F8F5B2AL, +		0x1EBFAFBCL, 0x3B60AE99L, 0x63083D95L, 0x2905083CL, +		0xF926F42EL, 0xD5389D31L, 0x6CA90A33L, 0xE1158CAAL, +		0x352434A4L, 0xB45FD6B1L, 0x17389418L, 0x70D400F6L, +		0x9127D3E0L, 0xA8EB8D18L, 0x39020FBEL, 0x417AB2E5L, +		0xA5E92B88L, 0x5F36AEFCL, 0x4057731CL, 0xD1E966F7L, +		0x0DA44875L, 0x3BE7D0DBL, 0x1C7850CDL, 0xE3B1462EL, +		0xF9AFEFF6L, 0x210E1CCEL, 0x36FBB8AEL, 0x8584030DL, +		0x2DD9731AL, 0x9554A44BL, 0x2C6F8100L, 0x983A1BE5L, +		0x25FAF22DL, 0x338316A7L, 0x0E5A690DL, 0xE702EBEBL, +		0x52AC420EL, 0xEAC503EFL, 0xD2FE1B98L, 0xE1D55B98L, +		0xD7DD5C6EL, 0xE756FFF0L, 0xD3FD66EBL, 0x1FD30A11L, +		0x03E18282L, 0x856F2216L, 0x6917F24CL, 0x12975941L, +		0xD98387CAL, 0x2B9E153FL, 0xFD7005E0L, 0x05A501F2L, +		0xA731DB07L, 0xBF268F18L, 0x47E9E9C2L, 0x442148F8L, +		0x1CCF6FACL, 0x239820BEL, 0x56C0EC64L, 0xC6C59DF1L, +		},{ +		0x1D985BEEL, 0x336930D2L, 0xCA40E672L, 0x7036E21CL, +		0x7B43BD3CL, 0xA02DBD7DL, 0x7DFA1A92L, 0xB13508C5L, +		0x01633D3CL, 0x6CBD1AA5L, 0xCDC61031L, 0x15993E15L, +		0x669E1B6FL, 0x78B79587L, 0x61D58836L, 0x888D5578L, +		0x8B99F671L, 0x346906B6L, 0x5EA37C50L, 0xC32C7220L, +		0xAA6101DEL, 0xAF0CD647L, 0x9840E7DFL, 0xBC4EB801L, +		0x071126BAL, 0xCD6D71A4L, 0x0CDA5F16L, 0x7838C18CL, +		0x8F1641CBL, 0x7DF307E3L, 0xB83E78D1L, 0x24E91D07L, +		0x0F5BB3BCL, 0x172BDFFBL, 0xD24AA952L, 0x41CF15C3L, +		0x78A696A5L, 0x15CD0C0AL, 0xD24D916DL, 0xA2CF942CL, +		0xA1EC1AAAL, 0x0B48FCE0L, 0xE1779859L, 0x99F8806AL, +		0x34333D69L, 0xABBA62D0L, 0xF6E91D76L, 0x0B0D5FDAL, +		0x5A467847L, 0x74DA0A4DL, 0x0335F980L, 0xE7C55B44L, +		0x6DD5E917L, 0xC7305285L, 0xCF1D07C6L, 0x8D017ECBL, +		0xE10A16C1L, 0x0DB9438CL, 0x2FA12B58L, 0x332FA54DL, +		0x02BD7743L, 0x4B544614L, 0x7907B6AEL, 0x75401EBAL, +		0xF7382064L, 0xF1325592L, 0x06FB5C05L, 0x9F5FEF1FL, +		0x3A641771L, 0x807BF700L, 0xC63EDF23L, 0x9FFD35E9L, +		0x437A410EL, 0x225D18FBL, 0xAD901352L, 0x9D2F8585L, +		0xEA317135L, 0xCB724C48L, 0xCA568A14L, 0xB153340AL, +		0x88794F5FL, 0x0C208094L, 0x85BE94E6L, 0x86C5F48AL, +		0xFC4AC759L, 0xFCCEA783L, 0x491AF14BL, 0x23C9622CL, +		0x85660BAFL, 0x110300CBL, 0xDE2D8E21L, 0xBAD7D22BL, +		0x3649D2A8L, 0x64439BF3L, 0xFDD7F2ADL, 0x68129C07L, +		0x3D03801DL, 0xE2D3B28CL, 0xA94193D2L, 0xEE2C34F0L, +		0x457DCDF1L, 0x4E21BC94L, 0x8F557C82L, 0x13EE8AB5L, +		0x0B2A8EC9L, 0x7796592BL, 0x5D9E3346L, 0x3621C85FL, +		0x1EB7FF52L, 0xCCDF71D8L, 0x538DD6AEL, 0x748274A9L, +		0x6552081CL, 0xFA61EE48L, 0xFB2A7098L, 0xA02BA33FL, +		0xB145EA01L, 0xE4C5DEC9L, 0x9E2BF9B1L, 0x6413006DL, +		0x8F7C7501L, 0x9B51E842L, 0x5ADD5755L, 0x06CAF452L, +		0x80050406L, 0xCB961521L, 0xEFC54E27L, 0x420EE737L, +		0xADB18EAEL, 0xF8B0B2FBL, 0xC8CDC88FL, 0x3A026D91L, +		0x5F99BB22L, 0x391C12F8L, 0xBDF1CEE6L, 0xFEBE0726L, +		0x6CC79280L, 0x3F7AC7F2L, 0x3B92345CL, 0x5C7BB986L, +		0xC60C12D7L, 0x4F29C1FAL, 0x04276434L, 0xC1272CD2L, +		0x5E64BC58L, 0xD473D8F8L, 0x38E9D502L, 0x5C00EE4EL, +		0x80A1A552L, 0xD49CD6D2L, 0xEA96CBE7L, 0x029E2A86L, +		0x0D04BA72L, 0xE9B0389DL, 0x4AC913EBL, 0x85927E61L, +		0x134A0D51L, 0xE63AFF82L, 0x5D7C3FEEL, 0x9373DA83L, +		0x361324B4L, 0x18569865L, 0x7EAC6BD8L, 0x945CA42CL, +		0x6A1FD8B8L, 0x6C9D06F7L, 0x01D4072FL, 0xAED3BEA5L, +		0x9C7BADA7L, 0x740C8802L, 0xAD1D6843L, 0xB84145EBL, +		0x2804CAEBL, 0x31EB19FBL, 0x402E5195L, 0x05451516L, +		0xF9770FC4L, 0x547FA291L, 0xF9B980EAL, 0xD6DC914DL, +		0x8A009CDFL, 0xFDFEDDADL, 0xEBAC5EF5L, 0x575B2AD2L, +		0x67A8655FL, 0x54590146L, 0x21FA9A1FL, 0xB8CD9B23L, +		0x1D313DFFL, 0xC5D15FFFL, 0xB6734243L, 0xD1B44EFFL, +		0xEE6DFF7EL, 0x0A6DB2BCL, 0x2A2AE34EL, 0x596782E6L, +		0x1DF3E26BL, 0xCE3EA01AL, 0x3CCBBEEFL, 0xD4B8AF1FL, +		0x555D5325L, 0x78F81205L, 0x528EFD8CL, 0x01F3D29FL, +		0xAD12326CL, 0x816D4F2EL, 0x6DD2FFE9L, 0x03C4EE90L, +		0xE9E561B6L, 0x28237064L, 0x82143F5FL, 0xEED4AA29L, +		0x9E63A1C6L, 0xB25E2AEAL, 0x516B9A8AL, 0xB52B4B71L, +		0xDDEF7CFFL, 0x6A8FFBDDL, 0x877EC0E5L, 0x72AF36D8L, +		0xF9EC2EC3L, 0xBD89E9AFL, 0x0A2FC438L, 0xD0E8BEE7L, +		0xD8979CF1L, 0x0AF071BEL, 0x0BC600C9L, 0x7E1F6318L, +		0xBFF4BF36L, 0x01DF67EEL, 0x6B35580BL, 0x2A3487ABL, +		0x1694328EL, 0x68358F88L, 0x23C60980L, 0xBE312A5BL, +		0x444E80C9L, 0x7ECE3A97L, 0xC3CE446CL, 0x5269084CL, +		0xC611CCE5L, 0xA156FBADL, 0xA2331EC8L, 0x1065EA4BL, +		0xA59F0F71L, 0xE46F2C17L, 0x2E2247DCL, 0xB5EBAA6FL, +		0xD8DE0349L, 0x0EA6F1B3L, 0x465FB0A0L, 0x0CE5A14CL, +		0x6A10A909L, 0xBCB590D3L, 0x8FA66C30L, 0xD1FCB44DL, +		},{ +		0x475CA7E8L, 0x4C51BBC1L, 0xA90763E1L, 0x7BDF2294L, +		0x04D96F34L, 0x11318CB9L, 0x54A65710L, 0x041597BEL, +		0xC49B15C2L, 0x09B9521AL, 0x5589972BL, 0x10167358L, +		0xA3927ED5L, 0x405F7752L, 0x2CBCB573L, 0x37106B2EL, +		0x4CF216A4L, 0x5AB1D0F2L, 0x3ED8CA8EL, 0xA612D957L, +		0xADC5D570L, 0xD45C1E98L, 0x53C28628L, 0xBCF19A34L, +		0x6CA25F5CL, 0x5C5E4FA2L, 0x7C155954L, 0xE99CE5F9L, +		0xD9A180F9L, 0x4F3CF09BL, 0x9DDF75A6L, 0x6D240EE0L, +		0x67973B52L, 0xE13895B4L, 0x36ADE486L, 0x22EC32D2L, +		0x075D6EAEL, 0x29C31053L, 0xAC06EE74L, 0x1A9D3316L, +		0x8A2D0CC3L, 0x57DC77D3L, 0x40B2D07FL, 0xDFA2051AL, +		0xFDC90DFCL, 0x342E9AC5L, 0xB04EB091L, 0x9E1C2D1FL, +		0x075A20A3L, 0xE45FA195L, 0x3F958FE3L, 0x18C98F15L, +		0xC70AE917L, 0x78040F9BL, 0xE4322DEBL, 0x0903841FL, +		0xAE71257EL, 0xA82C7909L, 0xA398504BL, 0x56A9A694L, +		0x7DA7F73BL, 0x12942475L, 0xAAC0C982L, 0xDFD0E53EL, +		0x27CE728BL, 0xE94327CBL, 0xF2EBA423L, 0x72B1476EL, +		0x317756F6L, 0x056654E3L, 0x074C0192L, 0x11B6FF21L, +		0x939FD4C5L, 0xE6E45B55L, 0x66211539L, 0x753C6C46L, +		0x536DB219L, 0x939C3AF0L, 0x9783EE73L, 0xC8978DE8L, +		0xBA0329F6L, 0x3B892181L, 0x4CDA3336L, 0xFD15F1EFL, +		0xAE2B2E61L, 0x2637C83BL, 0x9D9930BFL, 0x72ADFC41L, +		0x48DBFFFFL, 0x448E80F4L, 0xBA1CC3E1L, 0x61CCB37DL, +		0xD3CFEC32L, 0x0E6804A9L, 0x1ECE11A1L, 0x15809783L, +		0x9F7FD813L, 0x64A39648L, 0x9E67CA64L, 0x19B3E4B8L, +		0x8740466AL, 0xEBB79667L, 0x1CE86B36L, 0xC7BCE505L, +		0x2445215DL, 0x54ADCC77L, 0xAB187AC2L, 0x97B82A38L, +		0xA66B2D42L, 0xA3D07412L, 0x4A9CB0F4L, 0x2C51F98CL, +		0xCA7FC25BL, 0x73AEB532L, 0xF45769BBL, 0x8068AEF4L, +		0x48A14C08L, 0x011E7A0BL, 0xD4FEF360L, 0xB572B6ECL, +		0x947692FFL, 0x8EB6BE12L, 0xDEB04AF3L, 0xA9CD494EL, +		0x7C522A9DL, 0x4CC24357L, 0x616E3132L, 0x68073F0DL, +		0x20F7237AL, 0x7EA98584L, 0x3B6BF43CL, 0x29F11571L, +		0x759B5F60L, 0x7D5BCACCL, 0x8C86BC43L, 0xB378EF1BL, +		0xD00EAF88L, 0xBD85FE1AL, 0xB4A42C5DL, 0x2075442DL, +		0x184038CCL, 0xC3D9F6F8L, 0x1D72BAC3L, 0xDD8C41C0L, +		0xD85F7634L, 0xB48A6902L, 0x8BB3F160L, 0x178CCA70L, +		0x4EE8D16EL, 0x5121D6FDL, 0xF2F09DA9L, 0x84B55B38L, +		0x8D081959L, 0x13F21DADL, 0x19BCDA5CL, 0x909A9FDFL, +		0x11AD6731L, 0x2CE9D09FL, 0xAA8E9543L, 0x9F8D5555L, +		0x679FE7C1L, 0x251591CBL, 0xC4187630L, 0x57324F07L, +		0xB2C35182L, 0xBD16E4F0L, 0xC3B3DE3FL, 0xEA6CBA23L, +		0x00C810DBL, 0xBB040931L, 0xE0BA08A6L, 0xDC4AC24BL, +		0xEE1428BBL, 0x964A6F9FL, 0x2096F5DCL, 0x2170A50CL, +		0x3FBCA4BDL, 0x7C321FAAL, 0x88679D5DL, 0x0F5FFFDCL, +		0x88AA1865L, 0xFD51E01AL, 0xA35EF105L, 0x8B99A039L, +		0xD5C22176L, 0xB1A73D55L, 0xA0080F3DL, 0xDBC61A70L, +		0x3FB106E3L, 0xBAEA8E73L, 0x7E34C1B3L, 0x40F3DC19L, +		0xFD9AEEE4L, 0xA3E6A013L, 0xEECF6A5EL, 0xA83012D4L, +		0xDEDF0B25L, 0x7CB1D8C2L, 0x02C4180CL, 0xE38905D8L, +		0x2D631C38L, 0x36612C66L, 0x9845588CL, 0x9510F7FDL, +		0xBCD5C8B1L, 0x55D50272L, 0x9B35118EL, 0xFB7C4E3FL, +		0x2E3BD98FL, 0x56DD4BD7L, 0x4C3B6F27L, 0x0264DDB7L, +		0xBD4A811CL, 0x2A9A4F84L, 0x2292258AL, 0xE7799B02L, +		0xF5B529B2L, 0x894B5D58L, 0xD3392CAAL, 0x515CCAC1L, +		0xB6857B04L, 0xB2CBE5DFL, 0x28B230C2L, 0xE3CE03F5L, +		0x0581D4DFL, 0x3CC0D279L, 0xD0C1EDECL, 0x160B926FL, +		0x32F58056L, 0x9D574911L, 0xED9FB621L, 0xA2D920F7L, +		0xB4BE7EACL, 0x6947D33FL, 0xBB438F92L, 0xDD11B405L, +		0xDEFF0F70L, 0x03B3E6A8L, 0x4BD0A277L, 0xE28FA297L, +		0x7098CAF4L, 0xB74B88E5L, 0xC3330744L, 0x77E7975AL, +		0xB35AC1B1L, 0x3BFEA68CL, 0x84BF6163L, 0x101D5CC0L, +		0xF4558349L, 0x0CF6A28BL, 0xD76AF6B8L, 0xD6A3140DL, +		0x3F37D065L, 0x0E55EA90L, 0xC1A759D1L, 0x70265EABL, +		}}; + +#endif /* _CRYPT_KEY_INPUT_H */ diff --git a/src/libpiano/crypt_key_output.h b/src/libpiano/crypt_key_output.h new file mode 100644 index 0000000..b8823d5 --- /dev/null +++ b/src/libpiano/crypt_key_output.h @@ -0,0 +1,303 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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_KEY_OUTPUT_H +#define _CRYPT_KEY_OUTPUT_H + +#include <stdint.h> + +const unsigned int out_key_n = 16; + +static const uint32_t out_key_p[16 + 2] = { +		0x77B1CD94L, 0xDCB48217L, 0x69404CDCL, 0x2C02F724L, +		0x22961551L, 0xB497993BL, 0x5B5EEE8CL, 0xA209AE23L, +		0xE26B1B43L, 0x90F1CE4CL, 0xB86F975AL, 0xF3CB8371L, +		0xDED8E87CL, 0xB2882D4FL, 0x74984776L, 0x361650B2L, +		0x666FB475L, 0x85A10677L, +		}; + +static const uint32_t out_key_s[4][256] = {{ +		0xBA448614L, 0xC35FBBD7L, 0x31B6EC14L, 0xA85F989BL, +		0x89A83B0EL, 0xAB11C2E7L, 0xFC376FBBL, 0x55B2E7B6L, +		0xA330F22EL, 0xA8229AE0L, 0x9D025EF0L, 0x5E917398L, +		0x3BE382F9L, 0x8F103C90L, 0x463C36A2L, 0xD223C350L, +		0x29DDD3F8L, 0x35075D14L, 0x0F963F64L, 0x74D02046L, +		0x28DCFBF1L, 0xEE12889EL, 0x46C74707L, 0xA1C5A67FL, +		0x8FFE2E9DL, 0xACE75324L, 0x49DA447CL, 0x3061FBB3L, +		0x14579E12L, 0xF1E8ED6EL, 0x76A679C1L, 0xD8EF0FEFL, +		0xA5EA7835L, 0xD63EDB8DL, 0x484F139DL, 0x3D3AD62AL, +		0x8A6331F1L, 0xEF43FE4EL, 0x3745B29FL, 0xEAF8A9ADL, +		0xF9FFF4AEL, 0x1E5BB3C5L, 0xFF988E0AL, 0x8C9E1147L, +		0x3EC6CED1L, 0x4CE0F56DL, 0x206E4341L, 0x79C0520FL, +		0x4FA3C2FDL, 0x1A8189E5L, 0xFA0BC58EL, 0xA0F29358L, +		0x42B379BBL, 0xEC55CB3DL, 0xBD7F1551L, 0x31E17BEAL, +		0xACC91098L, 0x7C36A984L, 0x8611A88BL, 0x255CE7CFL, +		0xC80DB988L, 0x743CEEBCL, 0x7AA258B6L, 0xE82424C9L, +		0xD1EAC3DBL, 0x2D562386L, 0x5250E40BL, 0x9B5285F5L, +		0x895D0124L, 0xAB8037D6L, 0xFD67BA8FL, 0x351B05D7L, +		0x0B124E65L, 0x20CF592BL, 0x91BE281FL, 0x879AD90AL, +		0x6609FEB6L, 0xD8A2305FL, 0x861194A2L, 0xD51DB0E3L, +		0xF735D810L, 0xAEFA5174L, 0x56A9577FL, 0x24F3408BL, +		0x10627B95L, 0xBEE74251L, 0x7ECD2211L, 0x95A8B55EL, +		0xBDE1028EL, 0xDEF339E2L, 0xD0768D34L, 0x6BD5A569L, +		0xC2240D0FL, 0xE171393DL, 0x14A24028L, 0x96760DFAL, +		0x4C78040FL, 0xBD6F76D0L, 0x5EE4BA83L, 0xB20C926FL, +		0xC0F0DCD8L, 0xEF5D4105L, 0x383D3B65L, 0x51E42A4AL, +		0x1505EECEL, 0x86B2BFFDL, 0x56EE7DFCL, 0x8734574BL, +		0xCAA9E52DL, 0xE0F66450L, 0x76B7037BL, 0x84AE5148L, +		0xFB7EC4EBL, 0x6A3DEB3DL, 0x06C7EA69L, 0x165F2DFFL, +		0x7B9DB92AL, 0xB9B24C67L, 0x43AB448AL, 0xA64F30D7L, +		0x998BE34DL, 0x628E747AL, 0x294162B9L, 0xAB8014C7L, +		0x22E1516FL, 0x74C3E589L, 0x003D14D0L, 0x8D724CE1L, +		0x2053C615L, 0x9AD67B30L, 0x29C3D0E8L, 0xBC3269B5L, +		0x7CD7D118L, 0x892FD6BEL, 0x30170170L, 0xF582162AL, +		0x35C8F272L, 0x19844866L, 0x85259078L, 0x7C744927L, +		0x1DA54115L, 0x5505DEC7L, 0x7A84A6D8L, 0xC7D8C609L, +		0x2E198969L, 0xF6020F4BL, 0x837DCD75L, 0x2DF45B36L, +		0x83C0DA9FL, 0x4DE5E15CL, 0x8F70E4A4L, 0x364CF096L, +		0xECBDAE6FL, 0x548DC21BL, 0xAFD70D50L, 0x60378522L, +		0x7A405AB5L, 0x60A18616L, 0xFA0905BCL, 0x953A1CCBL, +		0xBE5141D0L, 0xA9403F7BL, 0x5D1E37B6L, 0x500DA5D5L, +		0xBCDB815CL, 0xE78B89E3L, 0x63A3546FL, 0x5AAD9FD4L, +		0x5C6E8B71L, 0xD7971A6FL, 0x40856F48L, 0x91F6CA81L, +		0x956C447AL, 0xF966868FL, 0xF191BB51L, 0x7C015EAFL, +		0x58A8785BL, 0x43710423L, 0x2C246B80L, 0x0072DCD6L, +		0x40569C99L, 0xCB544BB9L, 0x2CC2B579L, 0xA3AF010DL, +		0x5638B6A5L, 0x8918B2D4L, 0x18928D95L, 0x557BAE61L, +		0xA0D578F2L, 0x3CF4B1F1L, 0x1D592634L, 0xED9B40B5L, +		0x0BE033EBL, 0xDD437BAEL, 0x6188202DL, 0x9F0A444DL, +		0x4DCD2CC0L, 0xC28D6DC5L, 0x9ABDD269L, 0xB0843012L, +		0x00951EE5L, 0x4715466DL, 0x3CC39115L, 0xB270DD7BL, +		0x6510D189L, 0x2BBC6F8FL, 0x331B8E06L, 0x54F13F9EL, +		0xA8223944L, 0xC7B1B375L, 0xFD79FA77L, 0xB7930324L, +		0x6197A094L, 0x46CB50D9L, 0xC49A908FL, 0xAC297BAFL, +		0x84D14B51L, 0x0A50682AL, 0x8AFB5E73L, 0x1C1172C6L, +		0x358A5364L, 0x88415003L, 0x4D5666F8L, 0xA287110CL, +		0xD61B0A4AL, 0x3CC0961BL, 0x44BF5FC3L, 0xD69E0492L, +		0xCFD94EE6L, 0x019813D5L, 0xB7D38A5FL, 0x69C15DC1L, +		0x0D896A60L, 0x7ACB18CEL, 0x5CE6D6E7L, 0x743A4295L, +		0xD7E5A8B7L, 0x457E7DD5L, 0x4A07442BL, 0x2ADA51DEL, +		0xF3202F3BL, 0xD4574157L, 0x81A94A0AL, 0xF26BDDFDL, +		0x775935B3L, 0xB9BC3B76L, 0x3FD81E05L, 0xB95EE989L, +		0x9A0F555DL, 0xFD7E49C8L, 0x3A1D12C5L, 0x7955E2EFL, +		0x7F4A75A1L, 0x16DD1739L, 0x3B3EF7E0L, 0x8795C597L, +		}, { +		0x0640766DL, 0xCD661DAFL, 0x2BDECFBDL, 0xDAA77B87L, +		0x5A7E41B5L, 0x9A3CD4EAL, 0xC6CA8D2FL, 0x65F989EBL, +		0x736C3573L, 0xFA69679CL, 0xB317B71BL, 0x41A7E6FEL, +		0x72D83E2AL, 0xE22CAB56L, 0x08920117L, 0x7030D96EL, +		0x35CDE674L, 0x7405A058L, 0x97D69990L, 0xE95C5EF3L, +		0xDC992FB4L, 0xD33C9F8BL, 0xDAF1AD7AL, 0x03503095L, +		0x00967754L, 0x8CF12CD7L, 0x950FD719L, 0x1ADB3F8CL, +		0xDB4F120AL, 0x712C33D5L, 0x8626D609L, 0x1F2CA165L, +		0x3B8FB27FL, 0xBBA56B76L, 0xD0D7517CL, 0xE1B34706L, +		0x2D89956EL, 0xFFDFF151L, 0xD992E142L, 0x9C662E5AL, +		0xD3D210A4L, 0xD914DD04L, 0x712980F3L, 0xF5AE77E4L, +		0x1E186A6DL, 0xC3CED643L, 0x5A8841B0L, 0xD113DB05L, +		0x1C93C9FDL, 0xB0B64822L, 0xDCDA2B02L, 0x09F3B19AL, +		0xF59692CEL, 0x01117325L, 0xCA61CC6BL, 0xF3E6788AL, +		0xAE70FCF0L, 0x2BA3BDD7L, 0x359B04A2L, 0xB422ECFFL, +		0x4CF00372L, 0x6374AD34L, 0xEB0C631BL, 0x56587BA8L, +		0xC32CD2DEL, 0x5294BDC9L, 0x65B79362L, 0x5E38BFADL, +		0x2A8FBE8CL, 0x8E738683L, 0xC673FFD0L, 0x4B04FB4DL, +		0xCC76EE0FL, 0xF45FD305L, 0xB77848D3L, 0x0D3CB64EL, +		0x48772949L, 0xB5E5B2EEL, 0x354BFBEAL, 0x22BDE81FL, +		0x2181F5BEL, 0x40F5F099L, 0x99C49F11L, 0xEF46CF3BL, +		0x4F9B3DD0L, 0x2E34B17EL, 0xF35F478EL, 0xB0ADC5E2L, +		0x06A4CE4EL, 0xF0395C8AL, 0x3F344031L, 0x0B4A502CL, +		0x85DD868CL, 0x0E52D760L, 0x84124817L, 0x08197C7AL, +		0x5520AD9AL, 0xEA8268FCL, 0xA11B655BL, 0xE3204A0EL, +		0x9183F85FL, 0x9A294A29L, 0xE6350EC4L, 0x09202931L, +		0x28BA52EFL, 0x21B2DB1CL, 0xA20FF528L, 0x42918DAEL, +		0xB8E49971L, 0x9E203A81L, 0x2A07F36CL, 0xA2F84D75L, +		0x824D4513L, 0x1D8AC558L, 0x7E65E471L, 0x06002169L, +		0xBEBC8C82L, 0x9B7B8B6BL, 0x3FF164C2L, 0x5672E9C3L, +		0xBFC72AA3L, 0xD3C9D9E3L, 0xCB64E2DDL, 0xE196A84DL, +		0xCF336932L, 0xA5F3CA20L, 0xA8D3D903L, 0x81CB0B86L, +		0xFB4BF27DL, 0xFCA4C125L, 0x21F1D5B6L, 0xCF6BA988L, +		0x1D408BB7L, 0x629F088FL, 0xF4746130L, 0x1B5C2212L, +		0x47AD1F87L, 0x1E1E9B5CL, 0xCD01B844L, 0x5D3307E1L, +		0xA68FE8F7L, 0x3B13346BL, 0x602308E7L, 0x751416ABL, +		0x38030F2BL, 0x1ABC8EF6L, 0x8929E128L, 0x97040FCAL, +		0x13E59C8DL, 0xA121B4D9L, 0xDB599765L, 0x95EDA62DL, +		0xDAEA1CC5L, 0x2CAF5AC9L, 0x5490F679L, 0xFB410588L, +		0x023C15F3L, 0x5FCD4247L, 0x99455DD9L, 0x82CFC454L, +		0x2EBECB55L, 0xE6ED032FL, 0x876F578DL, 0xA4BF3657L, +		0x8DAD590EL, 0xF6ECC607L, 0xF8B5CD9CL, 0xEC124316L, +		0x4159E6DAL, 0xD7EFA744L, 0x2A20A160L, 0x982F527FL, +		0x60C84A77L, 0xFF60A850L, 0xFD5C6EAFL, 0xFD2D5797L, +		0x954F58C6L, 0xA48A9852L, 0x55B5A9D2L, 0xF3F29933L, +		0xB3580EC7L, 0xF7021CB8L, 0x25238BDBL, 0x7FE667E2L, +		0x47353A71L, 0xD9F9D37DL, 0x79374988L, 0x939566EFL, +		0xC1279574L, 0x835BD0DCL, 0xCB52DE4FL, 0x028364BDL, +		0xBE33E780L, 0xB09647D8L, 0x73FA4EABL, 0x859922EAL, +		0xC7520CCAL, 0x72A331D2L, 0x3F5CFE19L, 0x008F9772L, +		0x5CBFD2B8L, 0xF1937A57L, 0xACC6DBA9L, 0xEFF7AB89L, +		0x72A55667L, 0x628DE4B7L, 0xA0CE9591L, 0x3BFD1D5FL, +		0xCA8D7811L, 0x55BE1BD2L, 0x8B4E3C73L, 0xE0ADA4A4L, +		0xB0A9AB99L, 0xFE319FE4L, 0x1C2BE3A3L, 0x037B2517L, +		0xC084B5D6L, 0x2BE02274L, 0xFF05F558L, 0x8482CABDL, +		0x8B3D719AL, 0x1CB98561L, 0x80DA6AEEL, 0x443B8093L, +		0x01D8FAA4L, 0xD7B783D6L, 0x33F0B71EL, 0x73CA82D8L, +		0x4D9DFDA4L, 0xA91F57FEL, 0x17AB093CL, 0x689F8D37L, +		0x40EE7199L, 0xFA702024L, 0xD1DD8C1FL, 0x5F9BD69BL, +		0x64D28176L, 0xF9DAA31BL, 0xBB186496L, 0x078787B1L, +		0x3783C428L, 0xBDA68050L, 0x7E709830L, 0x1BBDB10EL, +		0x6349027FL, 0xF8306215L, 0xD8855420L, 0x0BE3D1A8L, +		0xD3D9C187L, 0x5329049FL, 0xE3395F69L, 0x65AC7995L, +		0x664848D1L, 0x68C64650L, 0x0F9C1F75L, 0xA4808E20L, +		}, { +		0x5CFD009FL, 0x4C09F290L, 0xA786F99CL, 0x76A5A243L, +		0x2DC97400L, 0x424D9AAEL, 0x6644DE0CL, 0x30DAFAE5L, +		0x5ED77CC3L, 0xD1003D99L, 0xCD3C1222L, 0x1CA766C1L, +		0x5B976615L, 0x014E4796L, 0x0A715936L, 0x405D0D57L, +		0x0AB115F1L, 0x8A963877L, 0xBE96D670L, 0xE2310AACL, +		0x148D00F2L, 0x9787F4BFL, 0xE5F62A68L, 0xFD025DA4L, +		0x194B6DF7L, 0x960D3E7BL, 0xB330C5C1L, 0x2932C25BL, +		0x13738072L, 0x9D62ABA1L, 0x0ECD92CAL, 0xF75ACC9BL, +		0x229E433AL, 0xD0A247BFL, 0xE4B0D9BAL, 0xFA69F70EL, +		0x9B7D254FL, 0xD2849281L, 0x4132F364L, 0xF2E4B87FL, +		0x4189B43CL, 0x7E807CBCL, 0x10498724L, 0xF48C5F29L, +		0x03312ACEL, 0x239307BDL, 0x3541CEBCL, 0x1B1AE36DL, +		0xF993F1B1L, 0x3B6BE060L, 0x9782191AL, 0xACC1CC1BL, +		0xA8B4798EL, 0x486399CDL, 0x59A7ECB9L, 0x46490B98L, +		0xB80EA77EL, 0x1071EE10L, 0x8FE10517L, 0xE29D8F08L, +		0x9BDA44C2L, 0x629C5056L, 0xE40E10E3L, 0x0048CBB1L, +		0xF8E698E7L, 0x09369CB7L, 0x898942DCL, 0x0F49BFE0L, +		0x3600B868L, 0x44EE4C88L, 0x6625BBFBL, 0x7C956C83L, +		0x5C42B182L, 0x080AF33BL, 0x1503CC24L, 0xAE64DA10L, +		0x9F3537D3L, 0x99618740L, 0xE7D50FFDL, 0x6CBB4AFFL, +		0x56062EE1L, 0x70C1AD52L, 0xAC54BF35L, 0x5A7D4D07L, +		0x65DC58DEL, 0x7B362255L, 0x6133AFC8L, 0x4C2ACE68L, +		0x858FA998L, 0x5C336C93L, 0x78193EA7L, 0x5613E9BDL, +		0x8B1F58ACL, 0x563D5D47L, 0x6163AF27L, 0x71183690L, +		0x5944DDC3L, 0x817D18BEL, 0x41260F8BL, 0x259ED297L, +		0xA3CCEE2EL, 0xDBB13DDDL, 0x1009CD47L, 0xD12B82C3L, +		0x9A6FF89DL, 0x4248C9D4L, 0x31484739L, 0x7C3DEEC3L, +		0x2E2CBAC1L, 0x9597DDA3L, 0xF64414B0L, 0x066FC96FL, +		0x31F4AAA0L, 0xB2DBBCFFL, 0x50B991ADL, 0x95AC5272L, +		0x0CAA50C4L, 0x0864DE61L, 0xF38A70D4L, 0x08CE8D6CL, +		0x53941C89L, 0xC54DBEBEL, 0xE4DBC2B0L, 0x2B3E9E66L, +		0x6F3E0BA4L, 0x164DC014L, 0xCC6CEC5FL, 0x08238664L, +		0x30988E18L, 0xFDE4501AL, 0x030B3099L, 0xE6F49802L, +		0x94A08714L, 0xC3A784E5L, 0xECDA930DL, 0x0B40E2F9L, +		0x0EE564F8L, 0xF5993B88L, 0x5B8DB5DBL, 0xF77CCA85L, +		0x9C4FCDA9L, 0x2114F372L, 0x2AA12CCEL, 0x2B07C3F1L, +		0xD660E47AL, 0xD0B26A65L, 0x56F8945CL, 0x4C07FCA5L, +		0x5EF2197FL, 0x073CBFFCL, 0xF83E8935L, 0x04DB4798L, +		0x79DE4FB4L, 0x207E0BB1L, 0xD0D47C14L, 0x9DADB205L, +		0x5EBD3EA0L, 0xCA83B290L, 0xC8BF53A1L, 0x4DCBF491L, +		0xB590CD79L, 0x9C98C12EL, 0x8C877D6EL, 0xD0F17FD2L, +		0xB3FFF22FL, 0xE8D38B07L, 0x15641B63L, 0x6FE5D245L, +		0x04045C48L, 0xEF16069BL, 0xB58781CEL, 0x7D07653DL, +		0xCFB9BD0CL, 0x21CA5DE7L, 0xB35606D9L, 0xA7854DE0L, +		0xC134207CL, 0xFE978430L, 0x0C830455L, 0xCB784991L, +		0xC95A3072L, 0xC0AC5E17L, 0x7B999149L, 0xA289D877L, +		0xB4E3254EL, 0x743F72B1L, 0x98CF8054L, 0x7E4E1C3FL, +		0x0A64C32CL, 0xF04CEB0FL, 0x0488ABF6L, 0x004554B3L, +		0x359E3441L, 0x192ABA6FL, 0x28DC322EL, 0xDDE52491L, +		0xF1D8C2A7L, 0xEAE3E74AL, 0xA10B3376L, 0x7A879F55L, +		0xB5F13C45L, 0x5194862CL, 0x6F65DC08L, 0x753F6AFEL, +		0xF08EA616L, 0x26D382C3L, 0x3315E1E5L, 0x538106B9L, +		0xEC0B9F78L, 0xF298C82DL, 0x0125FD86L, 0x07465A0DL, +		0x23953151L, 0x70569F93L, 0x75D261A5L, 0xC5AD33E5L, +		0x49464CDFL, 0xB4E0D04DL, 0xA0866011L, 0x383CC817L, +		0x545FBC56L, 0xA49BED33L, 0x4E4B516AL, 0x38CBF5D4L, +		0x6DBA987CL, 0x1DFE208FL, 0x65466F04L, 0x6D3DCD1DL, +		0xEB4D60C6L, 0xE3FB6AECL, 0xFA16DBDBL, 0xCD1CDF2BL, +		0xF07F845DL, 0x4DA0ECD1L, 0x0EEB40B0L, 0x1CB7A2F0L, +		0xCD8E54F3L, 0x37376D53L, 0xF7AAC8D3L, 0x8BA724AAL, +		0xEF5C922DL, 0x6F1BE181L, 0xD1808DF8L, 0x44764B58L, +		0x0CD247C4L, 0x0C137F60L, 0xB77F6981L, 0x4AC13745L, +		0xBA311B48L, 0x42A5DE75L, 0x4522E7E0L, 0x84E90F54L, +		0xCC0AD21CL, 0x00F8D9A7L, 0x9CA2CED9L, 0x4F8E0583L, +		}, { +		0x6AFF5CA7L, 0x0D8AB1F0L, 0x75E3AD44L, 0x6B5A1A52L, +		0xE9658216L, 0x71B42FBBL, 0xF57D3F6CL, 0x0A79678EL, +		0x534F306FL, 0xB9C725ABL, 0x7157BF11L, 0x2A52F490L, +		0x4D01079CL, 0x6D18FC2BL, 0x94EC0BDBL, 0xA736324EL, +		0x7540D554L, 0x6B9DFB4DL, 0xFA158CA1L, 0xECE8E1ABL, +		0xAFAF64B2L, 0x61450E7BL, 0x4CEBA4FAL, 0xB2AFAAA2L, +		0xFE669447L, 0x4E63D10BL, 0xFBD8AEC8L, 0x5F6B6B1AL, +		0x70A8F15BL, 0xA91D68B6L, 0x59034211L, 0x98273D40L, +		0xB9A9C9ADL, 0xCE4DDCD7L, 0xC3159554L, 0xFD5D1C2DL, +		0x9ABF93B5L, 0x70A8C01FL, 0xA70FCF1AL, 0x641301DDL, +		0x4EDB9E0BL, 0xC548E7B1L, 0x4884B172L, 0x714610B7L, +		0x4086DCCFL, 0xC8D88CC6L, 0x77594608L, 0xBCABFDE1L, +		0x77962F00L, 0x56F6372CL, 0xB9507A98L, 0x0EF9473EL, +		0xDBA8C6E2L, 0x5BE1AA28L, 0xCEA5C805L, 0x750F1D15L, +		0x1F986C17L, 0x3693A790L, 0x71B0C4CCL, 0xC0776116L, +		0xD660B7BCL, 0x8D0ABAB1L, 0x7F1FDFB7L, 0x4900FDE1L, +		0x2208372BL, 0xB8263157L, 0xB53378F5L, 0x10DF5849L, +		0xC3C8CD69L, 0x5E842514L, 0x8085986AL, 0xC305CE78L, +		0x6C5D3C16L, 0xC11A49B6L, 0x391DBE69L, 0x3BACD18DL, +		0x87253FDEL, 0x56D409DEL, 0x68629118L, 0x1C1E9C6FL, +		0x7F737B29L, 0x96838CC1L, 0xC300D7B2L, 0x2A23D185L, +		0x52271100L, 0xCB4B3F01L, 0xB78A9B86L, 0xB9BEDEF5L, +		0x5D8075FFL, 0x5C325E39L, 0x48A76A2BL, 0x96A61231L, +		0x933ADA05L, 0xF9971C9CL, 0xFF2C75FCL, 0x27FA5DAAL, +		0xAEF8AD6EL, 0xF2DEA20BL, 0x11F247FBL, 0xC383DA2AL, +		0xF85A5ED1L, 0xC35FBC79L, 0xBDCEF0ADL, 0xEEBBCFB3L, +		0xCA711BF4L, 0xB7DABFB3L, 0xE03177D0L, 0xBB727F1FL, +		0x142CC33DL, 0xDB6C384EL, 0xAC6D38B4L, 0xF55B4325L, +		0xF020F44FL, 0x5630D9C1L, 0xED39B172L, 0xACB5AFF7L, +		0x8D98DC58L, 0xB6DF90A1L, 0xEC98CD13L, 0xE0C6A237L, +		0xAC64BDF0L, 0x3560D439L, 0x7B0DDB44L, 0x1D3682C3L, +		0x664EBF1AL, 0xD41A4A0CL, 0x0D5DFE5BL, 0x4E133D8CL, +		0xB129ECD6L, 0xD9DA3194L, 0xE45DADBAL, 0x6B27E47FL, +		0xBA9600DDL, 0x8E1936D2L, 0x1F8B1E51L, 0x3860AE03L, +		0xEE540893L, 0x5F31C76BL, 0xE9302FA1L, 0x452CB6B9L, +		0x5D9CA533L, 0xA19F4B2FL, 0x6C0046A4L, 0x657713DDL, +		0x1B5D5A04L, 0xC3D594E6L, 0xBB80FA30L, 0x9BF9E647L, +		0x716F2F97L, 0xF2B8ADA6L, 0x7F242755L, 0x40FB6614L, +		0x4F85BCF9L, 0x18799EB2L, 0x76B4124AL, 0xFCAEC005L, +		0x38231D8AL, 0xD449CE69L, 0xC6877AD2L, 0x16B37A06L, +		0x7DAF096BL, 0xCE11C2B4L, 0x750754B5L, 0xCAC33C86L, +		0x10E20D73L, 0xE4997D0FL, 0x6B06DE8DL, 0x1D70D15FL, +		0xBF060E4FL, 0x18BC4C59L, 0xD1C8585EL, 0x1AEC12B4L, +		0x9AB3F241L, 0x46CFC4CDL, 0xCF16D587L, 0xF1722424L, +		0x0ECA4D9CL, 0xCC6131F3L, 0x0E990CC3L, 0x9771D4BFL, +		0x4C624E9FL, 0x5CA79CBCL, 0x02368C90L, 0x25826D54L, +		0x32D1B4C9L, 0xDA9A049BL, 0x616CC784L, 0x47B562F3L, +		0xB5553B6EL, 0xF205F397L, 0x6FA01B63L, 0xC857201FL, +		0xC5C7C8A1L, 0xA27C47E2L, 0xDB185877L, 0x67236F63L, +		0xBF369D88L, 0x4E7054BDL, 0xD6544BEAL, 0x36EF3BC3L, +		0x60F4B74DL, 0x430EA61EL, 0xC3E9C76DL, 0x499A0517L, +		0x91D45BCDL, 0xDCAEADFAL, 0x355FBC9DL, 0x8CA1770EL, +		0x820BE4F9L, 0x00AE9FD2L, 0x9E63CE49L, 0x46FE33E8L, +		0xA07048A3L, 0x225FBD27L, 0xAF0FD02CL, 0x8F9D7C95L, +		0xD4F0E647L, 0x6DFB3949L, 0xE289B0B0L, 0xF9CC7F56L, +		0x7F168AD2L, 0xED8433E0L, 0xEBB189B5L, 0x765AD69CL, +		0x7730DCF0L, 0xD54C3A0DL, 0xACF6BD6BL, 0x1E19DF12L, +		0xBD984D49L, 0xC4FC38B8L, 0x0D36C9FFL, 0xCC3AD912L, +		0x0A6E4ED6L, 0x27B27847L, 0x604F6917L, 0xD4C1ADADL, +		0xCB19F4BEL, 0x5127D2FDL, 0x38FFA03AL, 0xB983BC5FL, +		0x5CAF3A6EL, 0x84E94F45L, 0xFC3FA473L, 0xC9299B07L, +		0x322F38AFL, 0x2A228E93L, 0x76D63922L, 0x1326A518L, +		0xFEC3F151L, 0xB821D755L, 0x8D1C67ACL, 0x5DA96628L, +		0x04F7335FL, 0xC6F5CD2EL, 0x7D211328L, 0xE19180D3L, +		}}; + +#endif /* _CRYPT_KEY_OUTPUT_H */ diff --git a/src/libpiano/piano.c b/src/libpiano/piano.c new file mode 100644 index 0000000..f6343b4 --- /dev/null +++ b/src/libpiano/piano.c @@ -0,0 +1,1114 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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. +*/ + +#define _BSD_SOURCE /* required by strdup() */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <assert.h> +#include <stdint.h> + +/* needed for urlencode */ +#include <waitress.h> + +#include "piano_private.h" +#include "piano.h" +#include "xml.h" +#include "crypt.h" +#include "config.h" + +#define PIANO_PROTOCOL_VERSION "29" +#define PIANO_RPC_HOST "www.pandora.com" +#define PIANO_RPC_PORT "80" +#define PIANO_RPC_PATH "/radio/xmlrpc/v" PIANO_PROTOCOL_VERSION "?" +#define PIANO_SEND_BUFFER_SIZE 10000 + +/*	initialize piano handle + *	@param piano handle + *	@return nothing + */ +void PianoInit (PianoHandle_t *ph) { +	memset (ph, 0, sizeof (*ph)); + +	/* route-id seems to be random. we're using time anyway... */ +	snprintf (ph->routeId, sizeof (ph->routeId), "%07luP", +			(unsigned long) time (NULL) % 10000000); +} + +/*	free complete search result + *	@public yes + *	@param search result + */ +void PianoDestroySearchResult (PianoSearchResult_t *searchResult) { +	PianoArtist_t *curArtist, *lastArtist; +	PianoSong_t *curSong, *lastSong; + +	curArtist = searchResult->artists; +	while (curArtist != NULL) { +		free (curArtist->name); +		free (curArtist->musicId); +		lastArtist = curArtist; +		curArtist = curArtist->next; +		free (lastArtist); +	} + +	curSong = searchResult->songs; +	while (curSong != NULL) { +		free (curSong->title); +		free (curSong->artist); +		free (curSong->musicId); +		lastSong = curSong; +		curSong = curSong->next; +		free (lastSong); +	} +} + +/*	free single station + *	@param station + */ +void PianoDestroyStation (PianoStation_t *station) { +	free (station->name); +	free (station->id); +	memset (station, 0, sizeof (station)); +} + +/*	free complete station list + *	@param piano handle + */ +void PianoDestroyStations (PianoStation_t *stations) { +	PianoStation_t *curStation, *lastStation; + +	curStation = stations; +	while (curStation != NULL) { +		lastStation = curStation; +		curStation = curStation->next; +		PianoDestroyStation (lastStation); +		free (lastStation); +	} +} + +/* FIXME: copy & waste */ +/*	free _all_ elements of playlist + *	@param piano handle + *	@return nothing + */ +void PianoDestroyPlaylist (PianoSong_t *playlist) { +	PianoSong_t *curSong, *lastSong; + +	curSong = playlist; +	while (curSong != NULL) { +		free (curSong->audioUrl); +		free (curSong->coverArt); +		free (curSong->artist); +		free (curSong->musicId); +		free (curSong->title); +		free (curSong->userSeed); +		free (curSong->stationId); +		free (curSong->album); +		free (curSong->artistMusicId); +		lastSong = curSong; +		curSong = curSong->next; +		free (lastSong); +	} +} + +/*	destroy genre linked list + */ +void PianoDestroyGenres (PianoGenre_t *genres) { +	PianoGenre_t *curGenre, *lastGenre; + +	curGenre = genres; +	while (curGenre != NULL) { +		free (curGenre->name); +		free (curGenre->musicId); +		lastGenre = curGenre; +		curGenre = curGenre->next; +		free (lastGenre); +	} +} + +/*	destroy user information + */ +void PianoDestroyUserInfo (PianoUserInfo_t *user) { +	free (user->webAuthToken); +	free (user->authToken); +	free (user->listenerId); +} + +/*	frees the whole piano handle structure + *	@param piano handle + *	@return nothing + */ +void PianoDestroy (PianoHandle_t *ph) { +	PianoDestroyUserInfo (&ph->user); +	PianoDestroyStations (ph->stations); +	/* destroy genre stations */ +	PianoGenreCategory_t *curGenreCat = ph->genreStations, *lastGenreCat; +	while (curGenreCat != NULL) { +		PianoDestroyGenres (curGenreCat->genres); +		free (curGenreCat->name); +		lastGenreCat = curGenreCat; +		curGenreCat = curGenreCat->next; +		free (lastGenreCat); +	} +	memset (ph, 0, sizeof (*ph)); +} + +/*	destroy request, free post data. req->responseData is *not* freed here, as + *	it might be allocated by something else than malloc! + *	@param piano request + */ +void PianoDestroyRequest (PianoRequest_t *req) { +	free (req->postData); +	memset (req, 0, sizeof (*req)); +} + +/*	convert audio format id to string that can be used in xml requests + *	@param format id + *	@return constant string + */ +static const char *PianoAudioFormatToString (PianoAudioFormat_t format) { +	switch (format) { +		case PIANO_AF_AACPLUS: +			return "aacplus"; +			break; + +		case PIANO_AF_MP3: +			return "mp3"; +			break; + +		case PIANO_AF_MP3_HI: +			return "mp3-hifi"; +			break; + +		default: +			return NULL; +			break; +	} +} + +/*	prepare piano request (initializes request type, urlpath and postData) + *	@param piano handle + *	@param request structure + *	@param request type + */ +PianoReturn_t PianoRequest (PianoHandle_t *ph, PianoRequest_t *req, +		PianoRequestType_t type) { +	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE]; +	/* corrected timestamp */ +	time_t timestamp = time (NULL) - ph->timeOffset; + +	assert (ph != NULL); +	assert (req != NULL); + +	req->type = type; + +	switch (req->type) { +		case PIANO_REQUEST_LOGIN: { +			/* authenticate user */ +			PianoRequestDataLogin_t *logindata = req->data; + +			assert (logindata != NULL); + +			switch (logindata->step) { +				case 0: +					snprintf (xmlSendBuf, sizeof (xmlSendBuf),  +							"<?xml version=\"1.0\"?><methodCall>" +							"<methodName>misc.sync</methodName>" +							"<params></params></methodCall>"); +					snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +							"rid=%s&method=sync", ph->routeId); +					break; + +				case 1: +					snprintf (xmlSendBuf, sizeof (xmlSendBuf),  +							"<?xml version=\"1.0\"?><methodCall>" +							"<methodName>listener.authenticateListener</methodName>" +							"<params><param><value><int>%lu</int></value></param>" +							"<param><value><string>%s</string></value></param>" +							"<param><value><string>%s</string></value></param>" +							"</params></methodCall>", (unsigned long) timestamp, +							logindata->user, logindata->password); +					snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +							"rid=%s&method=authenticateListener", ph->routeId); +					break; +			} +			break; +		} + +		case PIANO_REQUEST_GET_STATIONS: +			/* get stations, user must be authenticated */ +			assert (ph->user.listenerId != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.getStations</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=getStations", ph->routeId, +					ph->user.listenerId); +			break; + +		case PIANO_REQUEST_GET_PLAYLIST: { +			/* get playlist for specified station */ +			PianoRequestDataGetPlaylist_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->station != NULL); +			assert (reqData->station->id != NULL); +			assert (reqData->format != PIANO_AF_UNKNOWN); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>playlist.getFragment</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					/* total listening time */ +					"<param><value><string>0</string></value></param>" +					/* time since last session */ +					"<param><value><string></string></value></param>" +					/* tracking code */ +					"<param><value><string></string></value></param>" +					/* audio format */ +					"<param><value><string>%s</string></value></param>" +					/* delta listening time */ +					"<param><value><string>0</string></value></param>" +					/* listening timestamp */ +					"<param><value><string>0</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->station->id, +					PianoAudioFormatToString (reqData->format)); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=getFragment&arg1=%s&arg2=0" +					"&arg3=&arg4=&arg5=%s&arg6=0&arg7=0", ph->routeId, +					ph->user.listenerId, reqData->station->id, +					PianoAudioFormatToString (reqData->format)); +			break; +		} + +		case PIANO_REQUEST_ADD_FEEDBACK: { +			/* low-level, don't use directly (see _RATE_SONG and _MOVE_SONG) */ +			PianoRequestDataAddFeedback_t *reqData = req->data; +			 +			assert (reqData != NULL); +			assert (reqData->stationId != NULL); +			assert (reqData->musicId != NULL); +			assert (reqData->rating != PIANO_RATE_NONE); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.addFeedback</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					/* music id */ +					"<param><value><string>%s</string></value></param>" +					/* user seed */ +					"<param><value><string>%s</string></value></param>" +					/* test strategy */ +					"<param><value>%u</value></param>" +					/* positive */ +					"<param><value><boolean>%i</boolean></value></param>" +					/* "is-creator-quickmix" */ +					"<param><value><boolean>0</boolean></value></param>" +					/* song type */ +					"<param><value><int>%u</int></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->stationId, reqData->musicId, +					(reqData->userSeed == NULL) ? "" : reqData->userSeed, +					reqData->testStrategy, +					(reqData->rating == PIANO_RATE_LOVE) ? 1 : 0, +					reqData->songType); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=addFeedback&arg1=%s&arg2=%s" +					"&arg3=%s&arg4=%u&arg5=%s&arg6=false&arg7=%u", +					ph->routeId, ph->user.listenerId, reqData->stationId, +					reqData->musicId, +					(reqData->userSeed == NULL) ? "" : reqData->userSeed, +					reqData->testStrategy, +					(reqData->rating == PIANO_RATE_LOVE) ? "true" : "false", +					reqData->songType); +			break; +		} + +		case PIANO_REQUEST_RENAME_STATION: { +			/* rename stations */ +			PianoRequestDataRenameStation_t *reqData = req->data; +			char *urlencodedNewName, *xmlencodedNewName; + +			assert (reqData != NULL); +			assert (reqData->station != NULL); +			assert (reqData->newName != NULL); + +			if ((xmlencodedNewName = PianoXmlEncodeString (reqData->newName)) == NULL) { +				return PIANO_RET_OUT_OF_MEMORY; +			} +			urlencodedNewName = WaitressUrlEncode (reqData->newName); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.setStationName</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					/* new name */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->station->id, +					xmlencodedNewName); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=setStationName&arg1=%s&arg2=%s", +					ph->routeId, ph->user.listenerId, reqData->station->id, +					urlencodedNewName); + +			free (urlencodedNewName); +			free (xmlencodedNewName); +			break; +		} + +		case PIANO_REQUEST_DELETE_STATION: { +			/* delete station */ +			PianoStation_t *station = req->data; + +			assert (station != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.removeStation</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, station->id); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=removeStation&arg1=%s", ph->routeId, +					ph->user.listenerId, station->id); +			break; +		} + +		case PIANO_REQUEST_SEARCH: { +			/* search for artist/song title */ +			PianoRequestDataSearch_t *reqData = req->data; +			char *xmlencodedSearchStr, *urlencodedSearchStr; + +			assert (reqData != NULL); +			assert (reqData->searchStr != NULL); + +			if ((xmlencodedSearchStr = PianoXmlEncodeString (reqData->searchStr)) == NULL) { +				return PIANO_RET_OUT_OF_MEMORY; +			} +			urlencodedSearchStr = WaitressUrlEncode (reqData->searchStr); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>music.search</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* search string */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, xmlencodedSearchStr); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=search&arg1=%s", ph->routeId, +					ph->user.listenerId, urlencodedSearchStr); + +			free (urlencodedSearchStr); +			free (xmlencodedSearchStr); +			break; +		} + +		case PIANO_REQUEST_CREATE_STATION: { +			/* create new station from specified musicid (type=mi, get one by +			 * performing a search) or shared station id (type=sh) */ +			PianoRequestDataCreateStation_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->id != NULL); +			assert (reqData->type != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.createStation</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					"<param><value><string>%s</string></value></param>" +					"<param><value><string>%s%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->type, reqData->id); + +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=createStation&arg1=%s%s", ph->routeId, +					ph->user.listenerId, reqData->type, reqData->id); +			break; +		} + +		case PIANO_REQUEST_ADD_SEED: { +			/* add another seed to specified station */ +			PianoRequestDataAddSeed_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->station != NULL); +			assert (reqData->musicId != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.addSeed</methodName><params>" +					"<param><value><int>%lu</int></value></param>" +					"<param><value><string>%s</string></value></param>" +					"<param><value><string>%s</string></value></param>" +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->station->id, reqData->musicId); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=addSeed&arg1=%s&arg2=%s", ph->routeId, +					ph->user.listenerId, reqData->station->id, reqData->musicId); +			break; +		} + +		case PIANO_REQUEST_ADD_TIRED_SONG: { +			/* ban song for a month from all stations */ +			PianoSong_t *song = req->data; + +			assert (song != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>listener.addTiredSong</methodName><params>" +					"<param><value><int>%lu</int></value></param>" +					"<param><value><string>%s</string></value></param>" +					/* key */ +					"<param><value><string>%s</string></value></param>" +					/* user seed */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, +					(song->musicId == NULL) ? "" : song->musicId, +					(song->userSeed == NULL) ? "" : song->userSeed, +					song->stationId); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=addTiredSong&arg1=%s&arg2=%s&arg3=%s", +					ph->routeId, ph->user.listenerId, +					(song->musicId == NULL) ? "" : song->musicId, +					(song->userSeed == NULL) ? "" : song->userSeed, +					song->stationId); +			break; +		} + +		case PIANO_REQUEST_SET_QUICKMIX: { +			/* select stations included in quickmix (see useQuickMix flag of +			 * PianoStation_t) */ +			char valueBuf[1000], urlArgBuf[1000]; +			PianoStation_t *curStation = ph->stations; + +			memset (urlArgBuf, 0, sizeof (urlArgBuf)); +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.setQuickMix</methodName><params>" +					"<param><value><int>%lu</int></value></param>" +					"<param><value><string>%s</string></value></param>" +					/* quick mix type */ +					"<param><value><string>RANDOM</string></value></param>" +					"<param><value><array><data>", (unsigned long) timestamp, +					ph->user.authToken); +			while (curStation != NULL) { +				/* quick mix can't contain itself */ +				if (!curStation->useQuickMix || curStation->isQuickMix) { +					curStation = curStation->next; +					continue; +				} +				/* append to xml doc */ +				snprintf (valueBuf, sizeof (valueBuf), +						"<value><string>%s</string></value>", curStation->id); +				strncat (xmlSendBuf, valueBuf, sizeof (xmlSendBuf) - +						strlen (xmlSendBuf) - 1); +				/* append to url arg */ +				strncat (urlArgBuf, curStation->id, sizeof (urlArgBuf) - +						strlen (urlArgBuf) - 1); +				curStation = curStation->next; +				/* if not last item: append "," */ +				if (curStation != NULL) { +					strncat (urlArgBuf, "%2C", sizeof (urlArgBuf) - +							strlen (urlArgBuf) - 1); +				} +			} +			strncat (xmlSendBuf, +					"</data></array></value></param>" +					/* content type */ +					"<param><value><string>CUSTOM</string></value></param>" +					/* genre */ +					"<param><value><string></string></value></param>" +					"</params></methodCall>", +					sizeof (xmlSendBuf) - strlen (xmlSendBuf) - 1); + +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=setQuickMix&arg1=RANDOM&arg2=%s&arg3=CUSTOM&arg4=", +					ph->routeId, ph->user.listenerId, urlArgBuf); +			break; +		} + +		case PIANO_REQUEST_GET_GENRE_STATIONS: +			/* receive list of pandora's genre stations */ +			xmlSendBuf[0] = '\0'; +			snprintf (req->urlPath, sizeof (req->urlPath), "/xml/genre?r=%lu", +					(unsigned long) timestamp); +			break; + +		case PIANO_REQUEST_TRANSFORM_STATION: { +			/* transform shared station into private */ +			PianoStation_t *station = req->data; + +			assert (station != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.transformShared</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, station->id); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=transformShared&arg1=%s", ph->routeId, +					ph->user.listenerId, station->id); +			break; +		} + +		case PIANO_REQUEST_EXPLAIN: { +			/* explain why particular song was played */ +			PianoRequestDataExplain_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->song != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>playlist.narrative</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					/* music id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->song->stationId, +					reqData->song->musicId); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=narrative&arg1=%s&arg2=%s", +					ph->routeId, ph->user.listenerId, reqData->song->stationId, +					reqData->song->musicId); +			break; +		} + +		case PIANO_REQUEST_GET_SEED_SUGGESTIONS: { +			/* find similar artists */ +			PianoRequestDataGetSeedSuggestions_t *reqData = req->data; + +			assert (reqData != NULL); +			assert (reqData->musicId != NULL); +			assert (reqData->max != 0); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>music.getSeedSuggestions</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* seed music id */ +					"<param><value><string>%s</string></value></param>" +					/* max */ +					"<param><value><int>%u</int></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, reqData->musicId, reqData->max); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=getSeedSuggestions&arg1=%s&arg2=%u", +					ph->routeId, ph->user.listenerId, reqData->musicId, reqData->max); +			break; +		} + +		case PIANO_REQUEST_BOOKMARK_SONG: { +			/* bookmark song */ +			PianoSong_t *song = req->data; + +			assert (song != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.createBookmark</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* station id */ +					"<param><value><string>%s</string></value></param>" +					/* music id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, song->stationId, song->musicId); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=createBookmark&arg1=%s&arg2=%s", +					ph->routeId, ph->user.listenerId, song->stationId, +					song->musicId); +			break; +		} + +		case PIANO_REQUEST_BOOKMARK_ARTIST: { +			/* bookmark artist */ +			PianoSong_t *song = req->data; + +			assert (song != NULL); + +			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>" +					"<methodCall><methodName>station.createArtistBookmark</methodName>" +					"<params><param><value><int>%lu</int></value></param>" +					/* auth token */ +					"<param><value><string>%s</string></value></param>" +					/* music id */ +					"<param><value><string>%s</string></value></param>" +					"</params></methodCall>", (unsigned long) timestamp, +					ph->user.authToken, song->artistMusicId); +			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH +					"rid=%s&lid=%s&method=createArtistBookmark&arg1=%s", +					ph->routeId, ph->user.listenerId, song->artistMusicId); +			break; +		} + +		/* "high-level" wrapper */ +		case PIANO_REQUEST_RATE_SONG: { +			/* love/ban song */ +			PianoRequestDataRateSong_t *reqData = req->data; +			PianoReturn_t pRet; + +			assert (reqData != NULL); +			assert (reqData->song != NULL); +			assert (reqData->rating != PIANO_RATE_NONE); + +			PianoRequestDataAddFeedback_t transformedReqData; +			transformedReqData.stationId = reqData->song->stationId; +			transformedReqData.musicId = reqData->song->musicId; +			transformedReqData.userSeed = reqData->song->userSeed; +			transformedReqData.rating = reqData->rating; +			transformedReqData.testStrategy = reqData->song->testStrategy; +			transformedReqData.songType = reqData->song->songType; +			req->data = &transformedReqData; + +			/* create request data (url, post data) */ +			pRet = PianoRequest (ph, req, PIANO_REQUEST_ADD_FEEDBACK); +			/* and reset request type/data */ +			req->type = PIANO_REQUEST_RATE_SONG; +			req->data = reqData; + +			return pRet; +			break; +		} + +		case PIANO_REQUEST_MOVE_SONG: { +			/* move song to a different station, needs two requests */ +			PianoRequestDataMoveSong_t *reqData = req->data; +			PianoRequestDataAddFeedback_t transformedReqData; +			PianoReturn_t pRet; + +			assert (reqData != NULL); +			assert (reqData->song != NULL); +			assert (reqData->from != NULL); +			assert (reqData->to != NULL); +			assert (reqData->step < 2); + +			transformedReqData.musicId = reqData->song->musicId; +			transformedReqData.userSeed = ""; +			transformedReqData.songType = reqData->song->songType; +			transformedReqData.testStrategy = reqData->song->testStrategy; +			req->data = &transformedReqData; + +			switch (reqData->step) { +				case 0: +					transformedReqData.stationId = reqData->from->id; +					transformedReqData.rating = PIANO_RATE_BAN; +					break; + +				case 1: +					transformedReqData.stationId = reqData->to->id; +					transformedReqData.rating = PIANO_RATE_LOVE; +					break; +			} + +			/* create request data (url, post data) */ +			pRet = PianoRequest (ph, req, PIANO_REQUEST_ADD_FEEDBACK); +			/* and reset request type/data */ +			req->type = PIANO_REQUEST_MOVE_SONG; +			req->data = reqData; + +			return pRet; +			break; +		} +	} + +	if ((req->postData = PianoEncryptString (xmlSendBuf)) == NULL) { +		return PIANO_RET_OUT_OF_MEMORY; +	} + +	return PIANO_RET_OK; +} + +/*	parse xml response and update data structures/return new data structure + *	@param piano handle + *	@param initialized request (expects responseData to be a NUL-terminated + *			string) + */ +PianoReturn_t PianoResponse (PianoHandle_t *ph, PianoRequest_t *req) { +	PianoReturn_t ret = PIANO_RET_ERR; + +	assert (ph != NULL); +	assert (req != NULL); + +	switch (req->type) { +		case PIANO_REQUEST_LOGIN: { +			/* authenticate user */ +			PianoRequestDataLogin_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			switch (reqData->step) { +				case 0: { +					char *cryptedTimestamp = NULL; + +					assert (req->responseData != NULL); + +					/* abusing parseNarrative; has same xml structure */ +					ret = PianoXmlParseNarrative (req->responseData, &cryptedTimestamp); +					if (cryptedTimestamp != NULL) { +						unsigned long timestamp = 0; +						time_t realTimestamp = time (NULL); +						char *decryptedTimestamp = NULL, *decryptedPos = NULL; +						unsigned char i = 4; + +						if ((decryptedTimestamp = PianoDecryptString (cryptedTimestamp)) != NULL) { +							decryptedPos = decryptedTimestamp; +							/* skip four bytes garbage? at beginning */ +							while (i-- > 0 && *decryptedPos++ != '\0'); +							timestamp = strtoul (decryptedPos, NULL, 0); +							ph->timeOffset = realTimestamp - timestamp; + +							free (decryptedTimestamp); +						} +						free (cryptedTimestamp); +					} +					ret = PIANO_RET_CONTINUE_REQUEST; +					++reqData->step; +					break; +				} + +				case 1: +					/* information exists when reauthenticating, destroy to +					 * avoid memleak */ +					if (ph->user.listenerId != NULL) { +						PianoDestroyUserInfo (&ph->user); +					} +					ret = PianoXmlParseUserinfo (ph, req->responseData); +					break; +			} +			break; +		} + +		case PIANO_REQUEST_GET_STATIONS: +			/* get stations */ +			assert (req->responseData != NULL); +			 +			ret = PianoXmlParseStations (ph, req->responseData); +			break; + +		case PIANO_REQUEST_GET_PLAYLIST: { +			/* get playlist, usually four songs */ +			PianoRequestDataGetPlaylist_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			reqData->retPlaylist = NULL; +			ret = PianoXmlParsePlaylist (ph, req->responseData, +					&reqData->retPlaylist); +			break; +		} + +		case PIANO_REQUEST_RATE_SONG: +			/* love/ban song */ +			assert (req->responseData != NULL); + +			ret = PianoXmlParseSimple (req->responseData); +			if (ret == PIANO_RET_OK) { +				PianoRequestDataRateSong_t *reqData = req->data; +				reqData->song->rating = reqData->rating; +			} +			break; + +		case PIANO_REQUEST_ADD_FEEDBACK: +			/* never ever use this directly, low-level call */ +			assert (0); +			break; + +		case PIANO_REQUEST_MOVE_SONG: { +			/* move song to different station */ +			PianoRequestDataMoveSong_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); +			assert (reqData->step < 2); + +			ret = PianoXmlParseSimple (req->responseData); +			if (ret == PIANO_RET_OK && reqData->step == 0) { +				ret = PIANO_RET_CONTINUE_REQUEST; +				++reqData->step; +			} +			break; +		} + +		case PIANO_REQUEST_RENAME_STATION: +			/* rename station and update PianoStation_t structure */ +			assert (req->responseData != NULL); + +			if ((ret = PianoXmlParseSimple (req->responseData)) == PIANO_RET_OK) { +				PianoRequestDataRenameStation_t *reqData = req->data; + +				assert (reqData != NULL); +				assert (reqData->station != NULL); +				assert (reqData->newName != NULL); + +				free (reqData->station->name); +				reqData->station->name = strdup (reqData->newName); +			} +			break; + +		case PIANO_REQUEST_DELETE_STATION: +			/* delete station from server and station list */ +			assert (req->responseData != NULL); + +			if ((ret = PianoXmlParseSimple (req->responseData)) == PIANO_RET_OK) { +				PianoStation_t *station = req->data; + +				assert (station != NULL); + +				/* delete station from local station list */ +				PianoStation_t *curStation = ph->stations, *lastStation = NULL; +				while (curStation != NULL) { +					if (curStation == station) { +						if (lastStation != NULL) { +							lastStation->next = curStation->next; +						} else { +							/* first station in list */ +							ph->stations = curStation->next; +						} +						PianoDestroyStation (curStation); +						free (curStation); +						break; +					} +					lastStation = curStation; +					curStation = curStation->next; +				} +			} +			break; + +		case PIANO_REQUEST_SEARCH: { +			/* search artist/song */ +			PianoRequestDataSearch_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			ret = PianoXmlParseSearch (req->responseData, &reqData->searchResult); +			break; +		} + +		case PIANO_REQUEST_CREATE_STATION: { +			/* create station, insert new station into station list on success */ +			assert (req->responseData != NULL); + +			ret = PianoXmlParseCreateStation (ph, req->responseData); +			break; +		} + +		case PIANO_REQUEST_ADD_SEED: { +			/* add seed to station, updates station structure */ +			PianoRequestDataAddSeed_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); +			assert (reqData->station != NULL); + +			/* FIXME: update station data instead of replacing them */ +			ret = PianoXmlParseAddSeed (ph, req->responseData, reqData->station); +			break; +		} + +		case PIANO_REQUEST_ADD_TIRED_SONG: +		case PIANO_REQUEST_SET_QUICKMIX: +		case PIANO_REQUEST_BOOKMARK_SONG: +		case PIANO_REQUEST_BOOKMARK_ARTIST: +			assert (req->responseData != NULL); + +			ret = PianoXmlParseSimple (req->responseData); +			break; + +		case PIANO_REQUEST_GET_GENRE_STATIONS: +			/* get genre stations */ +			assert (req->responseData != NULL); + +			ret = PianoXmlParseGenreExplorer (ph, req->responseData); +			break; + +		case PIANO_REQUEST_TRANSFORM_STATION: { +			/* transform shared station into private and update isCreator flag */ +			PianoStation_t *station = req->data; + +			assert (req->responseData != NULL); +			assert (station != NULL); + +			/* though this call returns a bunch of "new" data only this one is +			 * changed and important (at the moment) */ +			if ((ret = PianoXmlParseTranformStation (req->responseData)) == +					PIANO_RET_OK) { +				station->isCreator = 1; +			} +			break; +		} + +		case PIANO_REQUEST_EXPLAIN: { +			/* explain why song was selected */ +			PianoRequestDataExplain_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			ret = PianoXmlParseNarrative (req->responseData, &reqData->retExplain); +			break; +		} + +		case PIANO_REQUEST_GET_SEED_SUGGESTIONS: { +			/* find similar artists */ +			PianoRequestDataGetSeedSuggestions_t *reqData = req->data; + +			assert (req->responseData != NULL); +			assert (reqData != NULL); + +			ret = PianoXmlParseSeedSuggestions (req->responseData, +					&reqData->searchResult); +			break; +		} +	} + +	return ret; +} + +/*	get station from list by id + *	@param search here + *	@param search for this + *	@return the first station structure matching the given id + */ +PianoStation_t *PianoFindStationById (PianoStation_t *stations, +		const char *searchStation) { +	while (stations != NULL) { +		if (strcmp (stations->id, searchStation) == 0) { +			return stations; +		} +		stations = stations->next; +	} +	return NULL; +} + +/*	convert return value to human-readable string + *	@param enum + *	@return error string + */ +const char *PianoErrorToStr (PianoReturn_t ret) { +	switch (ret) { +		case PIANO_RET_OK: +			return "Everything is fine :)"; +			break; + +		case PIANO_RET_ERR: +			return "Unknown."; +			break; + +		case PIANO_RET_XML_INVALID: +			return "Invalid XML."; +			break; + +		case PIANO_RET_AUTH_TOKEN_INVALID: +			return "Invalid auth token."; +			break; +		 +		case PIANO_RET_AUTH_USER_PASSWORD_INVALID: +			return "Username and/or password not correct."; +			break; + +		case PIANO_RET_NOT_AUTHORIZED: +			return "Not authorized."; +			break; + +		case PIANO_RET_PROTOCOL_INCOMPATIBLE: +			return "Protocol incompatible. Please upgrade " PACKAGE "."; +			break; + +		case PIANO_RET_READONLY_MODE: +			return "Request cannot be completed at this time, please try " +					"again later."; +			break; + +		case PIANO_RET_STATION_CODE_INVALID: +			return "Station id is invalid."; +			break; + +		case PIANO_RET_IP_REJECTED: +			return "Your ip address was rejected. Please setup a control " +					"proxy (see manpage)."; +			break; + +		case PIANO_RET_STATION_NONEXISTENT: +			return "Station does not exist."; +			break; + +		case PIANO_RET_OUT_OF_MEMORY: +			return "Out of memory."; +			break; + +		case PIANO_RET_OUT_OF_SYNC: +			return "Out of sync. Please correct your system's time."; +			break; + +		case PIANO_RET_PLAYLIST_END: +			return "Playlist end."; +			break; + +		case PIANO_RET_QUICKMIX_NOT_PLAYABLE: +			return "Quickmix not playable."; +			break; + +		default: +			return "No error message available."; +			break; +	} +} + diff --git a/src/libpiano/piano.h b/src/libpiano/piano.h new file mode 100644 index 0000000..ef6e386 --- /dev/null +++ b/src/libpiano/piano.h @@ -0,0 +1,244 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _PIANO_H +#define _PIANO_H + +/* this is our public API; don't expect this api to be stable as long as + * pandora does not provide a stable api + * all strings _must_ be utf-8 encoded. i won't care, but pandora does. so + * be nice and check the encoding of your strings. thanks :) */ + +#define PIANO_RPC_HOST "www.pandora.com" +#define PIANO_RPC_PORT "80" + +typedef struct PianoUserInfo { +	char *webAuthToken; +	char *listenerId; +	char *authToken; +} PianoUserInfo_t; + +typedef struct PianoStation { +	char isCreator; +	char isQuickMix; +	char useQuickMix; /* station will be included in quickmix */ +	char *name; +	char *id; +	struct PianoStation *next; +} PianoStation_t; + +typedef enum { +	PIANO_RATE_NONE = 0, +	PIANO_RATE_LOVE = 1, +	PIANO_RATE_BAN = 2 +} PianoSongRating_t; + +/* UNKNOWN should be 0, because memset sets audio format to 0 */ +typedef enum { +	PIANO_AF_UNKNOWN = 0, +	PIANO_AF_AACPLUS = 1, +	PIANO_AF_MP3 = 2, +	PIANO_AF_MP3_HI = 3 +} PianoAudioFormat_t; + +typedef struct PianoSong { +	char *artist; +	char *artistMusicId; +	char *stationId; +	char *album; +	char *userSeed; +	char *audioUrl; +	char *coverArt; +	char *musicId; +	char *title; +	float fileGain; +	PianoSongRating_t rating; +	PianoAudioFormat_t audioFormat; +	int testStrategy; +	unsigned int songType; +	struct PianoSong *next; +} PianoSong_t; + +/* currently only used for search results */ +typedef struct PianoArtist { +	char *name; +	char *musicId; +	int score; +	struct PianoArtist *next; +} PianoArtist_t; + +typedef struct PianoGenre { +	char *name; +	char *musicId; +	struct PianoGenre *next; +} PianoGenre_t; + +typedef struct PianoGenreCategory { +	char *name; +	PianoGenre_t *genres; +	struct PianoGenreCategory *next; +} PianoGenreCategory_t; + +typedef struct PianoHandle { +	char routeId[9]; +	PianoUserInfo_t user; +	/* linked lists */ +	PianoStation_t *stations; +	PianoGenreCategory_t *genreStations; +	int timeOffset; +} PianoHandle_t; + +typedef struct PianoSearchResult { +	PianoSong_t *songs; +	PianoArtist_t *artists; +} PianoSearchResult_t; + +typedef enum { +	/* 0 is reserved: memset (x, 0, sizeof (x)) */ +	PIANO_REQUEST_LOGIN = 1, +	PIANO_REQUEST_GET_STATIONS = 2, +	PIANO_REQUEST_GET_PLAYLIST = 3, +	PIANO_REQUEST_RATE_SONG = 4, +	PIANO_REQUEST_ADD_FEEDBACK = 5, +	PIANO_REQUEST_MOVE_SONG = 6, +	PIANO_REQUEST_RENAME_STATION = 7, +	PIANO_REQUEST_DELETE_STATION = 8, +	PIANO_REQUEST_SEARCH = 9, +	PIANO_REQUEST_CREATE_STATION = 10, +	PIANO_REQUEST_ADD_SEED = 11, +	PIANO_REQUEST_ADD_TIRED_SONG = 12, +	PIANO_REQUEST_SET_QUICKMIX = 13, +	PIANO_REQUEST_GET_GENRE_STATIONS = 14, +	PIANO_REQUEST_TRANSFORM_STATION = 15, +	PIANO_REQUEST_EXPLAIN = 16, +	PIANO_REQUEST_GET_SEED_SUGGESTIONS = 17, +	PIANO_REQUEST_BOOKMARK_SONG = 18, +	PIANO_REQUEST_BOOKMARK_ARTIST = 19, +} PianoRequestType_t; + +typedef struct PianoRequest { +	PianoRequestType_t type; +	void *data; +	char urlPath[1024]; +	char *postData; +	char *responseData; +} PianoRequest_t; + +/* request data structures */ +typedef struct { +	char *user; +	char *password; +	unsigned char step; +} PianoRequestDataLogin_t; + +typedef struct { +	PianoStation_t *station; +	PianoAudioFormat_t format; +	PianoSong_t *retPlaylist; +} PianoRequestDataGetPlaylist_t; + +typedef struct { +	PianoSong_t *song; +	PianoSongRating_t rating; +} PianoRequestDataRateSong_t; + +typedef struct { +	char *stationId; +	char *musicId; +	char *userSeed; +	PianoSongRating_t rating; +	unsigned int testStrategy; +	unsigned int songType; +} PianoRequestDataAddFeedback_t; + +typedef struct { +	PianoSong_t *song; +	PianoStation_t *from; +	PianoStation_t *to; +	unsigned short step; +} PianoRequestDataMoveSong_t; + +typedef struct { +	PianoStation_t *station; +	char *newName; +} PianoRequestDataRenameStation_t; + +typedef struct { +	char *searchStr; +	PianoSearchResult_t searchResult; +} PianoRequestDataSearch_t; + +typedef struct { +	char *type; +	char *id; +} PianoRequestDataCreateStation_t; + +typedef struct { +	PianoStation_t *station; +	char *musicId; +} PianoRequestDataAddSeed_t; + +typedef struct { +	PianoSong_t *song; +	char *retExplain; +} PianoRequestDataExplain_t; + +typedef struct { +	char *musicId; +	unsigned short max; +	PianoSearchResult_t searchResult; +} PianoRequestDataGetSeedSuggestions_t; + +typedef enum { +	PIANO_RET_ERR = 0, +	PIANO_RET_OK = 1, +	PIANO_RET_XML_INVALID = 2, +	PIANO_RET_AUTH_TOKEN_INVALID = 3, +	PIANO_RET_AUTH_USER_PASSWORD_INVALID = 4, +	PIANO_RET_CONTINUE_REQUEST = 5, +	PIANO_RET_NOT_AUTHORIZED = 6, +	PIANO_RET_PROTOCOL_INCOMPATIBLE = 7, +	PIANO_RET_READONLY_MODE = 8, +	PIANO_RET_STATION_CODE_INVALID = 9, +	PIANO_RET_IP_REJECTED = 10, +	PIANO_RET_STATION_NONEXISTENT = 11, +	PIANO_RET_OUT_OF_MEMORY = 12, +	PIANO_RET_OUT_OF_SYNC = 13, +	PIANO_RET_PLAYLIST_END = 14, +	PIANO_RET_QUICKMIX_NOT_PLAYABLE = 15, +} PianoReturn_t; + +void PianoInit (PianoHandle_t *); +void PianoDestroy (PianoHandle_t *); +void PianoDestroyPlaylist (PianoSong_t *); +void PianoDestroySearchResult (PianoSearchResult_t *); + +PianoReturn_t PianoRequest (PianoHandle_t *, PianoRequest_t *, +		PianoRequestType_t); +PianoReturn_t PianoResponse (PianoHandle_t *, PianoRequest_t *); +void PianoDestroyRequest (PianoRequest_t *); + +PianoStation_t *PianoFindStationById (PianoStation_t *, const char *); +const char *PianoErrorToStr (PianoReturn_t); + +#endif /* _PIANO_H */ diff --git a/src/libpiano/piano_private.h b/src/libpiano/piano_private.h new file mode 100644 index 0000000..bb14c8f --- /dev/null +++ b/src/libpiano/piano_private.h @@ -0,0 +1,31 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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 + +#include "piano.h" + +void PianoDestroyStation (PianoStation_t *station); + +#endif /* _MAIN_H */ diff --git a/src/libpiano/xml.c b/src/libpiano/xml.c new file mode 100644 index 0000000..01294d8 --- /dev/null +++ b/src/libpiano/xml.c @@ -0,0 +1,826 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +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. +*/ + +#define _BSD_SOURCE /* required by strdup() */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ezxml.h> + +#include "piano.h" +#include "crypt.h" +#include "config.h" +#include "piano_private.h" + +static void PianoXmlStructParser (const ezxml_t, +		void (*callback) (const char *, const ezxml_t, void *), void *); +static char *PianoXmlGetNodeText (const ezxml_t); + +/*	parse fault and get fault type + *	@param xml <name> content + *	@param xml <value> node + *	@param return error string + *	@return nothing + */ +static void PianoXmlIsFaultCb (const char *key, const ezxml_t value, +		void *data) { +	PianoReturn_t *ret = data; +	char *valueStr = PianoXmlGetNodeText (value); +	char *matchStart, *matchEnd; + +	if (strcmp ("faultString", key) == 0) { +		*ret = PIANO_RET_ERR; +		/* find fault identifier in a string like this: +		 * com.savagebeast.radio.api.protocol.xmlrpc.RadioXmlRpcException: +		 * 192.168.160.78|1213101717317|AUTH_INVALID_TOKEN| +		 * Invalid auth token */ +		if ((matchStart = strchr (valueStr, '|')) != NULL) { +			if ((matchStart = strchr (matchStart+1, '|')) != NULL) { +				if ((matchEnd = strchr (matchStart+1, '|')) != NULL) { +					/* changes text in xml node, but we don't care... */ +					*matchEnd = '\0'; +					++matchStart; +					/* translate to our error message system */ +					if (strcmp ("AUTH_INVALID_TOKEN", matchStart) == 0) { +						*ret = PIANO_RET_AUTH_TOKEN_INVALID; +					} else if (strcmp ("AUTH_INVALID_USERNAME_PASSWORD", +							matchStart) == 0) { +						*ret = PIANO_RET_AUTH_USER_PASSWORD_INVALID; +					} else if (strcmp ("LISTENER_NOT_AUTHORIZED", +							matchStart) == 0) { +						*ret = PIANO_RET_NOT_AUTHORIZED; +					} else if (strcmp ("INCOMPATIBLE_VERSION", +							matchStart) == 0) { +						*ret = PIANO_RET_PROTOCOL_INCOMPATIBLE; +					} else if (strcmp ("READONLY_MODE", matchStart) == 0) { +						*ret = PIANO_RET_READONLY_MODE; +					} else if (strcmp ("STATION_CODE_INVALID", +							matchStart) == 0) { +						*ret = PIANO_RET_STATION_CODE_INVALID; +					} else if (strcmp ("STATION_DOES_NOT_EXIST", +							matchStart) == 0) { +						*ret = PIANO_RET_STATION_NONEXISTENT; +					} else if (strcmp ("OUT_OF_SYNC", matchStart) == 0) { +						*ret = PIANO_RET_OUT_OF_SYNC; +					} else if (strcmp ("PLAYLIST_END", matchStart) == 0) { +						*ret = PIANO_RET_PLAYLIST_END; +					} else if (strcmp ("QUICKMIX_NOT_PLAYABLE", matchStart) == 0) { +						*ret = PIANO_RET_QUICKMIX_NOT_PLAYABLE; +					} else { +						*ret = PIANO_RET_ERR; +						printf (PACKAGE ": Unknown error %s in %s\n", +								matchStart, valueStr); +					} +				} +			} +		} +	} else if (strcmp ("faultCode", key) == 0) { +		/* some errors can only be identified by looking at their id */ +		/* detect pandora's ip restriction */ +		if (strcmp ("12", valueStr) == 0) { +			*ret = PIANO_RET_IP_REJECTED; +		} +	} +} + +/*	check whether pandora returned an error or not + *	@param document root of xml doc + *	@return _RET_OK or fault code (_RET_*) + */ +static PianoReturn_t PianoXmlIsFault (ezxml_t xmlDoc) { +	PianoReturn_t ret; + +	if ((xmlDoc = ezxml_child (xmlDoc, "fault")) != NULL) { +		xmlDoc = ezxml_get (xmlDoc, "value", 0, "struct", -1); +		PianoXmlStructParser (xmlDoc, PianoXmlIsFaultCb, &ret); +		return ret; +	} +	return PIANO_RET_OK; +} + +/*	parses things like this: + *	<struct> + *		<member> + *			<name /> + *			<value /> + *		</member> + *		<!-- ... --> + *	</struct> + *	@param xml node named "struct" (or containing a similar structure) + *	@param who wants to use this data? callback: content of <name> as + *			string, content of <value> as xmlNode (may contain other nodes + *			or text), additional data used by callback(); don't forget + *			to *copy* data taken from <name> or <value> as they will be + *			freed soon + *	@param extra data for callback + */ +static void PianoXmlStructParser (const ezxml_t structRoot, +		void (*callback) (const char *, const ezxml_t, void *), void *data) { +	ezxml_t curNode, keyNode, valueNode; +	char *key; + +	/* get all <member> nodes */ +    for (curNode = ezxml_child (structRoot, "member"); curNode; curNode = curNode->next) { +		/* reset variables */ +		key = NULL; +		valueNode = keyNode = NULL; + +		keyNode = ezxml_child (curNode, "name"); +		if (keyNode != NULL) { +			key = ezxml_txt (keyNode); +		} + +		valueNode = ezxml_child (curNode, "value"); +		/* this will ignore empty <value /> nodes, but well... */ +		if (*key != '\0' && valueNode != NULL) { +			(*callback) ((char *) key, valueNode, data); +		} +	} +} + +/*	create xml parser from string + *	@param xml document + *	@param returns document pointer (needed to free memory later) + *	@param returns document root + *	@return _OK or error + */ +static PianoReturn_t PianoXmlInitDoc (char *xmlStr, ezxml_t *xmlDoc) { +	PianoReturn_t ret; + +	if ((*xmlDoc = ezxml_parse_str (xmlStr, strlen (xmlStr))) == NULL) { +		return PIANO_RET_XML_INVALID; +	} + +	if ((ret = PianoXmlIsFault (*xmlDoc)) != PIANO_RET_OK) { +		ezxml_free (*xmlDoc); +		return ret; +	} + +	return PIANO_RET_OK; +} + +/*	get text from <value> nodes; some of them have <boolean>, <string> + *	or <int> subnodes, just ignore them + *	@param xml node <value> + */ +static char *PianoXmlGetNodeText (const ezxml_t node) { +	char *retTxt = NULL; + +	retTxt = ezxml_txt (node); +	/* no text => empty string */ +	if (*retTxt == '\0') { +		retTxt = ezxml_txt (node->child); +	} +	return retTxt; +} + +/*	structParser callback; writes userinfo to PianoUserInfo structure + *	@param value identifier + *	@param value node + *	@param pointer to userinfo structure + *	@return nothing + */ +static void PianoXmlParseUserinfoCb (const char *key, const ezxml_t value, +		void *data) { +	PianoUserInfo_t *user = data; +	char *valueStr = PianoXmlGetNodeText (value); + +	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); +	} +} + +static void PianoXmlParseStationsCb (const char *key, const ezxml_t value, +		void *data) { +	PianoStation_t *station = data; +	char *valueStr = PianoXmlGetNodeText (value); + +	if (strcmp ("stationName", key) == 0) { +		station->name = strdup (valueStr); +	} else if (strcmp ("stationId", key) == 0) { +		station->id = strdup (valueStr); +	} else if (strcmp ("isQuickMix", key) == 0) { +		station->isQuickMix = (strcmp (valueStr, "1") == 0); +	} else if (strcmp ("isCreator", key) == 0) { +		station->isCreator = (strcmp (valueStr, "1") == 0); +	} +} + +static void PianoXmlParsePlaylistCb (const char *key, const ezxml_t value, +		void *data) { +	PianoSong_t *song = data; +	char *valueStr = PianoXmlGetNodeText (value); + +	if (strcmp ("audioURL", key) == 0) { +		/* last 48 chars of audioUrl are encrypted, but they put the key +		 * into the door's lock... */ +		const char urlTailN = 48; +		const size_t valueStrN = strlen (valueStr); +		char *urlTail = NULL, +				*urlTailCrypted = &valueStr[valueStrN - urlTailN]; + +		/* don't try to decrypt if string is too short (=> invalid memory +		 * reads/writes) */ +		if (valueStrN > urlTailN && +				(urlTail = PianoDecryptString (urlTailCrypted)) != NULL) { +			if ((song->audioUrl = calloc (valueStrN + 1, +					sizeof (*song->audioUrl))) != NULL) { +				memcpy (song->audioUrl, valueStr, valueStrN - urlTailN); +				/* FIXME: the key seems to be broken... so ignore 8 x 0x08 +				 * postfix; urlTailN/2 because the encrypted hex string is now +				 * decoded */ +				memcpy (&song->audioUrl[valueStrN - urlTailN], urlTail, +						urlTailN/2 - 8); +			} +			free (urlTail); +		} +	} else if (strcmp ("artRadio", key) == 0) { +		song->coverArt = strdup (valueStr); +	} else if (strcmp ("artistSummary", key) == 0) { +		song->artist = strdup (valueStr); +	} else if (strcmp ("musicId", key) == 0) { +		song->musicId = strdup (valueStr); +	} else if (strcmp ("userSeed", key) == 0) { +		song->userSeed = strdup (valueStr); +	} else if (strcmp ("songTitle", key) == 0) { +		song->title = strdup (valueStr); +	} else if (strcmp ("rating", key) == 0) { +		if (strcmp (valueStr, "1") == 0) { +			song->rating = PIANO_RATE_LOVE; +		} else { +			song->rating = PIANO_RATE_NONE; +		} +	} else if (strcmp ("stationId", key) == 0) { +		song->stationId = strdup (valueStr); +	} else if (strcmp ("albumTitle", key) == 0) { +		song->album = strdup (valueStr); +	} else if (strcmp ("fileGain", key) == 0) { +		song->fileGain = atof (valueStr); +	} else if (strcmp ("audioEncoding", key) == 0) { +		if (strcmp (valueStr, "aacplus") == 0) { +			song->audioFormat = PIANO_AF_AACPLUS; +		} else if (strcmp (valueStr, "mp3") == 0) { +			song->audioFormat = PIANO_AF_MP3; +		} else if (strcmp (valueStr, "mp3-hifi") == 0) { +			song->audioFormat = PIANO_AF_MP3_HI; +		} +	} else if (strcmp ("artistMusicId", key) == 0) { +		song->artistMusicId = strdup (valueStr); + 	} else if (strcmp ("testStrategy", key) == 0) { +		song->testStrategy = atoi (valueStr); +	} else if (strcmp ("songType", key) == 0) { +		song->songType = atoi (valueStr); +	} +} + +/*	parses userinfos sent by pandora as login response + *	@param piano handle + *	@param utf-8 string + *	@return _RET_OK or error + */ +PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, char *xml) { +	ezxml_t xmlDoc, structNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	/* <methodResponse> <params> <param> <value> <struct> */ +	structNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); +	PianoXmlStructParser (structNode, PianoXmlParseUserinfoCb, &ph->user); + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +static void PianoXmlParseQuickMixStationsCb (const char *key, const ezxml_t value, +		void *data) { +	char ***retIds = data; +	char **ids = NULL; +	size_t idsN = 0; +	ezxml_t curNode; + +	if (strcmp ("quickMixStationIds", key) == 0) { +		for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); +				curNode; curNode = curNode->next) { +			idsN++; +			if (ids == NULL) { +				if ((ids = calloc (idsN, sizeof (*ids))) == NULL) { +					*retIds = NULL; +					return; +				} +			} else { +				/* FIXME: memory leak (on failure) */ +				if ((ids = realloc (ids, idsN * sizeof (*ids))) == NULL) { +					*retIds = NULL; +					return; +				} +			} +			ids[idsN-1] = strdup (PianoXmlGetNodeText (curNode)); +		} +		/* append NULL: list ends here */ +		idsN++; +		/* FIXME: copy&waste */ +		if (ids == NULL) { +			if ((ids = calloc (idsN, sizeof (*ids))) == NULL) { +				*retIds = NULL; +				return; +			} +		} else { +			if ((ids = realloc (ids, idsN * sizeof (*ids))) == NULL) { +				*retIds = NULL; +				return; +			} +		} +		ids[idsN-1] = NULL; +	} +	*retIds = ids; +} + +/*	parse stations returned by pandora + *	@param piano handle + *	@param xml returned by pandora + *	@return _RET_OK or error + */ +PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, char *xml) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; +	char **quickMixIds = NULL, **curQuickMixId = NULL; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "array", +			0, "data", -1); + +	for (dataNode = ezxml_child (dataNode, "value"); dataNode; +			dataNode = dataNode->next) { +		PianoStation_t *tmpStation; + +		if ((tmpStation = calloc (1, sizeof (*tmpStation))) == NULL) { +			ezxml_free (xmlDoc); +			return PIANO_RET_OUT_OF_MEMORY; +		} + +		PianoXmlStructParser (ezxml_child (dataNode, "struct"), +				PianoXmlParseStationsCb, tmpStation); + +		/* get stations selected for quickmix */ +		if (tmpStation->isQuickMix) { +			PianoXmlStructParser (ezxml_child (dataNode, "struct"), +					PianoXmlParseQuickMixStationsCb, &quickMixIds); +		} +		/* 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; +		} +	} +	/* set quickmix flags after all stations are read */ +	if (quickMixIds != NULL) { +		curQuickMixId = quickMixIds; +		while (*curQuickMixId != NULL) { +			PianoStation_t *curStation = PianoFindStationById (ph->stations, +					*curQuickMixId); +			if (curStation != NULL) { +				curStation->useQuickMix = 1; +			} +			free (*curQuickMixId); +			curQuickMixId++; +		} +		free (quickMixIds); +	} + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	parse "create station" answer (it returns a new station structure) + *	@param piano handle + *	@param xml document + *	@return nothing yet + */ +PianoReturn_t PianoXmlParseCreateStation (PianoHandle_t *ph, char *xml) { +	ezxml_t xmlDoc, dataNode; +	PianoStation_t *tmpStation; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); + +	if ((tmpStation = calloc (1, sizeof (*tmpStation))) == NULL) { +		ezxml_free (xmlDoc); +		return PIANO_RET_OUT_OF_MEMORY; +	} +	PianoXmlStructParser (dataNode, PianoXmlParseStationsCb, tmpStation); +	/* FIXME: copy & waste */ +	/* start new linked list or append */ +	if (ph->stations == NULL) { +		ph->stations = tmpStation; +	} else { +		PianoStation_t *curStation = ph->stations; +		while (curStation->next != NULL) { +			curStation = curStation->next; +		} +		curStation->next = tmpStation; +	} +	 +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	parse "add seed" answer, nearly the same as ParseCreateStation + *	@param piano handle + *	@param xml document + *	@param update this station + */ +PianoReturn_t PianoXmlParseAddSeed (PianoHandle_t *ph, char *xml, +		PianoStation_t *station) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); +	PianoDestroyStation (station); +	PianoXmlStructParser (dataNode, PianoXmlParseStationsCb, station); +	 +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	parses playlist; used when searching too + *	@param piano handle + *	@param xml document + *	@param return: playlist + */ +PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, char *xml, +		PianoSong_t **retPlaylist) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "array", +			0, "data", -1); + +	for (dataNode = ezxml_child (dataNode, "value"); dataNode; +			dataNode = dataNode->next) { +		PianoSong_t *tmpSong; +		 +		if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { +			ezxml_free (xmlDoc); +			return PIANO_RET_OUT_OF_MEMORY; +		} + +		PianoXmlStructParser (ezxml_child (dataNode, "struct"), +				PianoXmlParsePlaylistCb, tmpSong); +		/* begin linked list or append */ +		if (*retPlaylist == NULL) { +			*retPlaylist = tmpSong; +		} else { +			PianoSong_t *curSong = *retPlaylist; +			while (curSong->next != NULL) { +				curSong = curSong->next; +			} +			curSong->next = tmpSong; +		} +	} + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	parse simple answers like this: <?xml version="1.0" encoding="UTF-8"?> + *	<methodResponse><params><param><value>1</value></param></params> + *	</methodResponse> + *	@param xml string + *	@return + */ +PianoReturn_t PianoXmlParseSimple (char *xml) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", -1); + +	if (strcmp (ezxml_txt (dataNode), "1") == 0) { +		ret = PIANO_RET_OK; +	} else { +		ret = PIANO_RET_ERR; +	} + +	ezxml_free (xmlDoc); + +	return ret; +} + +/*	xml struct parser callback, used in PianoXmlParseSearchCb + */ +static void PianoXmlParseSearchArtistCb (const char *key, const ezxml_t value, +		void *data) { +	PianoArtist_t *artist = data; +	char *valueStr = PianoXmlGetNodeText (value); + +	if (strcmp ("artistName", key) == 0) { +		artist->name = strdup (valueStr); +	} else if (strcmp ("musicId", key) == 0) { +		artist->musicId = strdup (valueStr); +	} +} + +/*	callback for xml struct parser used in PianoXmlParseSearch, "switch" for + *	PianoXmlParseSearchArtistCb and PianoXmlParsePlaylistCb + */ +static void PianoXmlParseSearchCb (const char *key, const ezxml_t value, +		void *data) { +	PianoSearchResult_t *searchResult = data; +	ezxml_t curNode; + +	if (strcmp ("artists", key) == 0) { +		/* skip <value><array><data> */ +		for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); +				curNode; curNode = curNode->next) { +			PianoArtist_t *artist; +			 +			if ((artist = calloc (1, sizeof (*artist))) == NULL) { +				/* fail silently */ +				break; +			} + +			memset (artist, 0, sizeof (*artist)); + +			PianoXmlStructParser (ezxml_child (curNode, "struct"), +					PianoXmlParseSearchArtistCb, artist); + +			/* add result to linked list */ +			if (searchResult->artists == NULL) { +				searchResult->artists = artist; +			} else { +				PianoArtist_t *curArtist = searchResult->artists; +				while (curArtist->next != NULL) { +					curArtist = curArtist->next; +				} +				curArtist->next = artist; +			} +		} +	} else if (strcmp ("songs", key) == 0) { +		for (curNode = ezxml_child (ezxml_get (value, "array", 0, "data", -1), "value"); +				curNode; curNode = curNode->next) { +			/* FIXME: copy & waste */ +			PianoSong_t *tmpSong; +			 +			if ((tmpSong = calloc (1, sizeof (*tmpSong))) == NULL) { +				/* fail silently */ +				break; +			} + +			PianoXmlStructParser (ezxml_child (curNode, "struct"), +					PianoXmlParsePlaylistCb, tmpSong); +			/* begin linked list or append */ +			if (searchResult->songs == NULL) { +				searchResult->songs = tmpSong; +			} else { +				PianoSong_t *curSong = searchResult->songs; +				while (curSong->next != NULL) { +					curSong = curSong->next; +				} +				curSong->next = tmpSong; +			} +		} +	} +} + +/*	parse search result; searchResult is nulled before use + *	@param xml document + *	@param returns search result + *	@return nothing yet + */ +PianoReturn_t PianoXmlParseSearch (char *xml, +		PianoSearchResult_t *searchResult) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} +	 +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", 0, "struct", -1); +	/* we need a "clean" search result (with null pointers) */ +	memset (searchResult, 0, sizeof (*searchResult)); +	PianoXmlStructParser (dataNode, PianoXmlParseSearchCb, searchResult); + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	FIXME: copy&waste (PianoXmlParseSearch) + */ +PianoReturn_t PianoXmlParseSeedSuggestions (char *xml, +		PianoSearchResult_t *searchResult) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} +	 +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", -1); +	/* we need a "clean" search result (with null pointers) */ +	memset (searchResult, 0, sizeof (*searchResult)); +	/* reuse seach result parser; structure is nearly the same */ +	PianoXmlParseSearchCb ("artists", dataNode, searchResult); + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	encode reserved xml chars + *	TODO: remove and use ezxml_ampencode + *	@param encode this + *	@return encoded string or NULL + */ +char *PianoXmlEncodeString (const char *s) { +	char *replacements[] = {"&&", "''", "\""", "<<", +			">>", NULL}; +	char **r, *sOut, *sOutCurr, found; + +	if ((sOut = calloc (strlen (s) * 5 + 1, sizeof (*sOut))) == NULL) { +		return NULL; +	} + +	sOutCurr = sOut; + +	while (*s != '\0') { +		r = replacements; +		found = 0; +		while (*r != NULL) { +			if (*s == *r[0]) { +				found = 1; +				strcat (sOutCurr, (*r) + 1); +				sOutCurr += strlen ((*r) + 1); +				break; +			} +			r++; +		} +		if (!found) { +			*sOutCurr = *s; +			sOutCurr++; +		} +		s++; +	} +	return sOut; +} + +PianoReturn_t PianoXmlParseGenreExplorer (PianoHandle_t *ph, char *xml) { +	ezxml_t xmlDoc, catNode; +	PianoReturn_t ret; + +    if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +        return ret; +    } + +	/* get all <member> nodes */ +    for (catNode = ezxml_child (xmlDoc, "category"); catNode; +			catNode = catNode->next) { +		PianoGenreCategory_t *tmpGenreCategory; +		ezxml_t genreNode; + +		if ((tmpGenreCategory = calloc (1, sizeof (*tmpGenreCategory))) == NULL) { +			ezxml_free (xmlDoc); +			return PIANO_RET_OUT_OF_MEMORY; +		} + +		tmpGenreCategory->name = strdup (ezxml_attr (catNode, "categoryName")); + +		/* get genre subnodes */ +		for (genreNode = ezxml_child (catNode, "genre"); genreNode; +				genreNode = genreNode->next) { +			PianoGenre_t *tmpGenre; + +			if ((tmpGenre = calloc (1, sizeof (*tmpGenre))) == NULL) { +				ezxml_free (xmlDoc); +				return PIANO_RET_OUT_OF_MEMORY; +			} + +			/* get genre attributes */ +			tmpGenre->name = strdup (ezxml_attr (genreNode, "name")); +			tmpGenre->musicId = strdup (ezxml_attr (genreNode, "musicId")); + +			/* append station */ +			if (tmpGenreCategory->genres == NULL) { +				tmpGenreCategory->genres = tmpGenre; +			} else { +				PianoGenre_t *curGenre = +						tmpGenreCategory->genres; +				while (curGenre->next != NULL) { +					curGenre = curGenre->next; +				} +				curGenre->next = tmpGenre; +			} +		} +		/* append category */ +		if (ph->genreStations == NULL) { +			ph->genreStations = tmpGenreCategory; +		} else { +			PianoGenreCategory_t *curCat = ph->genreStations; +			while (curCat->next != NULL) { +				curCat = curCat->next; +			} +			curCat->next = tmpGenreCategory; +		} +	} + +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	dummy function, only checks for errors + *	@param xml doc + *	@return _OK or error + */ +PianoReturn_t PianoXmlParseTranformStation (char *xml) { +	ezxml_t xmlDoc; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} +	 +	ezxml_free (xmlDoc); + +	return PIANO_RET_OK; +} + +/*	parses "why did you play ...?" answer + *	@param xml + *	@param returns the answer + *	@return _OK or error + */ +PianoReturn_t PianoXmlParseNarrative (char *xml, char **retNarrative) { +	ezxml_t xmlDoc, dataNode; +	PianoReturn_t ret; + +	if ((ret = PianoXmlInitDoc (xml, &xmlDoc)) != PIANO_RET_OK) { +		return ret; +	} + +	/* <methodResponse> <params> <param> <value> $textnode */ +	dataNode = ezxml_get (xmlDoc, "params", 0, "param", 0, "value", -1); +	*retNarrative = strdup (ezxml_txt (dataNode)); + +	ezxml_free (xmlDoc); + +	return ret; +} + diff --git a/src/libpiano/xml.h b/src/libpiano/xml.h new file mode 100644 index 0000000..dc778ca --- /dev/null +++ b/src/libpiano/xml.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2008-2010 +	Lars-Dominik Braun <PromyLOPh@lavabit.com> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _XML_H +#define _XML_H + +#include "piano.h" + +PianoReturn_t PianoXmlParseUserinfo (PianoHandle_t *ph, const char *xml); +PianoReturn_t PianoXmlParseStations (PianoHandle_t *ph, const char *xml); +PianoReturn_t PianoXmlParsePlaylist (PianoHandle_t *ph, const char *xml, +		PianoSong_t **); +PianoReturn_t PianoXmlParseSearch (const char *searchXml, +		PianoSearchResult_t *searchResult); +PianoReturn_t PianoXmlParseSimple (const char *xml); +PianoReturn_t PianoXmlParseCreateStation (PianoHandle_t *ph, +		const char *xml); +PianoReturn_t PianoXmlParseAddSeed (PianoHandle_t *ph, const char *xml, +		PianoStation_t *station); +PianoReturn_t PianoXmlParseGenreExplorer (PianoHandle_t *ph, +		const char *xmlContent); +PianoReturn_t PianoXmlParseTranformStation (const char *searchXml); +PianoReturn_t PianoXmlParseNarrative (const char *xml, char **retNarrative); +PianoReturn_t PianoXmlParseSeedSuggestions (char *, PianoSearchResult_t *); + +char *PianoXmlEncodeString (const char *s); + +#endif /* _XML_H */ | 
