Commits

jjacky committed f8e11df Merge

merging latest

Comments (0)

Files changed (34)

+
+# 04/14/2012, v0.1.5
+
+- Now using automake & autoconf. (Hopefully) this shouldn't really change
+much for most people, but if you don't care for kalu's updater and only want
+to use kalu as update notifier, you can use option --disable-updater to configure.
+You'll get a smaller binary, no second binary (kalu-dbus) nor dependency to
+DBus/PolicyKit.
+
+- When starting an external process to perform sysupgrade (or AUR upgrade), kalu
+now waits for the process to end (being "busy" meanwhile), and runs another check
+right after, to refresh its state. Closes #5.
+
+- kalu always shipped with a man page, and recently a (this) changelog. Both can
+both easily be read using menus Help & Change log.
+
+- Added new option to customize icon used on notification: none, kalu's default,
+or specifying a file to load the icon from. The icon will be shown full size, so
+e.g. using /usr/share/pixmaps/kalu.png will uses kalu's icon at 48x48 (if
+loading icon fails, silently falls back to kalu's default icon). Closes #6.
+
+- kalu's updater always used /etc/pacman.conf (instead of whatever is set in
+Preferences), fixed
+
+- Parsing kalu.conf would report & stop on first error, now it ignores the line,
+continues parsing, and report all errors (at once)
+
+- kalu's updater: log messages longer than 1023 characters would be truncated, fixed
+
+- Other minor fixes
+
 
 # 03/26/2012, v0.1.4
 
-- added section "Misc" under Preferences, with options to define action on single- & double-click on systray icon: nothing, check for upgrades, system upgrade, hide/show opened windows
+- added section "Misc" under Preferences, with options to define action on
+single- & double-click on systray icon: nothing, check for upgrades, system
+upgrade, hide/show opened windows
+
 - kalu updater: one can now click on columns to sort packages
+
 - Preferences/Misc: option to disable sane sort indicator
-- tooltip: now indicates if/how many dbs can be synchronized (regardless of upgrades avability). Can be disabled via option under "Misc" in Preferences
+
+- tooltip: now indicates if/how many dbs can be synchronized (regardless of
+upgrades avability). Can be disabled via option under "Misc" in Preferences
+
 - fixed possible memory leak if showing news failed on parsing
-- showing Preferences without "Upgrade system" button enabled didn't have PostSysUpgrade list disabled, fixed
+
+- showing Preferences without "Upgrade system" button enabled didn't have
+PostSysUpgrade list disabled, fixed
 
 
 # 03/20/2012, v0.1.3
 
-- when saving Preferences, \n in templates wasn't resolved to newline (for current run), fixed
+- when saving Preferences, \n in templates wasn't resolved to newline (for
+current run), fixed
 
 
 # 03/18/2012, v0.1.2
 
-- saving preferences if the folder (~/.config/kalu) did not already exist would fail, fixed
+- saving preferences if the folder (~/.config/kalu) did not already exist would
+fail, fixed
 
 
 # 03/11/2012, v0.1.1
 
-- kalu-updater: environment variables were unset, which could cause issues on some post_{install,upgrade} scripts, fixed
+- kalu-updater: environment variables were unset, which could cause issues on
+some post_{install,upgrade} scripts, fixed
 
