From: Richard Kettlewell Date: Sat, 28 Jun 2008 15:16:46 +0000 (+0100) Subject: Synchronize with DisOrder 4.1 X-Git-Tag: 4.2~11^2~7 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/bdd2a99650780a1ef4a9e788eaabbc5e810cc39c?hp=3665689ab79ea1697c58914453f676a180eec689 Synchronize with DisOrder 4.1 --- diff --git a/CHANGES.html b/CHANGES.html index 8a39719..2a3c894 100644 --- a/CHANGES.html +++ b/CHANGES.html @@ -57,7 +57,71 @@ span.command {

This file documents recent user-visible changes to DisOrder.

-

Changes up to version 3.1

+

Changes up to version 4.1

+ +
+ +

Disobedience

+ +
+ +

Disobedience has been largely rewritten:

+ +
    + +
  • All the tabs now use native GTK+ list/tree widgets, resulting in + greater speed in some cases and more consistency with other GTK+ + applications.
  • + +
  • You can now use type-ahead find in the choose tab. The initiation + of a search is delayed slightly to avoid lots of updates when you're + half way through entering search terms.
  • + +
  • The choose tab now shows track lengths.
  • + +
  • Many buttons are now more reliably made insensitive when they can't + be used.
  • + +
  • You can now play tracks off the recent tab.
  • + +
+ +

Disobedience attempts to cope with servers from older versions, up to + a point, but this is not well tested and it's best to keep the server + fully up to date.

+ +
+ +

Server

+ +
+ +

When a track shares a directory with its alias, the real track name is + now returned instead of the alias (the opposite way round to the previous + behaviour).

+ +
+
+ +

Changes up to version 4.0.2

+ +
+ +

Corrected web browser linked from Disobedience.

+ +
+ +

Changes up to version 4.0.1

+ +
+ +

Libtool and Automake now install the CGI correctly. As part of this, + cgidir has been renamed to cgiexecdir. The configure + script will report an error if you try to use the old name.

+ +
+ +

Changes up to version 4.0

diff --git a/README b/README index acd06ee..8cd2c35 100644 --- a/README +++ b/README @@ -34,9 +34,9 @@ Build dependencies: libao 0.8.6 libasound 1.0.13 libFLAC 1.1.2 - GNU C 4.1.2 - GNU Make 3.81 - GNU Sed 4.1.5 + GNU C 4.1.2 } + GNU Make 3.81 } Non-GNU versions will NOT work + GNU Sed 4.1.5 } Python 2.4.4 (optional) GTK+ 2.8.20 (if you want the GTK+ client) GLIB 2.12.4 (if you want the GTK+ client) @@ -91,7 +91,7 @@ platform, please get in touch. If configure cannot guess where your web server keeps its HTML documents and CGI programs, you may have to tell it, for instance: - ./configure cgidir=/whatever/cgi-bin httpdir=/whatever/htdocs + ./configure cgiexecdir=/whatever/cgi-bin httpdir=/whatever/htdocs See README.client for setting up a standalone client (or read the disobedience man page). @@ -229,9 +229,13 @@ You need to configure a number of things to make this work: disorder setup-guest --no-online-registration -3. Try it out. You should be able to perform read-only operations straight - away, and after visiting the 'Login' page to authenticate, perform other - operations like adding a track to the queue. +3. Try it out. The url will be (something like): + + http://localhost/cgi-bin/disorder + + You should be able to perform read-only operations straight away, and after + visiting the 'Login' page to authenticate, perform other operations like + adding a track to the queue. 4. If you run into problems, always look at the appropriate error log; the message you see in your web browser will usually not be sufficient to diff --git a/README.developers b/README.developers index 5a5dd89..d0c1cdc 100644 --- a/README.developers +++ b/README.developers @@ -14,6 +14,8 @@ Dependencies: libao-dev libmad0-dev libasound2-dev libdb4.3-dev \ libflac-dev + (Use the bzr from backports, the one in etch is obsolete.) + * On FreeBSD you'll need at least these packages: autotools bash @@ -138,10 +140,7 @@ Web Interface: keep it that way. Clever use of CSS is OK provided it works well on the mainstream browsers. - * I know that the web template syntax is rather nasty. Perhaps it will be - improved in a future version. - - * Update templates/help.html for any changes you make. + * Update templates/help.tmpl for any changes you make. Disobedience: @@ -188,12 +187,9 @@ Code And Patches: (But if your new feature only makes sense on a given platform then obviously its new dependencies don't need to be available elsewhere.) - * GCC is stated as a dependency. In fact the code is mostly standard C, - with C99 initializers, long long and possibly the occasional // comment as - the main departures from C89. Additional GCCisms will be accepted if it's - impractical to avoid them. At least one active user is still using GCC - 2.95, so extensions that only appear in later versions are to be avoided - for the time being. + * GCCisms such as typeof and C99isms such as mixed declarations and named + structure initializers are used; the configure script asks for -std=gnu99 + by default. Some supported platforms are still on GCC 4.0. * Please submit patches either using 'diff -u', or by publishing a bzr branch somewhere I can get at it. diff --git a/README.upgrades b/README.upgrades index 63b7852..185ea4f 100644 --- a/README.upgrades +++ b/README.upgrades @@ -17,7 +17,7 @@ all 1.1.x versions. If you install from .deb files then much of this work is automated. -* 3.0 -> 3.1 +* 3.0 -> 4.0 If you customized any of the templates, you will pretty much have to start from scratch as the web interface has been rewritten. See disorder.cgi(8) for a diff --git a/cgi/Makefile.am b/cgi/Makefile.am index e2fa895..72ea195 100644 --- a/cgi/Makefile.am +++ b/cgi/Makefile.am @@ -18,7 +18,7 @@ # USA # -cgi_PROGRAMS=disorder +cgiexec_PROGRAMS=disorder AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib @@ -28,3 +28,6 @@ disorder_LDADD=../lib/libdisorder.a \ $(LIBPCRE) $(LIBGCRYPT) $(LIBDL) $(LIBDB) disorder_LDFLAGS=-export-dynamic disorder_DEPENDENCIES=../lib/libdisorder.a + +install-exec-hook: + $(LIBTOOL) --mode=finish $(DESTDIR)$(cgiexecdir) diff --git a/cgi/actions.c b/cgi/actions.c index 611e9a4..4728503 100644 --- a/cgi/actions.c +++ b/cgi/actions.c @@ -240,7 +240,7 @@ static void act_play(void) { const char *track, *dir; char **tracks; int ntracks, n; - struct dcgi_entry *e; + struct tracksort_data *tsd; if(dcgi_client) { if((track = cgi_get("track"))) { @@ -248,16 +248,9 @@ static void act_play(void) { } else if((dir = cgi_get("dir"))) { if(disorder_files(dcgi_client, dir, 0, &tracks, &ntracks)) ntracks = 0; - /* TODO use tracksort_init */ - e = xmalloc(ntracks * sizeof (struct dcgi_entry)); - for(n = 0; n < ntracks; ++n) { - e[n].track = tracks[n]; - e[n].sort = trackname_transform("track", tracks[n], "sort"); - e[n].display = trackname_transform("track", tracks[n], "display"); - } - qsort(e, ntracks, sizeof (struct dcgi_entry), dcgi_compare_entry); + tsd = tracksort_init(ntracks, tracks, "track"); for(n = 0; n < ntracks; ++n) - disorder_play(dcgi_client, e[n].track); + disorder_play(dcgi_client, tsd[n].track); } } redirect(0); @@ -435,8 +428,7 @@ static void act_register(void) { } /* We could well do better address validation but for now we'll just do the * minimum */ - /* TODO use email_valid() */ - if(!strchr(email, '@')) { + if(!email_valid(email)) { login_error("bademail"); return; } @@ -525,8 +517,7 @@ static void act_edituser(void) { } } else password = password2 = 0; - /* TODO use email_valid() */ - if(email && !strchr(email, '@')) { + if(email && !email_valid(email)) { login_error("bademail"); return; } @@ -745,7 +736,7 @@ void dcgi_expand(const char *name, int header) { if(!(found = mx_find(p, 0/*report*/))) fatal(errno, "cannot find %s", p); if(header) { - if(printf("Content-Type: text/html\n" + if(printf("Content-Type: text/html; charset=UTF-8\n" "%s\n" "\n", dcgi_cookie_header()) < 0) fatal(errno, "error writing to stdout"); diff --git a/cgi/cgimain.c b/cgi/cgimain.c index 253f82e..e96bbab 100644 --- a/cgi/cgimain.c +++ b/cgi/cgimain.c @@ -33,7 +33,7 @@ int main(int argc, char **argv) { /* TODO we could make disorder/ACTION equivalent to disorder?action=ACTION */ if(getenv("PATH_INFO")) { /* TODO it might be nice to link back to the right place... */ - printf("Content-Type: text/html\n"); + printf("Content-Type: text/html; charset=UTF-8\n"); printf("Status: 404\n"); printf("\n"); printf("

