summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Cichoń <michcic@gmail.com>2015-08-26 19:16:08 +0200
committerMichał Cichoń <michcic@gmail.com>2015-08-26 19:16:08 +0200
commit37ece1613d957f6b717826e0ca44bc676ff20e0b (patch)
treebbb2119dd1b807188fd9b4c3f732df5dc33fa0c7
parentec8b31516e7f18dba73fcdf212b0353ddbef97f9 (diff)
downloadpianobar-windows-37ece1613d957f6b717826e0ca44bc676ff20e0b.tar.gz
pianobar-windows-37ece1613d957f6b717826e0ca44bc676ff20e0b.tar.bz2
pianobar-windows-37ece1613d957f6b717826e0ca44bc676ff20e0b.zip
Drop curl in favor of WinHTTP
Abstract out HTTP comunication and replace libcurl with WinHTTP.
-rw-r--r--src/http.c486
-rw-r--r--src/http.h46
-rw-r--r--src/main.c52
-rw-r--r--src/main.h6
-rw-r--r--src/settings.c2
-rw-r--r--src/ui.c116
-rw-r--r--src/ui.h4
-rw-r--r--src/ui_act.c22
8 files changed, 575 insertions, 159 deletions
diff --git a/src/http.c b/src/http.c
new file mode 100644
index 0000000..4a06cc7
--- /dev/null
+++ b/src/http.c
@@ -0,0 +1,486 @@
+/*
+Copyright (c) 2015
+ Michał Cichoń <thedmd@interia.pl>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+/* receive/play audio stream */
+
+/* based on DShow example player */
+
+#include "config.h"
+#include "http.h"
+#include <Windows.h>
+#include <winhttp.h>
+#pragma comment(lib, "winhttp.lib")
+
+struct _http_t {
+ HINTERNET session;
+ HINTERNET connection;
+ wchar_t* endpoint;
+ wchar_t* securePort;
+ wchar_t* autoProxy;
+ wchar_t* proxy;
+ wchar_t* proxyUsername;
+ wchar_t* proxyPassword;
+ char* error;
+};
+
+static char* HttpToString(const wchar_t* wideString, int size);
+static wchar_t* HttpToWideString(const char* string, int size);
+static bool HttpCreateConnection (http_t http);
+static void HttpCloseConnection (http_t http);
+static void HttpSetLastError (http_t http, const char* message);
+static void HttpSetLastErrorFromWinHttp (http_t http);
+static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module);
+static char* HttpFormatWinHttpError (DWORD errorCode);
+static void HttpClearProxy (http_t http);
+
+# define WINHTTP_SAFE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); return false; } while (false)
+# define WINHTTP_SAFE_DONE(condition) do { if (condition) break; HttpSetLastErrorFromWinHttp (http); goto done; } while (false)
+
+static char* HttpToString(const wchar_t* wideString, int size) {
+ int utfSize = WideCharToMultiByte(CP_UTF8, 0, wideString, size, NULL, 0, NULL, NULL);
+ char* utfMessage = malloc(utfSize + 1);
+ if (utfMessage) {
+ utfMessage[utfSize] = 0;
+ WideCharToMultiByte(CP_UTF8, 0, wideString, size, utfMessage, utfSize, NULL, NULL);
+ }
+ return utfMessage;
+}
+
+static wchar_t* HttpToWideString(const char* string, int size) {
+ int wideSize = MultiByteToWideChar(CP_UTF8, 0, string, size, NULL, 0);
+ int wideBytes = (wideSize + 1) * sizeof(wchar_t);
+ wchar_t* wideMessage = malloc(wideBytes);
+ if (wideMessage) {
+ wideMessage[wideSize] = 0;
+ MultiByteToWideChar(CP_UTF8, 0, string, size, wideMessage, wideSize);
+ }
+ return wideMessage;
+}
+
+
+static bool HttpCreateConnection (http_t http) {
+ INTERNET_PORT defaultPort = INTERNET_DEFAULT_PORT;
+
+ HttpCloseConnection (http);
+
+ http->session = WinHttpOpen(
+ L"WinHTTP/1.0",
+ WINHTTP_ACCESS_TYPE_NO_PROXY,
+ WINHTTP_NO_PROXY_NAME,
+ WINHTTP_NO_PROXY_BYPASS,
+ 0);
+ WINHTTP_SAFE(http->session != NULL);
+
+ WinHttpSetTimeouts(http->session,
+ 60 * 1000, // DNS time-out
+ 60 * 1000, // connect time-out
+ 30 * 1000, // send time-out
+ 30 * 1000); // receive time-out
+
+ http->connection = WinHttpConnect(
+ http->session,
+ http->endpoint,
+ defaultPort,
+ 0);
+ WINHTTP_SAFE(http->connection != NULL);
+
+ return true;
+}
+
+static void HttpCloseConnection (http_t http) {
+ if (http->connection) {
+ WinHttpCloseHandle(http->connection);
+ http->connection = NULL;
+ }
+
+ if (http->session) {
+ WinHttpCloseHandle(http->session);
+ http->session = NULL;
+ }
+}
+
+static void HttpSetLastError (http_t http, const char* message) {
+ free(http->error);
+ http->error = NULL;
+
+ if (message)
+ http->error = strdup(message);
+}
+
+static void HttpSetLastErrorFromWinHttp (http_t http) {
+ free(http->error);
+ http->error = NULL;
+
+ DWORD error = GetLastError();
+ if (error)
+ http->error = HttpFormatWinHttpError(error);
+}
+
+static char* HttpFormatWinApiError (DWORD errorCode, HINSTANCE module) {
+ const int source_flag = module ? FORMAT_MESSAGE_FROM_HMODULE : FORMAT_MESSAGE_FROM_SYSTEM;
+
+ HLOCAL buffer = NULL;
+ int bufferLength = FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | source_flag,
+ (void*)module,
+ errorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&buffer,
+ 0,
+ NULL);
+
+ if (bufferLength > 0) {
+ char* message;
+
+ wchar_t* wideMessage = (wchar_t*)buffer;
+
+ /* Drop new line from the end. */
+ wchar_t* wideMessageBack = wideMessage + bufferLength - 1;
+ while (wideMessageBack > wideMessage && (*wideMessageBack == '\r' || *wideMessageBack == '\n'))
+ --wideMessageBack;
+
+ message = HttpToString (wideMessage, wideMessageBack - wideMessage + 1);
+
+ LocalFree(buffer);
+
+ return message;
+ }
+ else
+ return NULL;
+}
+
+static char* HttpFormatWinHttpError (DWORD errorCode) {
+ if (errorCode >= WINHTTP_ERROR_BASE && errorCode <= WINHTTP_ERROR_LAST) {
+ HMODULE module = GetModuleHandleW(L"WinHTTP.dll");
+ if (module) {
+ char* message = HttpFormatWinApiError(errorCode, module);
+ if (message)
+ return message;
+ }
+ }
+
+ return HttpFormatWinApiError(errorCode, NULL);
+}
+
+bool HttpInit(http_t* http, const char* endpoint, const char* securePort) {
+ http_t out = malloc(sizeof(struct _http_t));
+ if (!out)
+ return false;
+ memset(out, 0, sizeof(struct _http_t));
+
+ out->endpoint = HttpToWideString(endpoint, -1);
+ out->securePort = HttpToWideString(securePort, -1);
+
+ if (!HttpCreateConnection (out)) {
+ HttpDestroy (out);
+ return false;
+ }
+
+ *http = out;
+ return true;
+}
+
+void HttpDestroy(http_t http) {
+ if (http) {
+ free(http->endpoint);
+ free(http->securePort);
+ http->endpoint = NULL;
+ http->securePort = NULL;
+ HttpCloseConnection (http);
+ HttpClearProxy (http);
+ }
+ free(http);
+}
+
+static void HttpClearProxy (http_t http) {
+ if (http->autoProxy) {
+ free(http->autoProxy);
+ http->autoProxy = NULL;
+ }
+
+ if (http->proxy) {
+ free(http->proxy);
+ http->proxy = NULL;
+ }
+
+ if (http->proxyUsername) {
+ free(http->proxyUsername);
+ http->proxyUsername = NULL;
+ }
+
+ if (http->proxyPassword) {
+ free(http->proxyPassword);
+ http->proxyPassword = NULL;
+ }
+}
+
+bool HttpSetAutoProxy (http_t http, const char* url) {
+ HttpClearProxy (http);
+ if (HttpSetProxy (http, url)) {
+ http->autoProxy = http->proxy;
+ http->proxy = NULL;
+ return true;
+ }
+ else
+ return false;
+}
+
+bool HttpSetProxy (http_t http, const char* url) {
+ URL_COMPONENTS urlComponents;
+ DWORD wideUrlLength;
+ wchar_t* wideUrl = NULL;
+ wchar_t* wideUrl2 = NULL;
+ wchar_t* wideUsername = NULL;
+ wchar_t* widePassword = NULL;
+
+ ZeroMemory(&urlComponents, sizeof(urlComponents));
+ urlComponents.dwStructSize = sizeof(urlComponents);
+ urlComponents.dwUserNameLength = -1;
+ urlComponents.dwPasswordLength = -1;
+
+ wideUrl = HttpToWideString(url, -1);
+ if (WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) {
+ if (urlComponents.lpszUserName && urlComponents.dwUserNameLength > 0) {
+ wideUsername = wcsdup(urlComponents.lpszUserName);
+ wideUsername[urlComponents.dwUserNameLength] = 0;
+ }
+ if (urlComponents.lpszPassword && urlComponents.dwPasswordLength > 0) {
+ widePassword = wcsdup(urlComponents.lpszPassword);
+ widePassword[urlComponents.dwPasswordLength] = 0;
+ }
+ }
+
+ ZeroMemory(&urlComponents, sizeof(urlComponents));
+ urlComponents.dwStructSize = sizeof(urlComponents);
+ urlComponents.dwHostNameLength = -1;
+ urlComponents.dwUrlPathLength = -1;
+
+ if (!WinHttpCrackUrl(wideUrl, wcslen(wideUrl), 0, &urlComponents)) {
+ free(wideUsername);
+ free(widePassword);
+ return false;
+ }
+
+ if (urlComponents.lpszHostName && urlComponents.dwHostNameLength > 0) {
+ wideUrl2 = wcsdup(urlComponents.lpszHostName);
+ wideUrl2[urlComponents.lpszUrlPath - urlComponents.lpszHostName] = 0;
+ }
+
+ free(wideUrl);
+
+ HttpClearProxy(http);
+ http->proxy = wideUrl2;
+ http->proxyUsername = wideUsername;
+ http->proxyPassword = widePassword;
+ return true;
+}
+
+bool HttpRequest(http_t http, PianoRequest_t * const request) {
+ HINTERNET handle = NULL;
+ wchar_t* wideQuery = NULL;
+ bool requestSent = false;
+ bool complete = false;
+ int retryLimit = 3;
+ size_t responseDataSize;
+
+ wideQuery = HttpToWideString(request->urlPath, -1);
+ WINHTTP_SAFE_DONE(wideQuery != NULL);
+
+ handle = WinHttpOpenRequest(
+ http->connection,
+ L"POST",
+ wideQuery,
+ L"HTTP/1.1",
+ WINHTTP_NO_REFERER,
+ WINHTTP_DEFAULT_ACCEPT_TYPES,
+ request->secure ? WINHTTP_FLAG_SECURE : 0);
+ WINHTTP_SAFE_DONE(handle != NULL);
+
+ if (http->proxy || http->autoProxy) {
+ wchar_t* fullUrl;
+ DWORD fullUrlSize = 0;
+ WINHTTP_PROXY_INFO proxyInfo;
+ bool success;
+
+ if (http->autoProxy) {
+ WINHTTP_AUTOPROXY_OPTIONS proxyOptions = { 0 };
+
+ success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, NULL, &fullUrlSize);
+ WINHTTP_SAFE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+ fullUrl = calloc(1, fullUrlSize + 1);
+ success = WinHttpQueryOption(request, WINHTTP_OPTION_URL, fullUrl, &fullUrlSize);
+ if (!success) {
+ free(fullUrl);
+ WINHTTP_SAFE(success);
+ }
+
+ proxyOptions.lpszAutoConfigUrl = http->autoProxy;
+ proxyOptions.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
+
+ if (!(success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo))) {
+ proxyOptions.fAutoLogonIfChallenged = true;
+ success = WinHttpGetProxyForUrl(http->session, fullUrl, &proxyOptions, &proxyInfo);
+ }
+
+ if (!success) {
+ free(fullUrl);
+ WINHTTP_SAFE(success);
+ }
+ }
+ else {
+ proxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
+ proxyInfo.lpszProxy = http->proxy;
+ proxyInfo.lpszProxyBypass = NULL;
+ }
+
+ WINHTTP_SAFE(WinHttpSetOption(handle,
+ WINHTTP_OPTION_PROXY,
+ &proxyInfo, sizeof(proxyInfo)));
+
+ if (http->proxyUsername && http->proxyPassword) {
+ WINHTTP_SAFE(WinHttpSetCredentials(handle,
+ WINHTTP_AUTH_TARGET_PROXY,
+ WINHTTP_AUTH_SCHEME_BASIC,
+ http->proxyUsername,
+ http->proxyPassword,
+ NULL));
+ }
+ }
+
+ while (retryLimit > 0) {
+ DWORD errorCode, statusCode, statusCodeSize;
+ bool succeeded = false;
+ bool retry = false;
+
+ if (!requestSent) {
+ size_t postDataSize = strlen(request->postData);
+ succeeded = WinHttpSendRequest(handle,
+ WINHTTP_NO_ADDITIONAL_HEADERS,
+ 0,
+ request->postData,
+ postDataSize,
+ postDataSize,
+ 0);
+
+ if (succeeded)
+ requestSent = true;
+ }
+
+ if (requestSent)
+ succeeded = WinHttpReceiveResponse(handle, NULL);
+
+ errorCode = GetLastError();
+
+ statusCode = 0;
+ statusCodeSize = sizeof(statusCode);
+ if (!WinHttpQueryHeaders(handle,
+ WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
+ WINHTTP_HEADER_NAME_BY_INDEX,
+ &statusCode, &statusCodeSize, WINHTTP_NO_HEADER_INDEX)) {
+ statusCode = 0;
+ }
+
+ if (succeeded && statusCode == 407) {
+ requestSent = false;
+ retry = true;
+ }
+ else {
+ if (errorCode == ERROR_SUCCESS)
+ break;
+
+ switch (errorCode) {
+ case ERROR_WINHTTP_RESEND_REQUEST:
+ requestSent = false;
+ /* pass trough */
+
+ case ERROR_WINHTTP_NAME_NOT_RESOLVED:
+ case ERROR_WINHTTP_CANNOT_CONNECT:
+ case ERROR_WINHTTP_TIMEOUT:
+ retry = true;
+ break;
+
+ default:
+ HttpSetLastErrorFromWinHttp (http);
+ goto done;
+ }
+ }
+
+ if (retry)
+ --retryLimit;
+ }
+
+ responseDataSize = 0;
+ while (retryLimit > 0)
+ {
+ DWORD bytesLeft;
+ char* writePtr;
+
+ DWORD bytesAvailable = 0;
+ if (!WinHttpQueryDataAvailable(handle, &bytesAvailable)) {
+ WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT);
+ --retryLimit;
+ continue;
+ }
+
+ if (0 == bytesAvailable)
+ break;
+
+ responseDataSize += bytesAvailable;
+ request->responseData = realloc(request->responseData, responseDataSize + 1);
+
+ writePtr = request->responseData + responseDataSize - bytesAvailable;
+ writePtr[bytesAvailable] = 0;
+
+ bytesLeft = bytesAvailable;
+ while (bytesLeft > 0)
+ {
+ DWORD bytesRead = 0;
+ if (!WinHttpReadData(handle, writePtr, bytesLeft, &bytesRead))
+ {
+ WINHTTP_SAFE(GetLastError() == ERROR_WINHTTP_TIMEOUT);
+ if (--retryLimit == 0)
+ break;
+
+ continue;
+ }
+
+ bytesLeft -= bytesRead;
+ writePtr += bytesRead;
+ }
+
+ if (bytesLeft > 0)
+ HttpSetLastError (http, "Maximum retries count exceeded");
+ }
+
+ complete = true;
+
+ HttpSetLastError (http, NULL);
+
+done:
+ free(wideQuery);
+ return complete;
+}
+
+const char* HttpGetError(http_t http) {
+ return http->error;
+}
diff --git a/src/http.h b/src/http.h
new file mode 100644
index 0000000..a321cd3
--- /dev/null
+++ b/src/http.h
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2015
+ Michał Cichoń <thedmd@interia.pl>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef SRC_HTTP_H_CN979RE9
+#define SRC_HTTP_H_CN979RE9
+
+#include "config.h"
+
+#include <stdbool.h>
+
+#include "piano.h"
+#include "settings.h"
+
+typedef struct _http_t *http_t;
+
+bool HttpInit (http_t*, const char*, const char*);
+void HttpDestroy (http_t);
+
+bool HttpSetAutoProxy (http_t, const char*);
+bool HttpSetProxy(http_t, const char*);
+
+bool HttpRequest (http_t, PianoRequest_t * const);
+const char* HttpGetError (http_t);
+
+#endif /* SRC_HTTP_H_CN979RE9 */
+
diff --git a/src/main.c b/src/main.c
index 7c6ac08..900e56e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -36,7 +36,6 @@ THE SOFTWARE.
*/
static bool BarMainLoginUser (BarApp_t *app) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataLogin_t reqData;
bool ret;
@@ -45,9 +44,9 @@ static bool BarMainLoginUser (BarApp_t *app) {
reqData.step = 0;
BarUiMsg (&app->settings, MSG_INFO, "Login... ");
- ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet, &wRet);
+ ret = BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &pRet);
BarUiStartEventCmd (&app->settings, "userlogin", NULL, NULL, &app->player,
- NULL, pRet, wRet);
+ NULL, pRet);
return ret;
}
@@ -139,13 +138,12 @@ static bool BarMainGetLoginCredentials (BarSettings_t *settings,
*/
static bool BarMainGetStations (BarApp_t *app) {
PianoReturn_t pRet;
- CURLcode wRet;
bool ret;
BarUiMsg (&app->settings, MSG_INFO, "Get stations... ");
- ret = BarUiPianoCall (app, PIANO_REQUEST_GET_STATIONS, NULL, &pRet, &wRet);
+ ret = BarUiPianoCall (app, PIANO_REQUEST_GET_STATIONS, NULL, &pRet);
BarUiStartEventCmd (&app->settings, "usergetstations", NULL, NULL, &app->player,
- app->ph.stations, pRet, wRet);
+ app->ph.stations, pRet);
return ret;
}
@@ -186,14 +184,13 @@ static void BarMainHandleUserInput (BarApp_t *app) {
*/
static void BarMainGetPlaylist (BarApp_t *app) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataGetPlaylist_t reqData;
reqData.station = app->curStation;
reqData.quality = app->settings.audioQuality;
BarUiMsg (&app->settings, MSG_INFO, "Receiving new playlist... ");
if (!BarUiPianoCall (app, PIANO_REQUEST_GET_PLAYLIST,
- &reqData, &pRet, &wRet)) {
+ &reqData, &pRet)) {
app->curStation = NULL;
} else {
app->playlist = reqData.retPlaylist;
@@ -204,7 +201,7 @@ static void BarMainGetPlaylist (BarApp_t *app) {
}
BarUiStartEventCmd (&app->settings, "stationfetchplaylist",
app->curStation, app->playlist, &app->player, app->ph.stations,
- pRet, wRet);
+ pRet);
}
/* start new player thread
@@ -225,16 +222,18 @@ static void BarMainStartPlayback (BarApp_t *app) {
strncmp (curSong->audioUrl, httpPrefix, strlen (httpPrefix)) != 0) {
BarUiMsg (&app->settings, MSG_ERR, "Invalid song url.\n");
} else {
- BarPlayer2Finish(app->player);
BarPlayer2SetGain(app->player, curSong->fileGain);
BarPlayer2Open(app->player, curSong->audioUrl);
/* throw event */
BarUiStartEventCmd (&app->settings, "songstart",
app->curStation, curSong, &app->player, app->ph.stations,
- PIANO_RET_OK, CURLE_OK);
+ PIANO_RET_OK);
- BarPlayer2Play(app->player);
+ if (!BarPlayer2Play(app->player))
+ ++app->playerErrors;
+ else
+ app->playerErrors = 0;
}
}
@@ -242,24 +241,17 @@ static void BarMainStartPlayback (BarApp_t *app) {
*/
static void BarMainPlayerCleanup (BarApp_t *app) {
BarUiStartEventCmd (&app->settings, "songfinish", app->curStation,
- app->playlist, &app->player, app->ph.stations, PIANO_RET_OK,
- CURLE_OK);
+ app->playlist, &app->player, app->ph.stations, PIANO_RET_OK);
BarPlayer2Finish(app->player);
BarConsoleSetTitle (TITLE);
- //if (threadRet == (void *) PLAYER_RET_OK) {
- // app->playerErrors = 0;
- //} else if (threadRet == (void *) PLAYER_RET_SOFTFAIL) {
- // ++app->playerErrors;
- // if (app->playerErrors >= app->settings.maxPlayerErrors) {
- // /* don't continue playback if thread reports too many error */
- // app->curStation = NULL;
- // }
- //} else {
- // app->curStation = NULL;
- //}
+ if (app->playerErrors >= app->settings.maxPlayerErrors) {
+ /* don't continue playback if thread reports too many error */
+ app->curStation = NULL;
+ app->playerErrors = 0;
+ }
}
/* print song duration
@@ -369,9 +361,10 @@ int main (int argc, char **argv) {
app.settings.keys[BAR_KS_HELP]);
}
- curl_global_init (CURL_GLOBAL_DEFAULT);
- app.http = curl_easy_init ();
- assert (app.http != NULL);
+ HttpInit(&app.http2, app.settings.rpcHost, app.settings.rpcTlsPort);
+ if (app.settings.controlProxy)
+ HttpSetProxy(app.http2, app.settings.controlProxy);
+
BarReadlineInit (&app.rl);
@@ -385,8 +378,7 @@ int main (int argc, char **argv) {
PianoDestroy (&app.ph);
PianoDestroyPlaylist (app.songHistory);
PianoDestroyPlaylist (app.playlist);
- curl_easy_cleanup (app.http);
- curl_global_cleanup ();
+ HttpDestroy (app.http2);
BarPlayer2Destroy (app.player);
BarSettingsDestroy (&app.settings);
BarConsoleDestroy ();
diff --git a/src/main.h b/src/main.h
index 41413d9..f16a168 100644
--- a/src/main.h
+++ b/src/main.h
@@ -24,17 +24,19 @@ THE SOFTWARE.
#ifndef SRC_MAIN_H_4ZGSCG6X
#define SRC_MAIN_H_4ZGSCG6X
-#include <curl/curl.h>
+//#include <curl/curl.h>
#include <piano.h>
#include "player2.h"
+#include "http.h"
#include "settings.h"
#include "ui_readline.h"
typedef struct {
PianoHandle_t ph;
- CURL *http;
+ //CURL *http;
+ http_t http2;
player2_t player;
BarSettings_t settings;
/* first item is current song */
diff --git a/src/settings.c b/src/settings.c
index 6ce55c9..d58eb5c 100644
--- a/src/settings.c
+++ b/src/settings.c
@@ -30,6 +30,8 @@ THE SOFTWARE.
#include "ui_dispatch.h"
#include <stdlib.h>
#include <assert.h>
+#include <memory.h>
+#include <string.h>
#define PACKAGE_CONFIG PACKAGE ".cfg"
#define PACKAGE_STATE PACKAGE ".state"
diff --git a/src/ui.c b/src/ui.c
index 023a849..aaa83ae 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -29,6 +29,7 @@ THE SOFTWARE.
#include "ui_readline.h"
#include "console.h"
#include <assert.h>
+#include <stdio.h>
typedef int (*BarSortFunc_t) (const void *, const void *);
@@ -147,103 +148,12 @@ void BarUiMsg (const BarSettings_t *settings, const BarUiMsg_t type,
fflush (stdout);
}
-typedef struct {
- char *data;
- size_t pos;
-} buffer;
-
-static size_t httpFetchCb (char *ptr, size_t size, size_t nmemb,
- void *userdata) {
- buffer * const buffer = userdata;
- size_t recvSize = size * nmemb;
-
- if (buffer->data == NULL) {
- if ((buffer->data = malloc (sizeof (*buffer->data) *
- (recvSize + 1))) == NULL) {
- return 0;
- }
- } else {
- char *newbuf;
- if ((newbuf = realloc (buffer->data, sizeof (*buffer->data) *
- (buffer->pos + recvSize + 1))) == NULL) {
- free (buffer->data);
- return 0;
- }
- buffer->data = newbuf;
- }
- memcpy (buffer->data + buffer->pos, ptr, recvSize);
- buffer->pos += recvSize;
- buffer->data[buffer->pos] = '\0';
-
- return recvSize;
-}
-
-#define setAndCheck(k,v) \
- httpret = curl_easy_setopt (http, k, v); \
- assert (httpret == CURLE_OK);
-
-static CURLcode BarPianoHttpRequest (CURL * const http,
- const BarSettings_t * const settings, PianoRequest_t * const req) {
- buffer buffer = {NULL, 0};
- char url[2048];
- int ret = snprintf (url, sizeof (url), "%s://%s:%s%s",
- req->secure ? "https" : "http",
- settings->rpcHost,
- req->secure ? settings->rpcTlsPort : "80",
- req->urlPath);
- assert (ret >= 0 && ret <= (int) sizeof (url));
-
- curl_easy_reset (http);
- CURLcode httpret;
- setAndCheck (CURLOPT_URL, url);
- setAndCheck (CURLOPT_USERAGENT, PACKAGE "-" VERSION);
- setAndCheck (CURLOPT_POSTFIELDS, req->postData);
- setAndCheck (CURLOPT_WRITEFUNCTION, httpFetchCb);
- setAndCheck (CURLOPT_WRITEDATA, &buffer);
- setAndCheck (CURLOPT_POST, 1);
- setAndCheck (CURLOPT_TIMEOUT, 30);
- if (settings->caBundle != NULL) {
- setAndCheck (CURLOPT_CAINFO, settings->caBundle);
- }
-
- /* set up proxy (control proxy for non-us citizen or global proxy for poor
- * firewalled fellows) */
- if (settings->controlProxy != NULL) {
- /* control proxy overrides global proxy */
- if (curl_easy_setopt (http, CURLOPT_PROXY,
- settings->controlProxy) != CURLE_OK) {
- /* if setting proxy fails, url is invalid */
- BarUiMsg (settings, MSG_ERR, "Control proxy (%s) is invalid!\n",
- settings->controlProxy);
- }
- } else if (settings->proxy != NULL && strlen (settings->proxy) > 0) {
- if (curl_easy_setopt (http, CURLOPT_PROXY,
- settings->proxy) != CURLE_OK) {
- /* if setting proxy fails, url is invalid */
- BarUiMsg (settings, MSG_ERR, "Proxy (%s) is invalid!\n",
- settings->proxy);
- }
- }
-
- struct curl_slist *list = NULL;
- list = curl_slist_append (list, "Content-Type: text/plain");
- setAndCheck (CURLOPT_HTTPHEADER, list);
-
- httpret = curl_easy_perform (http);
-
- curl_slist_free_all (list);
-
- req->responseData = buffer.data;
-
- return httpret;
-}
-
/* piano wrapper: prepare/execute http request and pass result back to
* libpiano (updates data structures)
* @return 1 on success, 0 otherwise
*/
int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
- void *data, PianoReturn_t *pRet, CURLcode *wRet) {
+ void *data, PianoReturn_t *pRet) {
PianoRequest_t req;
memset (&req, 0, sizeof (req));
@@ -259,14 +169,13 @@ int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
return 0;
}
- *wRet = BarPianoHttpRequest (app->http, &app->settings, &req);
- if (*wRet != CURLE_OK) {
- BarUiMsg (&app->settings, MSG_NONE, "Network error: %s\n",
- curl_easy_strerror (*wRet));
+ if (!HttpRequest(app->http2, &req)) {
+ BarUiMsg(&app->settings, MSG_NONE, "Network error: %s\n",
+ HttpGetError(app->http2));
if (req.responseData != NULL) {
- free (req.responseData);
+ free(req.responseData);
}
- PianoDestroyRequest (&req);
+ PianoDestroyRequest(&req);
return 0;
}
@@ -277,17 +186,14 @@ int BarUiPianoCall (BarApp_t * const app, PianoRequestType_t type,
type != PIANO_REQUEST_LOGIN) {
/* reauthenticate */
PianoReturn_t authpRet;
- CURLcode authwRet;
PianoRequestDataLogin_t reqData;
reqData.user = app->settings.username;
reqData.password = app->settings.password;
reqData.step = 0;
BarUiMsg (&app->settings, MSG_NONE, "Reauthentication required... ");
- if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet,
- &authwRet)) {
+ if (!BarUiPianoCall (app, PIANO_REQUEST_LOGIN, &reqData, &authpRet)) {
*pRet = authpRet;
- *wRet = authwRet;
if (req.responseData != NULL) {
free (req.responseData);
}
@@ -569,14 +475,12 @@ char *BarUiSelectMusicId (BarApp_t *app, PianoStation_t *station,
if (BarReadlineStr (lineBuf, sizeof (lineBuf), app->rl,
BAR_RL_DEFAULT) > 0) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataSearch_t reqData;
reqData.searchStr = lineBuf;
BarUiMsg (&app->settings, MSG_INFO, "Searching... ");
- if (!BarUiPianoCall (app, PIANO_REQUEST_SEARCH, &reqData, &pRet,
- &wRet)) {
+ if (!BarUiPianoCall (app, PIANO_REQUEST_SEARCH, &reqData, &pRet)) {
return NULL;
}
memcpy (&searchResult, &reqData.searchResult, sizeof (searchResult));
@@ -776,7 +680,7 @@ size_t BarUiListSongs (const BarSettings_t *settings,
void BarUiStartEventCmd (const BarSettings_t *settings, const char *type,
const PianoStation_t *curStation, const PianoSong_t *curSong,
const player2_t * const player, PianoStation_t *stations,
- PianoReturn_t pRet, CURLcode wRet) {
+ PianoReturn_t pRet) {
//pid_t chld;
//int pipeFd[2];
diff --git a/src/ui.h b/src/ui.h
index 67b6155..c9b3d70 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -49,9 +49,9 @@ void BarUiPrintSong (const BarSettings_t *, const PianoSong_t *,
size_t BarUiListSongs (const BarSettings_t *, const PianoSong_t *, const char *);
void BarUiStartEventCmd (const BarSettings_t *, const char *,
const PianoStation_t *, const PianoSong_t *, const player2_t * const,
- PianoStation_t *, PianoReturn_t, CURLcode);
+ PianoStation_t *, PianoReturn_t);
int BarUiPianoCall (BarApp_t * const, PianoRequestType_t,
- void *, PianoReturn_t *, CURLcode *);
+ void *, PianoReturn_t *);
void BarUiHistoryPrepend (BarApp_t *app, PianoSong_t *song);
#endif /* SRC_UI_H_46P20TS0 */
diff --git a/src/ui_act.c b/src/ui_act.c
index 64c756b..c8a808f 100644
--- a/src/ui_act.c
+++ b/src/ui_act.c
@@ -37,12 +37,12 @@ THE SOFTWARE.
*/
#define BarUiActDefaultEventcmd(name) BarUiStartEventCmd (&app->settings, \
name, selStation, selSong, &app->player, app->ph.stations, \
- pRet, wRet)
+ pRet)
/* standard piano call
*/
#define BarUiActDefaultPianoCall(call, arg) BarUiPianoCall (app, \
- call, arg, &pRet, &wRet)
+ call, arg, &pRet)
/* helper to _really_ skip a song (unlock mutex, quit player)
* @param player handle
@@ -60,7 +60,6 @@ static inline void BarUiDoSkipSong (player2_t player) {
*/
static int BarTransformIfShared (BarApp_t *app, PianoStation_t *station) {
PianoReturn_t pRet;
- CURLcode wRet;
assert (station != NULL);
@@ -68,7 +67,7 @@ static int BarTransformIfShared (BarApp_t *app, PianoStation_t *station) {
if (!station->isCreator) {
BarUiMsg (&app->settings, MSG_INFO, "Transforming station... ");
if (!BarUiPianoCall (app, PIANO_REQUEST_TRANSFORM_STATION, station,
- &pRet, &wRet)) {
+ &pRet)) {
return 0;
}
}
@@ -93,7 +92,6 @@ BarUiActCallback(BarUiActHelp) {
*/
BarUiActCallback(BarUiActAddMusic) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataAddSeed_t reqData;
assert (selStation != NULL);
@@ -119,7 +117,6 @@ BarUiActCallback(BarUiActAddMusic) {
*/
BarUiActCallback(BarUiActBanSong) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoStation_t *realStation;
assert (selStation != NULL);
@@ -151,7 +148,6 @@ BarUiActCallback(BarUiActBanSong) {
*/
BarUiActCallback(BarUiActCreateStation) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataCreateStation_t reqData;
reqData.type = PIANO_MUSICTYPE_INVALID;
@@ -169,7 +165,6 @@ BarUiActCallback(BarUiActCreateStation) {
*/
BarUiActCallback(BarUiActCreateStationFromSong) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataCreateStation_t reqData;
char selectBuf[2];
@@ -199,7 +194,6 @@ BarUiActCallback(BarUiActCreateStationFromSong) {
*/
BarUiActCallback(BarUiActAddSharedStation) {
PianoReturn_t pRet;
- CURLcode wRet;
char stationId[50];
PianoRequestDataCreateStation_t reqData;
@@ -219,7 +213,6 @@ BarUiActCallback(BarUiActAddSharedStation) {
*/
BarUiActCallback(BarUiActDeleteStation) {
PianoReturn_t pRet;
- CURLcode wRet;
assert (selStation != NULL);
@@ -244,7 +237,6 @@ BarUiActCallback(BarUiActDeleteStation) {
*/
BarUiActCallback(BarUiActExplain) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataExplain_t reqData;
assert (selSong != NULL);
@@ -263,7 +255,6 @@ BarUiActCallback(BarUiActExplain) {
*/
BarUiActCallback(BarUiActStationFromGenre) {
PianoReturn_t pRet;
- CURLcode wRet;
const PianoGenreCategory_t *curCat;
const PianoGenre_t *curGenre;
int i;
@@ -373,7 +364,6 @@ BarUiActCallback(BarUiActDebug) {
*/
BarUiActCallback(BarUiActLoveSong) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoStation_t *realStation;
assert (selStation != NULL);
@@ -429,7 +419,6 @@ BarUiActCallback(BarUiActTogglePause) {
*/
BarUiActCallback(BarUiActRenameStation) {
PianoReturn_t pRet;
- CURLcode wRet;
char lineBuf[100];
assert (selStation != NULL);
@@ -472,7 +461,6 @@ BarUiActCallback(BarUiActSelectStation) {
*/
BarUiActCallback(BarUiActTempBanSong) {
PianoReturn_t pRet;
- CURLcode wRet;
assert (selSong != NULL);
@@ -538,7 +526,6 @@ static void BarUiActQuickmixCallback (BarApp_t *app, char *buf) {
*/
BarUiActCallback(BarUiActSelectQuickMix) {
PianoReturn_t pRet;
- CURLcode wRet;
assert (selStation != NULL);
@@ -607,7 +594,6 @@ BarUiActCallback(BarUiActHistory) {
*/
BarUiActCallback(BarUiActBookmark) {
PianoReturn_t pRet;
- CURLcode wRet;
char selectBuf[2];
assert (selSong != NULL);
@@ -655,7 +641,6 @@ static const char *boolToYesNo (const bool value) {
*/
BarUiActCallback(BarUiActSettings) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoSettings_t settings;
PianoRequestDataChangeSettings_t reqData;
bool modified = false;
@@ -751,7 +736,6 @@ BarUiActCallback(BarUiActSettings) {
*/
BarUiActCallback(BarUiActManageStation) {
PianoReturn_t pRet;
- CURLcode wRet;
PianoRequestDataGetStationInfo_t reqData;
char selectBuf[2], allowedActions[6], *allowedPos = allowedActions;
char question[64];