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;
"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" },
};
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
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 */
#ifndef TRACKDB_INT_H
#define TRACKDB_INT_H
+struct vector; /* forward declaration */
+
extern DB_ENV *trackdb_env;
extern DB *trackdb_tracksdb;
* 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;
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);
/* 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;
}
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
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 */
"""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
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
}
sink_writes(ev_writer_sink(c->w), ".\n");
return 1; /* completed */
-
}
static int c_set_global(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 */
{ "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 }
};
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()
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()