chiark / gitweb /
correct eclient for new hashes
[disorder] / lib / eclient.c
index d12cf2b9ffc2336d1458888245edd5482d4a8222..3faf2592efbff0e8d06795f232cd462e84db195f 100644 (file)
@@ -249,6 +249,9 @@ void disorder_eclient_close(disorder_eclient *c) {
   /* We'll need to resend all operations */
   for(op = c->ops; op; op = op->next)
     op->sent = 0;
+  /* Drop our use a hint that we're disconnected */
+  if(c->log_callbacks && c->log_callbacks->state)
+    c->log_callbacks->state(c->log_v, c->statebits);
 }
 
 /** @brief Return current state */
@@ -488,6 +491,8 @@ static void maybe_connected(disorder_eclient *c) {
     c->state = state_connected;
     byte_xasprintf(&r, "connected to %s", c->ident);
     c->callbacks->report(c->u, r);
+    /* If this is a log client we expect to get a bunch of updates from the
+     * server straight away */
   }
 }
 
@@ -498,16 +503,31 @@ static void authbanner_opcallback(disorder_eclient *c,
   size_t nonce_len;
   const unsigned char *nonce;
   const char *res;
+  char **rvec;
+  int nrvec;
+  const char *algo = "SHA1";
   
   D(("authbanner_opcallback"));
-  if(c->rc / 100 != 2) {
-    /* Banner told us to go away.  We cannot proceed. */
+  if(c->rc / 100 != 2
+     || !(rvec = split(c->line + 4, &nrvec, SPLIT_QUOTES, 0, 0))
+     || nrvec < 1) {
+    /* Banner told us to go away, or was malformed.  We cannot proceed. */
     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
     disorder_eclient_close(c);
     return;
   }
-  nonce = unhex(c->line +  4, &nonce_len);
-  res = authhash(nonce, nonce_len, config->password);
+  if(nrvec > 1) {
+    algo = *rvec++;
+    --nrvec;
+  }
+  nonce = unhex(rvec[0], &nonce_len);
+  res = authhash(nonce, nonce_len, config->password, algo);
+  if(!res) {
+    protocol_error(c, op, c->rc, "%s: unknown authentication algorithm '%s'",
+                   c->ident, algo);
+    disorder_eclient_close(c);
+    return;
+  }
   stash_command(c, 1/*queuejump*/, authuser_opcallback, 0/*completed*/, 0/*v*/,
                 "user", quoteutf8(config->username), quoteutf8(res),
                 (char *)0);
@@ -1146,6 +1166,9 @@ int disorder_eclient_nop(disorder_eclient *c,
  * Once a client is being used for logging it cannot be used for anything else.
  * There is magic in authuser_opcallback() to re-submit the @c log command
  * after reconnection.
+ *
+ * NB that the @c state callback may be called from within this function,
+ * i.e. not solely later on from the event loop callback.
  */
 int disorder_eclient_log(disorder_eclient *c,
                          const disorder_eclient_log_callbacks *callbacks,
@@ -1153,6 +1176,9 @@ int disorder_eclient_log(disorder_eclient *c,
   if(c->log_callbacks) return -1;
   c->log_callbacks = callbacks;
   c->log_v = v;
+  /* Repoort initial state */
+  if(c->log_callbacks->state)
+    c->log_callbacks->state(c->log_v, c->statebits);
   stash_command(c, 0/*queuejump*/, log_opcallback, 0/*completed*/, v,
                 "log", (char *)0);
   return 0;
@@ -1178,7 +1204,7 @@ static void logline(disorder_eclient *c, const char *line) {
   char **vec;
   uintmax_t when;
 
-  D(("log_opcallback [%s]", line));
+  D(("logline [%s]", line));
   vec = split(line, &nvec, SPLIT_QUOTES, logline_error, c);
   if(nvec < 2) return;                  /* probably an error, already
                                          * reported */
@@ -1281,18 +1307,21 @@ static const struct {
   { DISORDER_PLAYING_ENABLED, "enable_play", "disable_play" },
   { DISORDER_RANDOM_ENABLED, "enable_random", "disable_random" },
   { DISORDER_TRACK_PAUSED, "pause", "resume" },
+  { DISORDER_PLAYING, "playing", "completed" },
+  { DISORDER_PLAYING, 0, "scratched" },
+  { DISORDER_PLAYING, 0, "failed" },
 };
-#define NSTATES (int)(sizeof states / sizeof *states)
+#define NSTATES (int)(sizeof statestrings / sizeof *statestrings)
 
 static void logentry_state(disorder_eclient *c,
                            int attribute((unused)) nvec, char **vec) {
   int n;
 
   for(n = 0; n < NSTATES; ++n)
-    if(!strcmp(vec[0], statestrings[n].enable)) {
+    if(statestrings[n].enable && !strcmp(vec[0], statestrings[n].enable)) {
       c->statebits |= statestrings[n].bit;
       break;
-    } else if(!strcmp(vec[0], statestrings[n].disable)) {
+    } else if(statestrings[n].disable && !strcmp(vec[0], statestrings[n].disable)) {
       c->statebits &= ~statestrings[n].bit;
       break;
     }
@@ -1331,6 +1360,8 @@ char *disorder_eclient_interpret_state(unsigned long statebits) {
 #define NBITS (sizeof bits / sizeof *bits)
 
   dynstr_init(d);
+  if(!statebits)
+    dynstr_append(d, '0');
   for(n = 0; n < NBITS; ++n)
     if(statebits & bits[n].bit) {
       if(d->nvec)