chiark / gitweb /
add "users" command
authorRichard Kettlewell <rjk@greenend.org.uk>
Thu, 20 Dec 2007 18:45:44 +0000 (18:45 +0000)
committerRichard Kettlewell <rjk@greenend.org.uk>
Thu, 20 Dec 2007 18:45:44 +0000 (18:45 +0000)
clients/disorder.c
lib/client.c
lib/client.h
lib/trackdb-int.h
lib/trackdb.c
lib/trackdb.h
python/disorder.py.in
scripts/completion.bash
server/server.c
tests/user.py

index 7d15afe..9402340 100644 (file)
@@ -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" },
 };
index 8184306..4fd2f48 100644 (file)
@@ -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
index 64f58b8..c81129d 100644 (file)
@@ -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 */
 
index 1d31cfe..9ec328e 100644 (file)
@@ -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;
index 90d9457..c57dab2 100644 (file)
@@ -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
index a136537..2c57e86 100644 (file)
@@ -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 */
 
index 325599b..9a6b385 100644 (file)
@@ -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
 
index 3c13c29..437165c 100644 (file)
@@ -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
index 6591d91..6392e89 100644 (file)
@@ -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 }
 };
index 13bee66..345fdef 100755 (executable)
@@ -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()