1
0
mirror of https://gitlab.xiph.org/xiph/ezstream.git synced 2024-09-15 04:08:07 -04:00

Rework quoting around metadata

* Do not shell-quote strings in the metadata token expansion function
  * This fixes https://github.com/xiph/ezstream/issues/6
* Expand all tokens at the same time in a way that ensures metadata
  is not additional input to expansion
* Simplify several functions and remove unused functionality
This commit is contained in:
Moritz Grimm 2017-09-15 19:30:52 +02:00
parent c21d47b8a9
commit 77f794a41e
4 changed files with 151 additions and 205 deletions

View File

@ -53,7 +53,7 @@ volatile sig_atomic_t queryMetadata;
volatile sig_atomic_t quit;
void sig_handler(int);
char * buildReencodeCommand(const char *, const char *, metadata_t);
char * _build_reencode_cmd(const char *, const char *, metadata_t);
metadata_t getMetadata(const char *);
FILE * openResource(stream_t, const char *, int *, metadata_t *,
int *, long *);
@ -89,15 +89,19 @@ sig_handler(int sig)
}
char *
buildReencodeCommand(const char *extension, const char *fileName,
_build_reencode_cmd(const char *extension, const char *fileName,
metadata_t mdata)
{
cfg_decoder_t decoder;
cfg_encoder_t encoder;
char *dec_str, *enc_str;
char *commandString;
size_t commandStringLen;
char *localTitle, *localArtist, *localMetaString, *localAlbum;
cfg_decoder_t decoder;
cfg_encoder_t encoder;
char *artist, *album, *title, *songinfo, *tmp;
char *filename_quoted;
char *custom_songinfo;
struct util_dict dicts[6];
char *dec_str;
char *enc_str;
char *cmd_str;
size_t cmd_str_size;
decoder = cfg_decoder_find(extension);
if (!decoder) {
@ -112,124 +116,89 @@ buildReencodeCommand(const char *extension, const char *fileName,
return (NULL);
}
localTitle = util_utf82char(metadata_get_title(mdata), ICONV_REPLACE);
localArtist = util_utf82char(metadata_get_artist(mdata), ICONV_REPLACE);
localAlbum = util_utf82char(metadata_get_album(mdata), ICONV_REPLACE);
localMetaString = util_utf82char(metadata_get_string(mdata),
ICONV_REPLACE);
tmp = util_utf82char(metadata_get_artist(mdata));
artist = util_shellquote(tmp);
xfree(tmp);
tmp = util_utf82char(metadata_get_album(mdata));
album = util_shellquote(tmp);
xfree(tmp);
tmp = util_utf82char(metadata_get_title(mdata));
title = util_shellquote(tmp);
xfree(tmp);
tmp = util_utf82char(metadata_get_string(mdata));
songinfo = util_shellquote(tmp);
xfree(tmp);
filename_quoted = util_shellquote(fileName);
dec_str = util_replacestring(cfg_decoder_get_program(decoder),
PLACEHOLDER_TRACK, fileName);
if (strstr(dec_str, PLACEHOLDER_ARTIST) != NULL) {
char *tmpStr = util_replacestring(dec_str, PLACEHOLDER_ARTIST,
localArtist);
xfree(dec_str);
dec_str = tmpStr;
}
if (strstr(dec_str, PLACEHOLDER_TITLE) != NULL) {
char *tmpStr = util_replacestring(dec_str, PLACEHOLDER_TITLE,
localTitle);
xfree(dec_str);
dec_str = tmpStr;
}
if (strstr(dec_str, PLACEHOLDER_ALBUM) != NULL) {
char *tmpStr = util_replacestring(dec_str, PLACEHOLDER_ALBUM,
localAlbum);
xfree(dec_str);
dec_str = tmpStr;
}
/*
* if meta
* if (prog && format)
* metatoformat
* if (prog && format)
* metatoformat
* else
* if (!prog && title)
* emptymeta
* else
* if (!prog && title)
* emptymeta
* else
* replacemeta
* replacemeta
*/
if (strstr(dec_str, PLACEHOLDER_METADATA) != NULL) {
if (cfg_get_metadata_program() &&
cfg_get_metadata_format_str()) {
char *mdataString = metadata_format_string(mdata,
cfg_get_metadata_format_str());
char *tmpStr = util_replacestring(dec_str,
PLACEHOLDER_METADATA, mdataString);
xfree(dec_str);
xfree(mdataString);
dec_str = tmpStr;
if (cfg_get_metadata_program() &&
cfg_get_metadata_format_str()) {
char *utf8, *unquoted;
utf8 = metadata_format_string(mdata,
cfg_get_metadata_format_str());
unquoted = util_utf82char(utf8);
xfree(utf8);
custom_songinfo = util_shellquote(unquoted);
xfree(unquoted);
} else {
if (!cfg_get_metadata_program() &&
strstr(cfg_decoder_get_program(decoder),
PLACEHOLDER_TITLE) != NULL) {
custom_songinfo = xstrdup("");
} else {
if (!cfg_get_metadata_program() &&
strstr(dec_str, PLACEHOLDER_TITLE) != NULL) {
char *tmpStr = util_replacestring(dec_str,
PLACEHOLDER_METADATA, "");
xfree(dec_str);
dec_str = tmpStr;
} else {
char *tmpStr = util_replacestring(dec_str,
PLACEHOLDER_METADATA, localMetaString);
xfree(dec_str);
dec_str = tmpStr;
}
custom_songinfo = xstrdup(songinfo);
}
}
if (!cfg_encoder_get_program(encoder))
return (dec_str);
memset(dicts, 0, sizeof(dicts));
dicts[0].from = PLACEHOLDER_ARTIST;
dicts[0].to = artist;
dicts[1].from = PLACEHOLDER_ALBUM;
dicts[1].to = album;
dicts[2].from = PLACEHOLDER_TITLE;
dicts[2].to = title;
dicts[3].from = PLACEHOLDER_TRACK;
dicts[3].to = filename_quoted;
dicts[4].from = PLACEHOLDER_METADATA;
dicts[4].to = custom_songinfo;
enc_str = util_replacestring(cfg_encoder_get_program(encoder),
PLACEHOLDER_ARTIST, localArtist);
if (strstr(enc_str, PLACEHOLDER_TITLE) != NULL) {
char *tmpStr = util_replacestring(enc_str, PLACEHOLDER_TITLE,
localTitle);
xfree(enc_str);
enc_str = tmpStr;
}
if (strstr(enc_str, PLACEHOLDER_ALBUM) != NULL) {
char *tmpStr = util_replacestring(enc_str, PLACEHOLDER_ALBUM,
localAlbum);
xfree(enc_str);
enc_str = tmpStr;
}
if (strstr(enc_str, PLACEHOLDER_METADATA) != NULL) {
if (cfg_get_metadata_program() &&
cfg_get_metadata_format_str()) {
char *mdataString = metadata_format_string(mdata,
cfg_get_metadata_format_str());
char *tmpStr = util_replacestring(enc_str,
PLACEHOLDER_METADATA, mdataString);
xfree(enc_str);
xfree(mdataString);
enc_str = tmpStr;
} else {
if (!cfg_get_metadata_program() &&
strstr(enc_str, PLACEHOLDER_TITLE) != NULL) {
char *tmpStr = util_replacestring(enc_str,
PLACEHOLDER_METADATA, "");
xfree(enc_str);
enc_str = tmpStr;
} else {
char *tmpStr = util_replacestring(enc_str,
PLACEHOLDER_METADATA, localMetaString);
xfree(enc_str);
enc_str = tmpStr;
}
}
dec_str = util_expand_words(cfg_decoder_get_program(decoder), dicts);
if (!cfg_get_metadata_program() &&
strstr(cfg_encoder_get_program(encoder),
PLACEHOLDER_TITLE) != NULL) {
xfree(custom_songinfo);
dicts[4].to = custom_songinfo = xstrdup("");
}
commandStringLen = strlen(dec_str) + strlen(" | ") +
strlen(enc_str) + 1;
commandString = xcalloc(commandStringLen, sizeof(char));
snprintf(commandString, commandStringLen, "%s | %s", dec_str,
enc_str);
enc_str = util_expand_words(cfg_encoder_get_program(encoder), dicts);
xfree(localTitle);
xfree(localArtist);
xfree(localMetaString);
cmd_str_size = strlen(dec_str) + strlen(" | ") + strlen(enc_str) + 1;
cmd_str = xcalloc(cmd_str_size, sizeof(char));
snprintf(cmd_str, cmd_str_size, "%s | %s", dec_str, enc_str);
xfree(dec_str);
xfree(enc_str);
return (commandString);
xfree(artist);
xfree(album);
xfree(title);
xfree(filename_quoted);
xfree(custom_songinfo);
return (cmd_str);
}
metadata_t
@ -325,7 +294,7 @@ openResource(stream_t stream, const char *fileName, int *popenFlag,
if (cfg_get_stream_encoder()) {
int stderr_fd = -1;
pCommandString = buildReencodeCommand(extension, fileName,
pCommandString = _build_reencode_cmd(extension, fileName,
mdata);
if (mdata_p != NULL)
*mdata_p = mdata;
@ -588,7 +557,7 @@ streamFile(stream_t stream, const char *fileName)
char *tmp, *metaData;
tmp = metadata_assemble_string(mdata);
if ((metaData = util_utf82char(tmp, ICONV_REPLACE)) == NULL)
if ((metaData = util_utf82char(tmp)) == NULL)
metaData = xstrdup("(unknown title)");
xfree(tmp);
log_notice("streaming: %s (%s)", metaData,

View File

@ -176,7 +176,7 @@ metadata_get_name(const char *file)
if (strlen(p1) == 0)
name = xstrdup("[unknown]");
else
name = util_char2utf8(p1, ICONV_REPLACE);
name = util_char2utf8(p1);
xfree(filename);
return (name);
@ -371,16 +371,14 @@ metadata_program_update(struct metadata *md, enum metadata_request md_req)
return (0);
}
if (fgets(buf, (int)sizeof(buf), filep) == NULL) {
if (ferror(filep))
log_error("%s: output read error: %s", md->filename,
strerror(errno));
memset(buf, 0, sizeof(buf));
if (fgets(buf, (int)sizeof(buf), filep) == NULL &&
ferror(filep)) {
log_alert("%s: output read error: %s", md->filename,
strerror(errno));
pclose(filep);
log_alert("program not (or no longer) usable: %s",
md->filename);
exit(1);
}
pclose(filep);
if (strlen(buf) == sizeof(buf) - 1)
@ -520,43 +518,22 @@ metadata_assemble_string(struct metadata *md)
char *
metadata_format_string(struct metadata *md, const char *format)
{
char *tmp, *str;
struct util_dict dicts[6];
if (format == NULL)
return (NULL);
str = xstrdup(format);
memset(dicts, 0, sizeof(dicts));
dicts[0].from = PLACEHOLDER_ARTIST;
dicts[0].to = metadata_get_artist(md);
dicts[1].from = PLACEHOLDER_ALBUM;
dicts[1].to = metadata_get_album(md);
dicts[2].from = PLACEHOLDER_TITLE;
dicts[2].to = metadata_get_title(md);
dicts[3].from = PLACEHOLDER_TRACK;
dicts[3].to = metadata_get_filename(md);
dicts[4].from = PLACEHOLDER_STRING;
dicts[4].to = metadata_get_string(md);
if (strstr(format, PLACEHOLDER_ARTIST) != NULL) {
tmp = util_replacestring(str, PLACEHOLDER_ARTIST,
metadata_get_artist(md));
xfree(str);
str = tmp;
}
if (strstr(format, PLACEHOLDER_TITLE) != NULL) {
tmp = util_replacestring(str, PLACEHOLDER_TITLE,
metadata_get_title(md));
xfree(str);
str = tmp;
}
if (strstr(format, PLACEHOLDER_STRING) != NULL) {
tmp = util_replacestring(str, PLACEHOLDER_STRING,
metadata_get_string(md));
xfree(str);
str = tmp;
}
if (strstr(format, PLACEHOLDER_TRACK) != NULL) {
tmp = util_replacestring(str, PLACEHOLDER_TRACK,
metadata_get_filename(md));
xfree(str);
str = tmp;
}
if (strstr(format, PLACEHOLDER_ALBUM) != NULL) {
tmp = util_replacestring(str, PLACEHOLDER_ALBUM,
metadata_get_album(md));
xfree(str);
str = tmp;
}
return (str);
return (util_expand_words(format, dicts));
}

View File

@ -53,11 +53,11 @@ static FILE *pidfile_file;
static pid_t pidfile_pid;
static unsigned int pidfile_numlocks;
static char * _iconvert(const char *, const char *, const char *, int);
static char * _iconvert(const char *, const char *, const char *);
static void _cleanup_pidfile(void);
static char *
_iconvert(const char *in_str, const char *from, const char *to, int mode)
_iconvert(const char *in_str, const char *from, const char *to)
{
#ifdef HAVE_ICONV
iconv_t cd;
@ -73,26 +73,7 @@ _iconvert(const char *in_str, const char *from, const char *to, int mode)
if (NULL == in_str)
return (xstrdup(""));
switch (mode) {
size_t siz;
case ICONV_TRANSLIT:
siz = strlen(to) + strlen("//TRANSLIT") + 1;
tocode = xcalloc(siz, sizeof(char));
snprintf(tocode, siz, "%s//TRANSLIT", to);
break;
case ICONV_IGNORE:
siz = strlen(to) + strlen("//IGNORE") + 1;
tocode = xcalloc(siz, sizeof(char));
snprintf(tocode, siz, "%s//IGNORE", to);
break;
case ICONV_REPLACE:
/* FALLTHROUGH */
default:
tocode = xstrdup(to);
break;
}
tocode = xstrdup(to);
if ((cd = iconv_open(tocode, from)) == (iconv_t)-1 &&
(cd = iconv_open("", from)) == (iconv_t)-1 &&
(cd = iconv_open(tocode, "")) == (iconv_t)-1) {
@ -147,7 +128,6 @@ _iconvert(const char *in_str, const char *from, const char *to, int mode)
#else
(void)from;
(void)to;
(void)mode;
if (NULL == in_str)
return (xstrdup(""));
@ -249,7 +229,7 @@ util_strrcasecmp(const char *s, const char *sub)
}
char *
util_char2utf8(const char *in_str, int mode)
util_char2utf8(const char *in_str)
{
char *codeset;
@ -257,11 +237,11 @@ util_char2utf8(const char *in_str, int mode)
codeset = nl_langinfo((nl_item)CODESET);
setlocale(LC_CTYPE, "C");
return (_iconvert(in_str, codeset, "UTF-8", mode));
return (_iconvert(in_str, codeset, "UTF-8"));
}
char *
util_utf82char(const char *in_str, int mode)
util_utf82char(const char *in_str)
{
char *codeset;
@ -269,32 +249,51 @@ util_utf82char(const char *in_str, int mode)
codeset = nl_langinfo((nl_item)CODESET);
setlocale(LC_CTYPE, "C");
return (_iconvert(in_str, "UTF-8", codeset, mode));
return (_iconvert(in_str, "UTF-8", codeset));
}
char *
util_replacestring(const char *source, const char *from, const char *to)
util_expand_words(const char *in, struct util_dict dicts[])
{
char *to_quoted, *dest;
size_t dest_size;
const char *p1, *p2;
size_t i;
char *out;
size_t out_size = strlen(in) + 1;
to_quoted = util_shellquote(to);
dest_size = strlen(source) + strlen(to_quoted) + 1;
dest = xcalloc(dest_size, sizeof(char));
/* empty input string? */
if (1 == out_size)
return (NULL);
p1 = source;
p2 = strstr(p1, from);
if (p2 != NULL) {
strncat(dest, p1, (size_t)(p2 - p1));
strlcat(dest, to_quoted, dest_size);
p1 = p2 + strlen(from);
out = xstrdup(in);
i = out_size - 1;
while (i--) {
struct util_dict *d = dicts;
while (d && d->from) {
if (0 == strncmp(&out[i], d->from, strlen(d->from))) {
char *buf, *tmp;
size_t buf_len;
buf_len = strlen(&out[i]) + strlen(d->to)
- strlen(d->from);
buf = xcalloc(buf_len + 1, sizeof(*buf));
snprintf(buf, buf_len + 1, "%s%s",
d->to, &out[i + strlen(d->from)]);
out_size += buf_len;
tmp = xcalloc(out_size, sizeof(*tmp));
snprintf(tmp, i + 1, "%s", out);
snprintf(tmp + i, out_size - i, "%s", buf);
free(buf);
free(out);
out = tmp;
break;
}
d++;
}
}
strlcat(dest, p1, dest_size);
xfree(to_quoted);
return (dest);
return (out);
}
#define SHELLQUOTE_INLEN_MAX 8191UL

View File

@ -16,16 +16,17 @@
#ifndef __UTIL_H__
#define __UTIL_H__
#define ICONV_REPLACE 0
#define ICONV_TRANSLIT 1
#define ICONV_IGNORE 2
struct util_dict {
const char *from;
const char *to;
};
int util_write_pid_file(const char *);
int util_strrcmp(const char *, const char *);
int util_strrcasecmp(const char *, const char *);
char * util_char2utf8(const char *, int);
char * util_utf82char(const char *, int);
char * util_replacestring(const char *, const char *, const char *);
char * util_char2utf8(const char *);
char * util_utf82char(const char *);
char * util_expand_words(const char *, struct util_dict[]);
char * util_shellquote(const char *);
int util_urlparse(const char *, char **, unsigned short *, char **);