chiark / gitweb /
More memory hygeine
[disorder] / lib / client.c
index 5c4cac5af445d0c382012063ac7b7de90bd66004..d9023a985bd3074d1da1d571ca5f0969a19a821f 100644 (file)
@@ -1,21 +1,19 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2004-2008 Richard Kettlewell
+ * Copyright (C) 2004-2009 Richard Kettlewell
  *
- * This program is free software; you can redistribute it and/or modify
+ * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 /** @file lib/client.c
  * @brief Simple C client
@@ -109,7 +107,7 @@ static int response(disorder_client *c, char **rp) {
     return (r[0] * 10 + r[1]) * 10 + r[2] - 111 * '0';
   } else {
     c->last = "invalid reply format";
-    error(0, "invalid reply format from %s", c->ident);
+    disorder_error(0, "invalid reply format from %s", c->ident);
     return -1;
   }
 }
@@ -143,10 +141,12 @@ static int check_response(disorder_client *c, char **rp) {
   else if(rc / 100 == 2) {
     if(rp)
       *rp = (rc % 10 == 9) ? 0 : xstrdup(r + 4);
+    xfree(r);
     return 0;
   } else {
     if(c->verbose)
-      error(0, "from %s: %s", c->ident, utf82mb(r));
+      disorder_error(0, "from %s: %s", c->ident, utf82mb(r));
+    xfree(r);
     return rc;
   }
 }
@@ -187,7 +187,7 @@ static int disorder_simple_v(disorder_client *c,
 
   if(!c->fpout) {
     c->last = "not connected";
-    error(0, "not connected to server");
+    disorder_error(0, "not connected to server");
     return -1;
   }
   if(cmd) {
@@ -202,6 +202,7 @@ static int disorder_simple_v(disorder_client *c,
     D(("command: %s", d.vec));
     if(fputs(d.vec, c->fpout) < 0)
       goto write_error;
+    xfree(d.vec);
     if(body) {
       if(nbody < 0)
         for(nbody = 0; body[nbody]; ++nbody)
@@ -224,7 +225,7 @@ static int disorder_simple_v(disorder_client *c,
   return check_response(c, rp);
 write_error:
   byte_xasprintf((char **)&c->last, "write error: %s", strerror(errno));
-  error(errno, "error writing to %s", c->ident);
+  disorder_error(errno, "error writing to %s", c->ident);
   return -1;
 }
 
@@ -293,10 +294,12 @@ static int dequote(int rc, char **rp) {
 
   if(!rc) {
     if((rr = split(*rp, 0, SPLIT_QUOTES, 0, 0)) && *rr) {
+      xfree(*rp);
       *rp = *rr;
+      xfree(rr);
       return 0;
     }
-    error(0, "invalid reply: %s", *rp);
+    disorder_error(0, "invalid reply: %s", *rp);
   }
   return rc;
 }
@@ -318,13 +321,13 @@ int disorder_connect_generic(struct config *conf,
                              const char *username,
                              const char *password,
                              const char *cookie) {
-  int fd = -1, fd2 = -1, nrvec, rc;
-  unsigned char *nonce;
+  int fd = -1, fd2 = -1, nrvec = 0, rc;
+  unsigned char *nonce = NULL;
   size_t nl;
-  const char *res;
-  char *r, **rvec;
+  char *res = NULL;
+  char *r = NULL, **rvec = NULL;
   const char *protocol, *algorithm, *challenge;
-  struct sockaddr *sa;
+  struct sockaddr *sa = NULL;
   socklen_t salen;
 
   if((salen = find_server(conf, &sa, &c->ident)) == (socklen_t)-1)
@@ -332,28 +335,28 @@ int disorder_connect_generic(struct config *conf,
   c->fpin = c->fpout = 0;
   if((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) {
     byte_xasprintf((char **)&c->last, "socket: %s", strerror(errno));
-    error(errno, "error calling socket");
+    disorder_error(errno, "error calling socket");
     return -1;
   }
   if(connect(fd, sa, salen) < 0) {
     byte_xasprintf((char **)&c->last, "connect: %s", strerror(errno));
-    error(errno, "error calling connect");
+    disorder_error(errno, "error calling connect");
     goto error;
   }
   if((fd2 = dup(fd)) < 0) {
     byte_xasprintf((char **)&c->last, "dup: %s", strerror(errno));
-    error(errno, "error calling dup");
+    disorder_error(errno, "error calling dup");
     goto error;
   }
   if(!(c->fpin = fdopen(fd, "rb"))) {
     byte_xasprintf((char **)&c->last, "fdopen: %s", strerror(errno));
-    error(errno, "error calling fdopen");
+    disorder_error(errno, "error calling fdopen");
     goto error;
   }
   fd = -1;
   if(!(c->fpout = fdopen(fd2, "wb"))) {
     byte_xasprintf((char **)&c->last, "fdopen: %s", strerror(errno));
-    error(errno, "error calling fdopen");
+    disorder_error(errno, "error calling fdopen");
     goto error;
   }
   fd2 = -1;
@@ -363,17 +366,17 @@ int disorder_connect_generic(struct config *conf,
     goto error;
   if(nrvec != 3) {
     c->last = "cannot parse server greeting";
-    error(0, "cannot parse server greeting %s", r);
+    disorder_error(0, "cannot parse server greeting %s", r);
     goto error;
   }
-  protocol = *rvec++;
+  protocol = rvec[0];
   if(strcmp(protocol, "2")) {
     c->last = "unknown protocol version";
-    error(0, "unknown protocol version: %s", protocol);
+    disorder_error(0, "unknown protocol version: %s", protocol);
     goto error;
   }
-  algorithm = *rvec++;
-  challenge = *rvec++;
+  algorithm = rvec[1];
+  challenge = rvec[2];
   if(!(nonce = unhex(challenge, &nl)))
     goto error;
   if(cookie) {
@@ -382,7 +385,7 @@ int disorder_connect_generic(struct config *conf,
       return 0;                                /* success */
     if(!username) {
       c->last = "cookie failed and no username";
-      error(0, "cookie did not work and no username available");
+      disorder_error(0, "cookie did not work and no username available");
       goto error;
     }
   }
