/* * 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); }