[misc] Consolidate control file reader (e.g. for pairing credentials) into misc.c

- also remove requirement to enter device name in .remote file
This commit is contained in:
ejurgensen 2017-06-14 23:49:18 +02:00
parent 2676b9bbab
commit 283df8aa72
9 changed files with 114 additions and 372 deletions

View File

@ -63,108 +63,6 @@ static char *lastfm_session_key = NULL;
/* --------------------------------- HELPERS ------------------------------- */
/* Reads a LastFM credentials file (1st line username, 2nd line password) */
static int
credentials_read(char *path, char **username, char **password)
{
FILE *fp;
char *u;
char *p;
char buf[256];
int len;
fp = fopen(path, "rb");
if (!fp)
{
DPRINTF(E_LOG, L_LASTFM, "Could not open lastfm credentials file %s: %s\n", path, strerror(errno));
return -1;
}
u = fgets(buf, sizeof(buf), fp);
if (!u)
{
DPRINTF(E_LOG, L_LASTFM, "Empty lastfm credentials file %s\n", path);
fclose(fp);
return -1;
}
len = strlen(u);
if (buf[len - 1] != '\n')
{
DPRINTF(E_LOG, L_LASTFM, "Invalid lastfm credentials file %s: username name too long or missing password\n", path);
fclose(fp);
return -1;
}
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
if (!len)
{
DPRINTF(E_LOG, L_LASTFM, "Invalid lastfm credentials file %s: empty line where username expected\n", path);
fclose(fp);
return -1;
}
u = strdup(buf);
if (!u)
{
DPRINTF(E_LOG, L_LASTFM, "Out of memory for username while reading %s\n", path);
fclose(fp);
return -1;
}
p = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (!p)
{
DPRINTF(E_LOG, L_LASTFM, "Invalid lastfm credentials file %s: no password\n", path);
free(u);
return -1;
}
len = strlen(p);
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
p = strdup(buf);
if (!p)
{
DPRINTF(E_LOG, L_LASTFM, "Out of memory for password while reading %s\n", path);
free(u);
return -1;
}
DPRINTF(E_LOG, L_LASTFM, "lastfm credentials file OK, logging in with username %s\n", u);
*username = u;
*password = p;
return 0;
}
/* Creates an md5 signature of the concatenated parameters and adds it to keyval */
static int
@ -417,59 +315,39 @@ scrobble(int id)
/* ---------------------------- Our lastfm API --------------------------- */
/* Thread: filescanner */
int
lastfm_login(char *path)
void
lastfm_login(char **arglist)
{
struct keyval *kv;
char *username;
char *password;
int ret;
DPRINTF(E_DBG, L_LASTFM, "Got LastFM login request\n");
DPRINTF(E_LOG, L_LASTFM, "LastFM credentials file OK, logging in with username %s\n", arglist[0]);
// Delete any existing session key
if (lastfm_session_key)
free(lastfm_session_key);
free(lastfm_session_key);
lastfm_session_key = NULL;
db_admin_delete("lastfm_sk");
// Read the credentials file
ret = credentials_read(path, &username, &password);
if (ret < 0)
return -1;
// Enable LastFM now that we got a login attempt
lastfm_disabled = 0;
kv = keyval_alloc();
if (!kv)
{
ret = -1;
goto out_free_credentials;
}
return;
ret = ( (keyval_add(kv, "api_key", lastfm_api_key) == 0) &&
(keyval_add(kv, "username", username) == 0) &&
(keyval_add(kv, "password", password) == 0) );
(keyval_add(kv, "username", arglist[0]) == 0) &&
(keyval_add(kv, "password", arglist[1]) == 0) );
if (!ret)
{
ret = -1;
goto out_free_kv;
}
goto out_free_kv;
// Send the login request
ret = request_post("auth.getMobileSession", kv, 1);
request_post("auth.getMobileSession", kv, 1);
out_free_kv:
keyval_clear(kv);
free(kv);
out_free_credentials:
free(username);
free(password);
return ret;
}
/* Thread: worker */

View File

@ -2,8 +2,8 @@
#ifndef __LASTFM_H__
#define __LASTFM_H__
int
lastfm_login(char *path);
void
lastfm_login(char **arglist);
int
lastfm_scrobble(int id);

View File

