Exemplo n.º 1
0
/*	set stations use by quickmix
 *	@param piano handle
 *	@return _OK or error
 */
PianoReturn_t PianoSetQuickmix (PianoHandle_t *ph) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], valueBuf[1000], urlArgBuf[1000],
			*retStr;
	PianoReturn_t ret;
	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>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>RANDOM</string></value></param>"
			"<param><value><array><data>", time (NULL), 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></params></methodCall>",
			sizeof (xmlSendBuf) - strlen (xmlSendBuf) - 1);

	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=setQuickMix&arg1=RANDOM&arg2=%s",
			ph->routeId, ph->user.listenerId, urlArgBuf);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseSimple (retStr);
		PianoFree (retStr, 0);
	}

	return ret;
}
Exemplo n.º 2
0
/*	add feedback
 *	@param piano handle
 *	@param station id
 *	@param song id
 *	@param song matching seed or NULL
 *	@param song user seed or NULL
 *	@param song focus trait id or NULL
 *	@param rating
 */
static PianoReturn_t PianoAddFeedback (PianoHandle_t *ph, const char *stationId,
		const char *songMusicId, const char *songMatchingSeed,
		const char *songUserSeed, const char *songFocusTraitId,
		PianoSongRating_t rating) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret = PIANO_RET_ERR;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>station.addFeedback</methodName>"
			"<params><param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value></value></param>"
			"<param><value><boolean>%i</boolean></value></param>"
			"<param><value><boolean>0</boolean></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			stationId, songMusicId,
			(songMatchingSeed == NULL) ? "" : songMatchingSeed,
			(songUserSeed == NULL) ? "" : songUserSeed,
			(songFocusTraitId == NULL) ? "" : songFocusTraitId,
			(rating == PIANO_RATE_LOVE) ? 1 : 0);
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=addFeedback&arg1=%s&arg2=%s"
			"&arg3=%s&arg4=%s&arg5=%s&arg6=&arg7=%s&arg8=false", ph->routeId,
			ph->user.listenerId, stationId, songMusicId,
			(songMatchingSeed == NULL) ? "" : songMatchingSeed,
			(songUserSeed == NULL) ? "" : songUserSeed,
			(songFocusTraitId == NULL) ? "" : songFocusTraitId,
			(rating == PIANO_RATE_LOVE) ? "true" : "false");

	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseSimple (retStr);
		PianoFree (retStr, 0);
	}

	return ret;
}
Exemplo n.º 3
0
/*	delete station
 *	@public yes
 *	@param piano handle
 *	@param station you want to delete
 */
PianoReturn_t PianoDeleteStation (PianoHandle_t *ph, PianoStation_t *station) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret = PIANO_RET_ERR;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>station.removeStation</methodName>"
			"<params><param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			station->id);

	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=removeStation&arg1=%s", ph->routeId,
			ph->user.listenerId, station->id);
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		if ((ret = PianoXmlParseSimple (retStr)) == PIANO_RET_OK) {
			/* 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);
					PianoFree (curStation, sizeof (*curStation));
					break;
				}
				lastStation = curStation;
				curStation = curStation->next;
			}
		}
	}

	return ret;
}
Exemplo n.º 4
0
/*	rename station (on the server and local)
 *	@public yes
 *	@param piano handle
 *	@param change this stations name
 *	@param new name
 *	@return
 */
PianoReturn_t PianoRenameStation (PianoHandle_t *ph, PianoStation_t *station,
		const char *newName) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	char *urlencodedNewName, *xmlencodedNewName;
	PianoReturn_t ret = PIANO_RET_ERR;

	if ((xmlencodedNewName = PianoXmlEncodeString (newName)) == NULL) {
		return PIANO_RET_OUT_OF_MEMORY;
	}

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>station.setStationName</methodName>"
			"<params><param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			station->id, xmlencodedNewName);

	urlencodedNewName = WaitressUrlEncode (newName);
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=setStationName&arg1=%s&arg2=%s",
			ph->routeId, ph->user.listenerId, station->id, urlencodedNewName);

	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		if ((ret = PianoXmlParseSimple (retStr)) == PIANO_RET_OK) {
			PianoFree (station->name, 0);
			station->name = strdup (newName);
		}
		PianoFree (retStr, 0);
	}

	PianoFree (urlencodedNewName, 0);
	PianoFree (xmlencodedNewName, 0);

	return ret;
}
Exemplo n.º 5
0
/*	ban a song temporary (for one month)
 *	@param piano handle
 *	@param song to be banned
 *	@return _OK or error
 */
PianoReturn_t PianoSongTired (PianoHandle_t *ph, const PianoSong_t *song) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>listener.addTiredSong</methodName><params>"
			"<param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			song->identity);

	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=addTiredSong&arg1=%s", ph->routeId,
			ph->user.listenerId, song->identity);

	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseSimple (retStr);
		PianoFree (retStr, 0);
	}

	return ret;
}
Exemplo n.º 6
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;
}