/*
 * kakumei_email.c
 *
 * E-mail management
 *
 * 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 <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include "sbuf.h"
#include "loglib.h"
#include "kakumei.h"
#include "kakumei_email.h"

#define RD 0
#define WR 1

static int email_openprogram(kakumei *ka, char *program,char **args, int *parent2child, int *child2parent);
static char **email_sendmailargs(kakumei *ka, sbuf *buf, char *fromuser);
static int writestr(int fd, char *ptr);

int
email_set(kakumei *ka, char *user, char *email)
{
        char filename[1024];
        int fd;
        if(ka==NULL || user==NULL || user[0]=='\0' || email==NULL) {
                log_write("MAIL","sanity check error");
                return(-1);
        }
        mkdir(USERSDIR,0700);
        snprintf(filename,sizeof(filename)-1,"%s/%s/email",USERSDIR,user);
        filename[sizeof(filename)-1]='\0';
        if(email[0]=='\0') {
                unlink(filename);
                return(0);
        }
        if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))==-1)
                return(-1);
        write(fd,email,strlen(email));
        close(fd),fd=-1;
        return(0);
}

int
email_get(kakumei *ka, char *user, char *email,int sizeemail)
{
        char filename[1024];
        int fd;
        if(ka==NULL || user==NULL || user[0]=='\0' || email==NULL || sizeemail<1) {
                log_write("MAIL","sanity check error");
                return(-1);
        }
        snprintf(filename,sizeof(filename)-1,"%s/%s/email",USERSDIR,user);
        filename[sizeof(filename)-1]='\0';
        if((fd=open(filename,O_RDONLY))==-1)
                return(-1);
        memset(email,0,sizeemail);
        read(fd,email,sizeemail-1);
        email[sizeemail-1]='\0';
        close(fd),fd=-1;
        return(0);
}

int
email_notify(kakumei *ka, char *fromuser, int numpost)
{
        int bufnum;
        sbuf *buf;
        int parent2child,child2parent;
        char **args;
        int i;
        /* check if from has been defined in config file */
        if(ka->config->from==NULL) {
                log_write("MAIL","mail isn't configured in kakumei config file (no \"from\")");
                return(-1);
        }
        /* generate the list of recipients */
        if((bufnum=wk_sbufacquire(ka->web))==-1) {
                log_write("MAIL","couldn't acquire buffer to prepare the recipients list");
                return(-1);
        }
        if((buf=wk_sbufget(ka->web,bufnum))==NULL) {
                log_write("EINT","%s:%i",__FILE__,__LINE__);
                return(-1);
        }
        if((args=email_sendmailargs(ka,buf,fromuser))==NULL) {
                wk_sbufrelease(ka->web,bufnum),bufnum=-1;
                log_write("MAIL","couldn't build recipient list");
                return(-1);
        }
        /* send the message */
        if(email_openprogram(ka,"/usr/sbin/sendmail",args,&parent2child,&child2parent)<=0) {
                wk_sbufrelease(ka->web,bufnum),bufnum=-1;
                log_write("MAIL","couldn't exec sendmail");
                return(-1);
        }
        wk_sbufrelease(ka->web,bufnum),bufnum=-1;
        writestr(parent2child,"From: ");
        writestr(parent2child,(ka->config->from!=NULL)?ka->config->from:"");
        writestr(parent2child,"\nSubject: ");
        if(numpost==-1)
                writestr(parent2child,(ka->config->subjpost!=NULL)?ka->config->subjpost:"kakumei post");
        else
                writestr(parent2child,(ka->config->subjcomment!=NULL)?ka->config->subjcomment:"kakumei comment");
        if(numpost!=-1) {
                char mybuf[32];
                snprintf(mybuf,sizeof(mybuf)," #%i",numpost);
                mybuf[sizeof(mybuf)-1]='\0';
                writestr(parent2child,mybuf);
        }
        writestr(parent2child,"\n\n");
        for(i=0;i<ka->config->usedlines;i++) {
                writestr(parent2child,(ka->config->lines[i]==NULL)?"":ka->config->lines[i]);
                writestr(parent2child,"\n");
        }
        close(parent2child),parent2child=-1;
        close(child2parent),child2parent=-1;
        log_write("MAIL","sent email notify from user:%s post:%i",fromuser,numpost);
        return(0);
}

static int
email_openprogram(kakumei *ka, char *program,char **args, int *paramparent2child, int *paramchild2parent)
{
        int parent2child[2];
        int child2parent[2];
        int pid;
        parent2child[0]=parent2child[1]=-1;
        child2parent[0]=child2parent[1]=-1;
        if(pipe(parent2child)!=0 || pipe(child2parent)!=0) {
                close(parent2child[0]); /* just in case the first pipe() succeeded but not the second */
                close(parent2child[1]);
                return(-1); /* Couldn't create pipes for communicating with child process */
        }
        if((pid=fork())==0) {
                /* child process */
                int i,l;
                close(0);
                dup(parent2child[RD]);
                close(1);
                dup(child2parent[WR]);
                l=getdtablesize();
                for(i=2;i<l;i++)
                        close(i);
                execv(program,args);
                exit(1); /* error in exec */
        }
        close(parent2child[RD]),parent2child[RD]=-1;
        close(child2parent[WR]),child2parent[WR]=-1;
        *paramparent2child=parent2child[WR];
        *paramchild2parent=child2parent[RD];
        return(pid);
}

static char **
email_sendmailargs(kakumei *ka, sbuf *buf, char *fromuser)
{
        DIR *dir;
        struct dirent *de;
        int pre;
        int n,k;
        char *ptr;
        char **args;
        char email[128];
        sbuf_wipe(buf);
        pre=2;
        sbuf_addstr(buf,"sendmail");
        sbuf_add(buf,"",1);
        sbuf_addstr(buf,"-i");
        sbuf_add(buf,"",1);
        if((dir=opendir(USERSDIR))==NULL) {
                log_write("MAIL","couldn't open users directory");
                return(NULL);
        }
        for(n=0;(de=readdir(dir))!=NULL;) {
                if(strcmp(de->d_name,fromuser)==0)
                        continue;
                if(email_get(ka,de->d_name,email,sizeof(email))!=0)
                        continue;
                uri_urldecode(email);
                sbuf_add(buf,email,strlen(email)+1);
                n++;
        }
        closedir(dir),dir=NULL;
        if(n==0) {
                log_write("MAIL","no recipients for e-mail notification");
                return(NULL); /* no recipients */
        }
        n+=pre;
        if(sbuf_unused(buf)<(sizeof(char *)*(n+1))) {
                log_write("MAIL","too many recipients, couldn't build list");
                return(NULL); /* too many recipients */
        }
        args=(char **)sbuf_ptrunused(buf);
        memset((char *)args,0,(sizeof(char *)*(n+1)));
        for(k=0,ptr=sbuf_ptr(buf);k<n;k++) {
                args[k]=ptr;
                ptr+=strlen(ptr)+1;
        }
        args[k]=NULL;
        sbuf_addfromunused(buf,(sizeof(char *)*(n+1)));
        return(args);
}

static int
writestr(int fd, char *ptr)
{
        return(write(fd,ptr,strlen(ptr)));
}