... | ... |
@@ -1,5 +1,10 @@ |
1 | 1 |
<!doctype html> |
2 | 2 |
<html> |
3 | 3 |
<head><title>Newsletter</title></head> |
4 |
-<body></body> |
|
4 |
+<body> |
|
5 |
+<form action="/~/addemail" method="post"> |
|
6 |
+ <input id="email" name="email" placeholder="e-mail"> |
|
7 |
+ <input type="submit" value="subscribe"> |
|
8 |
+<form> |
|
9 |
+</body> |
|
5 | 10 |
</html> |
... | ... |
@@ -27,7 +27,7 @@ typedef enum esection { |
27 | 27 |
|
28 | 28 |
|
29 | 29 |
newslconfig * |
30 |
-newslconfig_init(char *configfile) |
|
30 |
+newslconfig_init(char *configfile, char *deflogfile, char *defrootdir) |
|
31 | 31 |
{ |
32 | 32 |
newslconfig *config; |
33 | 33 |
FILE *f; |
... | ... |
@@ -96,6 +96,8 @@ newslconfig_init(char *configfile) |
96 | 96 |
if(section==section_general) { |
97 | 97 |
if(strcmp(ptr,"logfile")==0) { |
98 | 98 |
configvalue=&(config->logfile); |
99 |
+ } else if(strcmp(ptr,"rootdir")==0) { |
|
100 |
+ configvalue=&(config->rootdir); |
|
99 | 101 |
} else { |
100 | 102 |
log_write("CONF","%s:%i: unknown key, ignoring key-value pair; key:\"%s\"\n",configfile,lineno,ptr); |
101 | 103 |
continue; |
... | ... |
@@ -119,6 +121,11 @@ newslconfig_init(char *configfile) |
119 | 121 |
} |
120 | 122 |
} |
121 | 123 |
fclose(f),f=NULL; |
124 |
+ if((config->logfile==NULL && (config->logfile=strdup(deflogfile))==NULL) || |
|
125 |
+ (config->rootdir==NULL && (config->rootdir=strdup(defrootdir))==NULL)) { |
|
126 |
+ newslconfig_free(config),config=NULL; |
|
127 |
+ return(NULL); |
|
128 |
+ } |
|
122 | 129 |
return(config); |
123 | 130 |
} |
124 | 131 |
|
... | ... |
@@ -129,6 +136,8 @@ newslconfig_free(newslconfig *config) |
129 | 136 |
return; |
130 | 137 |
if(config->logfile!=NULL) |
131 | 138 |
free(config->logfile),config->logfile=NULL; |
139 |
+ if(config->rootdir!=NULL) |
|
140 |
+ free(config->rootdir),config->rootdir=NULL; |
|
132 | 141 |
free(config),config=NULL; |
133 | 142 |
return; |
134 | 143 |
} |
... | ... |
@@ -143,7 +152,7 @@ newslconfig_exists(char *configfile) |
143 | 152 |
} |
144 | 153 |
|
145 | 154 |
int |
146 |
-newslconfig_write(char *configfile,char *logfile) |
|
155 |
+newslconfig_write(char *configfile,char *logfile,char *rootdir) |
|
147 | 156 |
{ |
148 | 157 |
FILE *f; |
149 | 158 |
if((f=fopen(configfile,"w"))==NULL) |
... | ... |
@@ -151,6 +160,7 @@ newslconfig_write(char *configfile,char *logfile) |
151 | 160 |
fprintf(f,"; newslettersan config file\n"); |
152 | 161 |
fprintf(f,"[general]\n"); |
153 | 162 |
fprintf(f,"logfile=%s\n",(logfile!=NULL)?logfile:"newslettersan.log"); |
163 |
+ fprintf(f,"rootdir=%s\n",(rootdir!=NULL)?rootdir:"subscribe"); |
|
154 | 164 |
return(0); |
155 | 165 |
} |
156 | 166 |
|
... | ... |
@@ -14,12 +14,13 @@ |
14 | 14 |
|
15 | 15 |
typedef struct newslconfig { |
16 | 16 |
char *logfile; |
17 |
+ char *rootdir; |
|
17 | 18 |
} newslconfig; |
18 | 19 |
|
19 |
-newslconfig *newslconfig_init(char *configfile); |
|
20 |
+newslconfig *newslconfig_init(char *configfile, char *deflogfile, char *defrootdir); |
|
20 | 21 |
void newslconfig_free(newslconfig *config); |
21 | 22 |
|
22 | 23 |
int newslconfig_exists(char *configfile); |
23 |
-int newslconfig_write(char *configfile,char *logfile); |
|
24 |
+int newslconfig_write(char *configfile,char *logfile,char *rootdir); |
|
24 | 25 |
|
25 | 26 |
#endif |
... | ... |
@@ -23,20 +23,23 @@ |
23 | 23 |
|
24 | 24 |
#define CONFIGFILE "newslettersan.cfg" |
25 | 25 |
#define CFLOGFILE "newslettersan.log" |
26 |
+#define CFROOTDIR "subscribe" |
|
26 | 27 |
|
27 | 28 |
static int signal_init(int signum, void (*fn)(int)); |
28 | 29 |
static void sigint(int signum); |
29 | 30 |
volatile int sigint_flag=0; |
30 | 31 |
|
32 |
+wk_action callback_post(wk *web, int connid, wk_uri *uri, void *userptr); |
|
31 | 33 |
wk_action callback_http(wk *web, int connid, wk_uri *uri, void *userptr); |
34 |
+int newsl_serve_buffer_with_rootdir(newslettersan *newsl, wk *web, int connid, char *data, int datalen, const char *mime); |
|
32 | 35 |
|
33 | 36 |
int |
34 | 37 |
main(int argc, char *argv[]) |
35 | 38 |
{ |
36 | 39 |
int timeout=500; |
37 | 40 |
int serverfd; |
38 |
- newslettersan *newsl,newslstore; |
|
39 |
- char *hostnameport; |
|
41 |
+ newslettersan *newsl,newslstore; |
|
42 |
+ char *hostnameport; |
|
40 | 43 |
char hostname[128]; |
41 | 44 |
char *host; |
42 | 45 |
long hostsize; |
... | ... |
@@ -51,9 +54,9 @@ main(int argc, char *argv[]) |
51 | 54 |
if(newslconfig_exists(CONFIGFILE)!=0) { |
52 | 55 |
log_setlogfile(CFLOGFILE); |
53 | 56 |
log_write("INIT","Config file not found, writing default file %s",CONFIGFILE); |
54 |
- newslconfig_write(CONFIGFILE,CFLOGFILE); |
|
57 |
+ newslconfig_write(CONFIGFILE,CFLOGFILE,CFROOTDIR); |
|
55 | 58 |
} |
56 |
- if((newsl->config=newslconfig_init(CONFIGFILE))==NULL) { |
|
59 |
+ if((newsl->config=newslconfig_init(CONFIGFILE,CFLOGFILE,CFROOTDIR))==NULL) { |
|
57 | 60 |
log_setlogfile(CFLOGFILE); |
58 | 61 |
log_write("INIT","ERROR: insufficient memory or config file error"); |
59 | 62 |
return(1); |
... | ... |
@@ -82,7 +85,7 @@ main(int argc, char *argv[]) |
82 | 85 |
return(2); |
83 | 86 |
} |
84 | 87 |
sock_setunsafe(serverfd); |
85 |
- if((newsl->web=wk_init(serverfd,newsl->ssel,NULL,callback_http,NULL,NULL,newsl))==NULL) { |
|
88 |
+ if((newsl->web=wk_init(serverfd,newsl->ssel,NULL,callback_http,callback_post,NULL,newsl))==NULL) { |
|
86 | 89 |
sselect_free(newsl->ssel),newsl->ssel=NULL; |
87 | 90 |
log_write("INIT","ERROR: couldn't init web server"); |
88 | 91 |
return(2); |
... | ... |
@@ -120,25 +123,114 @@ sigint(int signum) |
120 | 123 |
sigint_flag=1; |
121 | 124 |
} |
122 | 125 |
|
126 |
+wk_action |
|
127 |
+callback_post(wk *web, int connid, wk_uri *uri, void *userptr) |
|
128 |
+{ |
|
129 |
+ newslettersan *newsl=(newslettersan *)userptr; |
|
130 |
+ char partialpath[1024]; |
|
131 |
+ int l; |
|
132 |
+ if(newsl==NULL) |
|
133 |
+ return(wkact_finished); |
|
134 |
+ /* check that URI starts with /$rootdir/ */ |
|
135 |
+ l=strlen(newsl->config->rootdir); |
|
136 |
+ if(uri->path[0]!='/' || memcmp(uri->path+1,newsl->config->rootdir,l)!=0 || |
|
137 |
+ uri->path[l+1]!='/') { |
|
138 |
+ return(wkact_finished); |
|
139 |
+ } |
|
140 |
+ /* copy the path below $rootdir into partialpath */ |
|
141 |
+ strncpy(partialpath,uri->path+1+l,sizeof(partialpath)-1); |
|
142 |
+ partialpath[sizeof(partialpath)-1]='\0'; |
|
143 |
+ /* set push variables for the specified URI */ |
|
144 |
+ /* to be able to retrieve them in callback_http */ |
|
145 |
+ if(strcmp(partialpath,"/addemail")==0) { |
|
146 |
+ wk_post_addvalid(web,connid,"email",NULL); |
|
147 |
+ } |
|
148 |
+ return(wkact_finished); |
|
149 |
+} |
|
150 |
+ |
|
123 | 151 |
wk_action |
124 | 152 |
callback_http(wk *web, int connid, wk_uri *uri, void *userptr) |
125 | 153 |
{ |
126 | 154 |
newslettersan *newsl=(newslettersan *)userptr; |
127 | 155 |
resindex *res; |
156 |
+ int l; |
|
128 | 157 |
char partialpath[1024]; |
129 |
- if(newsl==NULL) |
|
130 |
- return(wkact_finished); |
|
131 |
- strncpy(partialpath,uri->path,sizeof(partialpath)-1); |
|
158 |
+ if(newsl==NULL) |
|
159 |
+ return(wkact_finished); |
|
160 |
+ /* redirect to the real root URI if request is "/" */ |
|
161 |
+ if(strcmp(uri->path,"/")==0) { |
|
162 |
+ partialpath[0]='/'; |
|
163 |
+ strncpy(partialpath+1,newsl->config->rootdir,sizeof(partialpath)-1); |
|
164 |
+ partialpath[sizeof(partialpath)-1]='\0'; |
|
165 |
+ if((l=strlen(partialpath))<(sizeof(partialpath)-2)) |
|
166 |
+ strcpy(partialpath+l,"/"); |
|
167 |
+ wk_serve_redirect(web,connid,partialpath); |
|
168 |
+ return(wkact_finished); |
|
169 |
+ } |
|
170 |
+ /* check that URI starts with /$rootdir/ */ |
|
171 |
+ l=strlen(newsl->config->rootdir); |
|
172 |
+ if(uri->path[0]!='/' || memcmp(uri->path+1,newsl->config->rootdir,l)!=0 || |
|
173 |
+ uri->path[l+1]!='/') { |
|
174 |
+ wk_serve_error(web,connid,wkerr_notfound); |
|
175 |
+ return(wkact_finished); |
|
176 |
+ } |
|
177 |
+ /* copy the path below $rootdir into partialpath */ |
|
178 |
+ strncpy(partialpath,uri->path+1+l,sizeof(partialpath)-1); |
|
132 | 179 |
partialpath[sizeof(partialpath)-1]='\0'; |
133 |
- if(strcmp(uri->path,"/")==0) |
|
134 |
- strcpy(partialpath,"/index.html"); |
|
180 |
+ /* change the root url to index.html if neccessary */ |
|
181 |
+ if(strcmp(partialpath,"/")==0) { |
|
182 |
+ strncpy(partialpath,"/index.html",sizeof(partialpath)); |
|
183 |
+ partialpath[sizeof(partialpath)-1]='\0'; |
|
184 |
+ } |
|
185 |
+ /* serve the requested page */ |
|
135 | 186 |
if(partialpath[0]=='/' && (res=res_find(resindexdata,partialpath+1))!=NULL) { |
136 |
- log_write("HTTP","Serving in-memory file %s",partialpath+1); |
|
137 |
- wk_serve_etagset(web,connid,res->etag); |
|
138 |
- wk_serve_buffer_as_file(web,connid,res->data,res->len,mime_getdefault(res->name,"application/octet-stream")); |
|
139 |
- return(wkact_finished); |
|
140 |
- } |
|
141 |
- wk_serve_error(web,connid,wkerr_notfound); |
|
187 |
+ log_write("HTTP","Serving in-memory file %s",partialpath+1); |
|
188 |
+ wk_serve_etagset(web,connid,res->etag); |
|
189 |
+ newsl_serve_buffer_with_rootdir(newsl,web,connid,(char *) res->data,res->len,mime_getdefault(res->name,"application/octet-stream")); |
|
190 |
+ return(wkact_finished); |
|
191 |
+ } else if(strcmp(partialpath,"/addemail")==0) { |
|
192 |
+ char *email; |
|
193 |
+ if((email=wk_post_get(web,connid,"email",NULL))==NULL) { |
|
194 |
+ wk_serve_error(web,connid,wkerr_internal); |
|
195 |
+ return(wkact_finished); |
|
196 |
+ } |
|
197 |
+ #warning TODO: do something with the email |
|
198 |
+ wk_serve_buffer_as_file(web,connid,email,strlen(email),"text/plain"); |
|
199 |
+ return(wkact_finished); |
|
200 |
+ } |
|
201 |
+ wk_serve_error(web,connid,wkerr_notfound); |
|
142 | 202 |
return(wkact_finished); |
143 | 203 |
} |
144 | 204 |
|
205 |
+int |
|
206 |
+newsl_serve_buffer_with_rootdir(newslettersan *newsl, wk *web, int connid, char *data, int datalen, const char *mime) |
|
207 |
+{ |
|
208 |
+ int res; |
|
209 |
+ sbuf *buf; |
|
210 |
+ int sbufid; |
|
211 |
+ char *last,*next,*end; |
|
212 |
+ if(newsl==NULL || web==NULL || data==NULL || datalen<0) |
|
213 |
+ return(-1); /* sanity check failed */ |
|
214 |
+ if((sbufid=wk_sbufacquire(web))==-1 || (buf=wk_sbufget(web,sbufid))==NULL) |
|
215 |
+ return(-1); |
|
216 |
+ /* we copy the buffer substituting /~/ for /$rootdir/ */ |
|
217 |
+ end=data+datalen; |
|
218 |
+ for(last=data,next=((last+3)<=end)?memchr(last,'/',end-last-3):NULL;next!=NULL;next=((last+3)<=end)?memchr(last,'/',end-last-3):NULL) { |
|
219 |
+ if(memcmp(next,"/~/",3)==0) { |
|
220 |
+ sbuf_add(buf,last,next-last); |
|
221 |
+ sbuf_add(buf,"/",1); |
|
222 |
+ sbuf_addstr(buf,newsl->config->rootdir); |
|
223 |
+ sbuf_add(buf,"/",1); |
|
224 |
+ last=next+3; |
|
225 |
+ } else { |
|
226 |
+ sbuf_add(buf,last,next-last+1); |
|
227 |
+ last=next+1; |
|
228 |
+ } |
|
229 |
+ } |
|
230 |
+ sbuf_add(buf,last,end-last); |
|
231 |
+ /* send the constructed buffer */ |
|
232 |
+ res=wk_serve_buffer_as_file(web,connid,sbuf_ptr(buf),sbuf_count(buf),mime); |
|
233 |
+ wk_sbufrelease(web,sbufid),sbufid=-1,buf=NULL; |
|
234 |
+ return(res); |
|
235 |
+ |
|
236 |
+} |