summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/Makefile.am4
-rw-r--r--src/lib/config_file.c213
-rw-r--r--src/lib/config_file.h36
-rw-r--r--src/lib/misc.c27
-rw-r--r--src/lib/misc.h7
-rw-r--r--src/plugins/file.c33
6 files changed, 311 insertions, 9 deletions
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 3badb67..955007e 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,6 +1,6 @@
lib_LTLIBRARIES = libproxy.la
-libproxy_la_SOURCES = misc.c ip.c url.c pac.c dhcp.c dns.c slp.c wpad.c proxy_factory.c \
- misc.h ip.h url.h pac.h dhcp.h dns.h slp.h wpad.h proxy_factory.h proxy.h
+libproxy_la_SOURCES = misc.c ip.c url.c pac.c dhcp.c dns.c slp.c wpad.c proxy_factory.c config_file.c \
+ misc.h ip.h url.h pac.h dhcp.h dns.h slp.h wpad.h proxy_factory.h proxy.h config_file.h
libproxy_la_CFLAGS = -Wall
libproxy_la_LDFLAGS = -lm
diff --git a/src/lib/config_file.c b/src/lib/config_file.c
new file mode 100644
index 0000000..b19756a
--- /dev/null
+++ b/src/lib/config_file.c
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * libproxy - A library for proxy configuration
+ * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ ******************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "misc.h"
+#include "config_file.h"
+
+struct _pxConfigFileSection {
+ char *name;
+ char **keys;
+ char **vals;
+};
+typedef struct _pxConfigFileSection pxConfigFileSection;
+
+struct _pxConfigFile {
+ char *filename;
+ time_t mtime;
+ pxConfigFileSection **sections;
+};
+
+pxConfigFile *
+px_config_file_new(char *filename)
+{
+ // Open the file and stat it
+ struct stat st;
+ int fd = open(filename, O_RDONLY);
+ if (fd < 0) return NULL;
+ fstat(fd, &st);
+
+ // Allocate our structure; get mtime and filename
+ pxConfigFile *self = px_malloc0(sizeof(pxConfigFile));
+ self->mtime = st.st_mtime;
+ self->filename = px_strdup(filename);
+
+ // Add one section (PX_CONFIG_FILE_DEFAULT_SECTION)
+ self->sections = px_malloc0(sizeof(pxConfigFileSection *) * 2);
+ self->sections[0] = px_malloc0(sizeof(pxConfigFileSection));
+ self->sections[0]->name = px_strdup(PX_CONFIG_FILE_DEFAULT_SECTION);
+ pxConfigFileSection *current = self->sections[0];
+
+ // Parse our file
+ for (char *line=NULL ; (line = px_readline(fd)) ; px_free(line))
+ {
+ // Strip
+ char *tmp = px_strstrip(line);
+ px_free(line); line = tmp;
+
+ // Check for comment and/or empty line
+ if (*line == '#' || !strcmp(line, "")) continue;
+
+ // If we have a new section
+ if (*line == '[' || line[strlen(line)-1] == ']')
+ {
+ // Get just the section name
+ memmove(line, line+1, strlen(line)-1);
+ line[strlen(line)-2] = '\0';
+
+ // Check for each section...
+ for (int i=0 ; self->sections[i] ; i++)
+ {
+ // If we found the section already, set it as current and move on
+ if (!strcmp(self->sections[i]->name, line))
+ {
+ current = self->sections[i];
+ break;
+ }
+
+ // If the section wasn't found, add a new section
+ if (!self->sections[i+1])
+ {
+ // Create new section
+ current = px_malloc0(sizeof(pxConfigFileSection));
+ current->name = px_strdup(line);
+
+ // Add section to the end
+ pxConfigFileSection **sections = self->sections;
+ self->sections = px_malloc0(sizeof(pxConfigFileSection *) * (i+3));
+ memcpy(self->sections, sections, sizeof(pxConfigFileSection) * (i+1));
+ self->sections[i+1] = current;
+ px_free(sections);
+
+ break;
+ }
+ }
+ continue;
+ }
+
+ // If this is a key/val line, get the key/val.
+ if ((tmp = strchr(line, '=')) && tmp[1])
+ {
+ // If this is our first key/val, create a new array
+ if (!current->keys || !current->vals)
+ {
+ // Add key
+ current->keys = px_malloc0(sizeof(char *) * 2);
+ current->keys[0] = px_strndup(line, tmp - line);
+ current->keys[1] = NULL;
+
+ // Add val
+ current->vals = px_malloc0(sizeof(char *) * 2);
+ current->vals[0] = px_strdup(tmp+1);
+ current->vals[1] = NULL;
+ }
+
+ // If this is not our first key/val, tack it on the end
+ else
+ {
+ for (int i=0 ; current->keys[i] ; i++)
+ {
+ if (!current->keys[i+1])
+ {
+ // Add val
+ char **vals = px_malloc0(sizeof(char *) * (i+3));
+ memcpy(vals, current->vals, sizeof(char *) * (i+1));
+ vals[i+1] = px_strstrip(tmp+1);
+ px_free(current->vals); current->vals = vals;
+
+ // Add key
+ *tmp = '\0';
+ char **keys = px_malloc0(sizeof(char *) * (i+3));
+ memcpy(keys, current->keys, sizeof(char *) * (i+1));
+ keys[i+1] = px_strstrip(line);
+ px_free(current->keys); current->keys = keys;
+
+ break;
+ }
+ }
+ }
+ continue;
+ }
+ }
+
+ close(fd);
+ return self;
+}
+
+bool
+px_config_file_is_stale(pxConfigFile *self)
+{
+ struct stat st;
+ return (!stat(self->filename, &st) && st.st_mtime > self->mtime);
+}
+
+char **
+px_config_file_get_sections(pxConfigFile *self)
+{
+ int count;
+ for (count=0 ; self->sections[count] ; count++);
+ char **output = px_malloc0(sizeof(char *) * ++count);
+ for (count=0 ; self->sections[count] ; count++)
+ output[count] = px_strdup(self->sections[count]->name);
+ return output;
+}
+
+char **
+px_config_file_get_keys(pxConfigFile *self, char *section)
+{
+ for (int i=0 ; self->sections[i] ; i++)
+ {
+ if (!strcmp(self->sections[i]->name, section))
+ return px_strdupv((const char **) self->sections[i]->keys);
+ }
+
+ return NULL;
+}
+
+char *
+px_config_file_get_value(pxConfigFile *self, char *section, char *key)
+{
+ for (int i=0 ; self->sections[i] ; i++)
+ if (!strcmp(self->sections[i]->name, section))
+ for (int j=0 ; self->sections[i]->keys && self->sections[i]->keys[j] ; j++)
+ if (!strcmp(self->sections[i]->keys[j], key))
+ return px_strdup(self->sections[i]->vals[j]);
+
+ return NULL;
+}
+
+void
+px_config_file_free(pxConfigFile *self)
+{
+ for (int i=0 ; self->sections[i] ; i++)
+ {
+ px_free(self->sections[i]->name);
+ px_strfreev(self->sections[i]->keys);
+ px_strfreev(self->sections[i]->vals);
+ px_free(self->sections[i]);
+ }
+ px_free(self);
+}
+
+
diff --git a/src/lib/config_file.h b/src/lib/config_file.h
new file mode 100644
index 0000000..bcdb781
--- /dev/null
+++ b/src/lib/config_file.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * libproxy - A library for proxy configuration
+ * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ ******************************************************************************/
+
+#ifndef CONFIG_FILE_H_
+#define CONFIG_FILE_H_
+
+#include <stdbool.h>
+
+#define PX_CONFIG_FILE_DEFAULT_SECTION "__DEFAULT__"
+
+typedef struct _pxConfigFile pxConfigFile;
+
+pxConfigFile *px_config_file_new (char *filename);
+bool px_config_file_is_stale (pxConfigFile *self);
+char **px_config_file_get_sections(pxConfigFile *self);
+char **px_config_file_get_keys (pxConfigFile *self, char *section);
+char *px_config_file_get_value (pxConfigFile *self, char *section, char *key);
+void px_config_file_free (pxConfigFile *self);
+
+#endif /*CONFIG_FILE_H_*/
diff --git a/src/lib/misc.c b/src/lib/misc.c
index 02ff678..9095db1 100644
--- a/src/lib/misc.c
+++ b/src/lib/misc.c
@@ -80,6 +80,26 @@ px_strdup(const char *s)
}
/**
+ * Duplicates a string vector
+ * @sv String vector to duplicate
+ * @return Newly allocated string vector (free w/ px_strfreev())
+ */
+char **
+px_strdupv(const char **sv)
+{
+ int count;
+
+ if (!sv) return NULL;
+ for (count=0 ; sv[count] ; count++);
+
+ char **output = px_malloc0(sizeof(char *) * ++count);
+ for (int i=0 ; sv[i] ; i++)
+ output[i] = px_strdup(sv[i]);
+
+ return output;
+}
+
+/**
* Concatenates two or more strings into a newly allocated string
* @s The first string to concatenate.
* @... Subsequent strings. The last argument must be NULL.
@@ -200,13 +220,14 @@ px_readline(int fd)
char c;
// Receive a single character, check for newline or EOF
- if (read(fd, &c, 1) != 1 || c == '\n') break;
+ if (read(fd, &c, 1) != 1) return buffer;
+ if (c == '\n') return buffer ? buffer : px_strdup("");
// Allocate new buffer if we need
if (i % 1024 == 1)
{
char *tmp = buffer;
- buffer = px_malloc0(1024+i);
+ buffer = px_malloc0(1024 * i + 1);
if (tmp) { strcpy(buffer, tmp); px_free(tmp); }
}
@@ -243,7 +264,7 @@ px_strrstrip(char *string)
for (int i=0 ; string[i] ; i++)
if (!isspace(string[i]))
tmp = string + i;
- *tmp = '\0';
+ tmp[1] = '\0';
return string;
}
diff --git a/src/lib/misc.h b/src/lib/misc.h
index cab466c..e09b1ed 100644
--- a/src/lib/misc.h
+++ b/src/lib/misc.h
@@ -51,6 +51,13 @@ char *px_strndup(const char *s, size_t n);
char *px_strdup(const char *s);
/**
+ * Duplicates a string vector
+ * @sv String vector to duplicate
+ * @return Newly allocated string vector (free w/ px_strfreev())
+ */
+char **px_strdupv(const char **sv);
+
+/**
* Concatenates two or more strings into a newly allocated string
* @s The first string to concatenate.
* @... Subsequent strings. The last argument must be NULL.
diff --git a/src/plugins/file.c b/src/plugins/file.c
index 2551e4f..54c4689 100644
--- a/src/plugins/file.c
+++ b/src/plugins/file.c
@@ -22,21 +22,44 @@
#include <misc.h>
#include <proxy_factory.h>
+#include <config_file.h>
-pxConfig *get_config_from_file(char *filename)
+pxConfig *get_config_from_file(pxProxyFactory *self, char *misc, char *filename)
{
- return NULL;
+ pxConfigFile *cf = px_proxy_factory_misc_get(self, misc);
+ if (!cf || px_config_file_is_stale(cf))
+ {
+ if (cf) px_config_file_free(cf);
+ cf = px_config_file_new(filename);
+ }
+
+ if (!cf) return NULL;
+
+ pxConfig *config = px_malloc0(sizeof(pxConfig));
+ config->url = px_config_file_get_value(cf, PX_CONFIG_FILE_DEFAULT_SECTION, "proxy");
+ config->ignore = px_config_file_get_value(cf, PX_CONFIG_FILE_DEFAULT_SECTION, "ignore");
+ if (!config->url)
+ config->url = px_strdup("wpad://");
+ if (!config->ignore)
+ config->ignore = px_strdup("");
+
+ return config;
}
pxConfig *system_get_config_cb(pxProxyFactory *self)
{
- return get_config_from_file("/etc/proxy.conf");
+ return get_config_from_file(self, "file_system", "/etc/proxy.conf");
}
pxConfig *user_get_config_cb(pxProxyFactory *self)
{
- return get_config_from_file("~/.proxy.conf");
+ char *tmp = getenv("HOME");
+ if (!tmp) return NULL;
+ char *filename = px_strcat(tmp, "/", ".proxy.conf", NULL);
+ pxConfig *config = get_config_from_file(self, "file_user", filename);
+ px_free(filename);
+ return config;
}
bool on_proxy_factory_instantiate(pxProxyFactory *self)
@@ -53,4 +76,6 @@ void on_proxy_factory_destantiate(pxProxyFactory *self)
{
px_proxy_factory_config_del(self, "file_system");
px_proxy_factory_config_del(self, "file_user");
+ px_config_file_free(px_proxy_factory_misc_get(self, "file_system"));
+ px_config_file_free(px_proxy_factory_misc_get(self, "file_user"));
}