@ -92,6 +92,7 @@ enum file_type {
FILE_ITUNES,
FILE_ARTWORK,
FILE_CTRL_REMOTE,
FILE_CTRL_RAOP_VERIFICATION,
FILE_CTRL_LASTFM,
FILE_CTRL_SPOTIFY,
FILE_CTRL_INITSCAN,
@ -318,6 +319,9 @@ file_type_get(const char *path) {
if (strcasecmp(ext, ".remote") == 0)
return FILE_CTRL_REMOTE;
if (strcasecmp(ext, ".verification") == 0)
return FILE_CTRL_RAOP_VERIFICATION;
if (strcasecmp(ext, ".lastfm") == 0)
return FILE_CTRL_LASTFM;
@ -356,6 +360,25 @@ process_playlist(char *file, time_t mtime, int dir_id)
#endif
}
/* If we found a control file we want to kickoff some action */
static void
kickoff(void (*kickoff_func)(char **arg), const char *file, int lines)
{
char **file_content;
int i;
file_content = m_readfile(file, lines);
if (!file_content)
return;
kickoff_func(file_content);
for (i = 0; i < lines; i++)
free(file_content[i]);
free(file_content);
}
/* Thread: scan */
static void
defer_playlist(char *path, time_t mtime, int dir_id)
@ -523,7 +546,13 @@ process_file(char *file, struct stat *sb, int type, int flags, int dir_id)
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
else
remote_pairing_kickoff_byfile(file);
kickoff(remote_pairing_kickoff, file, 1);
case FILE_CTRL_RAOP_VERIFICATION:
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
// else
// kickoff(player_raop_verification_kickoff, file, 1);
break;
case FILE_CTRL_LASTFM:
@ -531,7 +560,7 @@ process_file(char *file, struct stat *sb, int type, int flags, int dir_id)
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
else
lastfm_login(file);
kickoff(lastfm_login, file, 2);
#else
DPRINTF(E_LOG, L_SCAN, "Found '%s', but this version was built without LastFM support\n", file);
#endif
@ -542,7 +571,7 @@ process_file(char *file, struct stat *sb, int type, int flags, int dir_id)
if (flags & F_SCAN_BULK)
DPRINTF(E_LOG, L_SCAN, "Bulk scan will ignore '%s' (to process, add it after startup)\n", file);
else
spotify_login(file);
kickoff(spotify_login, file, 2);
#else
DPRINTF(E_LOG, L_SCAN, "Found '%s', but this version was built without Spotify support\n", file);
#endif

View File

@ -533,6 +533,57 @@ m_realpath(const char *pathname)
return ret;
}
char **
m_readfile(const char *path, int num_lines)
{
char buf[256];
FILE *fp;
char **lines;
char *line;
int i;
// Alloc array of char pointers
lines = calloc(num_lines, sizeof(char *));
if (!lines)
return NULL;
fp = fopen(path, "rb");
if (!fp)
{
DPRINTF(E_LOG, L_MISC, "Could not open file '%s' for reading: %s\n", path, strerror(errno));
free(lines);
return NULL;
}
for (i = 0; i < num_lines; i++)
{
line = fgets(buf, sizeof(buf), fp);
if (!line)
{
DPRINTF(E_LOG, L_MISC, "File '%s' has fewer lines than expected (found %d, expected %d)\n", path, i, num_lines);
goto error;
}
lines[i] = trimwhitespace(line);
if (strlen(lines[i]) == 0)
{
DPRINTF(E_LOG, L_MISC, "Line %d in '%s' is invalid\n", i+1, path);
goto error;
}
}
fclose(fp);
return lines;
error:
for (i = 0; i < num_lines; i++)
free(lines[i]);
free(lines);
fclose(fp);
return NULL;
}
char *
unicode_fixup_string(char *str, const char *fromcode)

View File

@ -80,6 +80,9 @@ keyval_sort(struct keyval *kv);
char *
m_realpath(const char *pathname);
char **
m_readfile(const char *path, int num_lines);
char *
unicode_fixup_string(char *str, const char *fromcode);

View File

