From: Richard Kettlewell Date: Thu, 20 Dec 2007 18:45:44 +0000 (+0000) Subject: add "users" command X-Git-Tag: 3.0~198 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/disorder/commitdiff_plain/c3be4f19f3d6465ff4c1110a1a7e7a0686f8dc37 add "users" command --- diff --git a/clients/disorder.c b/clients/disorder.c index 7d15afe..9402340 100644 --- a/clients/disorder.c +++ b/clients/disorder.c @@ -369,6 +369,15 @@ static void cf_tags(disorder_client *c, xprintf("%s\n", nullcheck(utf82mb(*vec++))); } +static void cf_users(disorder_client *c, + char attribute((unused)) **argv) { + char **vec; + + if(disorder_users(c, &vec, 0)) exit(EXIT_FAILURE); + while(*vec) + xprintf("%s\n", nullcheck(utf82mb(*vec++))); +} + static void cf_get_global(disorder_client *c, char **argv) { char *value; @@ -512,6 +521,8 @@ static const struct command { "Unset a preference" }, { "unset-global", 1, 1, cf_unset_global, 0, "NAME", "Unset a global preference" }, + { "users", 0, 0, cf_users, 0, "", + "List all users" }, { "version", 0, 0, cf_version, 0, "", "Display the server version" }, }; diff --git a/lib/client.c b/lib/client.c index 8184306..4fd2f48 100644 --- a/lib/client.c +++ b/lib/client.c @@ -605,6 +605,11 @@ int disorder_tags(disorder_client *c, return disorder_simple_list(c, vecp, nvecp, "tags", (char *)0); } +int disorder_users(disorder_client *c, + char ***vecp, int *nvecp) { + return disorder_simple_list(c, vecp, nvecp, "users", (char *)0); +} + /** @brief Get recentl added tracks * @param c Client * @param vecp Where to store pointer to list diff --git a/lib/client.h b/lib/client.h index 64f58b8..c81129d 100644 --- a/lib/client.h +++ b/lib/client.h @@ -194,6 +194,8 @@ int disorder_deluser(disorder_client *c, const char *user); int disorder_userinfo(disorder_client *c, const char *user, const char *key); int disorder_edituser(disorder_client *c, const char *user, const char *key, const char *value); +int disorder_users(disorder_client *c, + char ***vecp, int *nvecp); #endif /* CLIENT_H */ diff --git a/lib/trackdb-int.h b/lib/trackdb-int.h index 1d31cfe..9ec328e 100644 --- a/lib/trackdb-int.h +++ b/lib/trackdb-int.h @@ -21,6 +21,8 @@ #ifndef TRACKDB_INT_H #define TRACKDB_INT_H +struct vector; /* forward declaration */ + extern DB_ENV *trackdb_env; extern DB *trackdb_tracksdb; @@ -108,8 +110,9 @@ int trackdb_scan(const char *root, * 0). Return 0 or DB_LOCK_DEADLOCK. CALLBACK should return 0 on success or * EINTR to cancel the scan. */ -/* fill KEY in with S, returns KEY */ +int trackdb_listkeys(DB *db, struct vector *v, DB_TXN *tid); +/* fill KEY in with S, returns KEY */ static inline DBT *make_key(DBT *key, const char *s) { memset(key, 0, sizeof *key); key->data = (void *)s; diff --git a/lib/trackdb.c b/lib/trackdb.c index 90d9457..c57dab2 100644 --- a/lib/trackdb.c +++ b/lib/trackdb.c @@ -74,7 +74,6 @@ static const char *getpart(const char *track, const char *part, const struct kvp *p, int *used_db); -static int trackdb_alltags_tid(DB_TXN *tid, char ***taglistp); static char **trackdb_new_tid(int *ntracksp, int maxtracks, DB_TXN *tid); @@ -1521,42 +1520,39 @@ fail: /* return the list of tags */ char **trackdb_alltags(void) { - DB_TXN *tid; - int err; - char **taglist; + int e; + struct vector v[1]; - for(;;) { - tid = trackdb_begin_transaction(); - err = trackdb_alltags_tid(tid, &taglist); - if(!err) break; - trackdb_abort_transaction(tid); - } - trackdb_commit_transaction(tid); - return taglist; + WITH_TRANSACTION(trackdb_listkeys(trackdb_tagsdb, v, tid)); + return v->vec; } -static int trackdb_alltags_tid(DB_TXN *tid, char ***taglistp) { - struct vector v; - DBC *c; +/** @brief List all the keys in @p db + * @param db Database + * @param v Vector to store keys in + * @param tid Transaction ID + * @return 0 or DB_LOCK_DEADLOCK + */ +int trackdb_listkeys(DB *db, struct vector *v, DB_TXN *tid) { + int e; DBT k, d; - int err; + DBC *const c = trackdb_opencursor(db, tid); - vector_init(&v); - c = trackdb_opencursor(trackdb_tagsdb, tid); + v->nvec = 0; memset(&k, 0, sizeof k); - while(!(err = c->c_get(c, &k, prepare_data(&d), DB_NEXT_NODUP))) - vector_append(&v, xstrndup(k.data, k.size)); - switch(err) { + while(!(e = c->c_get(c, &k, prepare_data(&d), DB_NEXT_NODUP))) + vector_append(v, xstrndup(k.data, k.size)); + switch(e) { case DB_NOTFOUND: break; case DB_LOCK_DEADLOCK: - return err; + return e; default: - fatal(0, "c->c_get: %s", db_strerror(err)); + fatal(0, "c->c_get: %s", db_strerror(e)); } - if((err = trackdb_closecursor(c))) return err; - vector_terminate(&v); - *taglistp = v.vec; + if((e = trackdb_closecursor(c))) + return e; + vector_terminate(v); return 0; } @@ -2658,6 +2654,18 @@ int trackdb_edituserinfo(const char *user, return 0; } +/** @brief List all users + * @return NULL-terminated list of users + */ +char **trackdb_listusers(void) { + int e; + struct vector v[1]; + + vector_init(v); + WITH_TRANSACTION(trackdb_listkeys(trackdb_usersdb, v, tid)); + return v->vec; +} + /* Local Variables: c-basic-offset:2 diff --git a/lib/trackdb.h b/lib/trackdb.h index a136537..2c57e86 100644 --- a/lib/trackdb.h +++ b/lib/trackdb.h @@ -167,6 +167,7 @@ int trackdb_deluser(const char *user); struct kvp *trackdb_getuserinfo(const char *user); int trackdb_edituserinfo(const char *user, const char *key, const char *value); +char **trackdb_listusers(void); #endif /* TRACKDB_H */ diff --git a/python/disorder.py.in b/python/disorder.py.in index 325599b..9a6b385 100644 --- a/python/disorder.py.in +++ b/python/disorder.py.in @@ -879,6 +879,13 @@ class client: """Set user information""" self._simple("edituser", user, key, value) + def users(self): + """List all users + + The return value is a list of all users.""" + self._simple("users") + return self._body() + ######################################################################## # I/O infrastructure diff --git a/scripts/completion.bash b/scripts/completion.bash index 3c13c29..437165c 100644 --- a/scripts/completion.bash +++ b/scripts/completion.bash @@ -31,7 +31,7 @@ complete -o default \ random-enable recent reconfigure remove rescan scratch search set set-volume shutdown stats unset version resolve part pause resume scratch-id get-global set-global unset-global - tags new rtp-address adduser + tags new rtp-address adduser users -h --help -H --help-commands --version -V --config -c --length --debug -d" \ disorder diff --git a/server/server.c b/server/server.c index 6591d91..6392e89 100644 --- a/server/server.c +++ b/server/server.c @@ -912,7 +912,6 @@ static int c_tags(struct conn *c, } sink_writes(ev_writer_sink(c->w), ".\n"); return 1; /* completed */ - } static int c_set_global(struct conn *c, @@ -1090,6 +1089,22 @@ static int c_userinfo(struct conn *c, return 1; } +static int c_users(struct conn *c, + char attribute((unused)) **vec, + int attribute((unused)) nvec) { + /* TODO de-dupe with c_tags */ + char **users = trackdb_listusers(); + + sink_writes(ev_writer_sink(c->w), "253 User list follows\n"); + while(*users) { + sink_printf(ev_writer_sink(c->w), "%s%s\n", + **users == '.' ? "." : "", *users); + ++users; + } + sink_writes(ev_writer_sink(c->w), ".\n"); + return 1; /* completed */ +} + #define C_AUTH 0001 /* must be authenticated */ #define C_TRUSTED 0002 /* must be trusted user */ @@ -1148,6 +1163,7 @@ static const struct command { { "unset-global", 1, 1, c_set_global, C_AUTH }, { "user", 2, 2, c_user, 0 }, { "userinfo", 2, 2, c_userinfo, C_AUTH }, + { "users", 0, 0, c_users, C_AUTH }, { "version", 0, 0, c_version, C_AUTH }, { "volume", 0, 2, c_volume, C_AUTH } }; diff --git a/tests/user.py b/tests/user.py index 13bee66..345fdef 100755 --- a/tests/user.py +++ b/tests/user.py @@ -27,6 +27,9 @@ def test(): print " checking user creation" c = disorder.client() c.adduser("bob", "bobpass") + users = c.users() + assert dtest.lists_have_same_contents(users, + ["fred", "bob", "root"]) print " checking new user can log in" c = disorder.client(user="bob", password="bobpass") c.version() @@ -46,6 +49,10 @@ def test(): except disorder.operationError: pass # good print " deleted user could no longer log in." + c = disorder.client() + users = c.users() + assert dtest.lists_have_same_contents(users, + ["fred", "root"]) if __name__ == '__main__': dtest.run()