e432d53edd5796496ebdb76c280673812778324f
[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                 wprintf("Cannot open %s: %s\r\n", what, strerror(errno));
50                 end_burst();
51         } else {
52                 len = strlen (what);
53                 content_type = GuessMimeByFilename(what, len);
54
55                 if (fstat(fd, &statbuf) == -1) {
56                         lprintf(9, "output_static('%s')  -- FSTAT FAILED --\n", what);
57                         hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
58                         hprintf("Content-Type: text/plain\r\n");
59                         wprintf("Cannot fstat %s: %s\n", what, strerror(errno));
60                         end_burst();
61                         return;
62                 }
63
64                 count = 0;
65                 bytes = statbuf.st_size;
66
67                 if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
68                 {
69                         if (fd > 0) close(fd);
70                         lprintf(9, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
71                                 hprintf("HTTP/1.1 500 internal server error \r\n");
72                                 hprintf("Content-Type: text/plain\r\n");
73                                 end_burst();
74                                 return;
75                 }
76
77
78                 close(fd);
79 #ifndef TECH_PREVIEW
80                 lprintf(9, "output_static('%s')  %s\n", what, content_type);
81 #endif
82                 http_transmit_thing(content_type, 2);
83         }
84         if (yesbstr("force_close_session")) {
85                 end_webcit_session();
86         }
87 }
88
89
90 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
91 {
92         char dirname[PATH_MAX];
93         char reldir[PATH_MAX];
94         StrBuf *FileName = NULL;
95         StrBuf *Dir = NULL;
96         StrBuf *WebDir = NULL;
97         StrBuf *OneWebName = NULL;
98         DIR *filedir = NULL;
99         struct dirent d;
100         struct dirent *filedir_entry;
101         int d_namelen;
102         int d_without_ext;
103                 
104         filedir = opendir (DirName);
105         if (filedir == NULL) {
106                 return 0;
107         }
108
109         Dir = NewStrBufPlain(DirName, -1);
110         WebDir = NewStrBufPlain(RelDir, -1);
111         OneWebName = NewStrBuf();
112
113         while ((readdir_r(filedir, &d, &filedir_entry) == 0) &&
114                (filedir_entry != NULL))
115         {
116                 char *PStart;
117 #ifdef _DIRENT_HAVE_D_NAMELEN
118                 d_namelen = filedir_entry->d_namelen;
119 #else
120                 d_namelen = strlen(filedir_entry->d_name);
121 #endif
122                 d_without_ext = d_namelen;
123
124                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
125                         continue; /* Ignore backup files... */
126
127                 if ((d_namelen == 1) && 
128                     (filedir_entry->d_name[0] == '.'))
129                         continue;
130
131                 if ((d_namelen == 2) && 
132                     (filedir_entry->d_name[0] == '.') &&
133                     (filedir_entry->d_name[1] == '.'))
134                         continue;
135
136                 switch (filedir_entry->d_type)
137                 {
138                 case DT_DIR:
139                         /* Skip directories we are not interested in... */
140                         if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
141                             (strcmp(filedir_entry->d_name, "t") == 0))
142                                 break;
143                         snprintf(dirname, PATH_MAX, "%s/%s", 
144                                  DirName, filedir_entry->d_name);
145                         snprintf(reldir, PATH_MAX, "%s/%s", 
146                                  RelDir, filedir_entry->d_name);
147                         LoadStaticDir(dirname, DirList, reldir);                                 
148                         break;
149                 case DT_LNK: /* TODO: check whether its a file or a directory */
150                 case DT_REG:
151                         PStart = filedir_entry->d_name;
152                         FileName = NewStrBufDup(Dir);
153                         if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
154                                 StrBufAppendBufPlain(FileName, "/", 1, 0);
155                         StrBufAppendBufPlain(FileName, filedir_entry->d_name, d_namelen, 0);
156
157                         FlushStrBuf(OneWebName);
158                         StrBufAppendBuf(OneWebName, WebDir, 0);
159                         if ((StrLength(OneWebName) != 0) && 
160                             (ChrPtr(OneWebName) [ StrLength(OneWebName)] != '/'))
161                                 StrBufAppendBufPlain(OneWebName, "/", 1, 0);
162                         StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
163
164                         Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
165 /*                      printf("[%s | %s]  \n", ChrPtr(OneWebName), ChrPtr(FileName));*/
166                         break;
167                 default:
168                         break;
169                 }
170
171
172         }
173         closedir(filedir);
174         FreeStrBuf(&Dir);
175         FreeStrBuf(&WebDir);
176         FreeStrBuf(&OneWebName);
177         return 1;
178 }
179
180
181 void output_flat_static(void)
182 {
183         wcsession *WCC = WC;
184         void *vFile;
185         StrBuf *File;
186
187         if (GetHash(StaticFilemappings[0], SKEY(WCC->Hdr->Handler->Name), &vFile) &&
188             (vFile != NULL))
189         {
190                 File = (StrBuf*) vFile;
191                 output_static(ChrPtr(vFile));
192         }
193 }
194
195
196
197 void output_static_safe(HashList *DirList)
198 {
199         wcsession *WCC = WC;
200         void *vFile;
201         StrBuf *File;
202
203         if (GetHash(DirList, SKEY(WCC->Hdr->ReqLine), &vFile) &&
204             (vFile != NULL))
205         {
206                 File = (StrBuf*) vFile;
207                 output_static(ChrPtr(vFile));
208         }
209         else {
210 ///TODO: detect image & output blank image
211         }
212 }
213 void output_static_0(void)
214 {
215         output_static_safe(StaticFilemappings[0]);
216 }
217 void output_static_1(void)
218 {
219         output_static_safe(StaticFilemappings[1]);
220 }
221 void output_static_2(void)
222 {
223         output_static_safe(StaticFilemappings[2]);
224 }
225 void output_static_3(void)
226 {
227         output_static_safe(StaticFilemappings[3]);
228 }
229
230 void 
231 ServerStartModule_STATIC
232 (void)
233 {
234         StaticFilemappings[0] = NewHash(1, NULL);
235         StaticFilemappings[1] = NewHash(1, NULL);
236         StaticFilemappings[2] = NewHash(1, NULL);
237         StaticFilemappings[3] = NewHash(1, NULL);
238 }
239 void 
240 ServerShutdownModule_STATIC
241 (void)
242 {
243         DeleteHash(&StaticFilemappings[0]);
244         DeleteHash(&StaticFilemappings[1]);
245         DeleteHash(&StaticFilemappings[2]);
246         DeleteHash(&StaticFilemappings[3]);
247 }
248
249
250 void 
251 InitModule_STATIC
252 (void)
253 {
254         LoadStaticDir(static_dirs[0], StaticFilemappings[0], "");
255         LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
256         LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
257         LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
258
259         WebcitAddUrlHandler(HKEY("robots.txt"), output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
260         WebcitAddUrlHandler(HKEY("favicon.ico"), output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
261         WebcitAddUrlHandler(HKEY("static"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
262         WebcitAddUrlHandler(HKEY("static.local"), output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
263         WebcitAddUrlHandler(HKEY("tinymce"), output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
264 }