@@ -393,6 +396,11 @@ int disorder_connect_generic(struct config *conf,
   if((rc = disorder_simple(c, 0, "user", username, res, (char *)0)))
     goto error_rc;
   c->user = xstrdup(username);
+  xfree(res);
+  free_strings(nrvec, rvec);
+  xfree(nonce);
+  xfree(sa);
+  xfree(r);
   return 0;
 error:
   rc = -1;
@@ -439,7 +447,7 @@ int disorder_connect(disorder_client *c) {
 
   if(!(username = config->username)) {
     c->last = "no username";
-    error(0, "no username configured");
+    disorder_error(0, "no username configured");
     return -1;
   }
   password = config->password;
@@ -453,7 +461,7 @@ int disorder_connect(disorder_client *c) {
   if(!password) {
     /* Oh well */
     c->last = "no password";
-    error(0, "no password configured");
+    disorder_error(0, "no password configured for user '%s'", username);
     return -1;
   }
   return disorder_connect_generic(config,
@@ -494,7 +502,7 @@ int disorder_close(disorder_client *c) {
   if(c->fpin) {
     if(fclose(c->fpin) < 0) {
       byte_xasprintf((char **)&c->last, "fclose: %s", strerror(errno));
-      error(errno, "error calling fclose");
+      disorder_error(errno, "error calling fclose");
       ret = -1;
     }
     c->fpin = 0;
@@ -502,12 +510,14 @@ int disorder_close(disorder_client *c) {
   if(c->fpout) {
     if(fclose(c->fpout) < 0) {
       byte_xasprintf((char **)&c->last, "fclose: %s", strerror(errno));
-      error(errno, "error calling fclose");
+      disorder_error(errno, "error calling fclose");
       ret = -1;
     }
     c->fpout = 0;
   }
+  xfree(c->ident);
   c->ident = 0;
+  xfree(c->user);
   c->user = 0;
   return 0;
 }
@@ -603,7 +613,7 @@ int disorder_version(disorder_client *c, char **rp) {
 
 static void client_error(const char *msg,
                         void attribute((unused)) *u) {
-  error(0, "error parsing reply: %s", msg);
+  disorder_error(0, "error parsing reply: %s", msg);
 }
 
 /** @brief Get currently playing track
@@ -653,10 +663,10 @@ static int disorder_somequeue(disorder_client *c,
   }
   if(ferror(c->fpin)) {
     byte_xasprintf((char **)&c->last, "input error: %s", strerror(errno));
-    error(errno, "error reading %s", c->ident);
+    disorder_error(errno, "error reading %s", c->ident);
   } else {
     c->last = "input error: unexpxected EOF";
-    error(0, "error reading %s: unexpected EOF", c->ident);
+    disorder_error(0, "error reading %s: unexpected EOF", c->ident);
   }
   return -1;
 }
@@ -708,10 +718,10 @@ static int readlist(disorder_client *c, char ***vecp, int *nvecp) {
   }
   if(ferror(c->fpin)) {
     byte_xasprintf((char **)&c->last, "input error: %s", strerror(errno));
-    error(errno, "error reading %s", c->ident);
+    disorder_error(errno, "error reading %s", c->ident);
   } else {
     c->last = "input error: unexpxected EOF";
-    error(0, "error reading %s: unexpected EOF", c->ident);
+    disorder_error(0, "error reading %s: unexpected EOF", c->ident);
   }
   return -1;
 }
@@ -828,7 +838,7 @@ int disorder_get(disorder_client *c,
 
 static void pref_error_handler(const char *msg,
                               void attribute((unused)) *u) {
-  error(0, "error handling 'prefs' reply: %s", msg);
+  disorder_error(0, "error handling 'prefs' reply: %s", msg);
 }
 
 /** @brief Get all preferences for a trcak
@@ -871,7 +881,7 @@ static int boolean(const char *cmd, const char *value,
   if(!strcmp(value, "yes")) *flagp = 1;
   else if(!strcmp(value, "no")) *flagp = 0;
   else {
-    error(0, "malformed response to '%s'", cmd);
+    disorder_error(0, "malformed response to '%s'", cmd);
     return -1;
   }
   return 0;
@@ -1007,7 +1017,7 @@ int disorder_get_volume(disorder_client *c, int *left, int *right) {
     return rc;
   if(sscanf(r, "%d %d", left, right) != 2) {
     c->last = "malformed volume response";
-    error(0, "error parsing response to 'volume': '%s'", r);
+    disorder_error(0, "error parsing response to 'volume': '%s'", r);
     return -1;
   }
   return 0;
@@ -1160,7 +1170,7 @@ int disorder_rtp_address(disorder_client *c, char **addressp, char **portp) {
   vec = split(r, &n, SPLIT_QUOTES, 0, 0);
   if(n != 2) {
     c->last = "malformed RTP address";
-    error(0, "malformed rtp-address reply");
+    disorder_error(0, "malformed rtp-address reply");
     return -1;
   }
   *addressp = vec[0];
@@ -1309,11 +1319,11 @@ int disorder_schedule_get(disorder_client *c, const char *id,
     return rc;
   while(*lines) {
     if(!(bits = split(*lines++, &nbits, SPLIT_QUOTES, 0, 0))) {
-      error(0, "invalid schedule-get reply: cannot split line");
+      disorder_error(0, "invalid schedule-get reply: cannot split line");
       return -1;
     }
     if(nbits != 2) {
-      error(0, "invalid schedule-get reply: wrong number of fields");
+      disorder_error(0, "invalid schedule-get reply: wrong number of fields");
       return -1;
     }
     kvp_set(actiondatap, bits[0], bits[1]);
@@ -1356,11 +1366,20 @@ int disorder_schedule_add(disorder_client *c,
                         action, key, value,
                         (char *)0);
   } else
-    fatal(0, "unknown action '%s'", action);
+    disorder_fatal(0, "unknown action '%s'", action);
   va_end(ap);
   return rc;
 }
 
+/** @brief Adopt a track
+ * @param c Client
+ * @param id Track ID to adopt
+ * @return 0 on success, non-0 on error
+ */
+int disorder_adopt(disorder_client *c, const char *id) {
+  return disorder_simple(c, 0, "adopt", id, (char *)0);
+}
+
 /** @brief Delete a playlist
  * @param c Client
  * @param playlist Playlist to delete