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