/*
 * kakumei_config.c
 *
 * Config management for the kakumei server.
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This program is licensed under the terms of the Affero GPL v1.0+ license.
 */


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

#include "loglib.h"
#include "kakumei_config.h"

#define MAXLINESIZE 2048
#define LINESBLOCK 32

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

kaconfig *
kaconfig_init(char *configfile)
{
        kaconfig *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(kaconfig)))==NULL) {
                fclose(f),f=NULL;
                return(NULL);
        }
        memset(config,0,sizeof(kaconfig));
        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);
                if(!(section==section_mail && memcmp(ptr,"line.",5)==0)) {
                        while(len>0 && strchr("\n\t ",line[len-1])!=NULL)
                                line[len-1]='\0',len--;
                } else {
                        while(len>0 && line[len-1]=='\n')
                                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 if(strcmp(ptr,"[mail]")==0) {
                                section=section_mail;
                        } 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';
                        }
                        if(!(section==section_mail && memcmp(ptr,"line.",5)==0)) {
                                /* trim value */
                                while(*value!='\0' && strchr(" \t",*value)!=NULL)
                                        value++;
                        }
                        /* sanity check */
                        if(*value=='\0') {
                                if(!(section==section_mail && memcmp(ptr,"line.",5)==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,"cookiename")==0) {
                                        configvalue=&(config->cookiename);
                                } else if(strcmp(ptr,"cookiedomain")==0) {
                                        configvalue=&(config->cookiedomain);
                                } else if(strcmp(ptr,"bannerpath")==0) {
                                        configvalue=&(config->bannerpath);
                                } else if(strcmp(ptr,"sslproxy")==0) {
                                        if(strcmp(value,"true")==0 || strcmp(value,"1")==0 || strcmp(value,"yes")==0)
                                                config->sslproxy=1;
                                        else
                                                config->sslproxy=0;
                                        continue;
                                } else {
                                        log_write("CONF","%s:%i: unknown key, ignoring key-value pair; key:\"%s\"\n",configfile,lineno,ptr);
                                        continue;
                                }
                        } else if(section==section_mail) {
                                if(strcmp(ptr,"from")==0) {
                                        configvalue=&(config->from);
                                } else if(strcmp(ptr,"subjpost")==0) {
                                        configvalue=&(config->subjpost);
                                } else if(strcmp(ptr,"subjcomment")==0) {
                                        configvalue=&(config->subjcomment);
                                } else if(memcmp(ptr,"line.",5)==0) {
                                        int lineno=atoi(ptr+5);
                                        if(lineno<0)
                                                lineno=0;
                                        if(lineno>=config->sizelines) {
                                                char **lines;
                                                int minsize;
                                                minsize=(lineno+LINESBLOCK)/LINESBLOCK;
                                                minsize*=LINESBLOCK;
                                                if((lines=realloc(config->lines,minsize*sizeof(char *)))==NULL) {
                                                        fclose(f),f=NULL;
                                                        kaconfig_free(config),config=NULL;
                                                        return(NULL); /* insufficient memory */
                                                }
                                                config->lines=lines;
                                                memset(lines+config->sizelines,0,sizeof(char *)*(minsize-config->sizelines));
                                                config->sizelines=minsize;
                                        }
                                        configvalue=config->lines+lineno;
                                        if(config->usedlines<=lineno)
                                                config->usedlines=lineno+1;
                                } 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;
                                kaconfig_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;
        return(config);

}

void
kaconfig_free(kaconfig *config)
{
        if(config==NULL)
                return;
        if(config->logfile!=NULL)
                free(config->logfile),config->logfile=NULL;
        if(config->cookiename!=NULL)
                free(config->cookiename),config->cookiename=NULL;
        if(config->cookiedomain!=NULL)
                free(config->cookiedomain),config->cookiedomain=NULL;
        if(config->bannerpath!=NULL)
                free(config->bannerpath),config->bannerpath=NULL;
        if(config->from!=NULL)
                free(config->from),config->from=NULL;
        if(config->subjpost!=NULL)
                free(config->subjpost),config->subjpost=NULL;
        if(config->subjcomment!=NULL)
                free(config->subjcomment),config->subjcomment=NULL;
        if(config->lines!=NULL) {
                int i;
                for(i=0;i<config->usedlines;i++) {
                        if(config->lines[i]!=NULL)
                                free(config->lines[i]),config->lines[i]=NULL;
                }
                config->sizelines=0;
                config->usedlines=0;
                free(config->lines),config->lines=NULL;
        }
        free(config),config=NULL;
        return;
}

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

int
kaconfig_write(char *configfile,char *logfile, char *cookiename,char *cookiedomain, char *bannerpath, int sslproxy)
{
        FILE *f;
        if((f=fopen(configfile,"w"))==NULL)
                return(-1);
        fprintf(f,"; kakumei config file\n");
        fprintf(f,"[general]\n");
        fprintf(f,"logfile=%s\n",(logfile!=NULL)?logfile:"kakumei.log");
        fprintf(f,"cookiename=%s\n",(cookiename!=NULL)?cookiename:"kakumeiauthid");
        fprintf(f,"cookiedomain=%s\n",(cookiedomain!=NULL)?cookiedomain:"localhost");
        fprintf(f,"bannerpath=%s\n",(bannerpath!=NULL)?bannerpath:"default.png");
        fprintf(f,"sslproxy=%s\n",(sslproxy==0)?"no":"yes");
        fprintf(f,"\n[mail]\nfrom=\nsubjpost=New post\nsubjcomment=New comment in post\nline.0=There is a new post or comment\nline.1=Best regards, kakumei web\n");
        return(0);
}