@ -714,131 +714,28 @@ touch_remote_cb(const char *name, const char *type, const char *domain, const ch
/* Thread: filescanner, mpd */
void
remote_pairing_kickoff_bypin(const char *pin)
remote_pairing_kickoff(char **arglist)
{
int ret;
DPRINTF(E_INFO, L_REMOTE, "Kickoff pairing with pin '%s'\n", pin);
ret = strlen(arglist[0]);
if (ret != 4)
{
DPRINTF(E_LOG, L_REMOTE, "Kickoff pairing failed, unexpected pin length (got %d, expected 4)\n", ret);
return;
}
DPRINTF(E_LOG, L_REMOTE, "Kickoff pairing with pin '%s'\n", arglist[0]);
CHECK_ERR(L_REMOTE, pthread_mutex_lock(&remote_lck));
ret = add_remote_pin_data(pin);
ret = add_remote_pin_data(arglist[0]);
if (ret == 0)
kickoff_pairing();
CHECK_ERR(L_REMOTE, pthread_mutex_unlock(&remote_lck));
}
/* Thread: filescanner */
void
remote_pairing_kickoff_byfile(char *path)
{
char buf[256];
FILE *fp;
char *devname;
char *pin;
int len;
fp = fopen(path, "rb");
if (!fp)
{
DPRINTF(E_LOG, L_REMOTE, "Could not open Remote pairing file %s: %s\n", path, strerror(errno));
return;
}
devname = fgets(buf, sizeof(buf), fp);
if (!devname)
{
DPRINTF(E_LOG, L_REMOTE, "Empty Remote pairing file %s\n", path);
fclose(fp);
return;
}
len = strlen(devname);
if (buf[len - 1] != '\n')
{
DPRINTF(E_LOG, L_REMOTE, "Invalid Remote pairing file %s: device name too long or missing pin\n", path);
fclose(fp);
return;
}
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
if (!len)
{
DPRINTF(E_LOG, L_REMOTE, "Invalid Remote pairing file %s: empty line where device name expected\n", path);
fclose(fp);
return;
}
devname = strdup(buf);
if (!devname)
{
DPRINTF(E_LOG, L_REMOTE, "Out of memory for device name while reading %s\n", path);
fclose(fp);
return;
}
pin = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (!pin)
{
DPRINTF(E_LOG, L_REMOTE, "Invalid Remote pairing file %s: no pin\n", path);
free(devname);
return;
}
len = strlen(pin);
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
if (len != 4)
{
DPRINTF(E_LOG, L_REMOTE, "Invalid pin in Remote pairing file %s: pin length should be 4, got %d\n", path, len);
free(devname);
return;
}
pin = strdup(buf);
if (!pin)
{
DPRINTF(E_LOG, L_REMOTE, "Out of memory for device pin while reading %s\n", path);
free(devname);
return;
}
DPRINTF(E_LOG, L_REMOTE, "Read Remote pairing data (name '%s', pin '%s') from %s\n", devname, pin, path);
remote_pairing_kickoff_bypin(pin);
free(devname);
free(pin);
}
/* Thread: main */
int

View File

@ -3,10 +3,7 @@
#define __REMOTE_PAIRING_H__
void
remote_pairing_kickoff_bypin(const char *pin);
void
remote_pairing_kickoff_byfile(char *path);
remote_pairing_kickoff(char **arglist);
int
remote_pairing_init(void);

View File

@ -406,110 +406,6 @@ webapi_pl_remove(void *arg, int *ret);
static void
create_base_playlist();
/* ------------------------------- MISC HELPERS ---------------------------- */
static int
spotify_file_read(char *path, char **username, char **password)
{
FILE *fp;
char *u;
char *p;
char buf[256];
int len;
fp = fopen(path, "rb");
if (!fp)
{
DPRINTF(E_LOG, L_SPOTIFY, "Could not open Spotify credentials file %s: %s\n", path, strerror(errno));
return -1;
}
u = fgets(buf, sizeof(buf), fp);
if (!u)
{
DPRINTF(E_LOG, L_SPOTIFY, "Empty Spotify credentials file %s\n", path);
fclose(fp);
return -1;
}
len = strlen(u);
if (buf[len - 1] != '\n')
{
DPRINTF(E_LOG, L_SPOTIFY, "Invalid Spotify credentials file %s: username name too long or missing password\n", path);
fclose(fp);
return -1;
}
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
if (!len)
{
DPRINTF(E_LOG, L_SPOTIFY, "Invalid Spotify credentials file %s: empty line where username expected\n", path);
fclose(fp);
return -1;
}
u = strdup(buf);
if (!u)
{
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for username while reading %s\n", path);
fclose(fp);
return -1;
}
p = fgets(buf, sizeof(buf), fp);
fclose(fp);
if (!p)
{
DPRINTF(E_LOG, L_SPOTIFY, "Invalid Spotify credentials file %s: no password\n", path);
free(u);
return -1;
}
len = strlen(p);
while (len)
{
if ((buf[len - 1] == '\r') || (buf[len - 1] == '\n'))
{
buf[len - 1] = '\0';
len--;
}
else
break;
}
p = strdup(buf);
if (!p)
{
DPRINTF(E_LOG, L_SPOTIFY, "Out of memory for password while reading %s\n", path);
free(u);
return -1;
}
DPRINTF(E_LOG, L_SPOTIFY, "Spotify credentials file OK, logging in with username %s\n", u);
*username = u;
*password = p;
return 0;
}
/* -------------------------- PLAYLIST HELPERS ------------------------- */
/* Should only be called from within the spotify thread */
@ -1945,12 +1841,9 @@ spotify_uri_register(const char *uri)
/* Thread: library */
void
spotify_login(char *path)
spotify_login(char **arglist)
{
sp_error err;
char *username;
char *password;
int ret;
if (!g_sess)
{
@ -1982,20 +1875,14 @@ spotify_login(char *path)
CHECK_ERR(L_SPOTIFY, pthread_mutex_unlock(&login_lck));
}
DPRINTF(E_INFO, L_SPOTIFY, "Logging into Spotify\n");
if (path)
if (arglist)
{
ret = spotify_file_read(path, &username, &password);
if (ret < 0)
return;
err = fptr_sp_session_login(g_sess, username, password, 1, NULL);
free(username);
free(password);
DPRINTF(E_LOG, L_SPOTIFY, "Spotify credentials file OK, logging in with username %s\n", arglist[0]);
err = fptr_sp_session_login(g_sess, arglist[0], arglist[1], 1, NULL);
}
else
{
DPRINTF(E_INFO, L_SPOTIFY, "Relogin to Spotify\n");
err = fptr_sp_session_relogin(g_sess);
}

View File

@ -37,7 +37,7 @@ void
spotify_oauth_callback(struct evbuffer *evbuf, struct evkeyvalq *param, const char *redirect_uri);
void
spotify_login(char *path);
spotify_login(char **arglist);
int
spotify_init(void);