Beispiel #1
0
/*	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 = (int)realTimestamp - (int)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:
		case PIANO_REQUEST_DELETE_FEEDBACK:
			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;
		}

		case PIANO_REQUEST_GET_STATION_INFO: {
			/* get station information (seeds and feedback) */
			PianoRequestDataGetStationInfo_t *reqData = req->data;

			assert (req->responseData != NULL);
			assert (reqData != NULL);

			ret = PianoXmlParseGetStationInfo (req->responseData,
					&reqData->info);
			break;
		}

		case PIANO_REQUEST_DELETE_SEED: {
			assert (req->responseData != NULL);

			/* dummy function, checks for errors only */
			ret = PianoXmlParseTranformStation (req->responseData);
		}
	}

	return ret;
}
Beispiel #2
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);
	}
}