-The sysupgrade is ran from kalu-dbus, which is automatically started through DBus. When starting something, DBus does clear all environment variables, which could cause problems is some scripts (e.g. mkinitcpio with autodetect hook, and the lack of a PATH defined).
-This is fixed by using a bash script to source /etc/profile (and therefore restore a proper environment) before launching kalu-dbus (See https://bbs.archlinux.org/viewtopic.php?id=136784)
+The sysupgrade is ran from kalu-dbus, which is automatically started through DBus.
+When starting something, DBus does clear all environment variables, which could
+cause problems is some scripts (e.g. mkinitcpio with autodetect hook, and the
+lack of a PATH defined).
+This is fixed by using a bash script to source /etc/profile (and therefore
+restore a proper environment) before launching kalu-dbus
+(See https://bbs.archlinux.org/viewtopic.php?id=136784)
 
 
 # 03/06/2012, v0.1.0
 
 - first stable release
-- The menu "System upgrade" was always present and running kalu's system updater. It now relies on the preferences for Upgrade notifications: only visible if enabled, and starts either kalu's updater or the specified command line. IOW those two (notifications' button & menu item) are 2 GUI elements of the same feature.
+
+- The menu "System upgrade" was always present and running kalu's system updater.
+It now relies on the preferences for Upgrade notifications: only visible if
+enabled, and starts either kalu's updater or the specified command line.
+IOW those two (notifications' button & menu item) are 2 GUI elements of the same
+feature.
 
 
 # 03/03/2012, v0.0.6
 
-- When performing a sysupgrade through kalu's updater, when (new) optionnal dependencies were to be listed, kalu would crash. Note that "only" kalu (aka the GUI) would crash, the updater part would still run fine and complete the upgrade, as the log (pacman.log) would show. Still pretty bad, and fixed.
-- When starting a sysupgrade, the message in the log (pacman.log) is now "starting sysupgrade" to be more consistent with the message upon completion ("sysupgrade completed")
+- When performing a sysupgrade through kalu's updater, when (new) optionnal
+dependencies were to be listed, kalu would crash. Note that "only" kalu (aka the
+GUI) would crash, the updater part would still run fine and complete the upgrade,
+as the log (pacman.log) would show. Still pretty bad, and fixed.
+
+- When starting a sysupgrade, the message in the log (pacman.log) is now
+"starting sysupgrade" to be more consistent with the message upon completion
+("sysupgrade completed")
 
 
 # 02/23/2012, v0.0.5
 
 - added man page
+
 - Preferences: added notification expiration delay
 
 
 # 02/21/2012, v0.0.4
 
 - added window Preferences to configure things
+
 - checking the news did not report error on failure, fixed
+
 - news were always checked regardless of settings, fixed
+
 - templates were overly complicated, rewrote the whole thing
 
 
 # 02/17/2012, v0.0.3
 
-- when creating local copy of dbs, it would fail if there were folders (in sync/); fixed (only copy files now)
+- when creating local copy of dbs, it would fail if there were folders (in sync/);
+fixed (only copy files now)
+
 - added basic command-line parser, and option -d/--debug to enable debug mode
 
 
 # 02/15/2012, v0.0.2
 
-- saving data (marking (AUR) watched packages, read news, managing (AUR) watched packages) would silently failed if the folder did not exists (yet kalu acted as if it had worked), which was pretty much always the case on a new installation, fixed
+- saving data (marking (AUR) watched packages, read news, managing (AUR) watched
+packages) would silently failed if the folder did not exists (yet kalu acted as
+if it had worked), which was pretty much always the case on a new installation, fixed
+
 - template Title was missing $INS (total install size), fixed
 
 
 # 02/14/2012, v0.0.1
 
 - first release, still in development phase
-

Makefile

-
-.PHONY = all kalu kalu-dbus doc install uninstall clean
-
-WARNINGS := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
-			-Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-			-Wredundant-decls -Wnested-externs -Winline -Wno-long-long \
-			-Wuninitialized -Wconversion -Wstrict-prototypes
-CFLAGS := -g -std=c99 $(WARNINGS) -imacros configure.h
-
-PROGRAMS = kalu kalu-dbus
-DOCS = kalu.1.gz index.html
-
-SRCFILES =	main.c alpm.c config.c util.c watched.c util-gtk.c kalu-updater.c \
-			updater.c closures.c cJSON.c aur.c curl.c news.c preferences.c
-
-HDRFILES =	alpm.h config.h util.h kalu.h watched.h util-gtk.h kalu-updater.h \
-			updater.h closures.h updater-dbus.h kupdater.h cJSON.h aur.h \
-			curl.h news.h arch_linux.h preferences.h
-
-OBJFILES =	main.o alpm.o config.o util.o watched.o util-gtk.o kalu-updater.o \
-			updater.o closures.o cJSON.o aur.o curl.o news.o preferences.o
-
-DBUSSRCFILES = kalu-dbus.c
-DBUSOBJFILES = kalu-dbus.o
-
-MANFILES = kalu.1
-
-all: $(PROGRAMS) $(DOCS)
-
-kalu: $(OBJFILES)
-	$(CC) -o kalu $(OBJFILES) `pkg-config --libs gtk+-3.0 libnotify` `curl-config --libs` -lalpm -lm
-
-main.o:	main.c arch_linux.h alpm.h config.h util.h kalu.h updater.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0 libnotify` -lalpm main.c
-
-alpm.o: alpm.c alpm.h config.h util.h kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` alpm.c
-
-config.o: config.c alpm.h config.h util.h kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` config.c
-
-util.o: util.c alpm.h util.h kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` util.c
-
-watched.o: watched.c alpm.h watched.h kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0` watched.c
-
-util-gtk.o: util-gtk.c kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0 libnotify` util-gtk.c
-
-kalu-updater.o:	kalu-updater.c kalu-updater.h kalu.h updater-dbus.h kupdater.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` kalu-updater.c
-
-updater.o:	updater.c updater.h kalu.h kupdater.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0` updater.c
-
-closures.o:	closures.c closures.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` closures.c
-
-cJSON.o:	cJSON.c cJSON.h
-	$(CC) -c $(CFLAGS) cJSON.c
-
-aur.o:	aur.c aur.h kalu.h curl.h cJSON.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` aur.c
-
-curl.o:	curl.c curl.h kalu.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0` `curl-config --cflags` curl.c
-
-news.o:	news.c news.h kalu.h curl.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0` news.c
-
-preferences.o:	preferences.c preferences.h kalu.h util.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags gtk+-3.0` preferences.c
-
-kalu-dbus: $(DBUSOBJFILES)
-	$(CC) -o kalu-dbus $(DBUSOBJFILES) `pkg-config --libs glib-2.0 polkit-gobject-1` -lalpm
-
-kalu-dbus.o: kalu-dbus.c updater-dbus.h kupdater.h
-	$(CC) -c $(CFLAGS) `pkg-config --cflags glib-2.0 polkit-gobject-1` kalu-dbus.c
-
-doc: $(DOCS)
-
-kalu.1.gz: $(MANFILES)
-	gzip -c kalu.1 > kalu.1.gz
-
-index.html: kalu.1
-	groff -T html -man kalu.1 > index.html
-
-install:
-	install -D -m755 kalu $(DESTDIR)/usr/bin/kalu
-	install -D -m755 kalu-dbus $(DESTDIR)/usr/bin/kalu-dbus
-	install -D -m755 kalu-dbus-launcher $(DESTDIR)/usr/bin/kalu-dbus-launcher
-	install -D -m644 kalu.1.gz $(DESTDIR)/usr/share/man/man1/kalu.1.gz
-	install -D -m644 index.html $(DESTDIR)usr/share/doc/kalu/html/index.html
-	install -D -m644 AUTHORS $(DESTDIR)usr/share/doc/kalu/AUTHORS
-	install -D -m644 COPYING $(DESTDIR)usr/share/licenses/kalu/COPYING
-	install -D -m644 HISTORY $(DESTDIR)usr/share/doc/kalu/HISTORY
-	install -D -m644 LICENSE $(DESTDIR)usr/share/doc/kalu/LICENSE
-	install -D -m644 README.md $(DESTDIR)usr/share/doc/kalu/README.md
-	install -D -m644 arch_linux_48x48_icon_by_painlessrob.png $(DESTDIR)usr/share/pixmaps/kalu.png
-	install -D -m644 org.jjk.kalu.policy $(DESTDIR)usr/share/polkit-1/actions/org.jjk.kalu.policy
-	install -D -m644 org.jjk.kalu.service $(DESTDIR)usr/share/dbus-1/system-services/org.jjk.kalu.service
-	install -D -m644 org.jjk.kalu.conf $(DESTDIR)etc/dbus-1/system.d/org.jjk.kalu.conf
-	install -D -m644 kalu.desktop $(DESTDIR)usr/share/applications/kalu.desktop
-
-uninstall:
-	rm -f $(DESTDIR)/usr/bin/kalu
-	rm -f $(DESTDIR)/usr/bin/kalu-dbus
-	rm -f $(DESTDIR)/usr/share/man/man1/kalu.1.gz
-	rm -rf $(DESTDIR)usr/share/doc/kalu
-	rm -rf $(DESTDIR)usr/share/licenses/kalu
-	rm -f $(DESTDIR)usr/share/pixmaps/kalu.png
-	rm -f $(DESTDIR)usr/share/polkit-1/actions/org.jjk.kalu.policy
-	rm -f $(DESTDIR)usr/share/dbus-1/system-services/org.jjk.kalu.service
-	rm -f $(DESTDIR)etc/dbus-1/system.d/org.jjk.kalu.conf
-	rm -f $(DESTDIR)usr/share/applications/kalu.desktop
-
-clean:
-	rm -f $(PROGRAMS)
-	rm -f $(OBJFILES)
-	rm -f $(DOCS)
+
+CLEANFILES = index.html kalu.png org.jjk.kalu.service
+
+bin_PROGRAMS = kalu
+if ! DISABLE_UPDATER
+bin_PROGRAMS += kalu-dbus
+dist_bin_SCRIPTS = kalu-dbus-launcher
+endif
+
+nodist_man_MANS = kalu.1
+dist_doc_DATA = AUTHORS COPYING HISTORY LICENSE README.md
+doc_DATA = index.html
+
+logodir = $(datadir)/pixmaps
+logo_DATA = kalu.png
+
+desktopdir = /usr/share/applications
+dist_desktop_DATA = kalu.desktop
+
+if ! DISABLE_UPDATER
+policydir = /usr/share/polkit-1/actions
+dist_policy_DATA = org.jjk.kalu.policy
+dbusservicedir = /usr/share/dbus-1/system-services
+nodist_dbusservice_DATA = org.jjk.kalu.service
+dbusconfdir = /etc/dbus-1/system.d
+dist_dbusconf_DATA = org.jjk.kalu.conf
+endif
+
+install-data-hook:
+	mkdir $(DESTDIR)$(docdir)/html
+	mv $(DESTDIR)$(docdir)/index.html $(DESTDIR)$(docdir)/html/
+
+dist-hook:
+	cp $(srcdir)/kalu.pod $(distdir)/
+	cp $(srcdir)/org.jjk.kalu.service.tpl $(distdir)/
+	cp $(srcdir)/arch_linux_48x48_icon_by_painlessrob.png $(distdir)/
+
+AM_CPPFLAGS = -DDOCDIR='"$(docdir)"'
+AM_CFLAGS = -g \
+		-Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
+		-Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
+		-Wredundant-decls -Wnested-externs -Winline -Wno-long-long \
+		-Wuninitialized -Wconversion -Wstrict-prototypes
+AM_CFLAGS += -D_BSD_SOURCE
+
+kalu_CFLAGS = ${AM_CFLAGS} @GTK_CFLAGS@ @NOTIFY_CFLAGS@
+kalu_LDADD = @GTK_LIBS@ @NOTIFY_LIBS@ -lalpm -lm @LIBCURL@
+kalu_SOURCES = main.c arch_linux.h kalu.h \
+		conf.h conf.c \
+		util.h util.c util-gtk.h util-gtk.c \
+		kalu-alpm.h kalu-alpm.c \
+		watched.h watched.c  \
+		curl.h curl.c \
+		cJSON.h cJSON.c \
+		aur.h aur.c \
+		news.h news.c \
+		preferences.h preferences.c
+if ! DISABLE_UPDATER
+kalu_SOURCES += closures.h closures.c \
+		updater-dbus.h kupdater.h \
+		kalu-updater.h kalu-updater.c \
+		updater.h updater.c
+
+
+kalu_dbus_CFLAGS = ${AM_CFLAGS} @GTK_CFLAGS@ @POLKIT_CFLAGS@
+kalu_dbus_LDADD = @GTK_LIBS@ @POLKIT_LIBS@ -lalpm
+kalu_dbus_SOURCES = updater-dbus.h kupdater.h kalu-dbus.c
+endif
+
+_bindir = $(subst /,\/,$(bindir))
+org.jjk.kalu.service: org.jjk.kalu.service.tpl
+	@sed 's/@BINDIR@/$(_bindir)/' org.jjk.kalu.service.tpl > org.jjk.kalu.service
+
+kalu.1: kalu.pod
+	pod2man --center='Keeping Arch Linux Up-to-date' --section=1 --release=$(PACKAGE_VERSION) kalu.pod kalu.1
+
+index.html: kalu.1
+	groff -T html -man kalu.1 > index.html
+
+kalu.png: arch_linux_48x48_icon_by_painlessrob.png
+	$(LN_S) arch_linux_48x48_icon_by_painlessrob.png kalu.png
+

alpm.c

-/**
- * kalu - Copyright (C) 2012 Olivier Brunel
- *
- * alpm.c
- * Copyright (C) 2012 Olivier Brunel <i.am.jack.mail@gmail.com>
- * 
- * This file is part of kalu.
- *
- * kalu 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.
- *
- * kalu 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
- * kalu. If not, see http://www.gnu.org/licenses/
- */
-
-#define _BSD_SOURCE /* for strdup w/ -std=c99 */
-
-/* C */
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <utime.h>
-
-/* alpm */
-#include <alpm.h>
-#include <alpm_list.h>
-
-/* glib */
-#include <glib-2.0/glib.h>
-
-/* kalu */
-#include "kalu.h"
-#include "alpm.h"
-#include "util.h"
-#include "config.h"
-
-/* global variable */
-unsigned short alpm_verbose;
-
-
-static kalu_alpm_t *alpm;
-
-static gboolean copy_file (const gchar *from, const gchar *to);
-static gboolean create_local_db (const gchar *dbpath, gchar **newpath, GError **error);
-
-
-
-static gboolean
-copy_file (const gchar *from, const gchar *to)
-{
-    gchar *contents;
-    gsize  length;
-    
-    debug ("copying %s to %s", from, to);
-    
-    if (!g_file_get_contents (from, &contents, &length, NULL))
-    {
-        debug ("cannot read %s", from);
-        return FALSE;
-    }
-    
-    if (!g_file_set_contents (to, contents, (gssize) length, NULL))
-    {
-        debug ("cannot write %s", to);
-        g_free (contents);
-        return FALSE;
-    }
-    
-    debug ("..done");
-    g_free (contents);
-    return TRUE;
-}
-
-static gboolean
-create_local_db (const gchar *_dbpath, gchar **newpath, GError **error)
-{
-    gchar    buf[MAX_PATH];
-    gchar    buf2[MAX_PATH];
-    gchar   *dbpath;
-    size_t   l;
-    gchar   *folder;
-    GDir    *dir;
-    
-    debug ("creating local db");
-    
-    /* create folder in tmp dir */
-    if (NULL == (folder = g_dir_make_tmp ("kalu-XXXXXX", NULL)))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to create temp folder");
-        return FALSE;
-    }
-    debug ("created tmp folder %s", folder);
-    
-    /* dbpath will not be slash-terminated */
-    dbpath = strdup (_dbpath);
-    l = strlen (dbpath) - 1;
-    if (dbpath[l] == '/')
-    {
-        dbpath[l] = '\0';
-    }
-    
-    /* symlink local */
-    snprintf (buf, MAX_PATH - 1, "%s/local", dbpath);
-    snprintf (buf2, MAX_PATH - 1, "%s/local", folder);
-    if (0 != symlink (buf, buf2))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to create symlink %s", buf2);
-        goto error;
-    }
-    debug ("created symlink %s", buf2);
-    
-    /* copy databases in sync */
-    snprintf (buf, MAX_PATH - 1, "%s/sync", folder);
-    if (0 != mkdir (buf, 0700))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to create folder %s", buf);
-        goto error;
-    }
-    debug ("created folder %s", buf);
-    
-    snprintf (buf, MAX_PATH - 1, "%s/sync", dbpath);
-    if (NULL == (dir = g_dir_open (buf, 0, NULL)))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to open folder %s", buf);
-        goto error;
-    }
-    
-    const gchar    *file;
-    struct stat     filestat;
-    struct utimbuf  times;
-    
-    while ((file = g_dir_read_name (dir)))
-    {
-        snprintf (buf, MAX_PATH - 1, "%s/sync/%s", dbpath, file);
-        /* stat so we copy files only. also, we need to preserve modified date,
-         * used to determine if DBs are up to date or not by libalpm */
-        if (0 == stat (buf, &filestat))
-        {
-            if (S_ISREG (filestat.st_mode))
-            {
-                snprintf (buf2, MAX_PATH - 1, "%s/sync/%s", folder, file);
-                if (!copy_file (buf, buf2))
-                {
-                    g_set_error (error, KALU_ERROR, 1, "Copy failed for %s", buf);
-                    g_dir_close (dir);
-                    goto error;
-                }
-                /* preserve time */
-                times.actime = filestat.st_atime;
-                times.modtime = filestat.st_mtime;
-                if (0 != utime (buf2, &times))
-                {
-                    /* sucks, but no fail, we'll just have to download this db */
-                    debug ("Unable to change time of %s", buf2);
-                }
-                else
-                {
-                    debug ("updated time for %s", buf2);
-                }
-            }
-            else
-            {
-                debug ("ignoring non-regular file: %s", buf);
-            }
-        }
-        else
-        {
-            g_set_error (error, KALU_ERROR, 1, "Unable to stat %s\n", buf);
-            g_dir_close (dir);
-            goto error;
-        }
-    }
-    g_dir_close (dir);
-    free (dbpath);
-    
-    *newpath = folder;
-    return TRUE;
-
-error:
-    free (dbpath);
-    g_free (folder);
-    return FALSE;
-}
-
-gboolean
-kalu_alpm_load (const gchar *conffile, GError **error)
-{
-    GError             *local_err = NULL;
-    gchar              *newpath;
-    enum _alpm_errno_t  err;
-    pacman_config_t    *pac_conf = NULL;
-    
-    /* parse pacman.conf */
-    debug ("parsing pacman.conf (%s) for options", conffile);
-    if (!parse_pacman_conf (conffile, NULL, 0, 0, &pac_conf, &local_err))
-    {
-        g_propagate_error (error, local_err);
-        free_pacman_config (pac_conf);
-        return FALSE;
-    }
-    
-    debug ("setting up libalpm");
-    if (NULL == (alpm = calloc (1, sizeof (*alpm))))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to allocate memory");
-        free_pacman_config (pac_conf);
-        return FALSE;
-    }
-    
-    /* create tmp copy of db (so we can sync w/out being root) */
-    if (!create_local_db (pac_conf->dbpath, &newpath, &local_err))
-    {
-        g_set_error (error, KALU_ERROR, 1, "Unable to create local copy of database: %s",
-            local_err->message);
-        g_clear_error (&local_err);
-        free_pacman_config (pac_conf);
-        kalu_alpm_free ();
-        return FALSE;
-    }
-    alpm->dbpath = newpath;
-    
-    /* init libalpm */
-    alpm->handle = alpm_initialize (pac_conf->rootdir, alpm->dbpath, &err);
-    if (alpm->handle == NULL)
-    {
-        g_set_error (error, KALU_ERROR, 1, "Failed to initialize alpm library: %s",
-            alpm_strerror (err));
-        free_pacman_config (pac_conf);
-        kalu_alpm_free ();
-        return FALSE;
-    }
-    
-    /* set arch & some options (what to ignore during update) */
-    alpm_option_set_arch (alpm->handle, pac_conf->arch);
-    alpm_option_set_ignorepkgs (alpm->handle, pac_conf->ignorepkgs);
-    alpm_option_set_ignoregroups (alpm->handle, pac_conf->ignoregroups);
-    
-    /* now we need to add dbs */
-    alpm_list_t *i;
-    for (i = pac_conf->databases; i; i = alpm_list_next (i))
-    {
-        database_t *db_conf = i->data;
-        alpm_db_t *db;
-        
-        /* register db */
-        debug ("register %s", db_conf->name);
-        db = alpm_db_register_sync (alpm->handle, db_conf->name, db_conf->siglevel);
-        if (db == NULL)
-        {
-            g_set_error (error, KALU_ERROR, 1, "Could not register database %s: %s",
-                db_conf->name, alpm_strerror (alpm_errno (alpm->handle)));
-            free_pacman_config (pac_conf);
-            kalu_alpm_free ();
-            return FALSE;
-        }
-        
-        /* add servers */
-        alpm_list_t *j;
-        for (j = db_conf->servers; j; j = alpm_list_next (j))
-        {
-            char *value = j->data;
-            const char *dbname = alpm_db_get_name (db);
-            /* let's attempt a replacement for the current repo */
-            char *temp = strreplace (value, "$repo", dbname);
-            /* let's attempt a replacement for the arch */
-            const char *arch = pac_conf->arch;
-            char *server;
-            
-            if (arch)
-            {
-                server = strreplace (temp, "$arch", arch);
-                free (temp);
-            }
-            else
-            {
-                if (strstr (temp, "$arch"))
-                {
-                    g_set_error (error, KALU_ERROR, 1, "Server %s contains the $arch variable, "
-                        "but no Architecture was defined", value);
-                    free (temp);
-                    free (value);
-                    free_pacman_config (pac_conf);
-                    kalu_alpm_free ();
-                    return FALSE;
-                }
-                server = temp;
-            }
-            
-            debug ("add server %s into %s", server, dbname);
-            if (alpm_db_add_server (db, server) != 0)
-            {
-                /* pm_errno is set by alpm_db_setserver */
-                g_set_error (error, KALU_ERROR, 1, "Could not add server %s to database %s: %s",
-                    server, dbname, alpm_strerror (alpm_errno (alpm->handle)));
-                free (server);
-                free (value);
-                free_pacman_config (pac_conf);
-                kalu_alpm_free ();
-                return FALSE;
-            }
-            
-            free (server);
-        }
-    }
-    
-    /* set global var */
-    alpm_verbose = pac_conf->verbosepkglists;
-    
-    free_pacman_config (pac_conf);
-    return TRUE;
-}
-
-gboolean
-kalu_alpm_syncdbs (gint *nb_dbs_synced, GError **error)
-{
-    alpm_list_t     *sync_dbs   = NULL;
-    alpm_list_t     *i;
-    GError          *local_err  = NULL;
-    int             ret;
-    
-    if (!check_syncdbs (alpm, 1, 0, &local_err))
-    {
-        g_propagate_error (error, local_err);
-		return FALSE;
-	}
-    
-    sync_dbs = alpm_option_get_syncdbs (alpm->handle);
-    *nb_dbs_synced = 0;
-    for (i = sync_dbs; i; i = alpm_list_next (i))
-    {
-		alpm_db_t *db = i->data;
-
-        ret = alpm_db_update (0, db);
-        if (ret < 0)
-        {
-            g_set_error (error, KALU_ERROR, 1, "Failed to update %s: %s",
-                alpm_db_get_name (db), alpm_strerror (alpm_errno (alpm->handle)));
-            return FALSE;
-		}
-        else if (ret == 1)
-        {
-			debug ("%s is up to date", alpm_db_get_name (db));
-		}
-        else
-        {
-            ++*nb_dbs_synced;
-            debug ("%s was updated", alpm_db_get_name (db));
-		}
-	}
-    
-    return TRUE;
-}
-
-gboolean
-kalu_alpm_has_updates (alpm_list_t **packages, GError **error)
-{
-    alpm_list_t *i;
-    alpm_list_t *data       = NULL;
-    GError      *local_err  = NULL;
-    
-    if (!check_syncdbs (alpm, 1, 1, &local_err))
-    {
-        g_propagate_error (error, local_err);
-		return FALSE;
-	}
-    
-    if (!trans_init (alpm, alpm->flags, 1, &local_err) == -1)
-    {
-        g_propagate_error (error, local_err);
-		return FALSE;
-	}
-    
-    if (alpm_sync_sysupgrade (alpm->handle, 0) == -1)
-    {
-        g_set_error (error, KALU_ERROR, 1, "%s", alpm_strerror (alpm_errno (alpm->handle)));
-        goto cleanup;
-    }
-    
-    if (alpm_trans_prepare (alpm->handle, &data) == -1)
-    {
-        int len = 1024;
-        gchar buf[255], err[len--];
-        err[0] = '\0';
-		switch (alpm_errno (alpm->handle))
-        {
-			case ALPM_ERR_PKG_INVALID_ARCH:
-				for (i = data; i; i = alpm_list_next (i))
-                {
-					const char *pkg = i->data;
-                    len -= snprintf (buf, 255, "- Package %s does not have a valid architecture\n",
-                                    pkg);
-					if (len >= 0)
-                    {
-                        strncat (err, buf, (size_t) len);
-                    }
-				}
-				break;
-			case ALPM_ERR_UNSATISFIED_DEPS:
-				for (i = data; i; i = alpm_list_next (i))
-                {
-					alpm_depmissing_t *miss = i->data;
-					char *depstring = alpm_dep_compute_string (miss->depend);
-                    len -= snprintf (buf, 255, "- %s requires %s\n", miss->target, depstring);
-					if (len >= 0)
-                    {
-                        strncat (err, buf, (size_t) len);
-                    }
-					free (depstring);
-				}
-				break;
-			case ALPM_ERR_CONFLICTING_DEPS:
-				for (i = data; i; i = alpm_list_next (i))
-                {
-					alpm_conflict_t *conflict = i->data;
-					/* only print reason if it contains new information */
-					if (conflict->reason->mod == ALPM_DEP_MOD_ANY)
-                    {
-						len -= snprintf (buf, 255, "- %s and %s are in conflict\n",
-								 conflict->package1, conflict->package2);
-                        if (len >= 0)
-                        {
-                            strncat (err, buf, (size_t) len);
-                        }
-					}
-                    else
-                    {
-						char *reason = alpm_dep_compute_string (conflict->reason);
-						len -= snprintf (buf, 255, "- %s and %s are in conflict (%s)\n",
-								 conflict->package1, conflict->package2, reason);
-                        if (len >= 0)
-                        {
-                            strncat (err, buf, (size_t) len);
-                        }
-                        free (reason);
-					}
-				}
-				break;
-			default:
-				break;
-		}
-        g_set_error (error, KALU_ERROR, 2, "Failed to prepare transaction: %s\n%s",
-            alpm_strerror (alpm_errno (alpm->handle)), err);
-		goto cleanup;
-	}
-    
-    alpm_db_t  *db_local = alpm_option_get_localdb (alpm->handle);
-    for (i = alpm_trans_get_add (alpm->handle); i; i = alpm_list_next (i))
-    {
-        alpm_pkg_t *pkg = i->data;
-        alpm_pkg_t *old = alpm_db_get_pkg (db_local, alpm_pkg_get_name (pkg));
-        kalu_package_t *package;
-        
-        package = calloc (1, sizeof (*package));
-        package->name = strdup (alpm_pkg_get_name (pkg));
-        package->new_version = strdup (alpm_pkg_get_version (pkg));
-        package->dl_size = (guint) alpm_pkg_download_size (pkg);
-        package->new_size = (guint) alpm_pkg_get_isize (pkg);
-        /* we might not have an old package, when an update requires to
-         * install a new package (e.g. after a split) */
-        if (old)
-        {
-            package->old_version = strdup (alpm_pkg_get_version (old));
-            package->old_size = (guint) alpm_pkg_get_isize (old);
-        }
-        else
-        {
-            package->old_version = strdup ("none");
-            package->old_size = 0;
-        }
-        
-        *packages = alpm_list_add (*packages, package);
-    }
-    
-cleanup:
-	if (data)
-    {
-		FREELIST (data);
-	}
-    trans_release (alpm, NULL);
-    
-    return (*packages != NULL);
-}
-
-gboolean
-kalu_alpm_has_updates_watched (alpm_list_t **packages, alpm_list_t *watched, GError **error)
-{
-    alpm_list_t *sync_dbs = alpm_option_get_syncdbs (alpm->handle);
-    alpm_list_t *i, *j;
-    GError *local_err = NULL;
-    
-    if (!check_syncdbs (alpm, 1, 1, &local_err))
-    {
-        g_propagate_error (error, local_err);
-		return FALSE;
-	}
-    
-    for (i = watched; i; i = alpm_list_next (i))
-    {
-        watched_package_t *w_pkg = i->data;
-        for (j = sync_dbs; j; j = alpm_list_next (j))
-        {
-            alpm_pkg_t *pkg = alpm_db_get_pkg ((alpm_db_t *) j->data, w_pkg->name);
-            if (pkg)
-            {
-                if (alpm_pkg_vercmp (alpm_pkg_get_version (pkg), w_pkg->version) > 0)
-                {
-                    kalu_package_t *package;
-                    package = calloc (1, sizeof (*package));
-                    
-                    package->name = strdup (alpm_pkg_get_name (pkg));
-                    package->old_version = strdup (w_pkg->version);
-                    package->new_version = strdup (alpm_pkg_get_version (pkg));
-                    package->dl_size = (guint) alpm_pkg_download_size (pkg);
-                    package->new_size = (guint) alpm_pkg_get_isize (pkg);
-                    
-                    *packages = alpm_list_add (*packages, package);
-                    debug ("found watched update %s: %s -> %s", package->name,
-                           package->old_version, package->new_version);
-                }
-                break;
-            }
-        }
-    }
-    
-    return (*packages != NULL);
-}
-
-gboolean
-kalu_alpm_has_foreign (alpm_list_t **packages, alpm_list_t *ignore, GError **error)
-{
-    alpm_db_t *dblocal;
-    alpm_list_t *sync_dbs, *i, *j;
-    gboolean found;
-    GError *local_err = NULL;
-    
-    if (!check_syncdbs (alpm, 1, 1, &local_err))
-    {
-        g_propagate_error (error, local_err);
-		return FALSE;
-	}
-    
-    dblocal  = alpm_option_get_localdb (alpm->handle);
-    sync_dbs = alpm_option_get_syncdbs (alpm->handle);
-    
-    for (i = alpm_db_get_pkgcache (dblocal); i; i = alpm_list_next (i))
-    {
-        alpm_pkg_t *pkg = i->data;
-        const char *pkgname = alpm_pkg_get_name (pkg);
-        found = FALSE;
-        
-        if (NULL != alpm_list_find_str (ignore, pkgname))
-        {
-            continue;
-        }
-        
-        for (j = sync_dbs; j; j = alpm_list_next (j))
-        {
-            if (alpm_db_get_pkg ((alpm_db_t *) j->data, pkgname))
-            {
-                found = TRUE;
-                break;
-            }
-        }
-        if (!found)
-        {
-            *packages = alpm_list_add (*packages, pkg);
-        }
-    }
-    
-    return (*packages != NULL);
-}
-
-void
-kalu_alpm_free (void)
-{
-    if (alpm == NULL)
-    {
-        return;
-    }
-    
-    if (alpm->handle != NULL)
-    {
-        alpm_release (alpm->handle);
-    }
-    
-    /* yes, we remove the dbpath. because we made a tmp copy of it */
-    if (alpm->dbpath)
-    {
-        rmrf (alpm->dbpath);
-    }
-	free (alpm->dbpath);
-    
-    g_free (alpm);
-    alpm = NULL;
-}

alpm.h

-/**
- * kalu - Copyright (C) 2012 Olivier Brunel
- *
- * alpm.h
- * Copyright (C) 2012 Olivier Brunel <i.am.jack.mail@gmail.com>
- * 
- * This file is part of kalu.
- *
- * kalu 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.
- *
- * kalu 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
- * kalu. If not, see http://www.gnu.org/licenses/
- */
-
-#ifndef _KALU_ALPM_H
-#define _KALU_ALPM_H
-
-/* glib */
-#include <glib-2.0/glib.h>
-
-/* alpm */
-#include <alpm.h>
-#include <alpm_list.h>
-
-typedef struct _kalu_alpm_t {
-    char            *dbpath; /* the tmp-path where we copied dbs */
-    alpm_handle_t   *handle;
-    alpm_transflag_t flags;
-} kalu_alpm_t;
-
-/* global variable */
-extern unsigned short alpm_verbose;
-
-gboolean
-kalu_alpm_load (const gchar *conffile, GError **error);
-
-gboolean
-kalu_alpm_syncdbs (gint *nb_dbs_synced, GError **error);
-
-gboolean
-kalu_alpm_has_updates (alpm_list_t **packages, GError **error);
-
-gboolean
-kalu_alpm_has_updates_watched (alpm_list_t **packages, alpm_list_t *watched, GError **error);
-
-gboolean
-kalu_alpm_has_foreign (alpm_list_t **packages, alpm_list_t *ignore, GError **error);
-
-void
-kalu_alpm_free (void);
-
-#endif /* _KALU_ALPM_H */
  * kalu. If not, see http://www.gnu.org/licenses/
  */
 
-#define _BSD_SOURCE /* for strdup w/ -std=c99 */
+#include <config.h>
 
 /* C */
 #include <string.h>
 #ifndef _KALU_AUR_H
 #define _KALU_AUR_H
 
-#define AUR_URL_PREFIX      "http://aur.archlinux.org/rpc.php?type=multiinfo"
-#define AUR_URL_PREFIX_PKG  "&arg[]="
-
 gboolean
 aur_has_updates (alpm_list_t **packages,
                  alpm_list_t *aur_pkgs,
+/**
+ * kalu - Copyright (C) 2012 Olivier Brunel
+ *
+ * conf.c
+ * Copyright (C) 2012 Olivier Brunel <i.am.jack.mail@gmail.com>
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ * 
+ * This file is part of kalu.
+ *
+ * kalu 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.
+ *
+ * kalu 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
+ * kalu. If not, see http://www.gnu.org/licenses/
+ */
+
+#include <config.h>
+
+/* C */
+#include <string.h>
+#include <glob.h>
+#include <sys/utsname.h> /* uname */
+#include <errno.h>
+
+/* alpm */
+#include <alpm.h>
+#include <alpm_list.h>
+
+/* kalu */
+#include "kalu.h"
+#include "conf.h"
+#include "util.h"
+
+/* some default values */
+#define PACMAN_ROOTDIR      "/"
+#define PACMAN_DBPATH       "/var/lib/pacman/"
+#define PACMAN_CACHEDIR     "/var/cache/pacman/pkg/"
+#define PACMAN_LOGFILE      "/var/log/pacman.log"
+#define PACMAN_GPGDIR       "/etc/pacman.d/gnupg/"
+
+typedef struct _siglevel_def_t {
+    char *file;
+    int   linenum;
+    char *def;
+} siglevel_def_t;
+
+/*******************************************************************************
+ * The following functions come from pacman's source code. (They might have
+ * been modified.)
+ * 
+ * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
+ * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
+ * http://projects.archlinux.org/pacman.git
+ * 
+ ******************************************************************************/
+
+/** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
+ * settings. Refactored out of the parseconfig code since all of them did
+ * the exact same thing and duplicated code.
+ * @param ptr a pointer to the start of the multiple options
+ * @param option the string (friendly) name of the option, used for messages
+ * @param list the list to add the option to
+ */
+static void
+setrepeatingoption (char *ptr, const char *option, alpm_list_t **list)
+{
+	char *q;
+
+	while ((q = strchr(ptr, ' ')))
+    {
+		*q = '\0';
+		*list = alpm_list_add (*list, strdup (ptr));
+		debug ("config: %s: %s", option, ptr);
+		ptr = q;
+		ptr++;
+	}
+	*list = alpm_list_add (*list, strdup (ptr));
+	debug ("config: %s: %s", option, ptr);
+}
+
+/**
+ * Parse a signature verification level line.
+ * @param values the list of parsed option values
+ * @param storage location to store the derived signature level; any existing
+ * value here is used as a starting point
+ * @param file path to the config file
+ * @param linenum current line number in file
+ * @return 0 on success, 1 on any parsing error
+ */
+static int
+process_siglevel (alpm_list_t *values, alpm_siglevel_t *storage,
+                  const char *file, int linenum, GError **error)
+{
+	alpm_siglevel_t level = *storage;
+	alpm_list_t *i;
+	int ret = 0;
+
+	/* Collapse the option names into a single bitmasked value */
+	for (i = values; i; i = alpm_list_next (i))
+    {
+		const char *original = i->data, *value;
+		int package = 0, database = 0;
+
+		if (strncmp (original, "Package", strlen ("Package")) == 0)
+        {
+			/* only packages are affected, don't flip flags for databases */
+			value = original + strlen("Package");
+			package = 1;
+		}
+        else if (strncmp (original, "Database", strlen ("Database")) == 0)
+        {
+			/* only databases are affected, don't flip flags for packages */
+			value = original + strlen("Database");
+			database = 1;
+		}
+        else
+        {
+			/* no prefix, so anything found will affect both packages and dbs */
+			value = original;
+			package = database = 1;
+		}
+
+		/* now parse out and store actual flag if it is valid */
+		if (strcmp (value, "Never") == 0)
+        {
+			if (package)
+            {
+				level &= ~ALPM_SIG_PACKAGE;
+			}
+			if (database)
+            {
+				level &= ~ALPM_SIG_DATABASE;
+			}
+		}
+        else if (strcmp (value, "Optional") == 0)
+        {
+			if (package)
+            {
+				level |= ALPM_SIG_PACKAGE;
+				level |= ALPM_SIG_PACKAGE_OPTIONAL;
+			}
+			if (database)
+            {
+				level |= ALPM_SIG_DATABASE;
+				level |= ALPM_SIG_DATABASE_OPTIONAL;
+			}
+		}
+        else if (strcmp (value, "Required") == 0)
+        {
+			if (package)
+            {
+				level |= ALPM_SIG_PACKAGE;
+				level &= ~ALPM_SIG_PACKAGE_OPTIONAL;
+			}
+			if (database)
+            {
+				level |= ALPM_SIG_DATABASE;
+				level &= ~ALPM_SIG_DATABASE_OPTIONAL;
+			}
+		}
+        else if (strcmp (value, "TrustedOnly") == 0)
+        {
+			if (package)
+            {
+				level &= ~ALPM_SIG_PACKAGE_MARGINAL_OK;
+				level &= ~ALPM_SIG_PACKAGE_UNKNOWN_OK;
+			}
+			if (database)
+            {
+				level &= ~ALPM_SIG_DATABASE_MARGINAL_OK;
+				level &= ~ALPM_SIG_DATABASE_UNKNOWN_OK;
+			}
+		}
+        else if (strcmp (value, "TrustAll") == 0)
+        {
+			if (package)
+            {
+				level |= ALPM_SIG_PACKAGE_MARGINAL_OK;
+				level |= ALPM_SIG_PACKAGE_UNKNOWN_OK;
+			}
+			if (database)
+            {
+				level |= ALPM_SIG_DATABASE_MARGINAL_OK;
+				level |= ALPM_SIG_DATABASE_UNKNOWN_OK;
+			}
+		}
+        else
+        {
+            g_set_error (error, KALU_ERROR, 1, "Config file %s, line %d: "
+                "invalid value for SigLevel: %s", file, linenum, original);
+			ret = 1;
+            break;
+		}
+		level &= ~ALPM_SIG_USE_DEFAULT;
+	}
+
+	if(!ret)
+    {
+		*storage = level;
+	}
+	return ret;
+}
+
+#define set_error(fmt, ...)  g_set_error (error, KALU_ERROR, 1, \
+    "Config file %s, line %d: " fmt, file, linenum, __VA_ARGS__);
+/** inspired from pacman's function */
+gboolean
+parse_pacman_conf (const char       *file,
+                   char             *name,
+                   int               is_options,
+                   int               depth,
+                   pacman_config_t **pacconf,
+                   GError          **error)
+{
+	FILE       *fp              = NULL;
+	char        line[MAX_PATH];
+	int         linenum         = 0;
+	int         success         = TRUE;
+	const int   max_depth       = 10;
+    GError     *local_err       = NULL;
+    alpm_list_t *i, *j;
+    
+    /* if struct is not init yet, we do it */
+    if (*pacconf == NULL)
+    {
+        *pacconf = calloc (1, sizeof (**pacconf));
+        if (*pacconf == NULL)
+        {
+            g_set_error (error, KALU_ERROR, 1, "Unable to allocate memory");
+            success = FALSE;
+            goto cleanup;
+        }
+        (*pacconf)->siglevel = ALPM_SIG_USE_DEFAULT;
+    }
+    pacman_config_t *pac_conf = *pacconf;
+    /* the db/repo we're currently parsing, if any */
+    static database_t *cur_db = NULL;
+
+	debug ("config: attempting to read file %s", file);
+	fp = fopen (file, "r");
+	if (fp == NULL)
+    {
+        g_set_error (error, KALU_ERROR, 1, "Config file %s could not be read",
+            file);
+		success = FALSE;
+		goto cleanup;
+	}
+    
+	while (fgets (line, MAX_PATH, fp))
+    {
+		char *key, *value, *ptr;
+		size_t line_len;
+
+		++linenum;
+		strtrim (line);
+		line_len = strlen(line);
+
+		/* ignore whole line and end of line comments */
+		if (line_len == 0 || line[0] == '#')
+        {
+			continue;
+		}
+		if ((ptr = strchr(line, '#')))
+        {
+			*ptr = '\0';
+		}
+
+		if (line[0] == '[' && line[line_len - 1] == ']')
+        {
+			/* only possibility here is a line == '[]' */
+			if (line_len <= 2)
+            {
+                set_error ("%s", "bad section name");
+				success = FALSE;
+				goto cleanup;
+			}
+			/* new config section, skip the '[' */
+            if (name != NULL)
+            {
+                free (name);
+            }
+			name = strdup (line + 1);
+			name[line_len - 2] = '\0';
+			debug ("config: new section '%s'", name);
+			is_options = (strcmp(name, "options") == 0);
+            /* parsed a db/repo? if so we add it */
+            if (cur_db != NULL)
+            {
+                pac_conf->databases = alpm_list_add (pac_conf->databases, cur_db);
+                cur_db = NULL;
+            }
+			continue;
+		}
+
+		/* directive */
+		/* strsep modifies the 'line' string: 'key \0 value' */
+		key = line;
+		value = line;
+		strsep (&value, "=");
+		strtrim (key);
+		strtrim (value);
+
+		if (key == NULL)
+        {
+            set_error ("%s", "syntax error: missing key.");
+			success = FALSE;
+			goto cleanup;
+		}
+        /* For each directive, compare to the camelcase string. */
+        if (name == NULL)
+        {
+            set_error ("%s", "All directives must belong to a section.");
+            success = FALSE;
+            goto cleanup;
+        }
+        /* Include is allowed in both options and repo sections */
+        if (strcmp(key, "Include") == 0)
+        {
+            glob_t globbuf;
+            int globret;
+            size_t gindex;
+            
+            if (depth + 1 >= max_depth)
+            {
+                set_error ("parsing exceeded max recursion depth of %d", max_depth);
+                success = FALSE;
+                goto cleanup;
+            }
+            
+            if (value == NULL)
+            {
+                set_error ("directive %s needs a value.", key);
+                success = FALSE;
+                goto cleanup;
+            }
+            
+            /* Ignore include failures... assume non-critical */
+            globret = glob (value, GLOB_NOCHECK, NULL, &globbuf);
+            switch (globret)
+            {
+                case GLOB_NOSPACE:
+                    debug ("config file %s, line %d: include globbing out of space",
+                            file, linenum);
+                break;
+                case GLOB_ABORTED:
+                    debug ("config file %s, line %d: include globbing read error for %s",
+                            file, linenum, value);
+                break;
+                case GLOB_NOMATCH:
+                    debug ("config file %s, line %d: no include found for %s",
+                            file, linenum, value);
+                break;
+                default:
+                    for (gindex = 0; gindex < globbuf.gl_pathc; gindex++)
+                    {
+                        debug ("config file %s, line %d: including %s",
+                               file, linenum, globbuf.gl_pathv[gindex]);
+                        parse_pacman_conf (globbuf.gl_pathv[gindex], name,
+                            is_options, depth + 1, &pac_conf, error);
+                    }
+                break;
+            }
+            globfree (&globbuf);
+            continue;
+        }
+        /* we are either in options ... */
+        if (is_options)
+        {
+            if (value == NULL)
+            {
+                /* options without settings */
+                if (strcmp (key, "UseSyslog") == 0)
+                {
+                    pac_conf->usesyslog = 1;
+                    debug ("config: usesyslog");
+                }
+                else if (strcmp (key, "VerbosePkgLists") == 0)
+                {
+                    pac_conf->verbosepkglists = 1;
+                    debug ("config: verbosepkglists");
+                }
+                else if (strcmp (key, "UseDelta") == 0)
+                {
+                    pac_conf->usedelta = 1;
+                    debug ("config: usedelta");
+                }
+                else if (strcmp (key, "CheckSpace") == 0)
+                {
+                    pac_conf->checkspace = 1;
+                    debug ("config: checkspace");
+                }
+                /* we silently ignore "unrecognized" options, since we don't
+                 * parse all of pacman's options anyways... */
+            }
+            else
+            {
+                /* options with settings */
+                
+                if (strcmp (key, "NoUpgrade") == 0)
+                {
+                    setrepeatingoption (value, "NoUpgrade", &(pac_conf->noupgrades));
+                }
+                else if (strcmp (key, "NoExtract") == 0)
+                {
+                    setrepeatingoption (value, "NoExtract", &(pac_conf->noextracts));
+                }
+                else if (strcmp (key, "IgnorePkg") == 0)
+                {
+                    setrepeatingoption (value, "IgnorePkg", &(pac_conf->ignorepkgs));
+                }
+                else if (strcmp (key, "IgnoreGroup") == 0)
+                {
+                    setrepeatingoption (value, "IgnoreGroup", &(pac_conf->ignoregroups));
+                }
+                else if (strcmp (key, "SyncFirst") == 0)
+                {
+                    setrepeatingoption (value, "SyncFirst", &(pac_conf->syncfirst));
+                }
+                else if (strcmp (key, "CacheDir") == 0)
+                {
+                    setrepeatingoption (value, "CacheDir", &(pac_conf->cachedirs));
+                }
+                else if (strcmp (key, "Architecture") == 0)
+                {
+                    if (strcmp(value, "auto") == 0)
+                    {
+                        struct utsname un;
+                        uname (&un);
+                        pac_conf->arch = strdup (un.machine);
+                    }
+                    else
+                    {
+                        pac_conf->arch = strdup (value);
+                    }
+                    debug ("config: arch: %s", pac_conf->arch);
+                }
+                else if (strcmp (key, "DBPath") == 0)
+                {
+                    pac_conf->dbpath = strdup (value);
+                    debug ("config: dbpath: %s", value);
+                }
+                else if (strcmp (key, "RootDir") == 0)
+                {
+                    pac_conf->rootdir = strdup (value);
+                    debug ("config: rootdir: %s", value);
+                }
+                else if (strcmp (key, "GPGDir") == 0)
+                {
+                    pac_conf->gpgdir = strdup (value);
+                    debug ("config: gpgdir: %s", value);
+                }
+                else if (strcmp (key, "LogFile") == 0)
+                {
+                    pac_conf->logfile = strdup (value);
+                    debug ("config: logfile: %s", value);
+                }
+                else if (strcmp (key, "SigLevel") == 0)
+                {
+                    alpm_list_t *values = NULL;
+                    setrepeatingoption (value, "SigLevel", &values);
+                    local_err = NULL;
+                    if (process_siglevel (values, &pac_conf->siglevel, file,
+                            linenum, &local_err))
+                    {
+                        g_propagate_error (error, local_err);
+                        FREELIST (values);
+                        success = FALSE;
+                        goto cleanup;
+                    }
+                    FREELIST (values);
+                }
+                /* we silently ignore "unrecognized" options, since we don't
+                 * parse all of pacman's options anyways... */
+            }
+        }
+        /* ... or in a repo section */
+        else
+        {
+            if (cur_db == NULL)
+            {
+                cur_db = calloc (1, sizeof (*cur_db));
+                cur_db->name = strdup (name);
+            }
+            
+            if (strcmp (key, "Server") == 0)
+            {
+                if (value == NULL)
+                {
+                    set_error ("directive %s needs a value.", key);
+                    success = FALSE;
+                    goto cleanup;
+                }
+                cur_db->servers = alpm_list_add (cur_db->servers, strdup (value));
+            }
+            else if (strcmp (key, "SigLevel") == 0)
+            {
+                siglevel_def_t *siglevel_def;
+                siglevel_def = calloc (1, sizeof (*siglevel_def));
+                siglevel_def->file = strdup (file);
+                siglevel_def->linenum = linenum;
+                siglevel_def->def = strdup (value);
+                cur_db->siglevel_def = alpm_list_add (cur_db->siglevel_def, siglevel_def);
+			}
+            else
+            {
+                set_error ("directive %s in section %s not recognized.", key, name);
+                success = FALSE;
+                goto cleanup;
+			}
+        }
+	}
+
+	if (depth == 0)
+    {
+        /* parsed a db/repo? if so we add it */
+        if (cur_db != NULL)
+        {
+            pac_conf->databases = alpm_list_add (pac_conf->databases, cur_db);
+            cur_db = NULL;
+        }
+        /* processing databases siglevel */
+        for (i = pac_conf->databases; i; i = alpm_list_next (i))
+        {
+            database_t *db = i->data;
+            db->siglevel = pac_conf->siglevel;
+            for (j = db->siglevel_def; j; j = alpm_list_next (j))
+            {
+				siglevel_def_t *siglevel_def = j->data;
+                alpm_list_t *values = NULL;
+				setrepeatingoption (siglevel_def->def, "SigLevel", &values);
+				if (values)
+                {
+                    local_err = NULL;
+					if (process_siglevel (values, &db->siglevel, siglevel_def->file,
+                            siglevel_def->linenum, &local_err))
+                    {
+                        g_propagate_error (error, local_err);
+						FREELIST (values);
+						success = FALSE;
+						goto cleanup;
+					}
+					FREELIST (values);
+				}
+            }
+        }
+        /* set some default values for undefined options */
+        if (NULL == pac_conf->rootdir)
+        {
+            pac_conf->rootdir = strdup (PACMAN_ROOTDIR);
+        }
+        if (NULL == pac_conf->dbpath)
+        {
+            pac_conf->dbpath = strdup (PACMAN_DBPATH);
+        }
+        if (NULL == pac_conf->cachedirs)
+        {
+            pac_conf->cachedirs = alpm_list_add (pac_conf->cachedirs,
+                                    strdup (PACMAN_CACHEDIR));
+        }
+        if (NULL == pac_conf->logfile)
+        {
+            pac_conf->logfile = strdup (PACMAN_LOGFILE);
+        }
+        if (NULL == pac_conf->gpgdir)
+        {
+            pac_conf->gpgdir = strdup (PACMAN_GPGDIR);
+        }
+	}
+
+cleanup:
+	if (fp)
+    {
+		fclose(fp);
+	}
+    if (depth == 0)
+    {
+        /* section name is for internal processing only */
+        if (name != NULL)
+        {
+            free (name);
+            name = NULL;
+        }
+        /* so are the siglevel_def of each & all databases */
+        for (i = pac_conf->databases; i; i = alpm_list_next (i))
+        {
+            database_t *db = i->data;
+            for (j = db->siglevel_def; j; j = alpm_list_next (j))
+            {
+                siglevel_def_t *siglevel_def = j->data;
+                free (siglevel_def->file);
+                free (siglevel_def->def);
+                free (siglevel_def);
+            }
+            alpm_list_free (db->siglevel_def);
+            db->siglevel_def = NULL;
+        }
+    }
+	debug ("config: finished parsing %s", file);
+	return success;
+}
+#undef set_error
+
+/******************************************************************************/
+
+void
+free_pacman_config (pacman_config_t *pac_conf)
+{
+    if (pac_conf == NULL)
+    {
+        return;
+    }
+    
+    /* alpm */
+    free (pac_conf->rootdir);
+    free (pac_conf->dbpath);
+    free (pac_conf->logfile);
+    free (pac_conf->gpgdir);
+    FREELIST (pac_conf->cachedirs);
+    free (pac_conf->arch);
+    FREELIST (pac_conf->ignorepkgs);
+    FREELIST (pac_conf->ignoregroups);
+    FREELIST (pac_conf->noupgrades);
+    FREELIST (pac_conf->noextracts);
+    
+    /* non-alpm */
+    FREELIST (pac_conf->syncfirst);
+    
+    /* dbs/repos */
+    alpm_list_t *i;
+    for (i = pac_conf->databases; i; i = alpm_list_next (i))
+    {
+        database_t *db = i->data;
+        free (db->name);
+        FREELIST (db->servers);
+        free (db);
+    }
+    alpm_list_free (pac_conf->databases);
+    
+    /* done */
+    free (pac_conf);
+}
+
+static void
+setstringoption (char *value, const char *option, char **cfg)
+{
+    size_t len;
+    
+    if (NULL != *cfg)
+        free (*cfg);
+    
+    if (value[0] == '"')
+    {
+        len = strlen (value) - 1;
+        if (value[len] == '"')
+        {
+            value[len] = '\0';
+            ++value;
+        }
+    }
+    
+    *cfg = strreplace (value, "\\n", "\n");
+    debug ("config: %s: %s", option, value);
+}
+
+#define add_error(fmt, ...) do {                                        \
+        if (!err_msg)                                                   \
+        {                                                               \
+            err_msg = g_string_sized_new (1024);                        \
+        }                                                               \
+        g_string_append_printf (err_msg,                                \
+                                "Config file %s, line %d: " fmt "\n",   \
+                                file, linenum, __VA_ARGS__);            \
+    } while (0)
+/** inspired from pacman's function */
+gboolean
+parse_config_file (const char       *file,
+                   conf_file_t       conf_file,
+                   GError          **error)
+{
+	FILE       *fp              = NULL;
+	char        line[MAX_PATH];
+	int         linenum         = 0;
+    char       *section         = NULL;
+	int         success         = TRUE;
+    GString    *err_msg         = NULL;
+
+	debug ("config: attempting to read file %s", file);
+	fp = fopen (file, "r");
+	if (fp == NULL)
+    {
+        /* not an error if file does not exists */
+        if (errno != ENOENT)
+        {
+            g_set_error (error, KALU_ERROR, 1, "Config file %s could not be read", file);
+            success = FALSE;
+        }
+		goto cleanup;
+	}
+
+	while (fgets (line, MAX_PATH, fp))
+    {
+		char *key, *value, *ptr;
+		size_t line_len;
+
+		++linenum;
+		strtrim (line);
+		line_len = strlen(line);
+
+		/* ignore whole line and end of line comments */
+		if (line_len == 0 || line[0] == '#')
+        {
+			continue;
+		}
+		if ((ptr = strchr(line, '#')))
+        {
+			*ptr = '\0';
+		}
+
+		if (line[0] == '[' && line[line_len - 1] == ']')
+        {
+			/* only possibility here is a line == '[]' */
+			if (line_len <= 2)
+            {
+                add_error ("%s", "bad section name");
+                free (section);
+                section = NULL;
+                continue;
+			}
+			/* new config section, skip the '[' */
+            free (section);
+			section = strdup (line + 1);
+			section[line_len - 2] = '\0';
+            
+			debug ("config: new section '%s'", section);
+			continue;
+		}
+        
+		/* directive */
+		/* strsep modifies the 'line' string: 'key \0 value' */
+		key = line;
+		value = line;
+		strsep (&value, "=");
+		strtrim (key);
+		strtrim (value);
+
+		if (key == NULL)
+        {
+            add_error ("%s", "syntax error: missing key");
+			continue;
+		}
+        
+        /* kalu.conf*/
+        if (conf_file == CONF_FILE_KALU)
+        {
+            if (value == NULL)
+            {
+                add_error ("value missing for %s", key);
+                continue;
+            }
+            else if (strcmp ("options", section) == 0)
+            {
+                if (strcmp (key, "PacmanConf") == 0)
+                {
+                    setstringoption (value, "pacmanconf", &(config->pacmanconf));
+                }
+                else if (strcmp (key, "Interval") == 0)
+                {
+                    config->interval = atoi (value);
+                    if (config->interval > 0)
+                    {
+                        config->interval *= 60; /* minutes into seconds */
+                    }
+                    else
+                    {
+                        config->interval = 3600; /* 1 hour */
+                    }
+                    
+                    debug ("config: interval: %d", config->interval);
+                }
+                else if (strcmp (key, "Timeout") == 0)
+                {
+                    if (strcmp (value, "DEFAULT") == 0)
+                    {
+                        config->timeout = NOTIFY_EXPIRES_DEFAULT;
+                    }
+                    else if (strcmp (value, "NEVER") == 0)
+                    {
+                        config->timeout = NOTIFY_EXPIRES_NEVER;
+                    }
+                    else
+                    {
+                        int timeout = atoi (value);
+                        if (timeout < 4 || timeout > 42)
+                        {
+                            add_error ("Invalid timeout delay: %s", value);
+                            continue;
+                        }
+                        config->timeout = timeout * 1000; /* from seconds to ms */
+                    }
+                    debug ("config: timeout: %d", config->timeout);
+                }
+                else if (strcmp (key, "SkipPeriod") == 0)
+                {
+                    int begin_hour, begin_minute, end_hour, end_minute;
+                    
+                    if (sscanf (value, "%d:%d-%d:%d", &begin_hour, &begin_minute,
+                            &end_hour, &end_minute) == 4)
+                    {
+                        if (begin_hour < 0 || begin_hour > 23
+                            || begin_minute < 0 || begin_minute > 59
+                            || end_hour < 0 || end_hour > 23
+                            || end_minute < 0 || end_minute > 59)
+                        {
+                            add_error ("invalid value for SkipPeriod: %s", value);
+                            continue;
+                        }
+                        config->has_skip = TRUE;
+                        config->skip_begin_hour   = begin_hour;
+                        config->skip_begin_minute = begin_minute;
+                        config->skip_end_hour     = end_hour;
+                        config->skip_end_minute   = end_minute;
+                        debug ("config: SkipPeriod: from %d:%d to %d:%d",
+                            config->skip_begin_hour, config->skip_begin_minute,
+                            config->skip_end_hour, config->skip_end_minute);
+                    }
+                    else
+                    {
+                        add_error ("unable to parse SkipPeriod (must be HH:MM-HH:MM) : %s",
+                                   value);
+                        continue;
+                    }
+                }
+                else if (strcmp (key, "NotificationIcon") == 0)
+                {
+                    if (strcmp (value, "KALU") == 0)
+                    {
+                        config->notif_icon = ICON_KALU;
+                    }
+                    else if (strcmp (value, "NONE") == 0)
+                    {
+                        config->notif_icon = ICON_NONE;
+                    }
+                    else if (value[0] == '/')
+                    {
+                        config->notif_icon = ICON_USER;
+                        config->notif_icon_user = strdup (value);
+                    }
+                    else
+                    {
+                        add_error ("invalid value for %s: %s", key, value);
+                        continue;
+                    }
+                    debug ("config: NotifIcon: %d", config->notif_icon);
+                    debug ("config: NotifIconUser: %s", config->notif_icon_user);
+                }
+                else if (strcmp (key, "UpgradeAction") == 0)
+                {
+                    if (strcmp (value, "NONE") == 0)
+                    {
+                        config->action = UPGRADE_NO_ACTION;
+                    }
+                    #ifndef DISABLE_UPDATER
+                    else if (strcmp (value, "KALU") == 0)
+                    {
+                        config->action = UPGRADE_ACTION_KALU;
+                    }
+                    #endif
+                    else if (strcmp (value, "CMDLINE") == 0)
+                    {
+                        config->action = UPGRADE_ACTION_CMDLINE;
+                    }
+                    else
+                    {
+                        add_error ("Invalid value for UpgradeAction: %s", value);
+                        continue;
+                    }
+                    debug ("config: action: %d", config->action);
+                }
+                else if (strcmp (key, "CmdLine") == 0)
+                {
+                    setstringoption (value, "cmdline", &(config->cmdline));
+                }
+                else if (strcmp (key, "CmdLineAur") == 0)
+                {
+                    setstringoption (value, "cmdline_aur", &(config->cmdline_aur));
+                }
+                #ifndef DISABLE_UPDATER
+                else if (strcmp (key, "PostSysUpgrade") == 0)
+                {
+                    config->cmdline_post = alpm_list_add (config->cmdline_post,
+                        strdup (value));
+                    debug ("config: postsysupgrade: %s", value);
+                }
+                #endif
+                else if (strcmp (key, "AurIgnore") == 0)
+                {
+                    setrepeatingoption (value, "aur_ignore", &(config->aur_ignore));
+                }
+                else if (strcmp (key, "ManualChecks") == 0
+                        || strcmp (key, "AutoChecks") == 0)
+                {
+                    char *v, *s;
+                    check_t checks = 0;
+                    
+                    for (v = value, s = (char *) 1; s; )
+                    {
+                        s = strchr(v, ' ');
+                        if (s)
+                        {
+                            *s = '\0';
+                        }
+                        
+                        if (strcmp ("UPGRADES", v) == 0)
+                        {
+                            checks |= CHECK_UPGRADES;
+                        }
+                        else if (strcmp ("WATCHED", v) == 0)
+                        {
+                            checks |= CHECK_WATCHED;
+                        }
+                        else if (strcmp ("AUR", v) == 0)
+                        {
+                            checks |= CHECK_AUR;
+                        }
+                        else if (strcmp ("WATCHED_AUR", v) == 0)
+                        {
+                            checks |= CHECK_WATCHED_AUR;
+                        }
+                        else if (strcmp ("NEWS", v) == 0)
+                        {
+                            checks |= CHECK_NEWS;
+                        }
+                        else
+                        {
+                            add_error ("unknown value for %s: %s", key, v);
+                            continue;
+                        }
+                        
+                        if (s)
+                        {
+                            v = s + 1;
+                        }
+                    }
+                    
+                    if (strcmp (key, "AutoChecks") == 0)
+                    {
+                        config->checks_auto = checks;
+                        debug ("config: checks_auto: %d", checks);
+                    }
+                    else /* if (strcmp (key, "ManualChecks") == 0) */
+                    {
+                        config->checks_manual = checks;
+                        debug ("config: checks_manual: %d", checks);
+                    }
+                }
+                else if (  strcmp (key, "OnSglClick") == 0
+                        || strcmp (key, "OnDblClick") == 0)
+                {
+                    on_click_t *on_click;
+                    if (strcmp (key, "OnSglClick") == 0)
+                    {
+                        on_click = &(config->on_sgl_click);
+                    }
+                    else
+                    {
+                        on_click = &(config->on_dbl_click);
+                    }
+                    
+                    if (strcmp (value, "CHECK") == 0)
+                    {
+                        *on_click = DO_CHECK;
+                    }
+                    else if (strcmp (value, "SYSUPGRADE") == 0)
+                    {
+                        *on_click = DO_SYSUPGRADE;
+                    }
+                    else if (strcmp (value, "NOTHING") == 0)
+                    {
+                        *on_click = DO_NOTHING;
+                    }
+                    else if (strcmp (value, "TOGGLE_WINDOWS") == 0)
+                    {
+                        *on_click = DO_TOGGLE_WINDOWS;
+                    }
+                    else
+                    {
+                        add_error ("unknown value for %s: %s", key, value);
+                        continue;
+                    }
+                    debug ("config: %s: %d", key, *on_click);
+                }
+                else if (strcmp (key, "SaneSortOrder") == 0)
+                {
+                    config->sane_sort_order = (*value == '1');
+                    debug ("config: sane sort order: %d", config->sane_sort_order);
+                }
+                else if (strcmp (key, "SyncDbsInTooltip") == 0)
+                {
+                    config->syncdbs_in_tooltip = (*value == '1');
+                    debug ("config: syncdbs in tooltip: %d", config->syncdbs_in_tooltip);
+                }
+                else
+                {
+                    add_error ("unknown option: %s", key);
+                    continue;
+                }
+            }
+            else
+            {
+                templates_t *t;
+                if (strcmp ("template-upgrades", section) == 0)
+                {
+                    t = config->tpl_upgrades;
+                }
+                else if (strcmp ("template-watched", section) == 0)
+                {
+                    t = config->tpl_watched;
+                }
+                else if (strcmp ("template-aur", section) == 0)
+                {
+                    t = config->tpl_aur;
+                }
+                else if (strcmp ("template-watched-aur", section) == 0)
+                {
+                    t = config->tpl_watched_aur;
+                }
+                else if (strcmp ("template-news", section) == 0)
+                {
+                    t = config->tpl_news;
+                }
+                else
+                {
+                    add_error ("unknown section: %s", section);
+                    continue;
+                }
+                
+                /* we're in a valid template */
+                
+                if (strcmp (key, "Title") == 0)
+                {
+                    setstringoption (value, "title", &(t->title));
+                }
+                else if (strcmp (key, "Package") == 0)
+                {
+                    setstringoption (value, "package", &(t->package));
+                }
+                else if (strcmp (key, "Sep") == 0)
+                {
+                    setstringoption (value, "sep", &(t->sep));
+                }
+            }
+        }
+        /* watched{,-aur}.conf */
+        else if (conf_file == CONF_FILE_WATCHED || conf_file == CONF_FILE_WATCHED_AUR)
+        {
+            if (value == NULL)
+            {
+                add_error ("watched package %s: version number missing", key);
+                continue;
+            }
+            else
+            {
+                alpm_list_t **list;
+                if (conf_file == CONF_FILE_WATCHED)
+                {
+                    list = &(config->watched);
+                }
+                else /* if (conf_file == CONF_FILE_WATCHED_AUR) */
+                {
+                    list = &(config->watched_aur);
+                }
+                
+                watched_package_t *w_pkg;
+                w_pkg = calloc (1, sizeof (*w_pkg));
+                w_pkg->name = strdup (key);
+                w_pkg->version = strdup (value);
+                *list = alpm_list_add (*list, w_pkg);
+                debug ("config: watched (aur) packages: added %s %s",
+                       w_pkg->name, w_pkg->version);
+            }
+        }
+        /* news.conf */
+        else if (conf_file == CONF_FILE_NEWS)
+        {
+            if (value == NULL)
+            {
+                add_error ("news data: value missing for %s", key);
+                continue;
+            }
+            else if (strcmp ("Last", key) == 0)
+            {
+                config->news_last = strdup (value);
+                debug ("config: news_last: %s", value);
+            }
+            else if (strcmp ("Read", key) == 0)
+            {
+                config->news_read = alpm_list_add (config->news_read, strdup (value));
+                debug ("config: news_read: added %s", value);
+            }
+        }
+	}
+
+cleanup:
+	if (fp)
+    {
+		fclose(fp);
+	}
+    free (section);
+    if (config->action == UPGRADE_ACTION_CMDLINE && config->cmdline == NULL)
+    {
+        #ifndef DISABLE_UPDATER
+        config->action = UPGRADE_ACTION_KALU;
+        #else
+        config->action = UPGRADE_NO_ACTION;
+        #endif
+        debug ("config: action: no cmdline set, reverting to %d", config->action);
+    }
+    if (err_msg)
+    {
+        g_set_error (error, KALU_ERROR, 1, "%s", err_msg->str);
+        g_string_free (err_msg, TRUE);
+        err_msg = NULL;
+        success = FALSE;
+    }
+	debug ("config: finished parsing %s", file);
+	return success;
+}
+#undef add_error
+/**
+ * kalu - Copyright (C) 2012 Olivier Brunel
+ *
+ * conf.h
+ * Copyright (C) 2012 Olivier Brunel <i.am.jack.mail@gmail.com>
+ * 
+ * This file is part of kalu.
+ *
+ * kalu 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.
+ *
+ * kalu 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
+ * kalu. If not, see http://www.gnu.org/licenses/
+ */
+
+#ifndef _KALU_CONFIG_H
+#define _KALU_CONFIG_H
+
+/* glib */
+#include <glib.h>
+
+/* alpm */
+#include <alpm.h>
+#include <alpm_list.h>
+
+/* type of conf file to parse */
+typedef enum _conf_file_t {
+    CONF_FILE_KALU,
+    CONF_FILE_WATCHED,
+    CONF_FILE_WATCHED_AUR,
+    CONF_FILE_NEWS
+} conf_file_t;
+
+/* database definition from parsing conf */
+typedef struct _database_t {
+    char            *name;
+    alpm_siglevel_t  siglevel;
+    alpm_list_t     *siglevel_def; /* for internal processing/parsing */
+    alpm_list_t     *servers;
+} database_t;
+
+/* config data loaded from parsing pacman.conf */
+typedef struct _pacman_config_t {
+    /* alpm */
+    char            *rootdir;
+    char            *dbpath;
+    char            *logfile;
+    char            *gpgdir;
+    alpm_list_t     *cachedirs;
+    alpm_siglevel_t  siglevel;
+    char            *arch;
+    int              checkspace;
+    int              usesyslog;
+    int              usedelta;
+    alpm_list_t     *ignorepkgs;
+    alpm_list_t     *ignoregroups;
+    alpm_list_t     *noupgrades;
+    alpm_list_t     *noextracts;
+    
+    /* non-alpm */
+    alpm_list_t     *syncfirst;
+    unsigned short   verbosepkglists;
+    
+    /* dbs/repos */
+    alpm_list_t     *databases;
+} pacman_config_t;
+
+gboolean
+parse_pacman_conf (const char       *file,
+                   char             *name,
+                   int               is_options,
+                   int               depth,
+                   pacman_config_t **pac_conf,
+                   GError          **error);
+
+void
+free_pacman_config (pacman_config_t *pac_conf);
+
+gboolean
+parse_config_file (const char       *file,
+                   conf_file_t       conf_file,
+                   GError          **error);
+
+
+#endif /* _KALU_CONFIG_H */

config.c

-/**
- * kalu - Copyright (C) 2012 Olivier Brunel
- *
- * config.c
- * Copyright (C) 2012 Olivier Brunel <i.am.jack.mail@gmail.com>
- * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
- * 
- * This file is part of kalu.
- *
- * kalu 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.
- *
- * kalu 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
- * kalu. If not, see http://www.gnu.org/licenses/
- */
-
-#define _BSD_SOURCE /* for strdup w/ -std=c99 */
-
-/* C */
-#include <string.h>
-#include <glob.h>
-#include <sys/utsname.h> /* uname */
-#include <errno.h>
-
-/* alpm */
-#include <alpm.h>
-#include <alpm_list.h>
-
-/* kalu */
-#include "kalu.h"
-#include "config.h"
-#include "util.h"
-#include "alpm.h"
-
-/* some default values */
-#define PACMAN_ROOTDIR      "/"
-#define PACMAN_DBPATH       "/var/lib/pacman/"
-#define PACMAN_CACHEDIR     "/var/cache/pacman/pkg/"
-#define PACMAN_LOGFILE      "/var/log/pacman.log"
-#define PACMAN_GPGDIR       "/etc/pacman.d/gnupg/"
-
-typedef struct _siglevel_def_t {
-    char *file;
-    int   linenum;
-    char *def;
-} siglevel_def_t;
-
-/*******************************************************************************
- * The following functions come from pacman's source code. (They might have
- * been modified.)
- * 
- * Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
- * Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
- * http://projects.archlinux.org/pacman.git
- * 
- ******************************************************************************/
-
-/** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm
- * settings. Refactored out of the parseconfig code since all of them did
- * the exact same thing and duplicated code.
- * @param ptr a pointer to the start of the multiple options
- * @param option the string (friendly) name of the option, used for messages
- * @param list the list to add the option to
- */
-static void
-setrepeatingoption (char *ptr, const char *option, alpm_list_t **list)
-{
-	char *q;
-
-	while ((q = strchr(ptr, ' ')))
-    {
-		*q = '\0';
-		*list = alpm_list_add (*list, strdup (ptr));
-		debug ("config: %s: %s", option, ptr);
-		ptr = q;