/* 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 */
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 */
}
}
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);
* 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,
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;
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 */
{ 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;
}
#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)