Browse code

implement sending notification e-mails (with the corresponding config file support)

Dario Rodriguez authored on 24/07/2014 11:03:47
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,219 @@
1
+/*
2
+ * kakumei_email.c
3
+ *
4
+ * E-mail management
5
+ *
6
+ * Author: Dario Rodriguez dario@softhome.net
7
+ * This program is licensed under the terms of the Affero GPL v1+
8
+ */
9
+
10
+#include <stdio.h>
11
+#include <stdlib.h>
12
+#include <unistd.h>
13
+#include <string.h>
14
+#include <fcntl.h>
15
+#include <sys/types.h>
16
+#include <sys/stat.h>
17
+#include <dirent.h>
18
+#include "sbuf.h"
19
+#include "loglib.h"
20
+#include "kakumei.h"
21
+#include "kakumei_email.h"
22
+
23
+#define RD 0
24
+#define WR 1
25
+
26
+static int email_openprogram(kakumei *ka, char *program,char **args, int *parent2child, int *child2parent);
27
+static char **email_sendmailargs(kakumei *ka, sbuf *buf, char *fromuser);
28
+static int writestr(int fd, char *ptr);
29
+
30
+int
31
+email_set(kakumei *ka, char *user, char *email)
32
+{
33
+        char filename[1024];
34
+        int fd;
35
+        if(ka==NULL || user==NULL || user[0]=='\0' || email==NULL) {
36
+                log_write("MAIL","sanity check error");
37
+                return(-1);
38
+        }
39
+        mkdir(USERSDIR,0700);
40
+        snprintf(filename,sizeof(filename)-1,"%s/%s/email",USERSDIR,user);
41
+        filename[sizeof(filename)-1]='\0';
42
+        if(email[0]=='\0') {
43
+                unlink(filename);
44
+                return(0);
45
+        }
46
+        if((fd=open(filename,O_WRONLY|O_TRUNC|O_CREAT,0600))==-1)
47
+                return(-1);
48
+        write(fd,email,strlen(email));
49
+        close(fd),fd=-1;
50
+        return(0);
51
+}
52
+
53
+int
54
+email_get(kakumei *ka, char *user, char *email,int sizeemail)
55
+{
56
+        char filename[1024];
57
+        int fd;
58
+        if(ka==NULL || user==NULL || user[0]=='\0' || email==NULL || sizeemail<1) {
59
+                log_write("MAIL","sanity check error");
60
+                return(-1);
61
+        }
62
+        snprintf(filename,sizeof(filename)-1,"%s/%s/email",USERSDIR,user);
63
+        filename[sizeof(filename)-1]='\0';
64
+        if((fd=open(filename,O_RDONLY))==-1)
65
+                return(-1);
66
+        memset(email,0,sizeemail);
67
+        read(fd,email,sizeemail-1);
68
+        email[sizeemail-1]='\0';
69
+        close(fd),fd=-1;
70
+        return(0);
71
+}
72
+
73
+int
74
+email_notify(kakumei *ka, char *fromuser, int numpost)
75
+{
76
+        int bufnum;
77
+        sbuf *buf;
78
+        int parent2child,child2parent;
79
+        char **args;
80
+        int i;
81
+        /* check if from has been defined in config file */
82
+        if(ka->config->from==NULL) {
83
+                log_write("MAIL","mail isn't configured in kakumei config file (no \"from\")");
84
+                return(-1);
85
+        }
86
+        /* generate the list of recipients */
87
+        if((bufnum=wk_sbufacquire(ka->web))==-1) {
88
+                log_write("MAIL","couldn't acquire buffer to prepare the recipients list");
89
+                return(-1);
90
+        }
91
+        if((buf=wk_sbufget(ka->web,bufnum))==NULL) {
92
+                log_write("EINT","%s:%i",__FILE__,__LINE__);
93
+                return(-1);
94
+        }
95
+        if((args=email_sendmailargs(ka,buf,fromuser))==NULL) {
96
+                wk_sbufrelease(ka->web,bufnum),bufnum=-1;
97
+                log_write("MAIL","couldn't build recipient list");
98
+                return(-1);
99
+        }
100
+        /* send the message */
101
+        if(email_openprogram(ka,"/usr/sbin/sendmail",args,&parent2child,&child2parent)<=0) {
102
+                wk_sbufrelease(ka->web,bufnum),bufnum=-1;
103
+                log_write("MAIL","couldn't exec sendmail");
104
+                return(-1);
105
+        }
106
+        wk_sbufrelease(ka->web,bufnum),bufnum=-1;
107
+        writestr(parent2child,"From: ");
108
+        writestr(parent2child,(ka->config->from!=NULL)?ka->config->from:"");
109
+        writestr(parent2child,"\nSubject: ");
110
+        if(numpost==-1)
111
+                writestr(parent2child,(ka->config->subjpost!=NULL)?ka->config->subjpost:"kakumei post");
112
+        else
113
+                writestr(parent2child,(ka->config->subjcomment!=NULL)?ka->config->subjcomment:"kakumei comment");
114
+        if(numpost!=-1) {
115
+                char mybuf[32];
116
+                snprintf(mybuf,sizeof(mybuf)," #%i",numpost);
117
+                mybuf[sizeof(mybuf)-1]='\0';
118
+                writestr(parent2child,mybuf);
119
+        }
120
+        writestr(parent2child,"\n\n");
121
+        for(i=0;i<ka->config->usedlines;i++) {
122
+                writestr(parent2child,(ka->config->lines[i]==NULL)?"":ka->config->lines[i]);
123
+                writestr(parent2child,"\n");
124
+        }
125
+        close(parent2child),parent2child=-1;
126
+        close(child2parent),child2parent=-1;
127
+        log_write("MAIL","sent email notify from user:%s post:%i",fromuser,numpost);
128
+        return(0);
129
+}
130
+
131
+static int
132
+email_openprogram(kakumei *ka, char *program,char **args, int *paramparent2child, int *paramchild2parent)
133
+{
134
+        int parent2child[2];
135
+        int child2parent[2];
136
+        int pid;
137
+        parent2child[0]=parent2child[1]=-1;
138
+        child2parent[0]=child2parent[1]=-1;
139
+        if(pipe(parent2child)!=0 || pipe(child2parent)!=0) {
140
+                close(parent2child[0]); /* just in case the first pipe() succeeded but not the second */
141
+                close(parent2child[1]);
142
+                return(-1); /* Couldn't create pipes for communicating with child process */
143
+        }
144
+        if((pid=fork())==0) {
145
+                /* child process */
146
+                int i,l;
147
+                close(0);
148
+                dup(parent2child[RD]);
149
+                close(1);
150
+                dup(child2parent[WR]);
151
+                l=getdtablesize();
152
+                for(i=2;i<l;i++)
153
+                        close(i);
154
+                execv(program,args);
155
+                exit(1); /* error in exec */
156
+        }
157
+        close(parent2child[RD]),parent2child[RD]=-1;
158
+        close(child2parent[WR]),child2parent[WR]=-1;
159
+        *paramparent2child=parent2child[WR];
160
+        *paramchild2parent=child2parent[RD];
161
+        return(pid);
162
+}
163
+
164
+static char **
165
+email_sendmailargs(kakumei *ka, sbuf *buf, char *fromuser)
166
+{
167
+        DIR *dir;
168
+        struct dirent *de;
169
+        int pre;
170
+        int n,k;
171
+        char *ptr;
172
+        char **args;
173
+        char email[128];
174
+        sbuf_wipe(buf);
175
+        pre=2;
176
+        sbuf_addstr(buf,"sendmail");
177
+        sbuf_add(buf,"",1);
178
+        sbuf_addstr(buf,"-i");
179
+        sbuf_add(buf,"",1);
180
+        if((dir=opendir(USERSDIR))==NULL) {
181
+                log_write("MAIL","couldn't open users directory");
182
+                return(NULL);
183
+        }
184
+        for(n=0;(de=readdir(dir))!=NULL;) {
185
+                if(strcmp(de->d_name,fromuser)==0)
186
+                        continue;
187
+                if(email_get(ka,de->d_name,email,sizeof(email))!=0)
188
+                        continue;
189
+                uri_urldecode(email);
190
+                sbuf_add(buf,email,strlen(email)+1);
191
+                n++;
192
+        }
193
+        closedir(dir),dir=NULL;
194
+        if(n==0) {
195
+                log_write("MAIL","no recipients for e-mail notification");
196
+                return(NULL); /* no recipients */
197
+        }
198
+        n+=pre;
199
+        if(sbuf_unused(buf)<(sizeof(char *)*(n+1))) {
200
+                log_write("MAIL","too many recipients, couldn't build list");
201
+                return(NULL); /* too many recipients */
202
+        }
203
+        args=(char **)sbuf_ptrunused(buf);
204
+        memset((char *)args,0,(sizeof(char *)*(n+1)));
205
+        for(k=0,ptr=sbuf_ptr(buf);k<n;k++) {
206
+                args[k]=ptr;
207
+                ptr+=strlen(ptr)+1;
208
+        }
209
+        args[k]=NULL;
210
+        sbuf_addfromunused(buf,(sizeof(char *)*(n+1)));
211
+        return(args);
212
+}
213
+
214
+static int
215
+writestr(int fd, char *ptr)
216
+{
217
+        return(write(fd,ptr,strlen(ptr)));
218
+}
219
+