chiark / gitweb /
make client.c return status code on error
[disorder] / lib / eclient.c
index 2bf86e9dff3192863aa72212c2dced66b7e1c733..0037fb5d362d352449bbb34cb5ff3105eb2fda2c 100644 (file)
@@ -114,7 +114,7 @@ struct operation {
 
 /** @brief Client structure */
 struct disorder_eclient {
-  const char *ident;
+  char *ident;
   int fd;                               /**< @brief connection to server */
   enum client_state state;              /**< @brief current state */
   int authenticated;                    /**< @brief true when authenicated */
@@ -150,15 +150,8 @@ struct disorder_eclient {
 
 /* Forward declarations ******************************************************/
 
-static int start_connect(void *cc,
-                        const struct sockaddr *sa,
-                        socklen_t len,
-                        const char *ident);
+static int start_connect(disorder_eclient *c);
 static void process_line(disorder_eclient *c, char *line);
-static int start_connect(void *cc,
-                        const struct sockaddr *sa,
-                        socklen_t len,
-                        const char *ident);
 static void maybe_connected(disorder_eclient *c);
 static void authbanner_opcallback(disorder_eclient *c,
                                   struct operation *op);
@@ -341,7 +334,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) {
       comms_error(c, "no password is configured");
       return;
     }
-    with_sockaddr(c, start_connect);
+    start_connect(c);
     /* might now be state_disconnected (on error), state_connecting (slow
      * connect) or state_connected (fast connect).  If state_disconnected then
      * we just rely on a periodic callback from the event loop sometime. */
@@ -467,14 +460,13 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) {
 }
 
 /** @brief Called to start connecting */
-static int start_connect(void *cc,
-                        const struct sockaddr *sa,
-                        socklen_t len,
-                        const char *ident) {
-  disorder_eclient *c = cc;
+static int start_connect(disorder_eclient *c) {
+  struct sockaddr *sa;
+  socklen_t len;
 
   D(("start_connect"));
-  c->ident = xstrdup(ident);
+  if((len = find_server(&sa, &c->ident)) == (socklen_t)-1)
+    return comms_error(c, "cannot look up server"); /* TODO better error */
   if(c->fd != -1) {
     xclose(c->fd);
     c->fd = -1;
@@ -494,7 +486,7 @@ static int start_connect(void *cc,
       return 0;
     default:
       /* Signal the error to the caller. */
-      return comms_error(c, "connecting to %s: %s", ident, strerror(errno));
+      return comms_error(c, "connecting to %s: %s", c->ident, strerror(errno));
     }
   } else
     c->state = state_connected;
@@ -536,7 +528,7 @@ static void authbanner_opcallback(disorder_eclient *c,
   const char *res;
   char **rvec;
   int nrvec;
-  const char *algo = "SHA1";
+  const char *protocol, *algorithm, *challenge;
   
   D(("authbanner_opcallback"));
   if(c->rc / 100 != 2
@@ -547,15 +539,22 @@ static void authbanner_opcallback(disorder_eclient *c,
     disorder_eclient_close(c);
     return;
   }
-  if(nrvec > 1) {
-    algo = *rvec++;
-    --nrvec;
+  if(nrvec != 3) {
+    protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
+    disorder_eclient_close(c);
+  }
+  protocol = *rvec++;
+  algorithm = *rvec++;
+  challenge = *rvec++;
+  if(strcmp(protocol, "2")) {
+    protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
+    disorder_eclient_close(c);
   }
-  nonce = unhex(rvec[0], &nonce_len);
-  res = authhash(nonce, nonce_len, config->password, algo);
+  nonce = unhex(challenge, &nonce_len);
+  res = authhash(nonce, nonce_len, config->password, algorithm);
   if(!res) {
     protocol_error(c, op, c->rc, "%s: unknown authentication algorithm '%s'",
-                   c->ident, algo);
+                   c->ident, algorithm);
     disorder_eclient_close(c);
     return;
   }
@@ -819,13 +818,19 @@ static void stash_command(disorder_eclient *c,
 
 /* Command support ***********************************************************/
 
-/* for commands with a simple string response */ 
+/* for commands with a quoted string response */ 
 static void string_response_opcallback(disorder_eclient *c,
                                        struct operation *op) {
   D(("string_response_callback"));
   if(c->rc / 100 == 2) {
-    if(op->completed)
-      ((disorder_eclient_string_response *)op->completed)(op->v, c->line + 4);
+    if(op->completed) {
+      char **rr = split(c->line + 4, 0, SPLIT_QUOTES, 0, 0);
+
+      if(rr && *rr)
+        ((disorder_eclient_string_response *)op->completed)(op->v, *rr);
+      else
+        protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
+    }
   } else
     protocol_error(c, op, c->rc, "%s: %s", c->ident, c->line);
 }