X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/blobdiff_plain/2563dc1f46fad1640e2472151a9f1cf918f841b9..2e9ba080dd30434f3e8f88e63029280889586a32:/lib/trackdb-playlists.c diff --git a/lib/trackdb-playlists.c b/lib/trackdb-playlists.c index 1492f8c..fd33393 100644 --- a/lib/trackdb-playlists.c +++ b/lib/trackdb-playlists.c @@ -32,6 +32,7 @@ #include "log.h" #include "configuration.h" #include "vector.h" +#include "eventlog.h" static int trackdb_playlist_get_tid(const char *name, const char *who, @@ -81,7 +82,7 @@ int playlist_parse_name(const char *name, if(!valid_username(name)) return -1; owner = 0; - share = "public"; + share = "shared"; } if(ownerp) *ownerp = owner; @@ -100,7 +101,7 @@ static int playlist_may_read(const char *name, const char *share) { char *owner; - if(!playlist_parse_name(name, &owner, 0)) + if(playlist_parse_name(name, &owner, 0)) return 0; /* Anyone can read shared playlists */ if(!owner) @@ -125,7 +126,7 @@ static int playlist_may_write(const char *name, const char attribute((unused)) *share) { char *owner; - if(!playlist_parse_name(name, &owner, 0)) + if(playlist_parse_name(name, &owner, 0)) return 0; /* Anyone can modify shared playlists */ if(!owner) @@ -147,7 +148,7 @@ static int playlist_may_write(const char *name, * * Possible return values: * - @c 0 on success - * - @c DB_NOTFOUND if the playlist doesn't exist + * - @c ENOENT if the playlist doesn't exist * - @c EINVAL if the playlist name is invalid * - @c EACCES if the playlist cannot be read by @p who */ @@ -158,13 +159,16 @@ int trackdb_playlist_get(const char *name, char **sharep) { int e; - if(!playlist_parse_name(name, 0, 0)) { - error(0, "invalid playlist name '%s'", name); + if(playlist_parse_name(name, 0, 0)) { + disorder_error(0, "invalid playlist name '%s'", name); return EINVAL; } WITH_TRANSACTION(trackdb_playlist_get_tid(name, who, tracksp, ntracksp, sharep, tid)); + /* Don't expose libdb error codes too much */ + if(e == DB_NOTFOUND) + e = ENOENT; return e; } @@ -182,7 +186,7 @@ static int trackdb_playlist_get_tid(const char *name, return e; /* Get sharability */ if(!(s = kvp_get(k, "sharing"))) { - error(0, "playlist '%s' has no 'sharing' key", name); + disorder_error(0, "playlist '%s' has no 'sharing' key", name); s = "private"; } /* Check the read is allowed */ @@ -193,12 +197,12 @@ static int trackdb_playlist_get_tid(const char *name, *sharep = xstrdup(s); /* Get track count */ if(!(s = kvp_get(k, "count"))) { - error(0, "playlist '%s' has no 'count' key", name); + disorder_error(0, "playlist '%s' has no 'count' key", name); s = "0"; } ntracks = atoi(s); if(ntracks < 0) { - error(0, "playlist '%s' has negative count", name); + disorder_error(0, "playlist '%s' has negative count", name); ntracks = 0; } /* Return track count */ @@ -212,7 +216,7 @@ static int trackdb_playlist_get_tid(const char *name, for(int n = 0; n < ntracks; ++n) { snprintf(b, sizeof b, "%d", n); if(!(s = kvp_get(k, b))) { - error(0, "playlist '%s' lacks track %d", name, n); + disorder_error(0, "playlist '%s' lacks track %d", name, n); s = "unknown"; } tracks[n] = xstrdup(s); @@ -226,6 +230,7 @@ static int trackdb_playlist_get_tid(const char *name, /** @brief Modify or create a playlist * @param name Playlist name + * @param who User modifying playlist * @param tracks List of tracks to set, or NULL to leave alone * @param ntracks Length of @p tracks * @param share Sharing status, or NULL to leave alone @@ -237,6 +242,10 @@ static int trackdb_playlist_get_tid(const char *name, * none, and the default sharing is private (if it is an owned one) or shared * (otherwise). * + * If neither @c tracks nor @c share are set then we only do an access check. + * The database is never modified (even to create the playlist) in this + * situation. + * * Possible return values: * - @c 0 on success * - @c EINVAL if the playlist name is invalid @@ -250,8 +259,8 @@ int trackdb_playlist_set(const char *name, int e; char *owner; - if(!playlist_parse_name(name, &owner, 0)) { - error(0, "invalid playlist name '%s'", name); + if(playlist_parse_name(name, &owner, 0)) { + disorder_error(0, "invalid playlist name '%s'", name); return EINVAL; } /* Check valid share types */ @@ -260,13 +269,13 @@ int trackdb_playlist_set(const char *name, /* Playlists with an owner must be public or private */ if(strcmp(share, "public") && strcmp(share, "private")) { - error(0, "playlist '%s' must be public or private", name); + disorder_error(0, "playlist '%s' must be public or private", name); return EINVAL; } } else { /* Playlists with no owner must be shared */ if(strcmp(share, "shared")) { - error(0, "playlist '%s' must be shared", name); + disorder_error(0, "playlist '%s' must be shared", name); return EINVAL; } } @@ -286,6 +295,7 @@ static int trackdb_playlist_set_tid(const char *name, struct kvp *k; int e; const char *s; + const char *event = "playlist_modified"; if((e = trackdb_getdata(trackdb_playlistsdb, name, &k, tid)) && e != DB_NOTFOUND) @@ -304,24 +314,28 @@ static int trackdb_playlist_set_tid(const char *name, k = 0; kvp_set(&k, "count", 0); kvp_set(&k, "sharing", defshare); + event = "playlist_created"; } /* Check that the modification is allowed */ if(!(s = kvp_get(k, "sharing"))) { - error(0, "playlist '%s' has no 'sharing' key", name); + disorder_error(0, "playlist '%s' has no 'sharing' key", name); s = "private"; } if(!playlist_may_write(name, who, s)) return EACCES; + /* If no change was requested then don't even create */ + if(!share && !tracks) + return 0; /* Set the new values */ if(share) - kvp_set(&k, "share", share); + kvp_set(&k, "sharing", share); if(tracks) { char b[16]; int oldcount, n; /* Sanity check track count */ if(ntracks < 0 || ntracks > config->playlist_max) { - error(0, "invalid track count %d", ntracks); + disorder_error(0, "invalid track count %d", ntracks); return EINVAL; } /* Set the tracks */ @@ -344,7 +358,11 @@ static int trackdb_playlist_set_tid(const char *name, kvp_set(&k, "count", b); } /* Store the resulting record */ - return trackdb_putdata(trackdb_playlistsdb, name, k, tid, 0); + e = trackdb_putdata(trackdb_playlistsdb, name, k, tid, 0); + /* Log the event */ + if(!e) + eventlog(event, name, kvp_get(k, "sharing"), (char *)0); + return e; } /** @brief Get a list of playlists @@ -376,11 +394,15 @@ static int trackdb_playlist_list_tid(const char *who, while(!(e = c->c_get(c, k, prepare_data(d), DB_NEXT))) { char *name = xstrndup(k->data, k->size), *owner; const char *share = kvp_get(kvp_urldecode(d->data, d->size), - "share"); + "sharing"); /* Extract owner; malformed names are skipped */ if(playlist_parse_name(name, &owner, 0)) { - error(0, "invalid playlist name '%s' found in database", name); + disorder_error(0, "invalid playlist name '%s' found in database", name); + continue; + } + if(!share) { + disorder_error(0, "playlist '%s' has no 'sharing' key", name); continue; } /* Always list public and shared playlists @@ -393,13 +415,14 @@ static int trackdb_playlist_list_tid(const char *who, && owner && !strcmp(owner, who))) vector_append(v, name); } + trackdb_closecursor(c); switch(e) { case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: return e; default: - fatal(0, "c->c_get: %s", db_strerror(e)); + disorder_fatal(0, "c->c_get: %s", db_strerror(e)); } vector_terminate(v); if(playlistsp) @@ -418,19 +441,21 @@ static int trackdb_playlist_list_tid(const char *who, * - @c 0 on success * - @c EINVAL if the playlist name is invalid * - @c EACCES if the playlist cannot be modified by @p who - * - @c DB_NOTFOUND if the playlist doesn't exist + * - @c ENOENT if the playlist doesn't exist */ int trackdb_playlist_delete(const char *name, const char *who) { int e; char *owner; - if(!playlist_parse_name(name, &owner, 0)) { - error(0, "invalid playlist name '%s'", name); + if(playlist_parse_name(name, &owner, 0)) { + disorder_error(0, "invalid playlist name '%s'", name); return EINVAL; } /* We've checked as much as we can for now, now go and attempt the change */ WITH_TRANSACTION(trackdb_playlist_delete_tid(name, who, tid)); + if(e == DB_NOTFOUND) + e = ENOENT; return e; } @@ -445,13 +470,16 @@ static int trackdb_playlist_delete_tid(const char *name, return e; /* Check that modification is allowed */ if(!(s = kvp_get(k, "sharing"))) { - error(0, "playlist '%s' has no 'sharing' key", name); + disorder_error(0, "playlist '%s' has no 'sharing' key", name); s = "private"; } if(!playlist_may_write(name, who, s)) return EACCES; /* Delete the playlist */ - return trackdb_delkey(trackdb_playlistsdb, name, tid); + e = trackdb_delkey(trackdb_playlistsdb, name, tid); + if(!e) + eventlog("playlist_deleted", name, 0); + return e; } /*