/*
 * newsl_config.c
 *
 * Configuration load/save for newslettersan
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This program is licensed under the terms of the Affero GPL v1+
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "loglib.h"
#include "newsl_config.h"

#define MAXLINESIZE 2048
#define LINESBLOCK 32

typedef enum esection {
        section_none=0,
        section_general
} esection;


newslconfig *
newslconfig_init(char *configfile, char *deflogfile, char *defrootdir)
{
        newslconfig *config;
        FILE *f;
        char line[MAXLINESIZE];
        int len;
        char *ptr,*sep,*value;
        esection section;
        int lineno;
        char **configvalue;
        if((f=fopen(configfile,"r"))==NULL)
                return(NULL);
        if((config=malloc(sizeof(newslconfig)))==NULL) {
                fclose(f),f=NULL;
                return(NULL);
        }
        memset(config,0,sizeof(newslconfig));
        section=section_none;
        lineno=0;
        while(fgets(line,sizeof(line),f)!=NULL) {
                lineno++;
                line[sizeof(line)-1]='\0';
                /* trim line */
                for(ptr=line;*ptr!='\0' && strchr("\t ",*ptr)!=NULL;ptr++)
                        ;
                len=strlen(line);
                while(len>0 && strchr("\n\t ",line[len-1])!=NULL)
                        line[len-1]='\0',len--;
                for(ptr=line;*ptr!='\0' && strchr("\t ",*ptr)!=NULL;ptr++)
                        ;
                len=strlen(ptr);
                /* ignore empty lines and comments */
                if(*ptr=='\0' || strchr("#;",*ptr)!=NULL)
                        continue;
                /* parse line */
                if(*ptr=='[' && ptr[len-1]==']') {
                        /* section */
                        if(strcmp(ptr,"[general]")==0) {
                                section=section_general;
                        } else {
                                log_write("CONF","%s:%i: unknown section name \"%s\"\n",configfile,lineno,ptr);
                                section=section_none;
                        }
                        continue;
                } else if((sep=strchr(ptr,'='))!=NULL) {
                        *sep='\0';
                        value=sep+1;
                        /* trim key */
                        while(sep>ptr && strchr(" \t",sep[-1])!=NULL) {
                                sep--;
                                *sep='\0';
                        }
                        /* trim value */
                        while(*value!='\0' && strchr(" \t",*value)!=NULL)
                                value++;
                        /* sanity check */
                        if(*value=='\0') {
                                log_write("CONF","%s:%i: ignoring key without value; key:\"%s\"\n",configfile,lineno,ptr);
                                continue;
                        }
                         /* assign value */
                        if(section==section_none) {
                                log_write("CONF","%s:%i: ignoring key-value pair in unknown section; key:\"%s\"\n",configfile,lineno,ptr);
                                continue;
                        }
                        /* identify key-value pair */
                        if(section==section_general) {
                                if(strcmp(ptr,"logfile")==0) {
                                        configvalue=&(config->logfile);
                                } else if(strcmp(ptr,"rootdir")==0) {
                                        configvalue=&(config->rootdir);
                                } else {
                                        log_write("CONF","%s:%i: unknown key, ignoring key-value pair; key:\"%s\"\n",configfile,lineno,ptr);
                                        continue;
                                }
                        } else
                                continue;
                        /* store value */
                        if(*configvalue!=NULL) {
                                log_write("CONF","%s:%i: duplicate key, ignoring key-value pair; key:\"%s\"\n",configfile,lineno,ptr);
                                continue;
                        }
                        if((*configvalue=strdup(value))==NULL) {
                                fclose(f),f=NULL;
                                newslconfig_free(config),config=NULL;
                                return(NULL); /* insufficient memory */
                        }
                        continue;
                } else {
                        log_write("CONF","%s:%i: malformed line, ignoring; contents:\"%s\"\n",configfile,lineno,ptr);
                        continue;
                }
        }
        fclose(f),f=NULL;
        if((config->logfile==NULL && (config->logfile=strdup(deflogfile))==NULL) ||
           (config->rootdir==NULL && (config->rootdir=strdup(defrootdir))==NULL)) {
                newslconfig_free(config),config=NULL;
                return(NULL);
        }
        return(config);
}

void
newslconfig_free(newslconfig *config)
{
        if(config==NULL)
                return;
        if(config->logfile!=NULL)
                free(config->logfile),config->logfile=NULL;
        if(config->rootdir!=NULL)
                free(config->rootdir),config->rootdir=NULL;
        free(config),config=NULL;
        return;
}

int
newslconfig_exists(char *configfile)
{
        struct stat st;
        if(stat(configfile,&st)!=0)
                return(-1);
        return(0);
}

int
newslconfig_write(char *configfile,char *logfile,char *rootdir)
{
        FILE *f;
        if((f=fopen(configfile,"w"))==NULL)
                return(-1);
        fprintf(f,"; newslettersan config file\n");
        fprintf(f,"[general]\n");
        fprintf(f,"logfile=%s\n",(logfile!=NULL)?logfile:"newslettersan.log");
        fprintf(f,"rootdir=%s\n",(rootdir!=NULL)?rootdir:"subscribe");
        return(0);
}