Example #1
0
/*	search for music (artist or track), needed to create new station; don't
 *	forget to free the search result; beware! searchResult will be nulled
 *	by PianoXmlParseSearch
 *	@public yes
 *	@param piano handle
 *	@param utf-8 search string
 *	@param return search result
 */
PianoReturn_t PianoSearchMusic (PianoHandle_t *ph,
		const char *searchStr, PianoSearchResult_t *searchResult) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	char *xmlencodedSearchStr, *urlencodedSearchStr;
	PianoReturn_t ret;

	if ((xmlencodedSearchStr = PianoXmlEncodeString (searchStr)) == NULL) {
		return PIANO_RET_OUT_OF_MEMORY;
	}

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>music.search</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,
			xmlencodedSearchStr);

	urlencodedSearchStr = WaitressUrlEncode (searchStr);
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=search&arg1=%s", ph->routeId,
			ph->user.listenerId, urlencodedSearchStr);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseSearch (retStr, searchResult);
		PianoFree (retStr, 0);
	}

	PianoFree (urlencodedSearchStr, 0);
	PianoFree (xmlencodedSearchStr, 0);

	return ret;
}
Example #2
0
/*	destroy genre linked list
 */
void PianoDestroyGenres (PianoGenre_t *genres) {
	PianoGenre_t *curGenre, *lastGenre;

	curGenre = genres;
	while (curGenre != NULL) {
		PianoFree (curGenre->name, 0);
		PianoFree (curGenre->musicId, 0);
		lastGenre = curGenre;
		curGenre = curGenre->next;
		PianoFree (lastGenre, sizeof (*lastGenre));
	}
}
Example #3
0
/*	get next songs for station (usually four tracks)
 *	@param piano handle
 *	@param station id
 *	@param audio format
 *	@param return value: playlist
 */
PianoReturn_t PianoGetPlaylist (PianoHandle_t *ph, const char *stationId,
		PianoAudioFormat_t format, PianoSong_t **retPlaylist) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	/* FIXME: remove static, "magic" numbers */
	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>playlist.getFragment</methodName>"
			"<params><param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>0</string></value></param>"
			"<param><value><string></string></value></param>"
			"<param><value><string></string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>0</string></value></param>"
			"<param><value><string>0</string></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			stationId, PianoAudioFormatToString (format));
	snprintf (ph->waith.path, sizeof (ph->waith.path), 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, stationId,
			PianoAudioFormatToString (format));

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

	return ret;
}
Example #4
0
/*	create new station on server
 *	@public yes
 *	@param piano handle
 *	@param type: "mi" for music id (from music search) or "sh" for
 *			shared station
 *	@param id
 */
PianoReturn_t PianoCreateStation (PianoHandle_t *ph, const char *type,
		const char *id) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

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

	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=createStation&arg1=%s%s", ph->routeId,
			ph->user.listenerId, type, id);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseCreateStation (ph, retStr);
		PianoFree (retStr, 0);
	}

	return ret;
}
Example #5
0
/*	add more music to existing station; multithreaded apps beware! this alters
 *	station data, don't forget to lock the station pointer you passed to this
 *	function
 *	@public yes
 *	@param piano handle
 *	@param add music to this station
 *	@param music id; can be obtained with PianoSearchMusic ()
 */
PianoReturn_t PianoStationAddMusic (PianoHandle_t *ph,
		PianoStation_t *station, const char *musicId) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>station.addSeed</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, musicId);

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

	return ret;
}
Example #6
0
/*	make shared stations private, needed to rate songs played on shared
 *	stations
 *	@param piano handle
 *	@param station to transform
 *	@return _OK or error
 */
PianoReturn_t PianoTransformShared (PianoHandle_t *ph,
		PianoStation_t *station) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>station.transformShared</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=transformShared&arg1=%s", ph->routeId,
			ph->user.listenerId, station->id);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseTranformStation (retStr);
		/* though this call returns a bunch of "new" data only this one is
		 * changed and important (at the moment) */
		if (ret == PIANO_RET_OK) {
			station->isCreator = 1;
		}
		PianoFree (retStr, 0);
	}

	return ret;
}
Example #7
0
/*	"why dit you play this song?"
 *	@param piano handle
 *	@param song (from playlist)
 *	@param return allocated string; you have to free it yourself
 *	@return _OK or error
 */
