rename wprintf to wc_printf; wchar.h also has a wprintf
[citadel.git] / webcit / static.c
1 /*
2  * $Id: webcit.c 7459 2009-05-17 08:34:33Z dothebart $
3  *
4  * This is the main transaction loop of the web service.  It maintains a
5  * persistent session to the Citadel server, handling HTTP WebCit requests as
6  * they arrive and presenting a user interface.
7  */
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <dirent.h>
11 #include <errno.h>
12
13 #include <unistd.h>
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <stddef.h>
17
18
19 #include "webcit.h"
20 #include "webserver.h"
21
22
23 HashList *StaticFilemappings[4] = {NULL, NULL, NULL, NULL};
24 /*
25                 {
26                         lprintf(9, "Suspicious request. Ignoring.");
27                         hprintf("HTTP/1.1 404 Security check failed\r\n");
28                         hprintf("Content-Type: text/plain\r\n\r\n");
29                         wc_printf("You have sent a malformed or invalid request.\r\n");
30                         end_burst();
31                 }
32 */
33 /*
34  * dump out static pages from disk
35  */
36 void output_static(const char *what)
37 {
38         int fd;
39         struct stat statbuf;
40         off_t bytes;
41         off_t count = 0;
42         const char *content_type;
43         int len;
44         const char *Err;
45
46         fd = open(what, O_RDONLY);
47         if (fd <= 0) {
48                 lprintf(9, "output_static('%s') [%s]  -- NOT FOUND --\n", what, ChrPtr(WC->Hdr->this_page));
49                 hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
50                 hprintf("Content-Type: text/plain\r\n");
51                 begin_burst();
52                 wc_printf("Cannot open %s: %s\r\n", what, strerror(errno));
53                 end_burst();
54         } else {
55                 len = strlen (what);
56                 content_type = GuessMimeByFilename(what, len);
57
58                 if (fstat(fd, &statbuf) == -1) {
59                         lprintf(9, "output_static('%s')  -- FSTAT FAILED --\n", what);
60                         hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
61                         hprintf("Content-Type: text/plain\r\n");
62                         begin_burst();
63                         wc_printf("Cannot fstat %s: %s\n", what, strerror(errno));
64                         end_burst();
65                         return;
66                 }
67
68                 count = 0;
69                 bytes = statbuf.st_size;
70
71                 if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
72                 {
73                         if (fd > 0) close(fd);
74                         lprintf(9, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
75                                 hprintf("HTTP/1.1 500 internal server error \r\n");
76                                 hprintf("Content-Type: text/plain\r\n");
77                                 end_burst();
78                                 return;
79                 }
80
81
82                 close(fd);
83 #ifndef TECH_PREVIEW
84                 lprintf(9, "output_static('%s')  %s\n", what, content_type);
85 #endif
86                 http_transmit_thing(content_type, 2);
87         }
88         if (yesbstr("force_close_session")) {
89                 end_webcit_session();
90         }
91 }
92
93
94 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
95 {
96         char dirname[PATH_MAX];
97         char reldir[PATH_MAX];
98         StrBuf *FileName = NULL;
99         StrBuf *Dir = NULL;
100         StrBuf *WebDir = NULL;
101         StrBuf *OneWebName = NULL;
102         DIR *filedir = NULL;
103         struct dirent *d;
104         struct dirent *filedir_entry;
105         int d_type = 0;
106         int d_namelen;
107         int d_without_ext;
108         int istoplevel;
109                 
110         filedir = opendir (DirName);
111         if (filedir == NULL) {
112                 return 0;
113         }
114
115         d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
116         if (d == NULL) {
117                 return 0;
118         }
119
120         Dir = NewStrBufPlain(DirName, -1);
121         WebDir = NewStrBufPlain(RelDir, -1);
122         istoplevel = IsEmptyStr(RelDir);
123         OneWebName = NewStrBuf();
124
125         while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
126                (filedir_entry != NULL))
127         {
128                 char *PStart;
129 #ifdef _DIRENT_HAVE_D_NAMELEN
130                 d_namelen = filedir_entry->d_namelen;
131                 d_type = filedir_entry->d_type;
132 #else
133
134 #ifndef DT_UNKNOWN
135 #define DT_UNKNOWN     0
136 #define DT_DIR         4
137 #define DT_REG         8
138 #define DT_LNK         10
139
140 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
141 #define DTTOIF(dirtype)        ((dirtype) << 12)
142 #endif
143                 d_namelen = strlen(filedir_entry->d_name);
144                 d_type = DT_UNKNOWN;
145 #endif
146                 d_without_ext = d_namelen;
147
148                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
149                         continue; /* Ignore backup files... */
150
151                 if ((d_namelen == 1) && 
152                     (filedir_entry->d_name[0] == '.'))
153                         continue;
154
155                 if ((d_namelen == 2) && 
156                     (filedir_entry->d_name[0] == '.') &&
157                     (filedir_entry->d_name[1] == '.'))
158                         continue;
159
160                 if (d_type == DT_UNKNOWN) {
161                         struct stat s;
162                         char path[PATH_MAX];
163                         snprintf(path, PATH_MAX, "%s/%s", 
164                                 DirName, filedir_entry->d_name);
165                         if (stat(path, &s) == 0) {
166                                 d_type = IFTODT(s.st_mode);
167                         }
168                 }
169
170                 switch (d_type)
171                 {
172                 case DT_DIR:
173                         /* Skip directories we are not interested in... */
174                         if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
175                             (strcmp(filedir_entry->d_name, "t") == 0))
176                                 break;
177                         snprintf(dirname, PATH_MAX, "%s/%s/", 
178                                  DirName, filedir_entry->d_name);
179                         if (istoplevel)
180                                 snprintf(reldir, PATH_MAX, "%s/", 
181                                          filedir_entry->d_name);
182                         else
183                                 snprintf(reldir, PATH_MAX, "%s/%s/", 
184                                          RelDir, filedir_entry->d_name);
185                         StripSlashes(dirname, 1);
186                         StripSlashes(reldir, 1);
187                         LoadStaticDir(dirname, DirList, reldir);                                 
188                         break;
189                 case DT_LNK: /* TODO: check whether its a file or a directory */
190                 case DT_REG:
191                         PStart = filedir_entry->d_name;
192                         FileName = NewStrBufDup(Dir);
193                         if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
194                                 StrBufAppendBufPlain(FileName, "/", 1, 0);
195                         StrBufAppendBufPlain(FileName, filedir_entry->d_name, d_namelen, 0);
196
197                         FlushStrBuf(OneWebName);
198                         StrBufAppendBuf(OneWebName, WebDir, 0);
199                         if ((StrLength(OneWebName) != 0) && 
200                             (ChrPtr(OneWebName) [ StrLength(OneWebName) - 1] != '/'))
201                                 StrBufAppendBufPlain(OneWebName, "/", 1, 0);
202                         StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
203
204                         Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
205                         /* lprintf(9, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
206                         break;
207                 default:
208                         break;
209                 }
210
211
212         }
213         free(d);
214         closedir(filedir);
215         FreeStrBuf(&Dir);
216         FreeStrBuf(&WebDir);
217         FreeStrBuf(&OneWebName);
218         return 1;
219 }
220
221
222 void output_flat_static(void)
223 {
224         wcsession *WCC = WC;
225         void *vFile;
226         StrBuf *File;
227
228         if (GetHash(StaticFilemappings[0], SKEY(WCC->Hdr->HR.Handler->Name), &vFile) &&
229             (vFile != NULL))
230         {
231                 File = (StrBuf*) vFile;
232                 output_static(ChrPtr(vFile));
233         }
234 }
235
236 extern void do_404(void);
237
238 void output_static_safe(HashList *DirList)
239 {
240         wcsession *WCC = WC;
241         void *vFile;
242         StrBuf *File;
243
244         if (GetHash(DirList, SKEY(WCC->Hdr->HR.ReqLine), &vFile) &&
245             (vFile != NULL))
246         {
247                 File = (StrBuf*) vFile;
248                 output_static(ChrPtr(vFile));
249         }
250         else {
251                 lprintf(1, "output_static_safe() file %s not found. \n", 
252                         ChrPtr(WCC->Hdr->HR.ReqLine));
253 ///TODO: detect image & output blank image
254                 do_404();
255         }
256 }
257 void output_static_0(void)
258 {
259         output_static_safe(StaticFilemappings[0]);
260 }
261 void output_static_1(void)
262 {
263         output_static_safe(StaticFilemappings[1]);
264 }
265 void output_static_2(void)
266 {
267         output_static_safe(StaticFilemappings[2]);
268 }
269 void output_static_3(void)
270 {
271         output_static_safe(StaticFilemappings[3]);
272 }
273
274 void 
275 ServerStartModule_STATIC
276 (void)
277 {
278         StaticFilemappings[0] = NewHash(1, NULL);
279         StaticFilemappings[1] = NewHash(1, NULL);
280         StaticFilemappings[2] = NewHash(1, NULL);
281         StaticFilemappings[3] = NewHash(1, NULL);
282 }
283 void 
284 ServerShutdownModule_STATIC
285 (void)
286 {
287         DeleteHash(&StaticFilemappings[0]);
288         DeleteHash(&StaticFilemappings[1]);
289         DeleteHash(&StaticFilemappings[2]);
290         DeleteHash(&StaticFilemappings[3]);
291 }
292
293
294 void 
295 InitModule_STATIC
296 (void)
297 {
298         LoadStaticDir(static_dirs[0], StaticFilemappings[0], "");
299         LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
300         LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
301         LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
302
303         WebcitAddUrlHandler(HKEY("robots.txt"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
304         WebcitAddUrlHandler(HKEY("favicon.ico"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
305         WebcitAddUrlHandler(HKEY("static"), "", 0, output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
306         WebcitAddUrlHandler(HKEY("static.local"), "", 0, output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
307         WebcitAddUrlHandler(HKEY("tinymce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
308         WebcitAddUrlHandler(HKEY("tiny_mce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
309 }