Commits

jjacky committed 523c1c1

now using automake & autoconf; added --disable-updater option to configure

Comments (0)

Files changed (27)

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
+
+dist_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)/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
+
+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 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_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;
+
+	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)
+            {
+                set_error ("%s", "bad section name");
+				success = FALSE;
+				goto cleanup;
+			}
+			/* new config section, skip the '[' */
+			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)
+        {
+            set_error ("%s", "syntax error: missing key");
+			success = FALSE;
+			goto cleanup;
+		}
+        
+        /* kalu.conf*/
+        if (conf_file == CONF_FILE_KALU)
+        {
+            if (value == NULL)
+            {
+                set_error ("value missing for %s", key);
+                success = FALSE;
+                goto cleanup;
+            }
+            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)
+                        {
+                            set_error ("Invalid timeout delay: %s", value);
+                            success = FALSE;
+                            goto cleanup;
+                        }
+                        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)
+                        {
+                            set_error ("invalid value for SkipPeriod: %s", value);
+                            success = FALSE;
+                            goto cleanup;
+                        }
+                        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
+                    {
+                        set_error ("unable to parse SkipPeriod (must be HH:MM-HH:MM) : %s",
+                                   value);
+                        success = FALSE;
+                        goto cleanup;
+                    }
+                }
+                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
+                    {
+                        set_error ("Invalid value for UpgradeAction: %s", value);
+                        success = FALSE;
+                        goto cleanup;
+                    }
+                    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
+                        {
+                            set_error ("unknown value for %s: %s", key, v);
+                            success = FALSE;
+                            goto cleanup;
+                        }
+                        
+                        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
+                    {
+                        set_error ("unknown value for %s: %s", key, value);
+                        success = FALSE;
+                        goto cleanup;
+                    }
+                    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
+                {
+                    set_error ("unknown option: %s", key);
+                    success = FALSE;
+                    goto cleanup;
+                }
+            }
+            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
+                {
+                    set_error ("unknown section: %s", section);
+                    success = FALSE;
+                    goto cleanup;
+                }
+                
+                /* 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)
+            {
+                set_error ("watched package %s: version number missing", key);
+                success = FALSE;
+                goto cleanup;
+            }
+            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)
+            {
+                set_error ("news data: value missing for %s", key);
+                success = FALSE;
+                goto cleanup;
+            }
+            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);
+	}
+    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);
+    }
+	debug ("config: finished parsing %s", file);
+	return success;
+}
+#undef set_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;
-		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;