PianoReturn_t PianoExplain (PianoHandle_t *ph, const PianoSong_t *song,
		char **retExplain) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>playlist.narrative</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,
			song->stationId, song->musicId);
	
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=method=narrative&arg1=%s&arg2=%s",
			ph->routeId, ph->user.listenerId, song->stationId, song->musicId);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseNarrative (retStr, retExplain);
		PianoFree (retStr, 0);
	}

	return ret;
}
Example #8
0
/*	Get seed suggestions by music id
 *	@param piano handle
 *	@param music id
 *	@param max results
 *	@param result buffer
 */
PianoReturn_t PianoSeedSuggestions (PianoHandle_t *ph, const char *musicId,
		unsigned int max, PianoSearchResult_t *searchResult) {
	char xmlSendBuf[PIANO_SEND_BUFFER_SIZE], *retStr;
	PianoReturn_t ret;

	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>music.getSeedSuggestions</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><int>%u</int></value></param>"
			"</params></methodCall>", time (NULL), ph->user.authToken,
			musicId, max);
	
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&lid=%s&method=method=getSeedSuggestions&arg1=%s&arg2=%u",
			ph->routeId, ph->user.listenerId, musicId, max);
	
	if ((ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseSeedSuggestions (retStr, searchResult);
		PianoFree (retStr, 0);
	}

	return ret;
}
Example #9
0
/*	frees the whole piano handle structure
 *	@param piano handle
 *	@return nothing
 */
void PianoDestroy (PianoHandle_t *ph) {
	PianoFree (ph->user.webAuthToken, 0);
	PianoFree (ph->user.authToken, 0);
	PianoFree (ph->user.listenerId, 0);

	PianoDestroyStations (ph->stations);
	/* destroy genre stations */
	PianoGenreCategory_t *curGenreCat = ph->genreStations, *lastGenreCat;
	while (curGenreCat != NULL) {
		PianoDestroyGenres (curGenreCat->genres);
		PianoFree (curGenreCat->name, 0);
		lastGenreCat = curGenreCat;
		curGenreCat = curGenreCat->next;
		PianoFree (lastGenreCat, sizeof (*lastGenreCat));
	}
	memset (ph, 0, sizeof (*ph));
}
Example #10
0
/*	free _all_ elements of playlist
 *	@param piano handle
 *	@return nothing
 */
void PianoDestroyPlaylist (PianoSong_t *playlist) {
	PianoSong_t *curSong, *lastSong;

	curSong = playlist;
	while (curSong != NULL) {
		PianoFree (curSong->audioUrl, 0);
		PianoFree (curSong->artist, 0);
		PianoFree (curSong->musicId, 0);
		PianoFree (curSong->title, 0);
		PianoFree (curSong->userSeed, 0);
		PianoFree (curSong->identity, 0);
		PianoFree (curSong->stationId, 0);
		PianoFree (curSong->album, 0);
		PianoFree (curSong->artistMusicId, 0);
		lastSong = curSong;
		curSong = curSong->next;
		PianoFree (lastSong, sizeof (*lastSong));
	}
}
Example #11
0
/*	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);
		PianoFree (lastStation, sizeof (*lastStation));
	}
}
Example #12
0
/*	authenticates user
 *	@param piano handle
 *	@param username (utf-8 encoded)
 *	@param password (plaintext, utf-8 encoded)
 *	@param use ssl when logging in (1 = on, 0 = off), note that the password
 *			is not hashed and will be sent as plain-text!
 */
PianoReturn_t PianoConnect (PianoHandle_t *ph, const char *user,
		const char *password) {
	char *retStr, xmlSendBuf[PIANO_SEND_BUFFER_SIZE];
	PianoReturn_t ret;

	/* sync and throw away result (it's an encrypted timestamp, decrypt with
	 * PianoDecryptString) */
	snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
			"<methodCall><methodName>misc.sync</methodName>"
			"<params></params></methodCall>");
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&method=sync", ph->routeId);
	ret = PianoHttpPost (&ph->waith, xmlSendBuf, &retStr);
	PianoFree (retStr, 0);

	if (ret != PIANO_RET_OK) {
		return ret;
	}

	/* authenticate */
	snprintf (xmlSendBuf, sizeof (xmlSendBuf), 
			"<?xml version=\"1.0\"?><methodCall>"
			"<methodName>listener.authenticateListener</methodName>"
			"<params><param><value><int>%li</int></value></param>"
			"<param><value><string>%s</string></value></param>"
			"<param><value><string>%s</string></value></param>"
			"</params></methodCall>", time (NULL), user, password);
	snprintf (ph->waith.path, sizeof (ph->waith.path), PIANO_RPC_PATH
			"rid=%s&method=authenticateListener", ph->routeId);

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

	return ret;
}
Example #13
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;
}
Example #14
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;
}
Example #15
0
/*	receive genre stations
 *	@param piano handle
 *	@return _OK or error
 */
