summaryrefslogtreecommitdiff
path: root/src/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf.c')
-rw-r--r--src/conf.c380
1 files changed, 380 insertions, 0 deletions
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..cf93f1b
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,380 @@
+/**
+ * @file conf.c Configuration utils
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#define _BSD_SOURCE 1
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdio.h>
+#include <sys/stat.h>
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "core.h"
+
+
+#define DEBUG_MODULE ""
+#define DEBUG_LEVEL 0
+#include <re_dbg.h>
+
+
+#ifdef WIN32
+#define open _open
+#define read _read
+#define close _close
+#endif
+
+
+#if defined (WIN32) || defined (__SYMBIAN32__)
+#define DIR_SEP "\\"
+#else
+#define DIR_SEP "/"
+#endif
+
+
+static const char *conf_path = NULL;
+static struct conf *conf_obj;
+
+
+/**
+ * Check if a file exists
+ *
+ * @param path Filename
+ *
+ * @return True if exist, False if not
+ */
+bool conf_fileexist(const char *path)
+{
+ struct stat st;
+
+ if (!path)
+ return false;
+
+ if (stat(path, &st) < 0)
+ return false;
+
+ if ((st.st_mode & S_IFMT) != S_IFREG)
+ return false;
+
+ return st.st_size > 0;
+}
+
+
+static void print_populated(const char *what, uint32_t n)
+{
+ info("Populated %u %s%s\n", n, what, 1==n ? "" : "s");
+}
+
+
+/**
+ * Parse a config file, calling handler for each line
+ *
+ * @param filename Config file
+ * @param ch Line handler
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int conf_parse(const char *filename, confline_h *ch)
+{
+ struct pl pl, val;
+ struct mbuf *mb;
+ int err = 0, fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return errno;
+
+ mb = mbuf_alloc(1024);
+ if (!mb) {
+ err = ENOMEM;
+ goto out;
+ }
+
+ for (;;) {
+ uint8_t buf[1024];
+
+ const ssize_t n = read(fd, (void *)buf, sizeof(buf));
+ if (n < 0) {
+ err = errno;
+ break;
+ }
+ else if (n == 0)
+ break;
+
+ err |= mbuf_write_mem(mb, buf, n);
+ }
+
+ pl.p = (const char *)mb->buf;
+ pl.l = mb->end;
+
+ while (pl.p < ((const char *)mb->buf + mb->end) && !err) {
+ const char *lb = pl_strchr(&pl, '\n');
+
+ val.p = pl.p;
+ val.l = lb ? (uint32_t)(lb - pl.p) : pl.l;
+ pl_advance(&pl, val.l + 1);
+
+ if (!val.l || val.p[0] == '#')
+ continue;
+
+ err = ch(&val);
+ }
+
+ out:
+ mem_deref(mb);
+ (void)close(fd);
+
+ return err;
+}
+
+
+/**
+ * Set the path to configuration files
+ *
+ * @param path Configuration path
+ */
+void conf_path_set(const char *path)
+{
+ conf_path = path;
+}
+
+
+/**
+ * Get the path to configuration files
+ *
+ * @param path Buffer to write path
+ * @param sz Size of path buffer
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int conf_path_get(char *path, size_t sz)
+{
+ char buf[256];
+ int err;
+
+ /* Use explicit conf path */
+ if (conf_path) {
+ if (re_snprintf(path, sz, "%s", conf_path) < 0)
+ return ENOMEM;
+ return 0;
+ }
+
+ err = fs_gethome(buf, sizeof(buf));
+ if (err)
+ return err;
+
+ if (re_snprintf(path, sz, "%s" DIR_SEP ".baresip", buf) < 0)
+ return ENOMEM;
+
+ return 0;
+}
+
+
+int conf_get_range(const struct conf *conf, const char *name,
+ struct range *rng)
+{
+ struct pl r, min, max;
+ uint32_t v;
+ int err;
+
+ err = conf_get(conf, name, &r);
+ if (err)
+ return err;
+
+ err = re_regex(r.p, r.l, "[0-9]+-[0-9]+", &min, &max);
+ if (err) {
+ /* fallback to non-range numeric value */
+ err = conf_get_u32(conf, name, &v);
+ if (err) {
+ warning("conf: %s: could not parse range: (%r)\n",
+ name, &r);
+ return err;
+ }
+
+ rng->min = rng->max = v;
+
+ return err;
+ }
+
+ rng->min = pl_u32(&min);
+ rng->max = pl_u32(&max);
+
+ if (rng->min > rng->max) {
+ warning("conf: %s: invalid range (%u - %u)\n",
+ name, rng->min, rng->max);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+
+int conf_get_csv(const struct conf *conf, const char *name,
+ char *str1, size_t sz1, char *str2, size_t sz2)
+{
+ struct pl r, pl1, pl2 = pl_null;
+ int err;
+
+ err = conf_get(conf, name, &r);
+ if (err)
+ return err;
+
+ err = re_regex(r.p, r.l, "[^,]+,[^]*", &pl1, &pl2);
+ if (err)
+ return err;
+
+ (void)pl_strcpy(&pl1, str1, sz1);
+ if (pl_isset(&pl2))
+ (void)pl_strcpy(&pl2, str2, sz2);
+
+ return 0;
+}
+
+
+int conf_get_vidsz(const struct conf *conf, const char *name, struct vidsz *sz)
+{
+ struct pl r, w, h;
+ int err;
+
+ err = conf_get(conf, name, &r);
+ if (err)
+ return err;
+
+ w.l = h.l = 0;
+ err = re_regex(r.p, r.l, "[0-9]+x[0-9]+", &w, &h);
+ if (err)
+ return err;
+
+ if (pl_isset(&w) && pl_isset(&h)) {
+ sz->w = pl_u32(&w);
+ sz->h = pl_u32(&h);
+ }
+
+ /* check resolution */
+ if (sz->w & 0x1 || sz->h & 0x1) {
+ warning("conf: %s: should be multiple of 2 (%u x %u)\n",
+ name, sz->w, sz->h);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+
+int conf_get_sa(const struct conf *conf, const char *name, struct sa *sa)
+{
+ struct pl opt;
+ int err;
+
+ if (!conf || !name || !sa)
+ return EINVAL;
+
+ err = conf_get(conf, name, &opt);
+ if (err)
+ return err;
+
+ return sa_decode(sa, opt.p, opt.l);
+}
+
+
+/**
+ * Configure the system with default settings
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int conf_configure(void)
+{
+ char path[256], file[256];
+ int err;
+
+#if defined (WIN32) || defined (__SYMBIAN32__)
+ dbg_init(DBG_INFO, DBG_NONE);
+#endif
+
+ err = conf_path_get(path, sizeof(path));
+ if (err) {
+ warning("conf: could not get config path: %m\n", err);
+ return err;
+ }
+
+ if (re_snprintf(file, sizeof(file), "%s/config", path) < 0)
+ return ENOMEM;
+
+ if (!conf_fileexist(file)) {
+
+ (void)fs_mkdir(path, 0700);
+
+ err = config_write_template(file, conf_config());
+ if (err)
+ goto out;
+ }
+
+ err = conf_alloc(&conf_obj, file);
+ if (err)
+ goto out;
+
+ err = config_parse_conf(conf_config(), conf_obj);
+ if (err)
+ goto out;
+
+ out:
+ conf_obj = mem_deref(conf_obj);
+ return err;
+}
+
+
+/**
+ * Load all modules from config file
+ *
+ * @return 0 if success, otherwise errorcode
+ */
+int conf_modules(void)
+{
+ char path[256], file[256];
+ int err;
+
+ err = conf_path_get(path, sizeof(path));
+ if (err)
+ return err;
+
+ if (re_snprintf(file, sizeof(file), "%s/config", path) < 0)
+ return ENOMEM;
+
+ err = conf_alloc(&conf_obj, file);
+ if (err)
+ goto out;
+
+ err = module_init(conf_obj);
+ if (err) {
+ warning("conf: configure module parse error (%m)\n", err);
+ goto out;
+ }
+
+ print_populated("audio codec", list_count(aucodec_list()));
+ print_populated("audio filter", list_count(aufilt_list()));
+#ifdef USE_VIDEO
+ print_populated("video codec", list_count(vidcodec_list()));
+ print_populated("video filter", list_count(vidfilt_list()));
+#endif
+
+ out:
+ conf_obj = mem_deref(conf_obj);
+ return err;
+}
+
+
+/**
+ * Get the current configuration object
+ *
+ * @return Config object
+ *
+ * @note It is only available during init
+ */
+struct conf *conf_cur(void)
+{
+ return conf_obj;
+}