From bf79a91a3f6381cade8a9e0fd50c2897bfb316c9 Mon Sep 17 00:00:00 2001
From: Lars-Dominik Braun <PromyLOPh@lavabit.com>
Date: Wed, 31 Mar 2010 11:32:39 +0200
Subject: Use new libpiano api

Adds error messages to libwaitress, too. Eventcmd implementation is
quick&dirty, needs to be rewritten.
---
 libwaitress/src/waitress.c |  64 +++++++++++++
 libwaitress/src/waitress.h |   1 +
 src/main.c                 |  68 +++++++++-----
 src/settings.h             |   4 +-
 src/ui.c                   | 133 ++++++++++++++++++++++++---
 src/ui.h                   |  11 ++-
 src/ui_act.c               | 224 +++++++++++++++++++++++++++++----------------
 7 files changed, 385 insertions(+), 120 deletions(-)

diff --git a/libwaitress/src/waitress.c b/libwaitress/src/waitress.c
index 72f5f0f..b3ef618 100644
--- a/libwaitress/src/waitress.c
+++ b/libwaitress/src/waitress.c
@@ -488,3 +488,67 @@ WaitressReturn_t WaitressFetchCall (WaitressHandle_t *waith) {
 #undef WRITE_RET
 #undef READ_RET
 
+const char *WaitressErrorToStr (WaitressReturn_t wRet) {
+	switch (wRet) {
+		case WAITRESS_RET_OK:
+			return "Everything's fine :)";
+			break;
+
+		case WAITRESS_RET_ERR:
+			return "Unknown.";
+			break;
+
+		case WAITRESS_RET_STATUS_UNKNOWN:
+			return "Unknown HTTP status code.";
+			break;
+
+		case WAITRESS_RET_NOTFOUND:
+			return "File not found.";
+			break;
+		
+		case WAITRESS_RET_FORBIDDEN:
+			return "Forbidden.";
+			break;
+
+		case WAITRESS_RET_CONNECT_REFUSED:
+			return "Connection refused.";
+			break;
+
+		case WAITRESS_RET_SOCK_ERR:
+			return "Socket error.";
+			break;
+
+		case WAITRESS_RET_GETADDR_ERR:
+			return "getaddr failed.";
+			break;
+
+		case WAITRESS_RET_CB_ABORT:
+			return "Callback aborted request.";
+			break;
+
+		case WAITRESS_RET_HDR_OVERFLOW:
+			return "HTTP header overflow.";
+			break;
+
+		case WAITRESS_RET_PARTIAL_FILE:
+			return "Partial file.";
+			break;
+	
+		case WAITRESS_RET_TIMEOUT:
+			return "Timeout.";
+			break;
+
+		case WAITRESS_RET_READ_ERR:
+			return "Read error.";
+			break;
+
+		case WAITRESS_RET_CONNECTION_CLOSED:
+			return "Connection closed by remote host.";
+			break;
+
+		default:
+			return "No error message available.";
+			break;
+	}
+}
+
diff --git a/libwaitress/src/waitress.h b/libwaitress/src/waitress.h
index ed5679f..04333fb 100644
--- a/libwaitress/src/waitress.h
+++ b/libwaitress/src/waitress.h
@@ -72,6 +72,7 @@ void WaitressSetHPP (WaitressHandle_t *, const char *, const char *,
 		const char *);
 WaitressReturn_t WaitressFetchBuf (WaitressHandle_t *, char **);
 WaitressReturn_t WaitressFetchCall (WaitressHandle_t *);
+const char *WaitressErrorToStr (WaitressReturn_t);
 
 #endif /* _WAITRESS_H */
 
diff --git a/src/main.c b/src/main.c
index 11ccd63..6ff9874 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,6 +39,7 @@ THE SOFTWARE.
 /* tcset/getattr () */
 #include <termios.h>
 #include <pthread.h>
+#include <assert.h>
 
 /* pandora.com library */
 #include <piano.h>
@@ -54,6 +55,7 @@ THE SOFTWARE.
 int main (int argc, char **argv) {
 	/* handles */
 	PianoHandle_t ph;
+	WaitressHandle_t waith;
 	static struct audioPlayer player;
 	BarSettings_t settings;
 	pthread_t playerThread;
@@ -82,6 +84,11 @@ int main (int argc, char **argv) {
 	/* init some things */
 	ao_initialize ();
 	PianoInit (&ph);
+
+	WaitressInit (&waith);
+	strncpy (waith.host, PIANO_RPC_HOST, sizeof (waith.host)-1);
+	strncpy (waith.port, PIANO_RPC_PORT, sizeof (waith.port)-1);
+
 	BarSettingsInit (&settings);
 	BarSettingsRead (&settings);
 
@@ -118,22 +125,36 @@ int main (int argc, char **argv) {
 	/* setup control connection */
 	if (settings.controlProxy != NULL) {
 		char tmpPath[2];
-		WaitressSplitUrl (settings.controlProxy, ph.waith.proxyHost,
-				sizeof (ph.waith.proxyHost), ph.waith.proxyPort,
-				sizeof (ph.waith.proxyPort), tmpPath, sizeof (tmpPath));
+		WaitressSplitUrl (settings.controlProxy, waith.proxyHost,
+				sizeof (waith.proxyHost), waith.proxyPort,
+				sizeof (waith.proxyPort), tmpPath, sizeof (tmpPath));
 	}
 
-	BarUiMsg (MSG_INFO, "Login... ");
-	if (BarUiPrintPianoStatus (PianoConnect (&ph, settings.username,
-			settings.password)) !=
-			PIANO_RET_OK) {
-		BarTermRestore (&termOrig);
-		return 0;
+	{
+		PianoReturn_t pRet;
+		WaitressReturn_t wRet;
+		PianoRequestDataLogin_t reqData;
+		reqData.user = settings.username;
+		reqData.password = settings.password;
+		
+		BarUiMsg (MSG_INFO, "Login... ");
+		if (!BarUiPianoCall (&ph, PIANO_REQUEST_LOGIN, &waith, &reqData, &pRet,
+				&wRet)) {
+			BarTermRestore (&termOrig);
+			return 0;
+		}
 	}
-	BarUiMsg (MSG_INFO, "Get stations... ");
-	if (BarUiPrintPianoStatus (PianoGetStations (&ph)) != PIANO_RET_OK) {
-		BarTermRestore (&termOrig);
-		return 0;
+
+	{
+		PianoReturn_t pRet;
+		WaitressReturn_t wRet;
+
+		BarUiMsg (MSG_INFO, "Get stations... ");
+		if (!BarUiPianoCall (&ph, PIANO_REQUEST_GET_STATIONS, &waith, NULL,
+				&pRet, &wRet)) {
+			BarTermRestore (&termOrig);
+			return 0;
+		}
 	}
 
 	/* try to get autostart station */
@@ -160,7 +181,7 @@ int main (int argc, char **argv) {
 		/* song finished playing, clean up things/scrobble song */
 		if (player.mode == PLAYER_FINISHED_PLAYBACK) {
 			BarUiStartEventCmd (&settings, "songfinish", curStation, playlist,
-					&player, PIANO_RET_OK);
+					&player, PIANO_RET_OK, WAITRESS_RET_OK);
 			/* FIXME: pthread_join blocks everything if network connection
 			 * is hung up e.g. */
 			void *threadRet;
@@ -210,21 +231,25 @@ int main (int argc, char **argv) {
 					}
 				}
 				if (playlist == NULL) {
-					PianoReturn_t pRet = PIANO_RET_ERR;
+					PianoReturn_t pRet;
+					WaitressReturn_t wRet;
+					PianoRequestDataGetPlaylist_t reqData;
+					reqData.station = curStation;
+					reqData.format = settings.audioFormat;
 
 					BarUiMsg (MSG_INFO, "Receiving new playlist... ");
-					if ((pRet = BarUiPrintPianoStatus (PianoGetPlaylist (&ph,
-							curStation->id, settings.audioFormat,
-							&playlist))) != PIANO_RET_OK) {
+					if (!BarUiPianoCall (&ph, PIANO_REQUEST_GET_PLAYLIST,
+							&waith, &reqData, &pRet, &wRet)) {
 						curStation = NULL;
 					} else {
+						playlist = reqData.retPlaylist;
 						if (playlist == NULL) {
 							BarUiMsg (MSG_INFO, "No tracks left.\n");
 							curStation = NULL;
 						}
 					}
 					BarUiStartEventCmd (&settings, "stationfetchplaylist",
-							curStation, playlist, &player, pRet);
+							curStation, playlist, &player, pRet, wRet);
 				}
 				/* song ready to play */
 				if (playlist != NULL) {
@@ -246,7 +271,8 @@ int main (int argc, char **argv) {
 			
 						/* throw event */
 						BarUiStartEventCmd (&settings, "songstart", curStation,
-								playlist, &player, PIANO_RET_OK);
+								playlist, &player, PIANO_RET_OK,
+								WAITRESS_RET_OK);
 
 						/* prevent race condition, mode must _not_ be FREED if
 						 * thread has been started */
@@ -289,7 +315,7 @@ int main (int argc, char **argv) {
 							BarUiActSelectStation, BarUiActTempBanSong,
 							BarUiActPrintUpcoming, BarUiActSelectQuickMix,
 							BarUiActDebug, BarUiActBookmark};
-					idToF[i] (&ph, &player, &settings, &playlist,
+					idToF[i] (&ph, &waith, &player, &settings, &playlist,
 							&curStation, &songHistory, &doQuit, curFd);
 					break;
 				}
diff --git a/src/settings.h b/src/settings.h
index 6185b93..85ab71a 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -25,10 +25,12 @@ THE SOFTWARE.
 #define _SETTINGS_H
 
 #include <piano.h>
+#include <waitress.h>
 
 #include "player.h"
 
-#define BAR_KS_ARGS PianoHandle_t *ph, struct audioPlayer *player, \
+#define BAR_KS_ARGS PianoHandle_t *ph, WaitressHandle_t *waith, \
+		struct audioPlayer *player, \
 		BarSettings_t *settings, PianoSong_t **curSong, \
 		PianoStation_t **curStation, PianoSong_t **songHistory, char *doQuit, \
 		FILE *curFd
diff --git a/src/ui.c b/src/ui.c
index 53fea6c..eb5e232 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -94,6 +94,81 @@ inline PianoReturn_t BarUiPrintPianoStatus (PianoReturn_t ret) {
 	return ret;
 }
 
+/*	fetch http resource (post request)
+ *	@param waitress handle
+ *	@param piano request (initialized by PianoRequest())
+ */
+static WaitressReturn_t BarPianoHttpRequest (WaitressHandle_t *waith,
+		PianoRequest_t *req) {
+	waith->extraHeaders = "Content-Type: text/xml\r\n";
+	waith->postData = req->postData;
+	waith->method = WAITRESS_METHOD_POST;
+	strncpy (waith->path, req->urlPath, sizeof (waith->path)-1);
+
+	return WaitressFetchBuf (waith, &req->responseData);
+}
+
+/*	piano wrapper: prepare/execute http request and pass result back to
+ *	libpiano (updates data structures)
+ *	@param piano handle
+ *	@param request type
+ *	@param waitress handle
+ *	@param data pointer (used as request data)
+ *	@return 1 on success, 0 otherwise
+ */
+int BarUiPianoCall (PianoHandle_t *ph, PianoRequestType_t type,
+		WaitressHandle_t *waith, void *data, PianoReturn_t *pRet,
+		WaitressReturn_t *wRet) {
+	PianoRequest_t req;
+
+	memset (&req, 0, sizeof (req));
+
+	/* repeat as long as there are http requests to do */
+	do {
+		req.data = data;
+
+		*pRet = PianoRequest (ph, &req, type);
+		if (*pRet != PIANO_RET_OK) {
+			BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
+			PianoDestroyRequest (&req);
+			return 0;
+		}
+
+		*wRet = BarPianoHttpRequest (waith, &req);
+		if (*wRet != WAITRESS_RET_OK) {
+			BarUiMsg (MSG_NONE, "Network error: %s\n", WaitressErrorToStr (*wRet));
+			PianoDestroyRequest (&req);
+			if (req.responseData != NULL) {
+				free (req.responseData);
+			}
+			return 0;
+		}
+
+		*pRet = PianoResponse (ph, &req);
+		if (*pRet != PIANO_RET_CONTINUE_REQUEST) {
+			if (*pRet != PIANO_RET_OK) {
+				BarUiMsg (MSG_NONE, "Error: %s\n", PianoErrorToStr (*pRet));
+				PianoDestroyRequest (&req);
+				if (req.responseData != NULL) {
+					free (req.responseData);
+				}
+				return 0;
+			} else {
+				BarUiMsg (MSG_NONE, "Ok.\n");
+			}
+		}
+		/* we can destroy the request at this point, even when this call needs
+		 * more than one http request. persistend data (step counter, e.g.) is
+		 * stored in req.data */
+		if (req.responseData != NULL) {
+			free (req.responseData);
+		}
+		PianoDestroyRequest (&req);
+	} while (*pRet == PIANO_RET_CONTINUE_REQUEST);
+
+	return 1;
+}
+
 /*	compare stations by name (ignore case)
  *	@param station a
  *	@param station b
@@ -232,7 +307,8 @@ PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd) {
  *	@param allow seed suggestions if != NULL
  *	@return musicId or NULL on abort/error
  */
-char *BarUiSelectMusicId (PianoHandle_t *ph, FILE *curFd, char *similarToId) {
+char *BarUiSelectMusicId (PianoHandle_t *ph, WaitressHandle_t *waith,
+		FILE *curFd, char *similarToId) {
 	char *musicId = NULL;
 	char lineBuf[100], selectBuf[2];
 	PianoSearchResult_t searchResult;
@@ -242,20 +318,36 @@ char *BarUiSelectMusicId (PianoHandle_t *ph, FILE *curFd, char *similarToId) {
 	BarUiMsg (MSG_QUESTION, "Search for artist/title: ");
 	if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
 		if (strcmp ("?", lineBuf) == 0 && similarToId != NULL) {
+			PianoReturn_t pRet;
+			WaitressReturn_t wRet;
+			PianoRequestDataGetSeedSuggestions_t reqData;
+
+			reqData.musicId = similarToId;
+			reqData.max = 20;
+
 			BarUiMsg (MSG_INFO, "Receiving suggestions... ");
-			if (BarUiPrintPianoStatus (PianoSeedSuggestions (ph, similarToId,
-					20, &searchResult)) != PIANO_RET_OK) {
+			if (!BarUiPianoCall (ph, PIANO_REQUEST_GET_SEED_SUGGESTIONS,
+					waith, &reqData, &pRet, &wRet)) {
 				return NULL;
 			}
+			memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));
 		} else {
+			PianoReturn_t pRet;
+			WaitressReturn_t wRet;
+			PianoRequestDataSearch_t reqData;
+
+			reqData.searchStr = lineBuf;
+
 			BarUiMsg (MSG_INFO, "Searching... ");
-			if (BarUiPrintPianoStatus (PianoSearchMusic (ph, lineBuf,
-					&searchResult)) != PIANO_RET_OK) {
+			if (!BarUiPianoCall (ph, PIANO_REQUEST_SEARCH, waith, &reqData,
+					&pRet, &wRet)) {
 				return NULL;
 			}
+			memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));
 		}
 		BarUiMsg (MSG_NONE, "\r");
-		if (searchResult.songs != NULL && searchResult.artists != NULL) {
+		if (searchResult.songs != NULL &&
+				searchResult.artists != NULL) {
 			/* songs and artists found */
 			BarUiMsg (MSG_QUESTION, "Is this an [a]rtist or [t]rack name? ");
 			BarReadline (selectBuf, sizeof (selectBuf), "at", 1, 0, curFd);
@@ -294,16 +386,22 @@ char *BarUiSelectMusicId (PianoHandle_t *ph, FILE *curFd, char *similarToId) {
 /*	browse genre stations and create shared station
  *	@param piano handle
  */
-void BarStationFromGenre (PianoHandle_t *ph, FILE *curFd) {
-	int i;
+void BarStationFromGenre (PianoHandle_t *ph, WaitressHandle_t *waith, FILE *curFd) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 	PianoGenreCategory_t *curCat;
 	PianoStation_t *curStation;
+	PianoRequestDataCreateStation_t reqData;
+	int i;
 
 	/* receive genre stations list if not yet available */
 	if (ph->genreStations == NULL) {
+		PianoReturn_t pRet;
+		WaitressReturn_t wRet;
+
 		BarUiMsg (MSG_INFO, "Receiving genre stations... ");
-		if (BarUiPrintPianoStatus (PianoGetGenreStations (ph)) !=
-				PIANO_RET_OK) {
+		if (!BarUiPianoCall (ph, PIANO_REQUEST_GET_GENRE_STATIONS, waith, NULL,
+				&pRet, &wRet)) {
 			return;
 		}
 	}
@@ -346,7 +444,10 @@ void BarStationFromGenre (PianoHandle_t *ph, FILE *curFd) {
 	}
 	/* create station */
 	BarUiMsg (MSG_INFO, "Adding shared station \"%s\"... ", curStation->name);
-	BarUiPrintPianoStatus (PianoCreateStation (ph, "sh", curStation->id));
+	reqData.id = curStation->id;
+	reqData.type = "sh";
+	BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData, &pRet,
+			&wRet);
 }
 
 /*	Print station infos (including station id)
@@ -373,11 +474,13 @@ inline void BarUiPrintSong (PianoSong_t *song, PianoStation_t *station) {
  *	@param event type
  *	@param current station
  *	@param current song
- *	@param piano error-code
+ *	@param piano error-code (PIANO_RET_OK if not applicable)
+ *	@param waitress error-code (WAITRESS_RET_OK if not applicable)
  */
 void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
 		const PianoStation_t *curStation, const PianoSong_t *curSong,
-		const struct audioPlayer *player, PianoReturn_t pRet) {
+		const struct audioPlayer *player, PianoReturn_t pRet,
+		WaitressReturn_t wRet) {
 	pid_t chld;
 	char pipeBuf[1024];
 	int pipeFd[2];
@@ -396,6 +499,8 @@ void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
 			"stationName=%s\n"
 			"pRet=%i\n"
 			"pRetStr=%s\n"
+			"wRet=%i\n"
+			"wRetStr=%s\n"
 			"songDuration=%lu\n"
 			"songPlayed=%lu\n"
 			"rating=%i\n",
@@ -405,6 +510,8 @@ void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
 			curStation == NULL ? "" : curStation->name,
 			pRet,
 			PianoErrorToStr (pRet),
+			wRet,
+			WaitressErrorToStr (wRet),
 			player->songDuration,
 			player->songPlayed,
 			curSong == NULL ? PIANO_RATE_NONE : curSong->rating
diff --git a/src/ui.h b/src/ui.h
index 46cdbe8..0a23881 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -25,6 +25,7 @@ THE SOFTWARE.
 #define _UI_H
 
 #include <piano.h>
+#include <waitress.h>
 
 #include "settings.h"
 #include "player.h"
@@ -38,12 +39,14 @@ PianoStation_t *BarUiSelectStation (PianoHandle_t *ph, const char *prompt,
 		FILE *curFd);
 PianoSong_t *BarUiSelectSong (PianoSong_t *startSong, FILE *curFd);
 PianoArtist_t *BarUiSelectArtist (PianoArtist_t *startArtist, FILE *curFd);
-char *BarUiSelectMusicId (PianoHandle_t *ph, FILE *curFd, char *);
-void BarStationFromGenre (PianoHandle_t *ph, FILE *curFd);
+char *BarUiSelectMusicId (PianoHandle_t *ph, WaitressHandle_t *, FILE *curFd, char *);
+void BarStationFromGenre (PianoHandle_t *ph, WaitressHandle_t *, FILE *curFd);
 void BarUiPrintStation (PianoStation_t *);
 void BarUiPrintSong (PianoSong_t *, PianoStation_t *);
 void BarUiStartEventCmd (const BarSettings_t *, const char *,
-		const PianoStation_t *, const PianoSong_t *,
-		const struct audioPlayer *, PianoReturn_t);
+		const PianoStation_t *, const PianoSong_t *, const struct audioPlayer *,
+		PianoReturn_t, WaitressReturn_t);
+int BarUiPianoCall (PianoHandle_t *, PianoRequestType_t, WaitressHandle_t *,
+		void *, PianoReturn_t *, WaitressReturn_t *);
 
 #endif /* _UI_H */
diff --git a/src/ui_act.c b/src/ui_act.c
index 23b0f34..bb0769b 100644
--- a/src/ui_act.c
+++ b/src/ui_act.c
@@ -52,12 +52,16 @@ static inline void BarUiDoSkipSong (struct audioPlayer *player) {
  *	@param transform this station
  *	@return 0 = error, 1 = everything went well
  */
-static int BarTransformIfShared (PianoHandle_t *ph, PianoStation_t *station) {
+static int BarTransformIfShared (PianoHandle_t *ph, WaitressHandle_t *waith,
+		PianoStation_t *station) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+
 	/* shared stations must be transformed */
 	if (!station->isCreator) {
 		BarUiMsg (MSG_INFO, "Transforming station... ");
-		if (BarUiPrintPianoStatus (PianoTransformShared (ph, station)) !=
-				PIANO_RET_OK) {
+		if (!BarUiPianoCall (ph, PIANO_REQUEST_TRANSFORM_STATION, waith,
+				station, &pRet, &wRet)) {
 			return 0;
 		}
 	}
@@ -104,81 +108,100 @@ void BarUiActHelp (BAR_KS_ARGS) {
 /*	add more music to current station
  */
 void BarUiActAddMusic (BAR_KS_ARGS) {
-	char *musicId;
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+	PianoRequestDataAddSeed_t reqData;
 
 	RETURN_IF_NO_STATION;
 
-	musicId = BarUiSelectMusicId (ph, curFd, (*curSong)->musicId);
-	if (musicId != NULL) {
-		if (!BarTransformIfShared (ph, *curStation)) {
+	reqData.musicId = BarUiSelectMusicId (ph, waith, curFd, (*curSong)->musicId);
+	if (reqData.musicId != NULL) {
+		if (!BarTransformIfShared (ph, waith, *curStation)) {
 			return;
 		}
+		reqData.station = *curStation;
+
 		BarUiMsg (MSG_INFO, "Adding music to station... ");
-		pRet = BarUiPrintPianoStatus (PianoStationAddMusic (ph, *curStation, musicId));
-		free (musicId);
+		BarUiPianoCall (ph, PIANO_REQUEST_ADD_SEED, waith, &reqData, &pRet,
+				&wRet);
+
+		free (reqData.musicId);
 
 		BarUiStartEventCmd (settings, "stationaddmusic", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
 /*	ban song
  */
 void BarUiActBanSong (BAR_KS_ARGS) {
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 
 	RETURN_IF_NO_SONG;
 
-	if (!BarTransformIfShared (ph, *curStation)) {
+	if (!BarTransformIfShared (ph, waith, *curStation)) {
 		return;
 	}
+
+	PianoRequestDataRateSong_t reqData;
+	reqData.song = *curSong;
+	reqData.rating = PIANO_RATE_BAN;
+
 	BarUiMsg (MSG_INFO, "Banning song... ");
-	if ((pRet = BarUiPrintPianoStatus (PianoRateTrack (ph, *curSong,
-			PIANO_RATE_BAN))) == PIANO_RET_OK) {
+	if (BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith, &reqData, &pRet,
+			&wRet)) {
 		BarUiDoSkipSong (player);
 	}
 	BarUiStartEventCmd (settings, "songban", *curStation, *curSong, player,
-			pRet);
+			pRet, wRet);
 }
 
 /*	create new station
  */
 void BarUiActCreateStation (BAR_KS_ARGS) {
-	char *musicId;
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+	PianoRequestDataCreateStation_t reqData;
 
-	musicId = BarUiSelectMusicId (ph, curFd, NULL);
-	if (musicId != NULL) {
+	reqData.id = BarUiSelectMusicId (ph, waith, curFd, NULL);
+	if (reqData.id != NULL) {
+		reqData.type = "mi";
 		BarUiMsg (MSG_INFO, "Creating station... ");
-		pRet = BarUiPrintPianoStatus (PianoCreateStation (ph, "mi", musicId));
-		free (musicId);
+		BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData,
+				&pRet, &wRet);
+		free (reqData.id);
 		BarUiStartEventCmd (settings, "stationcreate", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
 /*	add shared station by id
  */
 void BarUiActAddSharedStation (BAR_KS_ARGS) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+	PianoRequestDataCreateStation_t reqData;
 	char stationId[50];
-	PianoReturn_t pRet = PIANO_RET_ERR;
 
 	BarUiMsg (MSG_QUESTION, "Station id: ");
 	if (BarReadline (stationId, sizeof (stationId), "0123456789", 0, 0,
 			curFd) > 0) {
+		reqData.id = stationId;
+		reqData.type = "sh";
 		BarUiMsg (MSG_INFO, "Adding shared station... ");
-		pRet = BarUiPrintPianoStatus (PianoCreateStation (ph, "sh",
-				(char *) stationId));
+		BarUiPianoCall (ph, PIANO_REQUEST_CREATE_STATION, waith, &reqData,
+				&pRet, &wRet);
 		BarUiStartEventCmd (settings, "stationaddshared", *curStation,
-				*curSong, player, pRet);
+				*curSong, player, pRet, wRet);
 	}
 }
 
 /*	delete current station
  */
 void BarUiActDeleteStation (BAR_KS_ARGS) {
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 
 	RETURN_IF_NO_STATION;
 
@@ -186,41 +209,44 @@ void BarUiActDeleteStation (BAR_KS_ARGS) {
 			(*curStation)->name);
 	if (BarReadlineYesNo (0, curFd)) {
 		BarUiMsg (MSG_INFO, "Deleting station... ");
-		if ((pRet = BarUiPrintPianoStatus (PianoDeleteStation (ph,
-				*curStation))) == PIANO_RET_OK) {
+		if (BarUiPianoCall (ph, PIANO_REQUEST_DELETE_STATION, waith,
+				*curStation, &pRet, &wRet)) {
 			BarUiDoSkipSong (player);
 			PianoDestroyPlaylist (*curSong);
 			*curSong = NULL;
 			*curStation = NULL;
 		}
 		BarUiStartEventCmd (settings, "stationdelete", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
 /*	explain pandora's song choice
  */
 void BarUiActExplain (BAR_KS_ARGS) {
-	char *explanation;
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+	PianoRequestDataExplain_t reqData;
 
 	RETURN_IF_NO_STATION;
 
+	reqData.song = *curSong;
+
 	BarUiMsg (MSG_INFO, "Receiving explanation... ");
-	if ((pRet = BarUiPrintPianoStatus (PianoExplain (ph, *curSong,
-			&explanation))) == PIANO_RET_OK) {
-		BarUiMsg (MSG_INFO, "%s\n", explanation);
-		free (explanation);
+	if (BarUiPianoCall (ph, PIANO_REQUEST_EXPLAIN, waith, &reqData, &pRet,
+			&wRet)) {
+		BarUiMsg (MSG_INFO, "%s\n", reqData.retExplain);
+		free (reqData.retExplain);
 	}
 	BarUiStartEventCmd (settings, "songexplain", *curStation, *curSong, player,
-			pRet);
+			pRet, wRet);
 }
 
 /*	choose genre station and add it as shared station
  */
 void BarUiActStationFromGenre (BAR_KS_ARGS) {
 	/* use genre station */
-	BarStationFromGenre (ph, curFd);
+	BarStationFromGenre (ph, waith, curFd);
 }
 
 /*	print verbose song information
@@ -264,17 +290,24 @@ void BarUiActDebug (BAR_KS_ARGS) {
 /*	rate current song
  */
 void BarUiActLoveSong (BAR_KS_ARGS) {
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 
 	RETURN_IF_NO_SONG;
 
-	if (!BarTransformIfShared (ph, *curStation)) {
+	if (!BarTransformIfShared (ph, waith, *curStation)) {
 		return;
 	}
+
+	PianoRequestDataRateSong_t reqData;
+	reqData.song = *curSong;
+	reqData.rating = PIANO_RATE_LOVE;
+
 	BarUiMsg (MSG_INFO, "Loving song... ");
-	pRet = BarUiPrintPianoStatus (PianoRateTrack (ph, *curSong, PIANO_RATE_LOVE));
+	BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith, &reqData, &pRet,
+			&wRet);
 	BarUiStartEventCmd (settings, "songlove", *curStation, *curSong, player,
-			pRet);
+			pRet, wRet);
 }
 
 /*	skip song
@@ -286,29 +319,36 @@ void BarUiActSkipSong (BAR_KS_ARGS) {
 /*	move song to different station
  */
 void BarUiActMoveSong (BAR_KS_ARGS) {
-	PianoStation_t *moveStation, *fromStation;
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
+	PianoRequestDataMoveSong_t reqData;
+
+	reqData.step = 0;
 
 	RETURN_IF_NO_SONG;
 
-	moveStation = BarUiSelectStation (ph, "Move song to station: ", curFd);
-	if (moveStation != NULL) {
-		if (!BarTransformIfShared (ph, *curStation) ||
-				!BarTransformIfShared (ph, moveStation)) {
+	reqData.to = BarUiSelectStation (ph, "Move song to station: ", curFd);
+	if (reqData.to != NULL) {
+		/* find original station (just is case we're playing a quickmix
+		 * station) */
+		reqData.from = PianoFindStationById (ph->stations, (*curSong)->stationId);
+		if (reqData.from == NULL) {
+			BarUiMsg (MSG_ERR, "Station not found\n");
 			return;
 		}
-		BarUiMsg (MSG_INFO, "Moving song to \"%s\"... ", moveStation->name);
-		fromStation = PianoFindStationById (ph->stations, (*curSong)->stationId);
-		if (fromStation == NULL) {
-			BarUiMsg (MSG_ERR, "Station not found\n");
+
+		if (!BarTransformIfShared (ph, waith, reqData.from) ||
+				!BarTransformIfShared (ph, waith, reqData.to)) {
 			return;
 		}
-		if ((pRet = BarUiPrintPianoStatus (PianoMoveSong (ph, fromStation,
-				moveStation, *curSong))) == PIANO_RET_OK) {
+		BarUiMsg (MSG_INFO, "Moving song to \"%s\"... ", reqData.to->name);
+		reqData.song = *curSong;
+		if (BarUiPianoCall (ph, PIANO_REQUEST_MOVE_SONG, waith, &reqData,
+				&pRet, &wRet)) {
 			BarUiDoSkipSong (player);
 		}
 		BarUiStartEventCmd (settings, "songmove", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
@@ -324,21 +364,27 @@ void BarUiActPause (BAR_KS_ARGS) {
 /*	rename current station
  */
 void BarUiActRenameStation (BAR_KS_ARGS) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 	char lineBuf[100];
-	PianoReturn_t pRet = PIANO_RET_ERR;
 
 	RETURN_IF_NO_STATION;
 
 	BarUiMsg (MSG_QUESTION, "New name: ");
 	if (BarReadlineStr (lineBuf, sizeof (lineBuf), 0, curFd) > 0) {
-		if (!BarTransformIfShared (ph, *curStation)) {
+		PianoRequestDataRenameStation_t reqData;
+		if (!BarTransformIfShared (ph, waith, *curStation)) {
 			return;
 		}
+
+		reqData.station = *curStation;
+		reqData.newName = lineBuf;
+
 		BarUiMsg (MSG_INFO, "Renaming station... ");
-		pRet = BarUiPrintPianoStatus (PianoRenameStation (ph, *curStation,
-				(char *) lineBuf));
+		BarUiPianoCall (ph, PIANO_REQUEST_RENAME_STATION, waith, &reqData,
+				&pRet, &wRet);
 		BarUiStartEventCmd (settings, "stationrename", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
@@ -357,17 +403,18 @@ void BarUiActSelectStation (BAR_KS_ARGS) {
 /*	ban song for 1 month
  */
 void BarUiActTempBanSong (BAR_KS_ARGS) {
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 
 	RETURN_IF_NO_SONG;
 
 	BarUiMsg (MSG_INFO, "Putting song on shelf... ");
-	if ((pRet = BarUiPrintPianoStatus (PianoSongTired (ph, *curSong))) ==
-			PIANO_RET_OK) {
+	if (BarUiPianoCall (ph, PIANO_REQUEST_ADD_TIRED_SONG, waith, *curSong,
+			&pRet, &wRet)) {
 		BarUiDoSkipSong (player);
 	}
 	BarUiStartEventCmd (settings, "songshelf", *curStation, *curSong, player,
-			pRet);
+			pRet, wRet);
 }
 
 /*	print upcoming songs
@@ -393,7 +440,8 @@ void BarUiActPrintUpcoming (BAR_KS_ARGS) {
  *	quickmix
  */
 void BarUiActSelectQuickMix (BAR_KS_ARGS) {
-	PianoReturn_t pRet = PIANO_RET_ERR;
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 
 	RETURN_IF_NO_STATION;
 
@@ -404,9 +452,10 @@ void BarUiActSelectQuickMix (BAR_KS_ARGS) {
 			selStation->useQuickMix = !selStation->useQuickMix;
 		}
 		BarUiMsg (MSG_INFO, "Setting quickmix stations... ");
-		pRet = BarUiPrintPianoStatus (PianoSetQuickmix (ph));
+		BarUiPianoCall (ph, PIANO_REQUEST_SET_QUICKMIX, waith, NULL, &pRet,
+				&wRet);
 		BarUiStartEventCmd (settings, "stationquickmixtoggle", *curStation,
-				*curSong, player, pRet);
+				*curSong, player, pRet, wRet);
 	} else {
 		BarUiMsg (MSG_ERR, "Not a QuickMix station.\n");
 	}
@@ -422,6 +471,8 @@ void BarUiActQuit (BAR_KS_ARGS) {
 /*	song history
  */
 void BarUiActHistory (BAR_KS_ARGS) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 	char selectBuf[2], allowedBuf[3];
 	PianoSong_t *selectedSong;
 
@@ -440,7 +491,6 @@ void BarUiActHistory (BAR_KS_ARGS) {
 
 			if (selectBuf[0] == settings->keys[BAR_KS_LOVE] ||
 					selectBuf[0] == settings->keys[BAR_KS_BAN]) {
-				PianoReturn_t pRet = PIANO_RET_ERR;
 				/* make sure we're transforming the _original_ station (not
 				 * curStation) */
 				PianoStation_t *songStation =
@@ -452,23 +502,32 @@ void BarUiActHistory (BAR_KS_ARGS) {
 					return;
 				}
 
-				if (!BarTransformIfShared (ph, songStation)) {
+				if (!BarTransformIfShared (ph, waith, songStation)) {
 					return;
 				}
 
 				if (selectBuf[0] == settings->keys[BAR_KS_LOVE]) {
 					/* FIXME: copy&waste */
+					PianoRequestDataRateSong_t reqData;
+					reqData.song = selectedSong;
+					reqData.rating = PIANO_RATE_LOVE;
+
 					BarUiMsg (MSG_INFO, "Loving song... ");
-					pRet = BarUiPrintPianoStatus (PianoRateTrack (ph,
-							selectedSong, PIANO_RATE_LOVE));
+					BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith,
+							&reqData, &pRet, &wRet);
+
 					BarUiStartEventCmd (settings, "songlove", songStation,
-							selectedSong, player, pRet);
+							selectedSong, player, pRet, wRet);
 				} else if (selectBuf[0] == settings->keys[BAR_KS_BAN]) {
+					PianoRequestDataRateSong_t reqData;
+					reqData.song = selectedSong;
+					reqData.rating = PIANO_RATE_BAN;
+
 					BarUiMsg (MSG_INFO, "Banning song... ");
-					pRet = BarUiPrintPianoStatus (PianoRateTrack (ph,
-							selectedSong, PIANO_RATE_BAN));
+					BarUiPianoCall (ph, PIANO_REQUEST_RATE_SONG, waith,
+							&reqData, &pRet, &wRet);
 					BarUiStartEventCmd (settings, "songban", songStation,
-							selectedSong, player, pRet);
+							selectedSong, player, pRet, wRet);
 				} /* end if */
 			} /* end if selectBuf[0] */
 		} /* end if selectedSong != NULL */
@@ -481,8 +540,9 @@ void BarUiActHistory (BAR_KS_ARGS) {
 /*	create song bookmark
  */
 void BarUiActBookmark (BAR_KS_ARGS) {
+	PianoReturn_t pRet;
+	WaitressReturn_t wRet;
 	char selectBuf[2];
-	PianoReturn_t pRet = PIANO_RET_ERR;
 
 	RETURN_IF_NO_SONG;
 
@@ -490,14 +550,16 @@ void BarUiActBookmark (BAR_KS_ARGS) {
 	BarReadline (selectBuf, sizeof (selectBuf), "sa", 1, 0, curFd);
 	if (selectBuf[0] == 's') {
 		BarUiMsg (MSG_INFO, "Bookmarking song... ");
-		pRet = BarUiPrintPianoStatus (PianoBookmarkSong (ph, *curSong));
+		BarUiPianoCall (ph, PIANO_REQUEST_BOOKMARK_SONG, waith, *curSong,
+				&pRet, &wRet);
 		BarUiStartEventCmd (settings, "songbookmark", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	} else if (selectBuf[0] == 'a') {
 		BarUiMsg (MSG_INFO, "Bookmarking artist... ");
-		pRet = BarUiPrintPianoStatus (PianoBookmarkArtist (ph, *curSong));
+		BarUiPianoCall (ph, PIANO_REQUEST_BOOKMARK_ARTIST, waith, *curSong,
+				&pRet, &wRet);
 		BarUiStartEventCmd (settings, "artistbookmark", *curStation, *curSong,
-				player, pRet);
+				player, pRet, wRet);
 	}
 }
 
-- 
cgit v1.2.3