Sorry, PATH_INFO not supported.

\n"); diff --git a/cgi/disorder-cgi.h b/cgi/disorder-cgi.h index 3f19fe2..3cabe9b 100644 --- a/cgi/disorder-cgi.h +++ b/cgi/disorder-cgi.h @@ -60,16 +60,6 @@ extern char *dcgi_cookie; extern const char *dcgi_error_string; extern const char *dcgi_status_string; -/** @brief Entry in a list of tracks or directories */ -struct dcgi_entry { - /** @brief Track name */ - const char *track; - /** @brief Sort key */ - const char *sort; - /** @brief Display key */ - const char *display; -}; - /** @brief Compare two @ref entry objects */ int dcgi_compare_entry(const void *a, const void *b); diff --git a/cgi/macros-disorder.c b/cgi/macros-disorder.c index 8e891d6..5ea7413 100644 --- a/cgi/macros-disorder.c +++ b/cgi/macros-disorder.c @@ -814,15 +814,6 @@ static int exp_image(int attribute((unused)) nargs, return sink_writes(output, cgi_sgmlquote(url)) < 0 ? -1 : 0; } -/** @brief Compare two @ref entry objects */ -int dcgi_compare_entry(const void *a, const void *b) { - const struct dcgi_entry *ea = a, *eb = b; - - return compare_tracks(ea->sort, eb->sort, - ea->display, eb->display, - ea->track, eb->track); -} - /** @brief Implementation of exp_tracks() and exp_dirs() */ static int exp__files_dirs(int nargs, const struct mx_node **args, @@ -837,7 +828,7 @@ static int exp__files_dirs(int nargs, char **tracks, *dir, *re; int n, ntracks, rc; const struct mx_node *m; - struct dcgi_entry *e; + struct tracksort_data *tsd; if((rc = mx_expandstr(args[0], &dir, u, "argument #0 (DIR)"))) return rc; @@ -855,25 +846,18 @@ static int exp__files_dirs(int nargs, if(fn(dcgi_client, dir, re, &tracks, &ntracks)) return 0; /* Sort it. NB trackname_transform() does not go to the server. */ - /* TODO use tracksort_init */ - e = xcalloc(ntracks, sizeof *e); - for(n = 0; n < ntracks; ++n) { - e[n].track = tracks[n]; - e[n].sort = trackname_transform(type, tracks[n], "sort"); - e[n].display = trackname_transform(type, tracks[n], "display"); - } - qsort(e, ntracks, sizeof (struct dcgi_entry), dcgi_compare_entry); + tsd = tracksort_init(ntracks, tracks, type); /* Expand the subsiduary templates. We chuck in @sort and @display because * it is particularly easy to do so. */ for(n = 0; n < ntracks; ++n) if((rc = mx_expand(mx_rewritel(m, "index", make_index(n), "parity", n % 2 ? "odd" : "even", - "track", e[n].track, + "track", tsd[n].track, "first", n == 0 ? "true" : "false", "last", n + 1 == ntracks ? "false" : "true", - "sort", e[n].sort, - "display", e[n].display, + "sort", tsd[n].sort, + "display", tsd[n].display, (char *)0), output, u))) return rc; diff --git a/configure.ac b/configure.ac index 44ca4b2..9e9a7c7 100644 --- a/configure.ac +++ b/configure.ac @@ -20,9 +20,9 @@ # USA # -AC_INIT([disorder], [3.0+], [richard+disorder@sfere.greenend.org.uk]) +AC_INIT([disorder], [4.1], [richard+disorder@sfere.greenend.org.uk]) AC_CONFIG_AUX_DIR([config.aux]) -AM_INIT_AUTOMAKE(disorder, [3.0+]) +AM_INIT_AUTOMAKE(disorder, [4.1]) AC_CONFIG_SRCDIR([server/disorderd.c]) AM_CONFIG_HEADER([config.h]) @@ -226,14 +226,18 @@ if test $want_cgi = yes; then fi done ]) - if test "$rjk_cv_cgidir" = "not found"; then + if test "$rjk_cv_cgiexecdir" = "not found"; then AC_MSG_ERROR([cannot identify httpd documentroot. Set httpdir on configure command line]) fi httpdir="$rjk_cv_httpdir" fi - if test -z "$cgidir"; then - AC_CACHE_CHECK([for CGI directory],[rjk_cv_cgidir],[ - rjk_cv_cgidir="not found" + if test ! -z "$cgidir"; then + # This is a bit harsh but should stop any disasters + AC_MSG_ERROR([cgidir has been renamed to cgiexecdir]) + fi + if test -z "$cgiexecdir"; then + AC_CACHE_CHECK([for CGI directory],[rjk_cv_cgiexecdir],[ + rjk_cv_cgiexecdir="not found" for dir in /usr/lib/cgi-bin \ /Library/WebServer/CGI-Executables \ /srv/www/cgi-bin \ @@ -244,18 +248,18 @@ if test $want_cgi = yes; then /usr/local/www/cgi-bin \ /usr/local/www/*/cgi-bin; do if test -d "$dir"; then - rjk_cv_cgidir="$dir" + rjk_cv_cgiexecdir="$dir" break fi done ]) - if test "$rjk_cv_cgidir" = "not found"; then - AC_MSG_ERROR([cannot identify CGI install directory. Set cgidir on configure command line]) + if test "$rjk_cv_cgiexecdir" = "not found"; then + AC_MSG_ERROR([cannot identify CGI install directory. Set cgiexecdir on configure command line]) fi - cgidir="$rjk_cv_cgidir" + cgiexecdir="$rjk_cv_cgiexecdir" fi fi -AC_ARG_VAR([cgidir], [location of cgi-bin directory, e.g. /usr/lib/cgi-bin]) +AC_ARG_VAR([cgiexecdir], [location of cgi-bin directory, e.g. /usr/lib/cgi-bin]) AC_ARG_VAR([httpdir], [location of http document root, e.g. /var/www/htdocs]) if test -z "$pkghttpdir"; then pkghttpdir='$(httpdir)/disorder' diff --git a/debian/README.Debian b/debian/README.Debian index a670319..e7bf6f7 100644 --- a/debian/README.Debian +++ b/debian/README.Debian @@ -1,8 +1,13 @@ Debian package for DisOrder =========================== -The web interface should now start working automatically. Test it at -http://YOURHOSTNAME/cgi-bin/disorder/disorder If it doesn't work, -always look at the web server error log. +The web interface should now start working automatically. Test it at: - -- Richard Kettlewell , Sat, 29 Mar 2008 16:20:20 +0000 + http://YOURHOSTNAME/cgi-bin/disorder + +You will need to create yourself a user. + +If it doesn't work, always look at the web server error log and at +/var/log/daemon.log. + + -- Richard Kettlewell , Sun, 15 Jun 2008 12:15:50 +0100 diff --git a/debian/changelog b/debian/changelog index ab46f89..7799d2c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,29 @@ -disorder (3.0.99.dev) unstable; urgency=low +disorder (4.1) unstable; urgency=low - * Bodge version number + * DisOrder 4.1 - -- Richard Kettlewell Sun, 18 May 2008 21:30:14 +0100 + -- Richard Kettlewell Sat, 28 Jun 2008 14:35:20 +0100 + +disorder (4.0.2) unstable; urgency=low + + * Correct web browser linkage from Disobedience. + + -- Richard Kettlewell Sun, 15 Jun 2008 14:44:22 +0100 + +disorder (4.0.1) unstable; urgency=low + + * Version 4.0.1 + * Update READMEs + * Make group modification noisier + * Makefile fiddling for Automake/Libtool's benefit + + -- Richard Kettlewell Sun, 15 Jun 2008 12:22:52 +0100 + +disorder (4.0) unstable; urgency=low + + * Version 4.0 + + -- Richard Kettlewell Sun, 8 Jun 2008 14:44:05 +0100 disorder (3.0) unstable; urgency=low diff --git a/debian/postinst.disorder-server b/debian/postinst.disorder-server index 9e51648..458cc79 100755 --- a/debian/postinst.disorder-server +++ b/debian/postinst.disorder-server @@ -28,7 +28,7 @@ add_jukebox_user() { --no-create-home jukebox # If it happens that there's no audio group we don't fail; perhaps only # network play was required. - adduser --quiet jukebox audio || true + adduser jukebox audio || true } configure_init_d() { diff --git a/debian/rules b/debian/rules index 000be81..0c14444 100755 --- a/debian/rules +++ b/debian/rules @@ -18,12 +18,12 @@ # USA # -cgidir=/usr/lib/cgi-bin +cgiexecdir=/usr/lib/cgi-bin httpdir=/var/www browser=x-www-browser # Options to configure. This can be overridden by the caller if necessary. -CONFIGURE=--prefix=/usr --sysconfdir=/etc --localstatedir=/var/lib --mandir=/usr/share/man --with-browser=$browser cgidir="${cgidir}" httpdir="${httpdir}" +CONFIGURE=--prefix=/usr --sysconfdir=/etc --localstatedir=/var/lib --mandir=/usr/share/man --with-browser=${browser} cgiexecdir="${cgiexecdir}" httpdir="${httpdir}" # Set DEB_BUILD_OPTIONS=noopt to produce a non-optimized build. ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) @@ -149,7 +149,7 @@ pkg-disorder-server: build rm -f debian/disorder-server/usr/share/man/man5/disorder_protocol.5 $(MKDIR) debian/disorder-server/etc/disorder $(MKDIR) debian/disorder-server/etc/init.d - $(MKDIR) debian/disorder-server/usr/lib/cgi-bin + $(MKDIR) debian/disorder-server${cgiexecdir} $(MKDIR) debian/disorder-server/var/lib/disorder $(INSTALL_SCRIPT) examples/disorder.init \ debian/disorder-server/etc/init.d/disorder @@ -160,9 +160,9 @@ pkg-disorder-server: build $(INSTALL_DATA) debian/etc.disorder.options.user \ debian/disorder-server/etc/disorder/options.user $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) cgi/disorder \ - $(shell pwd)/debian/disorder-server/usr/lib/cgi-bin/disorder + $(shell pwd)/debian/disorder-server${cgiexecdir}/disorder dpkg-shlibdeps -Tdebian/substvars.disorder-server \ - debian/disorder-server/usr/lib/cgi-bin/disorder \ + debian/disorder-server${cgiexecdir}/disorder \ debian/disorder-server/usr/sbin/* \ debian/disorder-server/usr/lib/disorder/*.so* rm -rf debian/disorder-server/usr/share/doc/disorder-server diff --git a/disobedience/choose.h b/disobedience/choose.h index 1a9bf10..c101e6b 100644 --- a/disobedience/choose.h +++ b/disobedience/choose.h @@ -62,7 +62,7 @@ gboolean choose_button_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data); void choose_play_completed(void attribute((unused)) *v, - const char *error); + const char *err); char *choose_get_track(GtkTreeIter *iter); char *choose_get_sort(GtkTreeIter *iter); char *choose_get_display(GtkTreeIter *iter); diff --git a/disobedience/control.c b/disobedience/control.c index ce39124..6ed9fb3 100644 --- a/disobedience/control.c +++ b/disobedience/control.c @@ -275,6 +275,7 @@ GtkWidget *control_widget(void) { char **events = split(icons[n].events, 0, 0, 0, 0); while(*events) event_register(*events++, icon_changed, &icons[n]); + event_register("connected-changed", icon_changed, &icons[n]); } /* create the adjustments for the volume control */ volume_adj = GTK_ADJUSTMENT(gtk_adjustment_new(0, 0, goesupto, diff --git a/disobedience/disobedience.h b/disobedience/disobedience.h index f709a27..1f63108 100644 --- a/disobedience/disobedience.h +++ b/disobedience/disobedience.h @@ -232,7 +232,7 @@ void choose_update(void); /* Called when we think the choose tree might need updating */ void play_completed(void *v, - const char *error); + const char *err); /* Login details */ diff --git a/disobedience/log.c b/disobedience/log.c index a4db0cf..6779cbd 100644 --- a/disobedience/log.c +++ b/disobedience/log.c @@ -151,6 +151,7 @@ static const struct { { DISORDER_RANDOM_ENABLED, "random-changed" }, { DISORDER_TRACK_PAUSED, "pause-changed" }, { DISORDER_PLAYING, "playing-changed" }, + { DISORDER_CONNECTED, "connected-changed" }, }; #define NSTATE_EVENTS (sizeof state_events / sizeof *state_events) diff --git a/disobedience/menu.c b/disobedience/menu.c index 868c9dc..142857c 100644 --- a/disobedience/menu.c +++ b/disobedience/menu.c @@ -31,7 +31,7 @@ static GtkWidget *properties_widget; GtkItemFactory *mainmenufactory; static void about_popup_got_version(void *v, - const char *error, + const char *err, const char *value); /** @brief Called when the quit option is activated diff --git a/disobedience/properties.c b/disobedience/properties.c index 8b46109..16ee97c 100644 --- a/disobedience/properties.c +++ b/disobedience/properties.c @@ -32,7 +32,7 @@ static void completed_namepart(struct prefdata *f); static const char *get_edited_namepart(struct prefdata *f); static void set_edited_namepart(struct prefdata *f, const char *value); static void set_namepart(struct prefdata *f, const char *value); -static void set_namepart_completed(void *v, const char *error); +static void set_namepart_completed(void *v, const char *err); static void kickoff_string(struct prefdata *f); static void completed_string(struct prefdata *f); @@ -46,7 +46,7 @@ static const char *get_edited_boolean(struct prefdata *f); static void set_edited_boolean(struct prefdata *f, const char *value); static void set_boolean(struct prefdata *f, const char *value); -static void prefdata_completed(void *v, const char *error, const char *value); +static void prefdata_completed(void *v, const char *err, const char *value); static void prefdata_onerror(struct callbackdata *cbd, int code, const char *msg); diff --git a/disobedience/queue.c b/disobedience/queue.c index 7dbe563..d69b34d 100644 --- a/disobedience/queue.c +++ b/disobedience/queue.c @@ -32,10 +32,10 @@ struct queue_entry *playing_track; time_t last_playing; static void queue_completed(void *v, - const char *error, + const char *err, struct queue_entry *q); static void playing_completed(void *v, - const char *error, + const char *err, struct queue_entry *q); /** @brief Called when either the actual queue or the playing track change */ diff --git a/disobedience/recent.c b/disobedience/recent.c index 109ee5a..788b824 100644 --- a/disobedience/recent.c +++ b/disobedience/recent.c @@ -78,6 +78,7 @@ static const struct queue_column recent_columns[] = { /** @brief Pop-up menu for recently played list */ static struct menuitem recent_menuitems[] = { { "Track properties", ql_properties_activate, ql_properties_sensitive,0, 0 }, + { "Play track", ql_play_activate, ql_play_sensitive, 0, 0 }, { "Select all tracks", ql_selectall_activate, ql_selectall_sensitive, 0, 0 }, { "Deselect all tracks", ql_selectnone_activate, ql_selectnone_sensitive, 0, 0 }, }; diff --git a/disobedience/users.c b/disobedience/users.c index 60bdef6..a835ced 100644 --- a/disobedience/users.c +++ b/disobedience/users.c @@ -645,6 +645,8 @@ static GtkWidget *users_make_reporter() { users_reporter = gtk_label_new(""); gtk_label_set_ellipsize(GTK_LABEL(users_reporter), PANGO_ELLIPSIZE_END); gtk_misc_set_alignment(GTK_MISC(users_reporter), 0.99, 0); + g_signal_connect(users_reporter, "destroy", + G_CALLBACK(gtk_widget_destroyed), &users_reporter); } return users_reporter; } @@ -681,6 +683,9 @@ void manage_users(void) { gtk_window_present(GTK_WINDOW(users_window)); return; } + /* Destroy old widgets */ + if(users_reporter) + gtk_widget_destroy(users_reporter); /* Create the window */ users_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_style(users_window, tool_style); diff --git a/lib/eclient.h b/lib/eclient.h index be5730c..efb6b2d 100644 --- a/lib/eclient.h +++ b/lib/eclient.h @@ -209,14 +209,14 @@ struct sink; /** @brief Trivial completion callback * @param v User data - * @param error Error string or NULL on succes + * @param err Error string or NULL on succes */ typedef void disorder_eclient_no_response(void *v, - const char *error); + const char *err); /** @brief String result completion callback * @param v User data - * @param error Error string or NULL on succes + * @param err Error string or NULL on succes * @param value Result or NULL * * @p error will be NULL on success. In this case @p value will be the result @@ -226,12 +226,12 @@ typedef void disorder_eclient_no_response(void *v, * @p error will be non-NULL on failure. In this case @p value is always NULL. */ typedef void disorder_eclient_string_response(void *v, - const char *error, + const char *err, const char *value); /** @brief String result completion callback * @param v User data - * @param error Error string or NULL on succes + * @param err Error string or NULL on succes * @param value Result or 0 * * @p error will be NULL on success. In this case @p value will be the result. @@ -239,11 +239,11 @@ typedef void disorder_eclient_string_response(void *v, * @p error will be non-NULL on failure. In this case @p value is always 0. */ typedef void disorder_eclient_integer_response(void *v, - const char *error, + const char *err, long value); /** @brief Volume completion callback * @param v User data - * @param error Error string or NULL on success + * @param err Error string or NULL on success * @param l Left channel volume * @param r Right channel volume * @@ -254,12 +254,12 @@ typedef void disorder_eclient_integer_response(void *v, * 0. */ typedef void disorder_eclient_volume_response(void *v, - const char *error, + const char *err, int l, int r); /** @brief Queue request completion callback * @param v User data - * @param error Error string or NULL on success + * @param err Error string or NULL on success * @param q Head of queue data list * * @p error will be NULL on success. In this case @p q will be the (head of @@ -270,12 +270,12 @@ typedef void disorder_eclient_volume_response(void *v, * be ignored in the error case. */ typedef void disorder_eclient_queue_response(void *v, - const char *error, + const char *err, struct queue_entry *q); /** @brief List request completion callback * @param v User data - * @param error Error string or NULL on success + * @param err Error string or NULL on success * @param nvec Number of elements in response list * @param vec Pointer to response list * @@ -286,7 +286,7 @@ typedef void disorder_eclient_queue_response(void *v, * be 0 and NULL. */ typedef void disorder_eclient_list_response(void *v, - const char *error, + const char *err, int nvec, char **vec); disorder_eclient *disorder_eclient_new(const disorder_eclient_callbacks *cb, diff --git a/lib/trackdb.c b/lib/trackdb.c index 4287104..718970a 100644 --- a/lib/trackdb.c +++ b/lib/trackdb.c @@ -60,6 +60,7 @@ #include "unicode.h" #include "unidata.h" #include "base64.h" +#include "sendmail.h" #define RESCAN "disorder-rescan" #define DEADLOCK "disorder-deadlock" @@ -508,8 +509,13 @@ void trackdb_close(void) { /* generic db routines *******************************************************/ -/* fetch and decode a database entry. Returns 0, DB_NOTFOUND or - * DB_LOCK_DEADLOCK. */ +/** @brief Fetch and decode a database entry + * @param db Database + * @param track Track name + * @param kp Where to put decoded list (or NULL if you don't care) + * @param tid Owning transaction + * @return 0, @c DB_NOTFOUND or @c DB_LOCK_DEADLOCK + */ int trackdb_getdata(DB *db, const char *track, struct kvp **kp, @@ -520,10 +526,12 @@ int trackdb_getdata(DB *db, switch(err = db->get(db, tid, make_key(&key, track), prepare_data(&data), 0)) { case 0: - *kp = kvp_urldecode(data.data, data.size); + if(kp) + *kp = kvp_urldecode(data.data, data.size); return 0; case DB_NOTFOUND: - *kp = 0; + if(kp) + *kp = 0; return err; case DB_LOCK_DEADLOCK: error(0, "error querying database: %s", db_strerror(err)); @@ -1852,7 +1860,7 @@ static int do_list(struct vector *v, const char *dir, char *ptr; int err; size_t l, last_dir_len = 0; - char *last_dir = 0, *track, *alias; + char *last_dir = 0, *track; struct kvp *p; dl = strlen(dir); @@ -1885,12 +1893,35 @@ static int do_list(struct vector *v, const char *dir, if((err = trackdb_getdata(trackdb_prefsdb, track, &p, tid)) == DB_LOCK_DEADLOCK) goto deadlocked; + /* There's an awkward question here... + * + * If a track shares a directory with its alias then we could + * do one of three things: + * - report both. Looks ridiculuous in most UIs. + * - report just the alias. Remarkably inconvenient to write + * UI code for! + * - report just the real name. Ugly if the UI doesn't prettify + * names via the name parts. + */ +#if 1 + /* If this file is an alias for a track in the same directory then we + * skip it */ + struct kvp *t = kvp_urldecode(d.data, d.size); + const char *alias_target = kvp_get(t, "_alias_for"); + if(!(alias_target + && !strcmp(d_dirname(alias_target), + d_dirname(track)))) + if(track_matches(dl, k.data, k.size, re)) + vector_append(v, track); +#else /* if this file has an alias in the same directory then we skip it */ + char *alias; if((err = compute_alias(&alias, track, p, tid))) goto deadlocked; if(!(alias && !strcmp(d_dirname(alias), d_dirname(track)))) if(track_matches(dl, k.data, k.size, re)) vector_append(v, track); +#endif } } err = cursor->c_get(cursor, &k, &d, DB_NEXT); @@ -2383,9 +2414,6 @@ char **trackdb_new(int *ntracksp, * @return null-terminated array of track names, or NULL on deadlock * * The most recently added track is first in the array. - * - * TODO: exclude tracks that have been deleted again. - * */ static char **trackdb_new_tid(int *ntracksp, int maxtracks, @@ -2394,12 +2422,24 @@ static char **trackdb_new_tid(int *ntracksp, DBT k, d; int err = 0; struct vector tracks[1]; + hash *h = hash_new(1); vector_init(tracks); c = trackdb_opencursor(trackdb_noticeddb, tid); while((maxtracks <= 0 || tracks->nvec < maxtracks) - && !(err = c->c_get(c, prepare_data(&k), prepare_data(&d), DB_PREV))) - vector_append(tracks, xstrndup(d.data, d.size)); + && !(err = c->c_get(c, prepare_data(&k), prepare_data(&d), DB_PREV))) { + char *const track = xstrndup(d.data, d.size); + /* Don't add any track more than once */ + if(hash_add(h, track, "", HASH_INSERT)) + continue; + /* See if the track still exists */ + err = trackdb_getdata(trackdb_tracksdb, track, NULL/*kp*/, tid); + if(err == DB_NOTFOUND) + continue; /* It doesn't, skip it */ + if(err == DB_LOCK_DEADLOCK) + break; /* Doh */ + vector_append(tracks, track); + } switch(err) { case 0: /* hit maxtracks */ case DB_NOTFOUND: /* ran out of tracks */ @@ -2761,8 +2801,8 @@ int trackdb_edituserinfo(const char *user, } } else if(!strcmp(key, "email")) { if(*value) { - if(!strchr(value, '@')) { - error(0, "invalid email address '%s' for user '%s'", user, value); + if(!email_valid(value)) { + error(0, "invalid email address '%s' for user '%s'", value, user); return -1; } } else diff --git a/scripts/setup.in b/scripts/setup.in index 48f87c2..68d9a4a 100755 --- a/scripts/setup.in +++ b/scripts/setup.in @@ -151,23 +151,31 @@ if [ -z "$roots" ]; then echo "(enter one or more directories separated by spaces)" read -r roots ok=true + anyroots=false for root in $roots; do if [ ! -d $root ]; then echo "'$root' does not exist" ok=false + else + anyroots=true fi done - if $ok; then + if $anyroots && $ok; then break fi done fi if [ -z "$encoding" ]; then - echo - echo "What filesystem encoding should I assume for track names?" - echo "(e.g. UTF-8, ISO-8859-1, ...)" - read -r encoding + while :; do + echo + echo "What filesystem encoding should I assume for track names?" + echo "(e.g. UTF-8, ISO-8859-1, ...)" + read -r encoding + if [ ! -z "$encoding" ]; then + break + fi + done fi if [ -z "$port" ]; then @@ -180,7 +188,7 @@ if [ -z "$port" ]; then none ) break ;; - [^0-9] ) + [^0-9] | "" ) echo "'$port' is not a valid port number" continue ;; @@ -225,7 +233,7 @@ if [ "x$play" = xnetwork ]; then none ) break ;; - [^0-9] ) + [^0-9] | "" ) echo "'$mcast_port' is not a valid port number" continue ;; @@ -269,7 +277,7 @@ fi echo echo "Proposed DisOrder setup:" echo " Music directory: $roots" -if [ $port = none ]; then +if [ "$port" = none ]; then echo " Do not listen on a TCP port" else echo " TCP port to listen on: $port" diff --git a/server/server.c b/server/server.c index ad3a7ab..c4c889a 100644 --- a/server/server.c +++ b/server/server.c @@ -1426,9 +1426,8 @@ static int c_reminder(struct conn *c, sink_writes(ev_writer_sink(c->w), "550 Cannot send a reminder email\n"); return 1; } - /* TODO use email_valid() */ if(!(email = kvp_get(k, "email")) - || !strchr(email, '@')) { + || !email_valid(email)) { error(0, "user '%s' has no valid email address", vec[0]); sink_writes(ev_writer_sink(c->w), "550 Cannot send a reminder email\n"); return 1; diff --git a/server/speaker-alsa.c b/server/speaker-alsa.c index 41e53b2..21a9a75 100644 --- a/server/speaker-alsa.c +++ b/server/speaker-alsa.c @@ -49,7 +49,6 @@ static void alsa_init(void) { static void log_params(snd_pcm_hw_params_t *hwparams, snd_pcm_sw_params_t *swparams) { snd_pcm_uframes_t f; - unsigned u; return; /* too verbose */ if(hwparams) { @@ -60,14 +59,22 @@ static void log_params(snd_pcm_hw_params_t *hwparams, info("sw silence_size=%lu", (unsigned long)f); snd_pcm_sw_params_get_silence_threshold(swparams, &f); info("sw silence_threshold=%lu", (unsigned long)f); - snd_pcm_sw_params_get_sleep_min(swparams, &u); - info("sw sleep_min=%lu", (unsigned long)u); +#if HAVE_SND_PCM_SW_PARAMS_GET_SLEEP_MIN + { + unsigned u; + + snd_pcm_sw_params_get_sleep_min(swparams, &u); + info("sw sleep_min=%lu", (unsigned long)u); + } +#endif snd_pcm_sw_params_get_start_threshold(swparams, &f); info("sw start_threshold=%lu", (unsigned long)f); snd_pcm_sw_params_get_stop_threshold(swparams, &f); info("sw stop_threshold=%lu", (unsigned long)f); +#if HAVE_SND_PCM_SW_PARAMS_GET_XFER_ALIGN snd_pcm_sw_params_get_xfer_align(swparams, &f); info("sw xfer_align=%lu", (unsigned long)f); +#endif } } diff --git a/templates/choose.tmpl b/templates/choose.tmpl index 4c2547b..11d0e95 100644 --- a/templates/choose.tmpl +++ b/templates/choose.tmpl @@ -167,7 +167,7 @@ USA

- @display + @quote{@display}

}
@@ -191,7 +191,7 @@ USA }@# - @display + @quote{@display} @if{@eq{@trackstate{@track}}{playing}} {[playing]} diff --git a/tests/Makefile.am b/tests/Makefile.am index 9358b19..e8e8507 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -22,8 +22,8 @@ noinst_PROGRAMS=disorder-udplog AM_CPPFLAGS=-I${top_srcdir}/lib -I../lib -disorder_udplog_SOURCES=udplog.c -disorder_udplog_LDADD=$(LIBOBJS) ../lib/libdisorder.a +disorder_udplog_SOURCES=udplog.c ../lib/memgc.c +disorder_udplog_LDADD=$(LIBOBJS) ../lib/libdisorder.a $(LIBGC) disorder_udplog_DEPENDENCIES=../lib/libdisorder.a TESTS=cookie.py dbversion.py dump.py files.py play.py queue.py \