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