/*
* 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
* it under the terms of the GNU General Public License as published by
char *v;
if(disorder_version(getclient(), &v)) exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(v)));
+ v = nullcheck(utf82mb_f(v));
+ xprintf("%s\n", v);
+ xfree(v);
}
static void print_queue_entry(const struct queue_entry *q) {
static void cf_somequeue(int (*fn)(disorder_client *c,
struct queue_entry **qp)) {
- struct queue_entry *q;
+ struct queue_entry *q, *qbase;
- if(fn(getclient(), &q)) exit(EXIT_FAILURE);
- while(q) {
+ if(fn(getclient(), &qbase)) exit(EXIT_FAILURE);
+ for(q = qbase; q; q = q->next)
print_queue_entry(q);
- q = q->next;
- }
+ queue_free(qbase, 1);
}
static void cf_recent(char attribute((unused)) **argv) {
int (*fn)(disorder_client *c,
const char *arg, const char *re,
char ***vecp, int *nvecp)) {
- char **vec;
+ char **vec, **base;
const char *re;
if(argv[1])
re = xstrdup(argv[1] + 1);
else
re = 0;
- if(fn(getclient(), argv[0], re, &vec, 0)) exit(EXIT_FAILURE);
- while(*vec)
- xprintf("%s\n", nullcheck(utf82mb(*vec++)));
+ if(fn(getclient(), argv[0], re, &base, 0)) exit(EXIT_FAILURE);
+ for(vec = base; *vec; ++vec)
+ xprintf("%s\n", nullcheck(utf82mb_f(*vec)));
+ xfree(base);
}
static int isarg_regexp(const char *s) {
char *value;
if(disorder_get(getclient(), argv[0], argv[1], &value)) exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(value)));
+ xprintf("%s\n", nullcheck(utf82mb_f(value)));
}
static void cf_length(char **argv) {
}
static void cf_prefs(char **argv) {
- struct kvp *k;
+ struct kvp *k, *base;
- if(disorder_prefs(getclient(), argv[0], &k)) exit(EXIT_FAILURE);
- for(; k; k = k->next)
+ if(disorder_prefs(getclient(), argv[0], &base)) exit(EXIT_FAILURE);
+ for(k = base; k; k = k->next)
xprintf("%s = %s\n",
nullcheck(utf82mb(k->name)), nullcheck(utf82mb(k->value)));
+ kvp_free(base);
}
static void cf_search(char **argv) {
if(disorder_search(getclient(), *argv, &results, &nresults)) exit(EXIT_FAILURE);
for(n = 0; n < nresults; ++n)
xprintf("%s\n", nullcheck(utf82mb(results[n])));
+ free_strings(nresults, results);
}
static void cf_random_disable(char attribute((unused)) **argv) {
static void cf_stats(char attribute((unused)) **argv) {
char **vec;
+ int nvec;
- if(disorder_stats(getclient(), &vec, 0)) exit(EXIT_FAILURE);
- while(*vec)
- xprintf("%s\n", nullcheck(utf82mb(*vec++)));
+ if(disorder_stats(getclient(), &vec, &nvec)) exit(EXIT_FAILURE);
+ for(int n = 0; n < nvec; ++n)
+ xprintf("%s\n", nullcheck(utf82mb(vec[n])));
+ free_strings(nvec, vec);
}
static void cf_get_volume(char attribute((unused)) **argv) {
char *s;
if(disorder_part(getclient(), &s, argv[0], argv[1], argv[2])) exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(s)));
+ xprintf("%s\n", nullcheck(utf82mb_f(s)));
}
static int isarg_filename(const char *s) {
char *track;
if(disorder_resolve(getclient(), &track, argv[0])) exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(track)));
+ xprintf("%s\n", nullcheck(utf82mb_f(track)));
}
static void cf_pause(char attribute((unused)) **argv) {
char *value;
if(disorder_get_global(getclient(), argv[0], &value)) exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(value)));
+ xprintf("%s\n", nullcheck(utf82mb_f(value)));
}
static void cf_set_global(char **argv) {
if(disorder_userinfo(getclient(), argv[0], argv[1], &s))
exit(EXIT_FAILURE);
- xprintf("%s\n", nullcheck(utf82mb(s)));
+ xprintf("%s\n", nullcheck(utf82mb_f(s)));
}
static int isarg_option(const char *arg) {
static void cf_playlists(char attribute((unused)) **argv) {
char **vec;
+ int nvec;
- if(disorder_playlists(getclient(), &vec, 0))
+ if(disorder_playlists(getclient(), &vec, &nvec))
exit(EXIT_FAILURE);
- while(*vec)
- xprintf("%s\n", nullcheck(utf82mb(*vec++)));
+ for(int n = 0; n < nvec; ++n)
+ xprintf("%s\n", nullcheck(utf82mb(vec[n])));
+ free_strings(nvec, vec);
}
static void cf_playlist_del(char **argv) {
static void cf_playlist_get(char **argv) {
char **vec;
+ int nvec;
- if(disorder_playlist_get(getclient(), argv[0], &vec, 0))
+ if(disorder_playlist_get(getclient(), argv[0], &vec, &nvec))
exit(EXIT_FAILURE);
- while(*vec)
- xprintf("%s\n", nullcheck(utf82mb(*vec++)));
+ for(int n = 0; n < nvec; ++n)
+ xprintf("%s\n", nullcheck(utf82mb(vec[n])));
+ free_strings(nvec, vec);
}
static void cf_playlist_set(char **argv) {
}
if(config_read(0, NULL)) disorder_fatal(0, "cannot read configuration");
if(user) {
- config->username = user;
+ xfree(config->username);
+ config->username = xstrdup(user);
config->password = 0;
}
- if(password)
- config->password = password;
+ if(password) {
+ xfree(config->password);
+ config->password = xstrdup(password);
+ }
if(local)
config->connect.af = -1;
if(wfr)
vector_init(&args);
/* Include the command name in the args, but at element -1, for
* the benefit of subcommand getopt calls */
- vector_append(&args, argv[n]);
+ vector_append(&args, xstrdup(argv[n]));
n++;
for(j = 0; j < commands[i].min; ++j)
vector_append(&args, nullcheck(mb2utf8(argv[n + j])));
vector_append(&args, nullcheck(mb2utf8(argv[n + j])));
vector_terminate(&args);
commands[i].fn(args.vec + 1);
+ vector_clear(&args);
n += j;
}
if(client && disorder_close(client)) exit(EXIT_FAILURE);
if(fclose(stdout) < 0) disorder_fatal(errno, "error closing stdout");
+ config_free(config);
+ xfree(client);
return status;
}
}
static void set_username(struct config *c, const char *s) {
- c->username = s;
+ xfree(c->username);
+ c->username = xstrdup(s);
}
static void set_password(struct config *c, const char *s) {
- c->password = s;
+ xfree(c->password);
+ c->password = xstrdup(s);
}
/** @brief Table used to generate the form */
TRACKDB=trackdb-stub.c
endif
-libdisorder_a_SOURCES=charset.c charset.h \
+libdisorder_a_SOURCES=charset.c charsetf.c charset.h \
addr.c addr.h \
arcfour.c arcfour.h \
authhash.c authhash.h \
/*
* 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
* it under the terms of the GNU General Public License as published by
int byte_vasprintf(char **ptrp,
const char *fmt,
va_list ap) {
+ struct sink *s;
struct dynstr d;
int n;
dynstr_init(&d);
- if((n = byte_vsinkprintf(sink_dynstr(&d), fmt, ap)) >= 0) {
+ s = sink_dynstr(&d);
+ n = byte_vsinkprintf(s, fmt, ap);
+ xfree(s);
+ if(n >= 0) {
dynstr_terminate(&d);
*ptrp = d.vec;
}
/*
* This file is part of DisOrder
- * Copyright (C) 2004, 2006, 2007 Richard Kettlewell
+ * Copyright (C) 2004, 2006, 2007, 2009 Richard Kettlewell
*
* 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
* Computes H(challenge|password) and returns it as a newly allocated hex
* string, or returns NULL on error.
*/
-const char *authhash(const void *challenge, size_t nchallenge,
- const char *password, const char *algo) {
+char *authhash(const void *challenge, size_t nchallenge,
+ const char *password, const char *algo) {
gcrypt_hash_handle h;
- const char *res;
+ char *res;
size_t n;
int id;
/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2006, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2006-2009 Richard Kettlewell
*
* 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
#ifndef AUTHHASH_H
#define AUTHHASH_H
-const char *authhash(const void *challenge, size_t nchallenge,
- const char *user, const char *algo);
+char *authhash(const void *challenge, size_t nchallenge,
+ const char *user, const char *algo);
int valid_authhash(const char *algo);
#endif /* AUTHHASH_H */
/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2007-2009 Richard Kettlewell
*
* 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
* that iconv knows. If FROM and TO are both 0 then ANY is returned
* unchanged. */
+char *mb2utf8_f(char *mb);
+char *utf82mb_f(char *utf8);
+char *any2utf8_f(const char *from/*encoding*/,
+ char *any/*string*/);
+char *any2mb_f(const char *from/*encoding or 0*/,
+ char *any/*string*/);
+char *any2any_f(const char *from/*encoding or 0*/,
+ const char *to/*encoding to 0*/,
+ char *any/*string*/);
+
/** @brief Insist that @p s is not null
* @param s Pointer to check
* @return @p s
--- /dev/null
+/*
+ * This file is part of DisOrder.
+ * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
+ *
+ * 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 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @file lib/charsetf.c @brief Character set conversion with free() */
+
+#include "common.h"
+
+#include "charset.h"
+#include "mem.h"
+
+char *mb2utf8_f(char *mb) {
+ char *s = mb2utf8(mb);
+ xfree(mb);
+ return s;
+}
+
+char *utf82mb_f(char *utf8) {
+ char *s = utf82mb(utf8);
+ xfree(utf8);
+ return s;
+}
+
+char *any2utf8_f(const char *from,
+ char *any) {
+ char *s = any2utf8(from, any);
+ xfree(any);
+ return s;
+}
+
+char *any2mb_f(const char *from,
+ char *any) {
+ char *s = any2mb(from, any);
+ xfree(any);
+ return s;
+}
+
+char *any2any_f(const char *from,
+ const char *to,
+ char *any) {
+ char *s = any2any(from, to, any);
+ xfree(any);
+ return s;
+}
+
+/*
+Local Variables:
+c-basic-offset:2
+comment-column:40
+fill-column:79
+indent-tabs-mode:nil
+End:
+*/
/*
* This file is part of DisOrder
- * Copyright (C) 2004, 2005, 2006, 2007 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2006, 2007, 2009 Richard Kettlewell
*
* 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
strcpy(su.sun_path, name);
sa = (struct sockaddr *)&su;
len = sizeof su;
+ xfree(name);
}
*sap = xmalloc_noptr(len);
memcpy(*sap, sa, len);
/*
* 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
* it under the terms of the GNU General Public License as published by
else if(rc / 100 == 2) {
if(rp)
*rp = (rc % 10 == 9) ? 0 : xstrdup(r + 4);
+ xfree(r);
return 0;
} else {
if(c->verbose)
disorder_error(0, "from %s: %s", c->ident, utf82mb(r));
+ xfree(r);
return rc;
}
}
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)
if(!rc) {
if((rr = split(*rp, 0, SPLIT_QUOTES, 0, 0)) && *rr) {
+ xfree(*rp);
*rp = *rr;
+ xfree(rr);
return 0;
}
disorder_error(0, "invalid reply: %s", *rp);
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)
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";
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) {
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;
}
c->fpout = 0;
}
+ xfree(c->ident);
c->ident = 0;
+ xfree(c->user);
c->user = 0;
return ret;
}
if(!strcmp(l, ".")) {
*qt = 0;
*qp = qh;
+ xfree(l);
return 0;
}
q = xmalloc(sizeof *q);
*qt = q;
qt = &q->next;
}
+ xfree(l);
}
if(ferror(c->fpin)) {
byte_xasprintf((char **)&c->last, "input error: %s", strerror(errno));
if(nvecp)
*nvecp = v.nvec;
*vecp = v.vec;
+ xfree(l);
return 0;
}
- vector_append(&v, l + (*l == '.'));
+ vector_append(&v, xstrdup(l + (*l == '.')));
+ xfree(l);
}
if(ferror(c->fpin)) {
byte_xasprintf((char **)&c->last, "input error: %s", strerror(errno));
k->name = pvec[0];
k->value = pvec[1];
kp = &k->next;
+ xfree(pvec);
}
+ free_strings(nvec, vec);
*kp = 0;
return 0;
}
cs->path, cs->line, whoami->name);
return -1;
}
+ xfree(VALUE(cs->config, char *));
VALUE(cs->config, char *) = xstrdup(vec[0]);
return 0;
}
cs->path, cs->line, vec[0]);
return -1;
}
- *ADDRESS(cs->config, char *) = vec[0];
- return 0;
+ return set_string(cs, whoami, nvec, vec);
}
static int set_netaddress(const struct config_state *cs,
type_namepart = { set_namepart, free_namepartlist },
type_transform = { set_transform, free_transformlist },
type_netaddress = { set_netaddress, free_netaddress },
- type_rights = { set_rights, free_none };
+ type_rights = { set_rights, free_string };
/* specific validation routine */
disorder_error(0, "%s:%d: destination address required", cs->path, cs->line);
return -1;
}
+ xfree(na->address);
return 0;
}
vector_append(v, s);
va_end(ap);
vector_terminate(v);
- return config_set(cs, v->nvec, v->vec);
+ int rc = config_set(cs, v->nvec, v->vec);
+ xfree(v->vec);
+ return rc;
}
/** @brief Error callback used by config_include()
*
* @p c is indeterminate after this function is called.
*/
-static void config_free(struct config *c) {
+void config_free(struct config *c) {
int n;
if(c) {
const char *home;
/** @brief Login username */
- const char *username;
+ char *username;
/** @brief Login password */
- const char *password;
+ char *password;
/** @brief Address to connect to */
struct netaddress connect;
int config_verify(void);
+void config_free(struct config *c);
+
extern char *configfile;
extern int config_per_user;
/*
* This file is part of DisOrder
- * Copyright (C) 2004, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2007-2009 Richard Kettlewell
*
* 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
#include "printf.h"
#include "sink.h"
+#include "mem.h"
/** @brief vfprintf() workalike that always accepts UTF-8
* @param fp Stream to write to
* @return -1 on error or bytes written on success
*/
int byte_vfprintf(FILE *fp, const char *fmt, va_list ap) {
- return byte_vsinkprintf(sink_stdio(0, fp), fmt, ap);
+ struct sink *s = sink_stdio(0, fp);
+ int rc = byte_vsinkprintf(s, fmt, ap);
+ xfree(s);
+ return rc;
}
/** @brief fprintf() workalike that always accepts UTF-8
return kvp;
}
+void kvp_free(struct kvp *k) {
+ if(k) {
+ kvp_free(k->next);
+ xfree((void *)k->name);
+ xfree((void *)k->value);
+ xfree(k);
+ }
+}
+
/*
Local Variables:
c-basic-offset:2
char *urldecodestring(const char *s, size_t ns);
struct kvp *kvp_make(const char *key, ...);
+void kvp_free(struct kvp *k);
+
#endif /* KVP_H */
/*
#include "syscalls.h"
#include "table.h"
#include "printf.h"
+#include "vector.h"
const char *const playing_states[] = {
"failed",
return xstrdup(buffer);
}
+static void free_none(struct queue_entry attribute((unused)) *q,
+ size_t attribute((unused)) offset) {
+}
+
+#define free_long free_none
+
static int unmarshall_string(char *data, struct queue_entry *q,
size_t offset,
void attribute((unused)) (*error_handler)(const char *, void *),
void attribute((unused)) *u) {
- VALUE(q, offset, char *) = data;
+ VALUE(q, offset, char *) = xstrdup(data);
return 0;
}
return VALUE(q, offset, char *);
}
+static void free_string(struct queue_entry *q, size_t offset) {
+ xfree(VALUE(q, offset, char *));
+}
+
static int unmarshall_time_t(char *data, struct queue_entry *q,
size_t offset,
void (*error_handler)(const char *, void *),
return xstrdup(buffer);
}
+#define free_time_t free_none
+
static int unmarshall_state(char *data, struct queue_entry *q,
size_t offset,
void (*error_handler)(const char *, void *),
return track_origins[VALUE(q, offset, enum track_origin)];
}
-#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h }
+#define free_state free_none
+#define free_origin free_none
+
+#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h, free_##h }
static const struct field {
const char *name;
int (*unmarshall)(char *data, struct queue_entry *q, size_t offset,
void (*error_handler)(const char *, void *),
void *u);
+ void (*free)(struct queue_entry *q, size_t offset);
} fields[] = {
/* Keep this table sorted. */
F(expected, time_t),
F(when, time_t),
F(wstat, long)
};
+#define NFIELDS (sizeof fields / sizeof *fields)
int queue_unmarshall(struct queue_entry *q, const char *s,
void (*error_handler)(const char *, void *),
q->pid = -1; /* =none */
if(!(vec = split(s, &nvec, SPLIT_QUOTES, error_handler, u)))
return -1;
- return queue_unmarshall_vec(q, nvec, vec, error_handler, u);
+ int rc = queue_unmarshall_vec(q, nvec, vec, error_handler, u);
+ free_strings(nvec, vec);
+ return rc;
}
int queue_unmarshall_vec(struct queue_entry *q, int nvec, char **vec,
return r;
}
+void queue_free(struct queue_entry *q, int rest) {
+ if(!q)
+ return;
+ if(rest)
+ queue_free(q->next, rest);
+ for(unsigned n = 0; n < NFIELDS; ++n)
+ fields[n].free(q, fields[n].offset);
+ xfree(q);
+}
+
/*
Local Variables:
c-basic-offset:2
/*
* 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
* it under the terms of the GNU General Public License as published by
char *queue_marshall(const struct queue_entry *q);
/* marshall @q@ into a UTF-8 string */
+void queue_free(struct queue_entry *q, int rest);
+
#endif /* QUEUE_H */
/*
/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2007-2009 Richard Kettlewell
*
* 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
}
}
+/** @brief Free a string list */
+void free_strings(int nvec, char **vec) {
+ for(int n = 0; n < nvec; ++n)
+ xfree(vec[n]);
+ xfree(vec);
+}
+
+/** @brief Free and re-initialize a vector */
+void vector_clear(struct vector *v) {
+ free_strings(v->nvec, v->vec);
+ vector_init(v);
+}
+
/*
Local Variables:
c-basic-offset:2
/*
* This file is part of DisOrder.
- * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2007-2009 Richard Kettlewell
*
* 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
dynstr_append_bytes(v, ptr, strlen(ptr));
}
+void free_strings(int nvec, char **vec);
+void vector_clear(struct vector *v);
+
#endif /* VECTOR_H */
/*