Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package libshout for openSUSE:Factory checked in at 2021-02-11 12:46:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libshout (Old) and /work/SRC/openSUSE:Factory/.libshout.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libshout" Thu Feb 11 12:46:40 2021 rev:26 rq:869214 version:2.4.5 Changes: -------- --- /work/SRC/openSUSE:Factory/libshout/libshout.changes 2020-10-12 13:46:25.877899789 +0200 +++ /work/SRC/openSUSE:Factory/.libshout.new.28504/libshout.changes 2021-02-11 12:47:44.157519326 +0100 @@ -1,0 +2,13 @@ +Sun Jan 17 23:31:06 UTC 2021 - Dirk M??ller <[email protected]> + +- update to 2.4.5: + * Improved shout.h for reading, and understanding. + * Marked dumpfile support as obsolete (as SHOUT_PROTOCOL_XAUDIOCAST already is). + * Added Support for setting the content language. + * Avoid the use of obsolete functions (#2317). + * Several small fixes for non-blocking mode (#2321, #2315). + * Corrected detection of libogg (mostly for windows targets). + * Now accept TLS mode "auto" when build without TLS support. + * Added new tool shout(1). + +------------------------------------------------------------------- Old: ---- libshout-2.4.4.tar.gz New: ---- libshout-2.4.5.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libshout.spec ++++++ --- /var/tmp/diff_new_pack.1as3rr/_old 2021-02-11 12:47:44.753520194 +0100 +++ /var/tmp/diff_new_pack.1as3rr/_new 2021-02-11 12:47:44.753520194 +0100 @@ -1,7 +1,7 @@ # # spec file for package libshout # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: libshout -Version: 2.4.4 +Version: 2.4.5 Release: 0 Summary: Library for communcating with Icecast servers License: LGPL-2.1-or-later @@ -80,8 +80,10 @@ %files devel %doc README doc/*.xml examples/*.c %license COPYING +%_bindir/shout %_libdir/*.so %_includedir/shout +%_mandir/man1/shout.1%{?ext_man} %_datadir/aclocal/*.m4 %_libdir/pkgconfig/*.pc ++++++ libshout-2.4.4.tar.gz -> libshout-2.4.5.tar.gz ++++++ ++++ 2511 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/Makefile.am new/libshout-2.4.5/Makefile.am --- old/libshout-2.4.4/Makefile.am 2019-05-20 20:33:51.000000000 +0200 +++ new/libshout-2.4.5/Makefile.am 2020-12-16 13:50:13.000000000 +0100 @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = 1.6 foreign ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = include src doc win32 +SUBDIRS = include src doc win32 tools if HAVE_EXAMPLES SUBDIRS += examples endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/NEWS new/libshout-2.4.5/NEWS --- old/libshout-2.4.4/NEWS 2020-10-02 00:34:44.000000000 +0200 +++ new/libshout-2.4.5/NEWS 2020-12-19 14:50:01.000000000 +0100 @@ -1,3 +1,14 @@ +libshout 2.4.5 (20201219) + +* Improved shout.h for reading, and understanding. +* Marked dumpfile support as obsolete (as SHOUT_PROTOCOL_XAUDIOCAST already is). +* Added Support for setting the content language. +* Avoid the use of obsolete functions (#2317). +* Several small fixes for non-blocking mode (#2321, #2315). +* Corrected detection of libogg (mostly for windows targets). +* Now accept TLS mode "auto" when build without TLS support. +* Added new tool shout(1). + libshout 2.4.4 (20201001) * Fixed handling of blocking/non-blocking mode diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/README new/libshout-2.4.5/README --- old/libshout-2.4.4/README 2016-09-04 16:23:16.000000000 +0200 +++ new/libshout-2.4.5/README 2020-12-19 14:49:22.000000000 +0100 @@ -2,11 +2,11 @@ -------- Libshout is a library for communicating with and sending data to an -icecast server. It handles the socket connection, the timing of the -data, and prevents bad data from getting to the icecast server. +Icecast server. It handles the socket connection, the timing of the +data, and prevents bad data from getting to the Icecast server. With just a few lines of code, a programmer can easily turn any application -into a streaming source for an icecast server. Libshout also allows +into a streaming source for an Icecast server. Libshout also allows developers who want a specific feature set (database access, request taking) to concentrate on that feature set, instead of worrying about how server communication works. @@ -17,4 +17,4 @@ Libshout is licensed under the LGPL. Please see the COPYING file for details. If you have any questions or comments, please visit us at -http://www.icecast.org or email us at [email protected]. +https://www.icecast.org/ or email us at [email protected]. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/configure.ac new/libshout-2.4.5/configure.ac --- old/libshout-2.4.4/configure.ac 2020-10-02 00:06:56.000000000 +0200 +++ new/libshout-2.4.5/configure.ac 2020-12-19 13:33:42.000000000 +0100 @@ -3,7 +3,7 @@ m4_define(libshout_major, 2) m4_define(libshout_minor, 4) -m4_define(libshout_micro, 4) +m4_define(libshout_micro, 5) m4_define(libshout_version, libshout_major.libshout_minor.libshout_micro) AC_INIT([libshout], libshout_version, [[email protected]]) @@ -124,7 +124,14 @@ AC_DEFINE([NO_THREAD], 1, [Define if you don't want to use the thread library]) fi -SHOUT_REQUIRES="ogg" +PKG_CHECK_MODULES([OGG], [ogg], [ + HAVE_OGG="yes" + SHOUT_REQUIRES="$SHOUT_REQUIRES, ogg" + ], [ + XIPH_PATH_OGG(, [AC_MSG_ERROR([required Ogg library not found])]) + ]) +OGG_LIBS="$OGG_LDFLAGS $OGG_LIBS" +XIPH_CFLAGS="$XIPH_CFLAGS $OGG_CFLAGS" PKG_CHECK_MODULES(VORBIS, vorbis, [ HAVE_VORBIS="yes" @@ -241,4 +248,4 @@ AC_OUTPUT([Makefile include/Makefile include/shout/Makefile include/shout/shout.h src/Makefile src/common/net/Makefile src/common/timing/Makefile src/common/thread/Makefile src/common/avl/Makefile src/common/httpp/Makefile doc/Makefile - examples/Makefile win32/Makefile shout.pc]) + tools/Makefile examples/Makefile win32/Makefile shout.pc]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/examples/nonblocking.c new/libshout-2.4.5/examples/nonblocking.c --- old/libshout-2.4.4/examples/nonblocking.c 2019-08-24 13:52:16.000000000 +0200 +++ new/libshout-2.4.5/examples/nonblocking.c 2020-12-15 22:38:46.000000000 +0100 @@ -8,6 +8,10 @@ #include <string.h> #include <unistd.h> +#if !(defined(WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)) +#include <time.h> +#endif + #include <shout/shout.h> int main() @@ -70,8 +74,13 @@ if (ret == SHOUTERR_BUSY) printf("Connection pending...\n"); - while (ret == SHOUTERR_BUSY) { + while (ret == SHOUTERR_BUSY || ret == SHOUTERR_RETRY) { +#if !(defined(WIN32) && !defined(__MINGW64__) && !defined(__MINGW32__)) + static const struct timespec ts = {.tv_sec = 0, .tv_nsec = 10 * 1000 * 1000}; + nanosleep(&ts, NULL); +#else usleep(10000); +#endif ret = shout_get_connected(shout); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/include/shout/shout.h.in new/libshout-2.4.5/include/shout/shout.h.in --- old/libshout-2.4.4/include/shout/shout.h.in 2019-08-24 13:52:16.000000000 +0200 +++ new/libshout-2.4.5/include/shout/shout.h.in 2020-12-07 16:59:40.000000000 +0100 @@ -123,6 +123,9 @@ typedef int (*shout_callback_t)(shout_t *shout, shout_event_t event, void *userdata, va_list ap); + +/* ----------------[ Generic ]---------------- */ + /* initializes the shout library. Must be called before anything else */ void shout_init(void); @@ -151,6 +154,8 @@ /* returns SHOUTERR_CONNECTED or SHOUTERR_UNCONNECTED */ int shout_get_connected(shout_t *self); + +/* ----------------[ Configuration ]---------------- */ /* Parameter manipulation functions. libshout makes copies of all parameters, * the caller may free its copies after giving them to libshout. May return * SHOUTERR_MALLOC */ @@ -207,21 +212,7 @@ const char *shout_get_mount(shout_t *self); /* Other parameters */ -int shout_set_name(shout_t *self, const char *name); // obsolete -const char *shout_get_name(shout_t *self); // obsolete - -int shout_set_url(shout_t *self, const char *url); // obsolete -const char *shout_get_url(shout_t *self); // obsolete - -int shout_set_genre(shout_t *self, const char *genre); // obsolete -const char *shout_get_genre(shout_t *self); // obsolete - -int shout_set_description(shout_t *self, const char *description); // obsolete -const char *shout_get_description(shout_t *self); // obsolete - -int shout_set_dumpfile(shout_t *self, const char *dumpfile); -const char *shout_get_dumpfile(shout_t *self); - +/* takes a SHOUT_AI_xxxx argument */ int shout_set_audio_info(shout_t *self, const char *name, const char *value); const char *shout_get_audio_info(shout_t *self, const char *name); @@ -232,9 +223,20 @@ int shout_set_public(shout_t *self, unsigned int make_public); unsigned int shout_get_public(shout_t *self); -/* takes a SHOUT_FORMAT_xxxx argument */ -int shout_set_format(shout_t *self, unsigned int format); // obsolete -unsigned int shout_get_format(shout_t *self); // obsolete +/* Set the content language. + * Values as per RFC5646 Section 2.1. + * This lists the target audiance language(s), not the language of songs + * (unless the station has a focus on songs in a specific language). + * The value of NULL is allowed if the content language is not known or is expected to change. + * + * Examples: + * A German station with moderations and news in German and Gamern and international songs + * would generally set this to "de-DE". + * A similar station in Switzerland would set this to "de-CH". + * A station with content in Portuguese, and Klingon should set this to "pt, tlh". + */ +int shout_set_content_language(shout_t *self, const char *content_language); +const char *shout_get_content_language(shout_t *self); /* Set the format of the content to send. * * format is one of SHOUT_FORMAT_xxxx. @@ -254,6 +256,9 @@ int shout_set_nonblocking(shout_t* self, unsigned int nonblocking); unsigned int shout_get_nonblocking(shout_t *self); + +/* ----------------[ Actions ]---------------- */ + /* Opens a connection to the server. All parameters must already be set */ int shout_open(shout_t *self); @@ -279,6 +284,10 @@ /* Amount of time in ms caller should wait before sending again */ int shout_delay(shout_t *self); + +/* ----------------[ MP3/AAC ONLY ]---------------- */ +/* Functions in this block are for use with MP3, and AAC streams only */ + /* Sets MP3 metadata. * Returns: * SHOUTERR_SUCCESS @@ -303,10 +312,38 @@ * SHOUTERR_MALLOC if memory can't be allocated */ int shout_metadata_add(shout_metadata_t *self, const char *name, const char *value); + +/* ----------------[ Advanced ]---------------- */ /* Advanced. Do not use. */ + int shout_control(shout_t *self, shout_control_t control, ...); int shout_set_callback(shout_t *self, shout_callback_t callback, void *userdata); + +/* ----------------[ Obsolete ]---------------- */ +/* Those functions are obsolete and MUST NOT be used in newer software. + * They may be removed with any future version. + */ + +int shout_set_name(shout_t *self, const char *name); // obsolete +const char *shout_get_name(shout_t *self); // obsolete + +int shout_set_url(shout_t *self, const char *url); // obsolete +const char *shout_get_url(shout_t *self); // obsolete + +int shout_set_genre(shout_t *self, const char *genre); // obsolete +const char *shout_get_genre(shout_t *self); // obsolete + +int shout_set_description(shout_t *self, const char *description); // obsolete +const char *shout_get_description(shout_t *self); // obsolete + +/* takes a SHOUT_FORMAT_xxxx argument */ +int shout_set_format(shout_t *self, unsigned int format); // obsolete +unsigned int shout_get_format(shout_t *self); // obsolete + +int shout_set_dumpfile(shout_t *self, const char *dumpfile); // obsolete +const char *shout_get_dumpfile(shout_t *self); // obsolete + #ifdef __cplusplus } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/src/Makefile.am new/libshout-2.4.5/src/Makefile.am --- old/libshout-2.4.4/src/Makefile.am 2020-09-30 01:46:00.000000000 +0200 +++ new/libshout-2.4.5/src/Makefile.am 2020-12-16 13:47:08.000000000 +0100 @@ -34,7 +34,7 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(srcdir)/common @XIPH_CPPFLAGS@ libshout_la_LIBADD = common/net/libicenet.la common/timing/libicetiming.la common/avl/libiceavl.la\ - common/httpp/libicehttpp.la $(MAYBE_THREAD_LIB) $(THEORA_LIBS) $(VORBIS_LIBS) $(SPEEX_LIBS) @XIPH_LIBS@ + common/httpp/libicehttpp.la $(MAYBE_THREAD_LIB) $(THEORA_LIBS) $(OGG_LIBS) $(VORBIS_LIBS) $(SPEEX_LIBS) @XIPH_LIBS@ debug: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/src/connection.c new/libshout-2.4.5/src/connection.c --- old/libshout-2.4.4/src/connection.c 2020-08-24 18:59:36.000000000 +0200 +++ new/libshout-2.4.5/src/connection.c 2020-12-07 16:59:40.000000000 +0100 @@ -563,7 +563,7 @@ if (con->socket != SOCK_ERROR || con->current_socket_state != SHOUT_SOCKSTATE_UNCONNECTED) return SHOUTERR_BUSY; - if (con->nonblocking == SHOUT_BLOCKING_DEFAULT) + if (con->nonblocking != SHOUT_BLOCKING_DEFAULT) shout_connection_set_nonblocking(con, shout_get_nonblocking(shout)); port = shout->port; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/src/proto_http.c new/libshout-2.4.5/src/proto_http.c --- old/libshout-2.4.4/src/proto_http.c 2019-05-22 11:05:32.000000000 +0200 +++ new/libshout-2.4.5/src/proto_http.c 2020-12-15 22:35:10.000000000 +0100 @@ -125,6 +125,8 @@ break; if (shout_queue_printf(connection, "Content-Type: %s\r\n", mimetype)) break; + if (self->content_language && shout_queue_printf(connection, "Content-Language: %s\r\n", self->content_language)) + break; if (poke) { if (shout_queue_str(connection, "Content-Length: 0\r\nConnection: Keep-Alive\r\n")) break; @@ -149,6 +151,8 @@ } free(ai); } + if (shout_queue_str(connection, "Prefer: return=minimal\r\n")) + break; if (shout_queue_str(connection, "\r\n")) break; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/src/shout.c new/libshout-2.4.5/src/shout.c --- old/libshout-2.4.4/src/shout.c 2020-08-12 18:31:43.000000000 +0200 +++ new/libshout-2.4.5/src/shout.c 2020-12-16 13:47:08.000000000 +0100 @@ -149,6 +149,8 @@ free(self->host); if (self->password) free(self->password); + if (self->content_language) + free(self->content_language); if (self->mount) free(self->mount); if (self->user) @@ -678,6 +680,47 @@ return self->useragent; } +int shout_set_content_language(shout_t *self, const char *content_language) +{ + const char *p; + + if (!self) + return SHOUTERR_INSANE; + + if (!content_language) { + if (self->content_language) + free(self->content_language); + return self->error = SHOUTERR_SUCCESS; + } + + // we do at least a simple check for the correct format. This will at least detect unsafe chars. + for (p = content_language; *p; p++) { + if (*p == ' ' || *p == ',') + continue; + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) + continue; + if (*p == '-') + continue; + + return self->error = SHOUTERR_INSANE; + } + + + if (self->content_language) + free(self->content_language); + + if ( !(self->content_language = _shout_util_strdup(content_language)) ) + return self->error = SHOUTERR_MALLOC; + + return self->error = SHOUTERR_SUCCESS; +} + +const char *shout_get_content_language(shout_t *self) +{ + if (!self) + return NULL; + return self->content_language; +} int shout_set_user(shout_t *self, const char *username) { @@ -1145,10 +1188,11 @@ if (!self) return SHOUTERR_INSANE; - if (mode == SHOUT_TLS_DISABLED) - return SHOUTERR_SUCCESS; + if (mode != SHOUT_TLS_DISABLED && + mode != SHOUT_TLS_AUTO) + return self->error = SHOUTERR_UNSUPPORTED; - return self->error = SHOUTERR_UNSUPPORTED; + return SHOUTERR_SUCCESS; } int shout_get_tls(shout_t *self) @@ -1335,6 +1379,7 @@ } ret = shout_connection_iter(self->connection, self); + self->error = ret; if (self->connection->current_message_state == SHOUT_MSGSTATE_SENDING1 && !self->send) { int rc; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/src/shout_private.h new/libshout-2.4.5/src/shout_private.h --- old/libshout-2.4.4/src/shout_private.h 2019-08-24 13:52:16.000000000 +0200 +++ new/libshout-2.4.5/src/shout_private.h 2020-12-07 16:59:40.000000000 +0100 @@ -93,19 +93,6 @@ size_t len; } shout_queue_t; -/* -typedef enum { - SHOUT_STATE_UNCONNECTED = 0, - SHOUT_STATE_CONNECT_PENDING, - SHOUT_STATE_TLS_PENDING, - SHOUT_STATE_REQ_CREATION, - SHOUT_STATE_REQ_PENDING, - SHOUT_STATE_RESP_PENDING, - SHOUT_STATE_CONNECTED, - SHOUT_STATE_RECONNECT -} shout_state_e; -*/ - typedef enum { SHOUT_SOCKSTATE_UNCONNECTED = 0, SHOUT_SOCKSTATE_CONNECTING, @@ -218,6 +205,8 @@ unsigned int usage; /* audio encoding parameters */ util_dict *audio_info; + /* content-language */ + char *content_language; /* user-agent to use when doing HTTP login */ char *useragent; @@ -323,7 +312,7 @@ shout_connection_return_state_t shout_get_xaudiocast_response(shout_t *self, shout_connection_t *connection); shout_connection_return_state_t shout_parse_xaudiocast_response(shout_t *self, shout_connection_t *connection); -/* containsers */ +/* containers */ int shout_open_ogg(shout_t *self); int shout_open_mp3(shout_t *self); int shout_open_webm(shout_t *self); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/tools/Makefile.am new/libshout-2.4.5/tools/Makefile.am --- old/libshout-2.4.4/tools/Makefile.am 1970-01-01 01:00:00.000000000 +0100 +++ new/libshout-2.4.5/tools/Makefile.am 2020-12-19 14:33:37.000000000 +0100 @@ -0,0 +1,11 @@ +AUTOMAKE_OPTIONS = foreign + +EXTRA_DIST = shout.1 + +bin_PROGRAMS = shout +AM_CFLAGS = @XIPH_CFLAGS@ -I$(top_builddir)/include -Wall -Wextra + +man1_MANS = shout.1 + +shout_SOURCES = shout.c +shout_LDADD = $(top_builddir)/src/libshout.la diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/tools/shout.1 new/libshout-2.4.5/tools/shout.1 --- old/libshout-2.4.4/tools/shout.1 1970-01-01 01:00:00.000000000 +0100 +++ new/libshout-2.4.5/tools/shout.1 2020-12-16 13:50:13.000000000 +0100 @@ -0,0 +1,122 @@ +.Dd $Mdocdate: Dec 16 2020$ +.Dt SHOUT 1 +.Os +.\" +.Sh NAME +.\" +.Nm shout +.Nd Icecast source client +.\" +.Sh SYNOPSIS +.\" +.Nm +[OPTIONS] +.\" +.Sh DESCRIPTION +.\" +.Nm +reads data from standard input and streams it to Icecast. +.\" +.Sh OPTIONS +.\" +.Bl -tag -width 4n +.\" +.It Fl \-format Ar format +Set stream format. This can be "ogg", "mp3", or "webm". Default is "ogg". +.\" +.It Fl H Ar host +See +.Fl \-host +.\" +.It Fl h +See +.Fl \-help +.\" +.It Fl \-help +Show help. +.\" +.It Fl \-host Ar host +Set destination host. Default is "localhost". +.It Fl \-mount Ar string +Set mountpoint. Default is "/example.ogg". +.\" +.It Fl P Ar port +See +.Fl \-port +.\" +.It Fl \-pass Ar string +Set source password. Default is "hackme". +.\" +.It Fl \-port Ar port +Set destination port. Symbolic names are supported. Default is 8000. +.\" +.It Fl \-proto Ar protocol +Set protocol. Default is "http". +.\" STATION METADATA +.It Fl \-station-description Ar string +Set stream description. +.\" +.It Fl \-station-genre Ar string +Set stream genre. +.\" +.\" --station-meta +.It Fl \-station-meta Ar key Ns No = Ns Ar value +Set meta information. Both +.Ar key +and +.Ar value +are arbitrary strings. +.\" +.It Fl \-station-name Ar string +Set stream name. +.\" +.It Fl \-station-url Ar string +Set stream URL. +.\" +.It Fl \-tls-mode Ar tls-mode +Set TLS mode. This can be "disabled", "auto", "auto_no_plain", "rfc2818", or "rfc2817". Default is "auto". + +When libshout is build without TLS support only "disabled", and "auto" are supported. +.\" +.It Fl \-usage Ar usage{,usage} +Set stream usages. This can be: +.Bl -tag -width 13n -compact +.It Qq audio +for audio substreams +.It Qq visual +for picture/video substreams (most often combined with "audio") +.It Qq text +for text substreams that are not subtitles +.It Qq subtitle +for subtitle substreams +.It Qq light +for light control substreams +.It Qq ui +for user interface data, such as DVD menus or buttons +.It Qq metadata +for substreams that include metadata for the stream +.It Qq application +for application specific data substreams +.It Qq control +for substreams that control the infrastructure +.It Qq complex +for substreams that are themself a mixture of other types +.It Qq other +for substream of types not listed here +.It Qq unknown +for streams that may contain additional substreams of unknown nature +.It Qq 3d +for streams that contain information for 3D playback +.It Qq 4d +for streams that contain information for 4D/XD playback +.El +.\" +.It Fl \-user Ar string +Set source user. Default is "source". +.\" +.El +.\" +.Sh NOTES +If this binary is symlinked, or hardlinked to the name "oggfwd" it provides drop-in compatibly with +.Xr oggfwd 1 . +.\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/libshout-2.4.4/tools/shout.c new/libshout-2.4.5/tools/shout.c --- old/libshout-2.4.4/tools/shout.c 1970-01-01 01:00:00.000000000 +0100 +++ new/libshout-2.4.5/tools/shout.c 2020-12-16 13:50:13.000000000 +0100 @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2020 Philipp "ph3-der-loewe" Schafft <[email protected]> + * Copyright (C) 2020 Jakob Wied <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <getopt.h> +#include <libgen.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdbool.h> + +#ifndef _WIN32 +#include <arpa/inet.h> +#include <netdb.h> +#else +#include <winsock2.h> +#include <io.h> +#include <fcntl.h> +#endif + +#include <shout/shout.h> + +#define DEFAULT_MOUNT "/example.ogg" +#define DEFAULT_PASSWORD "hackme" + +/* only long options need a flag value */ +enum flag { + FLAG__NONE = 0, + FLAG_PROTO = 1, + FLAG_MOUNT = 2, + FLAG_USER = 3, + FLAG_PASS = 4, + FLAG_TLS_MODE = 5, + FLAG_FORMAT = 6, + + /* metadata */ + FLAG_STATION_DESCRIPTION = 7, + FLAG_STATION_GENRE = 8, + FLAG_STATION_NAME = 9, + FLAG_STATION_URL = 10, + FLAG_STATION_META = 11, + + /* other */ + FLAG_USAGE = 20 +}; + +struct format_usage { + char *name; + unsigned int flag; +}; + +static struct format_usage format_usages[] = { + {"audio", SHOUT_USAGE_AUDIO}, + {"visual", SHOUT_USAGE_VISUAL}, + {"text", SHOUT_USAGE_TEXT}, + {"subtitle", SHOUT_USAGE_SUBTITLE}, + {"light", SHOUT_USAGE_LIGHT}, + {"ui", SHOUT_USAGE_UI}, + {"metadata", SHOUT_USAGE_METADATA}, + {"application", SHOUT_USAGE_APPLICATION}, + {"control", SHOUT_USAGE_CONTROL}, + {"complex", SHOUT_USAGE_COMPLEX}, + {"other", SHOUT_USAGE_OTHER}, + {"unknown", SHOUT_USAGE_UNKNOWN}, + {"3d", SHOUT_USAGE_3D}, + {"4d", SHOUT_USAGE_4D}, +}; + +#ifdef SHOUT_TLS +static const char supported_tls_modes[] = "disabled|auto|auto_no_plain|rfc2818|rfc2817"; +#else +static const char supported_tls_modes[] = "disabled|auto"; +#endif + +static inline int string2format(const char *name, unsigned int *format) +{ + if (!format) + return -1; + + if (strcmp(name, "ogg") == 0) { + *format = SHOUT_FORMAT_OGG; + } else if (strcmp(name, "mp3") == 0) { + *format = SHOUT_FORMAT_MP3; + } else if (strcmp(name, "webm") == 0) { + *format = SHOUT_FORMAT_WEBM; + } else { + return -1; + } + + return 0; +} + +static inline int string2proto(const char *name, unsigned int *res) +{ + if (!res) + return -1; + + if (strcmp(name, "http") == 0) { + *res = SHOUT_PROTOCOL_HTTP; + } else if (strcmp(name, "icy") == 0) { + *res = SHOUT_PROTOCOL_ICY; + } else if (strcmp(name, "roar") == 0) { + *res = SHOUT_PROTOCOL_ROARAUDIO; + } else { + return -1; + } + + return 0; +} + +static inline int string2tlsmode(const char *name, int *res) +{ + if (!res) + return -1; + + if (strcasecmp(name, "disabled") == 0) { + *res = SHOUT_TLS_DISABLED; + } else if (strcasecmp(name, "auto") == 0) { + *res = SHOUT_TLS_AUTO; + } else if (strcasecmp(name, "auto_no_plain") == 0) { + *res = SHOUT_TLS_AUTO_NO_PLAIN; + } else if (strcasecmp(name, "rfc2818") == 0) { + *res = SHOUT_TLS_RFC2818; + } else if (strcasecmp(name, "rfc2817") == 0) { + *res = SHOUT_TLS_RFC2817; + } else { + return -1; + } + + return 0; +} + +static inline int string2port(const char *name, int *res) +{ + const struct servent *service; + + if (!name || !res) + return -1; + + service = getservbyname(name, "tcp"); + if (service) { + *res = ntohs(service->s_port); + return 0; + } else { + *res = atoi(name); + if (*res < 1 || *res > 65535) + return -1; + return 0; + } +} + +int set_mount(shout_t *self, const char *mount) +{ + if (!mount || *mount != '/' || strlen(mount) < 2) + fprintf(stderr, "Warning: Mount point not starting with a slash (\"/\").\n"); + return shout_set_mount(self, mount); +} + +int set_meta(shout_t *self, const char *name, const char *value, bool allow_unknown_key) +{ + + if (!name || !value) + return SHOUTERR_INSANE; + + if (strcmp(name, SHOUT_META_NAME) != 0 && strcmp(name, SHOUT_META_URL) != 0 && + strcmp(name, SHOUT_META_GENRE) != 0 && strcmp(name, SHOUT_META_DESCRIPTION) != 0 && + strcmp(name, SHOUT_META_IRC) != 0 && strcmp(name, SHOUT_META_AIM) != 0 && + strcmp(name, SHOUT_META_ICQ) != 0) { + if (allow_unknown_key) { + fprintf(stderr, "Warning: Invalid station metadata key (but trying to set anyway): %s\n", name); + } else { + // just reject, the caller must handle. + return SHOUTERR_INSANE; + } + } + + if (strcmp(name, SHOUT_META_URL) == 0) { + if (strstr(value, ":") == NULL) { + fprintf(stderr, "Warning: URL \"%s\" is not absolute. This may not work as expected. Please include a protocol. E.g. \"https://www.example.org/\".\n", value); + } else { + if (strncmp(value, "http://", 7) != 0 && strncmp(value, "https://", 8) != 0) { + fprintf(stderr, "Warning: Unusual protocol in URL \"%s\". This may not work as expected.\n", value); + } + } + } + + return shout_set_meta(self, name, value); +} + +void usage_oggfwd(const char *progname) +{ + fprintf(stderr, + "Usage: %s [OPTIONS] address port password mountpoint\n" + "\n" + "OPTIONS:\n" + " -d <description> set stream description\n" + " -g <genre> set stream genre\n" + " -h show this help\n" + " -m <file> parse metadata from file\n" + " -n <name> set stream name\n" + " -p make stream public\n" + " -u <url> set stream url\n" + " ???T {%s}\n" + " set TLS mode\n" + , progname, supported_tls_modes); +} + +void usage_shout(const char *progname) +{ + fprintf(stderr, + "Usage: %s [OPTIONS]\n" + "\n" + "OPTIONS:\n" + "General options:\n" + " --format <format> set format {ogg|mp3|webm}\n" + " -H <host>, --host <host> set host\n" + " -h, --help show this help\n" + " --mount <mountpoint> set mountpoint (e.g. \"/example.ogg\")\n" + " -P <port>, --port <port> set port (e.g. \"http\", or \"8300\")\n" + " --pass <password> set source password\n" + " --proto <protocol> set protocol (e.g. \"http\")\n" + " --user <user> set source user\n" + " --tls-mode <tls-mode> set TLS mode {%s}\n" + " --usage <usage> set usage (e.g. \"audio\", or \"visual,audio,subtitle\")\n" + "Station metadata options:\n" + " --station-description <string> set station description\n" + " --station-genre <string> set station genre\n" + " --station-meta <key>=<value> set station meta information\n" + " --station-name <string> set station name\n" + " --station-url <string> set station URL\n" + , progname, supported_tls_modes); +} + +/* parse_metadata_file is called at `oggfwd -m`. + * It fills the shout struct with information read from file. + * It returns 0 on success, or -1 on error. + */ +static int parse_metadata_file(const char *path, shout_t *shout) +{ + FILE *fh; + char line[256]; + int lineno = 0; + size_t len; + char *pos; + char c; + + if ((fh = fopen(path, "r")) == NULL) { + perror(path); + return -1; + } + + while (fgets(line, sizeof(line), fh)) { + lineno++; + + len = strlen(line); + if (len == 0) { + continue; + } + + /* skip comments and empty lines */ + c = line[0]; + if ((c == '#') || (c == '\r') || (c == '\n')) { + continue; + } + + /* strip line endings */ + if (line[len-1] == '\n') { + line[len-1] = '\0'; + len--; + } + if (line[len-1] == '\r') { + line[len-1] = '\0'; + len--; + } + + /* find '=' */ + if ((pos = strchr(line, '=')) == NULL) { + fprintf(stderr, "%s:%d: syntax error\n", path, lineno); + continue; /* oggfwd doesn't abort */ + } + + *pos = '\0'; /* terminate key */ + pos++; + + if (set_meta(shout, line, pos, false) != SHOUTERR_SUCCESS) { + fprintf(stderr, "%s:%d: \"%s\" is not a valid key\n", + path, lineno, line); + continue; /* oggfwd doesn't abort */ + } + } + + if (feof(fh) == 0) { + perror(path); + fclose(fh); + return -1; + } + + fclose(fh); + return 0; +} + +static int string2usage(char *str, unsigned int *usage) +{ + char *tok; + size_t i; + + if (!usage) + return -1; + + *usage = 0; /* clean for ORing */ + + /* split string on commas */ + for (tok = strtok(str, ","); tok; (tok = strtok(NULL, ","))) { + int found = 0; + + /* match token with predefined usages */ + for (i = 0; i < (sizeof(format_usages) / sizeof(format_usages[0])); i++) { + if (strcmp(tok, format_usages[i].name) == 0) { + *usage |= format_usages[i].flag; + found = 1; + break; + } + } + + if (!found) + return -1; + } + + return 0; +} + +static int getopts_oggfwd(int argc, char *argv[], shout_t *shout) +{ + const int ok = SHOUTERR_SUCCESS; /* helps to keep lines at 80 chars */ + int c; + int tls_mode; + int port; + + while ((c = getopt(argc, argv, "d:g:hm:n:pu:T:")) != -1) { + switch (c) { + case 'd': + if (set_meta(shout, SHOUT_META_DESCRIPTION, optarg, false) != ok) { + fprintf(stderr, "Error setting description: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 'g': + if (set_meta(shout, SHOUT_META_GENRE, optarg, false) != ok) { + fprintf(stderr, "Error setting genre: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 'h': + usage_oggfwd(argv[0]); + return -1; /* stop further processing */ + + case 'm': + if (parse_metadata_file(optarg, shout) != 0) { + return -1; + } + break; + + case 'n': + if (set_meta(shout, SHOUT_META_NAME, optarg, false) != ok) { + fprintf(stderr, "Error setting name: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 'p': + if (shout_set_public(shout, 1) != ok) { + fprintf(stderr, "Error setting public: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 'u': + if (set_meta(shout, SHOUT_META_URL, optarg, false) != ok) { + fprintf(stderr, "Error setting url: %s\n", + shout_get_error(shout)); + return -1; + } + break; + case 'T': + if (string2tlsmode(optarg, &tls_mode) != 0) { + fprintf(stderr, "Error parsing TLS mode: %s: Invalid protocol name", optarg); + return -1; + } + + if (shout_set_tls(shout, tls_mode) != ok) { + fprintf(stderr, "Error setting TLS mode: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + default: + usage_oggfwd(argv[0]); + return -1; + } + } + + /* need exacly 4 remaining arguments */ + if ((argc - optind) != 4) { + fprintf(stderr, "Wrong number of arguments\n"); + usage_oggfwd(argv[0]); + return -1; + } + + if (shout_set_host(shout, argv[optind++]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting hostname: %s\n", shout_get_error(shout)); + return -1; + } + + if (string2port(argv[optind], &port) != 0) { + fprintf(stderr, "Error parsing port: %s: Invalid port name\n", argv[optind]); + return -1; + } + if (shout_set_port(shout, port) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting port: %s\n", shout_get_error(shout)); + return -1; + } + optind++; + + if (shout_set_password(shout, argv[optind++]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting password: %s\n", shout_get_error(shout)); + return -1; + } + + if (set_mount(shout, argv[optind++]) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting mount: %s\n", shout_get_error(shout)); + return -1; + } + + return 0; +} + +static int getopts_shout(int argc, char *argv[], shout_t *shout) +{ + int flag = FLAG__NONE; + const struct option possible[] = { + /* connection options */ + {"proto", required_argument, &flag, FLAG_PROTO}, + {"host", required_argument, NULL, 'H'}, + {"port", required_argument, NULL, 'P'}, + {"mount", required_argument, &flag, FLAG_MOUNT}, + {"user", required_argument, &flag, FLAG_USER}, + {"pass", required_argument, &flag, FLAG_PASS}, + {"tls-mode", required_argument, &flag, FLAG_TLS_MODE}, + /* metadata options */ + {"station-description", required_argument, &flag, FLAG_STATION_DESCRIPTION}, + {"station-genre", required_argument, &flag, FLAG_STATION_GENRE}, + {"station-name", required_argument, &flag, FLAG_STATION_NAME}, + {"station-url", required_argument, &flag, FLAG_STATION_URL}, + {"station-meta", required_argument, &flag, FLAG_STATION_META}, + /* other options */ + {"format", required_argument, &flag, FLAG_FORMAT}, + {"usage", required_argument, &flag, FLAG_USAGE}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}, + }; + + int format_set = 0, format_usage_set = 0; + unsigned int format, format_usage; + unsigned int proto; + int tls_mode; + char *pos; + int port; + int c; + int i = 0; + + while ((c = getopt_long(argc, argv, "H:hP:", possible, &i)) != -1) { + switch (c) { + case 'H': + if (shout_set_host(shout, optarg) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting hostname: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 'h': + usage_shout(argv[0]); + return -1; + + case 'P': + if (string2port(optarg, &port) != 0) { + fprintf(stderr, "Error parsing port: %s: Invalid port name\n", optarg); + return -1; + } + if (shout_set_port(shout, port) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting port: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + case 0: /* long-only option */ + switch ((enum flag)flag) { + case FLAG_PROTO: + if (string2proto(optarg, &proto) != 0) { + fprintf(stderr, "Error parsing protocol: %s: Invalid protocol name\n", optarg); + return -1; + } + if (shout_set_protocol(shout, proto) != + SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting protocol: %s\n", + shout_get_error(shout)); + return -1; + } + break; + case FLAG_MOUNT: + if (set_mount(shout, optarg) != + SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting mount: %s\n", + shout_get_error(shout)); + return -1; + } + break; + case FLAG_USER: + if (shout_set_user(shout, optarg) != + SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting user: %s\n", + shout_get_error(shout)); + return -1; + } + break; + case FLAG_PASS: + if (shout_set_password(shout, optarg) != + SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting password: %s\n", + shout_get_error(shout)); + return -1; + } + break; + case FLAG_TLS_MODE: + if (string2tlsmode(optarg, &tls_mode) != 0) { + fprintf(stderr, "Error parsing TLS mode: %s: Invalid protocol name", optarg); + return -1; + } + + if (shout_set_tls(shout, tls_mode) != + SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting TLS mode: %s\n", + shout_get_error(shout)); + return -1; + } + break; + + /* metadata options */ + case FLAG_STATION_DESCRIPTION: + if (set_meta(shout, SHOUT_META_DESCRIPTION, optarg, false) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting description: %s\n", shout_get_error(shout)); + return -1; + } + break; + case FLAG_STATION_GENRE: + if (set_meta(shout, SHOUT_META_GENRE, optarg, false) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting genre: %s\n", shout_get_error(shout)); + return -1; + } + break; + case FLAG_STATION_NAME: + if (set_meta(shout, SHOUT_META_NAME, optarg, false) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting name: %s\n", shout_get_error(shout)); + return -1; + } + break; + case FLAG_STATION_URL: + if (set_meta(shout, SHOUT_META_URL, optarg, false) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting URL: %s\n", shout_get_error(shout)); + return -1; + } + break; + case FLAG_STATION_META: + /* find '=' */ + if ((pos = strchr(optarg, '=')) == NULL) { + fprintf(stderr, "%s: Missing '='\n", optarg); + return -1; + } + *pos = '\0'; /* terminate key */ + + if (set_meta(shout, optarg, pos + 1, true) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting meta information: %s\n", shout_get_error(shout)); + return -1; + } + break; + + /* other options */ + case FLAG_FORMAT: + /* backup usage */ + shout_get_content_format(shout, &format, &format_usage, NULL); + + if (string2format(optarg, &format) != 0) { + fprintf(stderr, "%s: Invalid format name\n", optarg); + return -1; + } + if (shout_set_content_format(shout, format, format_usage, NULL) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting format: %s\n", + shout_get_error(shout)); + return -1; + } + format_set = 1; /* may need to set usage below */ + break; + + case FLAG_USAGE: + /* backup format */ + shout_get_content_format(shout, &format, &format_usage, NULL); + + if (string2usage(optarg, &format_usage) != 0) { + fprintf(stderr, "Invalid format usage\n"); + return -1; + } + + if (shout_set_content_format(shout, format, format_usage, NULL) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting format and usage: %s\n", shout_get_error(shout)); + return -1; + } + format_usage_set = 1; /* don't override usage below */ + break; + + default: + usage_shout(argv[0]); + return -1; + break; + } + break; + default: /* unknown short option */ + usage_shout(argv[0]); + return -1; + break; + } + } + + /* set default usage for format */ + if (format_set && !format_usage_set) { + switch (format) { + case SHOUT_FORMAT_OGG: + format_usage = SHOUT_USAGE_UNKNOWN; + break; + case SHOUT_FORMAT_MP3: + format_usage = SHOUT_USAGE_AUDIO; + break; + case SHOUT_FORMAT_WEBM: + format_usage = SHOUT_USAGE_AUDIO|SHOUT_USAGE_VISUAL; + break; + default: /* unknown format => unknown usage */ + format_usage = SHOUT_USAGE_UNKNOWN; + break; + } + + if (shout_set_content_format(shout, format, format_usage, NULL) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting format and usage: %s\n", shout_get_error(shout)); + return -1; + } + format_usage_set = 1; + } + + /* prohibit trailing arguments + * NOTE: maybe we should treat them as input files + */ + if (optind != argc) { + for (; optind < argc; optind++) { + fprintf(stderr, "%s: unused argument\n", argv[optind]); + } + fprintf(stderr, "\n"); /* don't stick usage to warnings */ + usage_shout(argv[0]); + return -1; + } + + return 0; +} + +int main (int argc, char *argv[]) +{ + unsigned char buf[4096]; + int err; + size_t nread = 0; + const char *progname; /* don't use __progname from glibc */ + shout_t *shout; + +#ifdef _WIN32 + if (_setmode(_fileno(stdin), _O_BINARY) == -1) { + fprintf(stderr, "Could not set stdin to binary mode\n"); + return EXIT_FAILURE; + } +#endif + + shout_init(); + + if (!(shout = shout_new())) { + fprintf(stderr, "Could not allocate shout_t\n"); + return EXIT_FAILURE; + } + + if ((progname = basename(argv[0])) && (strcmp(progname, "oggfwd") == 0 || strcmp(progname, "oggfwd.exe") == 0)) { + err = getopts_oggfwd(argc, argv, shout); + } else { + err = getopts_shout(argc, argv, shout); + } + if (err) { + return EXIT_FAILURE; + } + + /* mount is not set by shout_new */ + if (!shout_get_mount(shout)) { + if (set_mount(shout, DEFAULT_MOUNT) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting mount: %s\n", shout_get_error(shout)); + return EXIT_FAILURE; + } + } + + /* password is not set by shout_new */ + if (!shout_get_password(shout)) { + if (shout_set_password(shout, DEFAULT_PASSWORD) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error setting password: %s\n", shout_get_error(shout)); + return EXIT_FAILURE; + } + } + + if (shout_open(shout) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error connecting: %s\n", shout_get_error(shout)); + return EXIT_FAILURE; + } + + while ((nread = fread(buf, 1, sizeof(buf), stdin)) > 0) { + if(shout_send(shout, buf, nread) != SHOUTERR_SUCCESS) { + fprintf(stderr, "Error sending: %s\n", shout_get_error(shout)); + return EXIT_FAILURE; + } + + shout_sync(shout); + } + + shout_close(shout); + shout_shutdown(); + + /* don't return 0 if the loop isn't terminated by EOF */ + if (feof(stdin) == 0) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +}