PianoReturn_t PianoGetGenreStations (PianoHandle_t *ph) {
	char *retStr;
	PianoReturn_t ret;

	snprintf (ph->waith.path, sizeof (ph->waith.path), "/xml/genre?r=%li",
			time (NULL));
	
	if ((ret = PianoHttpGet (&ph->waith, &retStr)) ==
			PIANO_RET_OK) {
		ret = PianoXmlParseGenreExplorer (ph, retStr);
		PianoFree (retStr, 0);
	}

	return ret;
}
Example #16
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;
}
Example #17
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;
}
Example #18
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;
}
Example #19
0
/*	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) {
		PianoFree (curArtist->name, 0);
		PianoFree (curArtist->musicId, 0);
		lastArtist = curArtist;
		curArtist = curArtist->next;
		PianoFree (lastArtist, sizeof (*lastArtist));
	}

	curSong = searchResult->songs;
	while (curSong != NULL) {
		PianoFree (curSong->title, 0);
		PianoFree (curSong->artist, 0);
		PianoFree (curSong->musicId, 0);
		lastSong = curSong;
		curSong = curSong->next;
		PianoFree (lastSong, sizeof (*lastSong));
	}
}
Example #20
0
/*	destroy request, free post data. req->responseData is *not* freed here!
 *	@param piano request
 */
void PianoDestroyRequest (PianoRequest_t *req) {
	PianoFree (req->postData, 0);
	memset (req, 0, sizeof (*req));
}
Example #21
0
/*	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);

			/* FIXME: remove static, "magic" numbers */
			snprintf (xmlSendBuf, sizeof (xmlSendBuf), "<?xml version=\"1.0\"?>"
					"<methodCall><methodName>playlist.getFragment</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>0</string></value></param>"
					"<param><value><string></string></value></param>"
					"<param><value><string></string></value></param>"
					"<param><value><string>%s</string></value></param>"
					"<param><value><string>0</string></value></param>"
					"<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>"
					"<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,
					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);

			PianoFree (urlencodedNewName, 0);
			PianoFree (xmlencodedNewName, 0);
			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>"
					"<param><value><string>%s</string></value></param>"
					"<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>"
					"<param><value><string>%s</string></value></param>"
					"<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);

			PianoFree (urlencodedSearchStr, 0);
			PianoFree (xmlencodedSearchStr, 0);
			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>"
					"<param><value><string>%s</string></value></param>"
					"</params></methodCall>", (unsigned long) timestamp,
					ph->user.authToken, song->identity);
			snprintf (req->urlPath, sizeof (req->urlPath), PIANO_RPC_PATH
					"rid=%s&lid=%s&method=addTiredSong&arg1=%s", ph->routeId,
					ph->user.listenerId, song->identity);
			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>"
					"<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>"
					"<param><value><string>CUSTOM</string></value></param>"
					"<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>"
					"<param><value><string>%s</string></value></param>"
					"<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>"
					"<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->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>"
					"<param><value><string>%s</string></value></param>"
					"<param><value><string>%s</string></value></param>"
					"<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>"
					"<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, 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>"
					"<param><value><string>%s</string></value></param>"
					"<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;
}
Example #22
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 = realTimestamp - timestamp;

							PianoFree (decryptedTimestamp, 0);
						}
						PianoFree (cryptedTimestamp, 0);
					}
					ret = PIANO_RET_CONTINUE_REQUEST;
					++reqData->step;
					break;
				}

				case 1:
					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);

				PianoFree (reqData->station->name, 0);
				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);
						PianoFree (curStation, sizeof (*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;
}
Example #23
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);
			}
			PianoFree (urlTail, urlTailN/2);
		}
	} 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 ("identity", key) == 0) {
		song->identity = 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);
	}
}
Example #24
0
/*	free single station
 *	@param station
 */
void PianoDestroyStation (PianoStation_t *station) {
	PianoFree (station->name, 0);
	PianoFree (station->id, 0);
	memset (station, 0, sizeof (station));
}