|
5cf1206…
|
drh
|
1 |
/* |
|
c19f34c…
|
drh
|
2 |
** Copyright (c) 2007 D. Richard Hipp |
|
5cf1206…
|
drh
|
3 |
** |
|
5cf1206…
|
drh
|
4 |
** This program is free software; you can redistribute it and/or |
|
c06edd2…
|
drh
|
5 |
** modify it under the terms of the Simplified BSD License (also |
|
c06edd2…
|
drh
|
6 |
** known as the "2-Clause License" or "FreeBSD License".) |
|
03ce4e7…
|
drh
|
7 |
** |
|
5cf1206…
|
drh
|
8 |
** This program is distributed in the hope that it will be useful, |
|
c06edd2…
|
drh
|
9 |
** but without any warranty; without even the implied warranty of |
|
c06edd2…
|
drh
|
10 |
** merchantability or fitness for a particular purpose. |
|
5cf1206…
|
drh
|
11 |
** |
|
5cf1206…
|
drh
|
12 |
** Author contact information: |
|
5cf1206…
|
drh
|
13 |
** [email protected] |
|
5cf1206…
|
drh
|
14 |
** http://www.hwaci.com/drh/ |
|
5cf1206…
|
drh
|
15 |
** |
|
5cf1206…
|
drh
|
16 |
******************************************************************************* |
|
5cf1206…
|
drh
|
17 |
** |
|
5cf1206…
|
drh
|
18 |
** This file contains code to implement the "/doc" web page and related |
|
5cf1206…
|
drh
|
19 |
** pages. |
|
5cf1206…
|
drh
|
20 |
*/ |
|
5cf1206…
|
drh
|
21 |
#include "config.h" |
|
5cf1206…
|
drh
|
22 |
#include "doc.h" |
|
5cf1206…
|
drh
|
23 |
#include <assert.h> |
|
5cf1206…
|
drh
|
24 |
|
|
5cf1206…
|
drh
|
25 |
/* |
|
d14adf1…
|
kejoki
|
26 |
** Try to guess the mimetype from content. |
|
d14adf1…
|
kejoki
|
27 |
** |
|
d14adf1…
|
kejoki
|
28 |
** If the content is pure text, return NULL. |
|
d14adf1…
|
kejoki
|
29 |
** |
|
d14adf1…
|
kejoki
|
30 |
** For image types, attempt to return an appropriate mimetype |
|
20d02ab…
|
jan.nijtmans
|
31 |
** name like "image/gif" or "image/jpeg". |
|
d14adf1…
|
kejoki
|
32 |
** |
|
d14adf1…
|
kejoki
|
33 |
** For any other binary type, return "unknown/unknown". |
|
d14adf1…
|
kejoki
|
34 |
*/ |
|
d14adf1…
|
kejoki
|
35 |
const char *mimetype_from_content(Blob *pBlob){ |
|
d14adf1…
|
kejoki
|
36 |
int i; |
|
d14adf1…
|
kejoki
|
37 |
int n; |
|
d14adf1…
|
kejoki
|
38 |
const unsigned char *x; |
|
d14adf1…
|
kejoki
|
39 |
|
|
d14adf1…
|
kejoki
|
40 |
/* A table of mimetypes based on file content prefixes |
|
d14adf1…
|
kejoki
|
41 |
*/ |
|
d14adf1…
|
kejoki
|
42 |
static const struct { |
|
6643d4a…
|
drh
|
43 |
const char *z; /* Identifying file text */ |
|
6643d4a…
|
drh
|
44 |
const unsigned char sz1; /* Length of the prefix */ |
|
6643d4a…
|
drh
|
45 |
const unsigned char of2; /* Offset to the second segment */ |
|
6643d4a…
|
drh
|
46 |
const unsigned char sz2; /* Size of the second segment */ |
|
6643d4a…
|
drh
|
47 |
const unsigned char mn; /* Minimum size of input */ |
|
d14adf1…
|
kejoki
|
48 |
const char *zMimetype; /* The corresponding mimetype */ |
|
d14adf1…
|
kejoki
|
49 |
} aMime[] = { |
|
6643d4a…
|
drh
|
50 |
{ "GIF87a", 6, 0, 0, 6, "image/gif" }, |
|
6643d4a…
|
drh
|
51 |
{ "GIF89a", 6, 0, 0, 6, "image/gif" }, |
|
6643d4a…
|
drh
|
52 |
{ "\211PNG\r\n\032\n", 8, 0, 0, 8, "image/png" }, |
|
6643d4a…
|
drh
|
53 |
{ "\377\332\377", 3, 0, 0, 3, "image/jpeg" }, |
|
6643d4a…
|
drh
|
54 |
{ "\377\330\377", 3, 0, 0, 3, "image/jpeg" }, |
|
6643d4a…
|
drh
|
55 |
{ "RIFFWAVEfmt", 4, 8, 7, 15, "sound/wav" }, |
|
d14adf1…
|
kejoki
|
56 |
}; |
|
d14adf1…
|
kejoki
|
57 |
|
|
b51ba29…
|
jan.nijtmans
|
58 |
if( !looks_like_binary(pBlob) ) { |
|
b51ba29…
|
jan.nijtmans
|
59 |
return 0; /* Plain text */ |
|
b51ba29…
|
jan.nijtmans
|
60 |
} |
|
d14adf1…
|
kejoki
|
61 |
x = (const unsigned char*)blob_buffer(pBlob); |
|
d14adf1…
|
kejoki
|
62 |
n = blob_size(pBlob); |
|
3cb9ba4…
|
andygoth
|
63 |
for(i=0; i<count(aMime); i++){ |
|
6643d4a…
|
drh
|
64 |
if( n<aMime[i].mn ) continue; |
|
6643d4a…
|
drh
|
65 |
if( memcmp(x, aMime[i].z, aMime[i].sz1)!=0 ) continue; |
|
6643d4a…
|
drh
|
66 |
if( aMime[i].sz2 |
|
6643d4a…
|
drh
|
67 |
&& memcmp(x+aMime[i].of2, aMime[i].z+aMime[i].sz1, aMime[i].sz2)!=0 |
|
6643d4a…
|
drh
|
68 |
){ |
|
6643d4a…
|
drh
|
69 |
continue; |
|
b51ba29…
|
jan.nijtmans
|
70 |
} |
|
6643d4a…
|
drh
|
71 |
return aMime[i].zMimetype; |
|
d14adf1…
|
kejoki
|
72 |
} |
|
d14adf1…
|
kejoki
|
73 |
return "unknown/unknown"; |
|
d14adf1…
|
kejoki
|
74 |
} |
|
d14adf1…
|
kejoki
|
75 |
|
|
51751b0…
|
drh
|
76 |
/* A table of mimetypes based on file suffixes. |
|
51751b0…
|
drh
|
77 |
** Suffixes must be in sorted order so that we can do a binary |
|
4cb50c4…
|
stephan
|
78 |
** search to find the mimetype. |
|
51751b0…
|
drh
|
79 |
*/ |
|
51751b0…
|
drh
|
80 |
static const struct { |
|
51751b0…
|
drh
|
81 |
const char *zSuffix; /* The file suffix */ |
|
51751b0…
|
drh
|
82 |
int size; /* Length of the suffix */ |
|
51751b0…
|
drh
|
83 |
const char *zMimetype; /* The corresponding mimetype */ |
|
51751b0…
|
drh
|
84 |
} aMime[] = { |
|
51751b0…
|
drh
|
85 |
{ "ai", 2, "application/postscript" }, |
|
51751b0…
|
drh
|
86 |
{ "aif", 3, "audio/x-aiff" }, |
|
51751b0…
|
drh
|
87 |
{ "aifc", 4, "audio/x-aiff" }, |
|
51751b0…
|
drh
|
88 |
{ "aiff", 4, "audio/x-aiff" }, |
|
51751b0…
|
drh
|
89 |
{ "arj", 3, "application/x-arj-compressed" }, |
|
51751b0…
|
drh
|
90 |
{ "asc", 3, "text/plain" }, |
|
51751b0…
|
drh
|
91 |
{ "asf", 3, "video/x-ms-asf" }, |
|
51751b0…
|
drh
|
92 |
{ "asx", 3, "video/x-ms-asx" }, |
|
51751b0…
|
drh
|
93 |
{ "au", 2, "audio/ulaw" }, |
|
51751b0…
|
drh
|
94 |
{ "avi", 3, "video/x-msvideo" }, |
|
51751b0…
|
drh
|
95 |
{ "bat", 3, "application/x-msdos-program" }, |
|
51751b0…
|
drh
|
96 |
{ "bcpio", 5, "application/x-bcpio" }, |
|
51751b0…
|
drh
|
97 |
{ "bin", 3, "application/octet-stream" }, |
|
613fe1b…
|
jan.nijtmans
|
98 |
{ "bmp", 3, "image/bmp" }, |
|
c7e9625…
|
drh
|
99 |
{ "bz2", 3, "application/x-bzip2" }, |
|
c7e9625…
|
drh
|
100 |
{ "bzip", 4, "application/x-bzip" }, |
|
51751b0…
|
drh
|
101 |
{ "c", 1, "text/plain" }, |
|
51751b0…
|
drh
|
102 |
{ "cc", 2, "text/plain" }, |
|
51751b0…
|
drh
|
103 |
{ "ccad", 4, "application/clariscad" }, |
|
51751b0…
|
drh
|
104 |
{ "cdf", 3, "application/x-netcdf" }, |
|
51751b0…
|
drh
|
105 |
{ "class", 5, "application/octet-stream" }, |
|
51751b0…
|
drh
|
106 |
{ "cod", 3, "application/vnd.rim.cod" }, |
|
51751b0…
|
drh
|
107 |
{ "com", 3, "application/x-msdos-program" }, |
|
51751b0…
|
drh
|
108 |
{ "cpio", 4, "application/x-cpio" }, |
|
51751b0…
|
drh
|
109 |
{ "cpt", 3, "application/mac-compactpro" }, |
|
5e81f4c…
|
drh
|
110 |
{ "cs", 2, "text/plain" }, |
|
51751b0…
|
drh
|
111 |
{ "csh", 3, "application/x-csh" }, |
|
51751b0…
|
drh
|
112 |
{ "css", 3, "text/css" }, |
|
e4c420b…
|
drh
|
113 |
{ "csv", 3, "text/csv" }, |
|
51751b0…
|
drh
|
114 |
{ "dcr", 3, "application/x-director" }, |
|
51751b0…
|
drh
|
115 |
{ "deb", 3, "application/x-debian-package" }, |
|
613fe1b…
|
jan.nijtmans
|
116 |
{ "dib", 3, "image/bmp" }, |
|
51751b0…
|
drh
|
117 |
{ "dir", 3, "application/x-director" }, |
|
51751b0…
|
drh
|
118 |
{ "dl", 2, "video/dl" }, |
|
51751b0…
|
drh
|
119 |
{ "dms", 3, "application/octet-stream" }, |
|
51751b0…
|
drh
|
120 |
{ "doc", 3, "application/msword" }, |
|
51751b0…
|
drh
|
121 |
{ "docx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
122 |
"officedocument.wordprocessingml.document"}, |
|
51751b0…
|
drh
|
123 |
{ "dot", 3, "application/msword" }, |
|
51751b0…
|
drh
|
124 |
{ "dotx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
125 |
"officedocument.wordprocessingml.template"}, |
|
51751b0…
|
drh
|
126 |
{ "drw", 3, "application/drafting" }, |
|
51751b0…
|
drh
|
127 |
{ "dvi", 3, "application/x-dvi" }, |
|
51751b0…
|
drh
|
128 |
{ "dwg", 3, "application/acad" }, |
|
51751b0…
|
drh
|
129 |
{ "dxf", 3, "application/dxf" }, |
|
51751b0…
|
drh
|
130 |
{ "dxr", 3, "application/x-director" }, |
|
51751b0…
|
drh
|
131 |
{ "eps", 3, "application/postscript" }, |
|
51751b0…
|
drh
|
132 |
{ "etx", 3, "text/x-setext" }, |
|
51751b0…
|
drh
|
133 |
{ "exe", 3, "application/octet-stream" }, |
|
51751b0…
|
drh
|
134 |
{ "ez", 2, "application/andrew-inset" }, |
|
51751b0…
|
drh
|
135 |
{ "f", 1, "text/plain" }, |
|
51751b0…
|
drh
|
136 |
{ "f90", 3, "text/plain" }, |
|
51751b0…
|
drh
|
137 |
{ "fli", 3, "video/fli" }, |
|
51751b0…
|
drh
|
138 |
{ "flv", 3, "video/flv" }, |
|
51751b0…
|
drh
|
139 |
{ "gif", 3, "image/gif" }, |
|
51751b0…
|
drh
|
140 |
{ "gl", 2, "video/gl" }, |
|
51751b0…
|
drh
|
141 |
{ "gtar", 4, "application/x-gtar" }, |
|
51751b0…
|
drh
|
142 |
{ "gz", 2, "application/x-gzip" }, |
|
51751b0…
|
drh
|
143 |
{ "h", 1, "text/plain" }, |
|
51751b0…
|
drh
|
144 |
{ "hdf", 3, "application/x-hdf" }, |
|
51751b0…
|
drh
|
145 |
{ "hh", 2, "text/plain" }, |
|
51751b0…
|
drh
|
146 |
{ "hqx", 3, "application/mac-binhex40" }, |
|
51751b0…
|
drh
|
147 |
{ "htm", 3, "text/html" }, |
|
51751b0…
|
drh
|
148 |
{ "html", 4, "text/html" }, |
|
51751b0…
|
drh
|
149 |
{ "ice", 3, "x-conference/x-cooltalk" }, |
|
613fe1b…
|
jan.nijtmans
|
150 |
{ "ico", 3, "image/vnd.microsoft.icon" }, |
|
51751b0…
|
drh
|
151 |
{ "ief", 3, "image/ief" }, |
|
51751b0…
|
drh
|
152 |
{ "iges", 4, "model/iges" }, |
|
51751b0…
|
drh
|
153 |
{ "igs", 3, "model/iges" }, |
|
51751b0…
|
drh
|
154 |
{ "ips", 3, "application/x-ipscript" }, |
|
51751b0…
|
drh
|
155 |
{ "ipx", 3, "application/x-ipix" }, |
|
51751b0…
|
drh
|
156 |
{ "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, |
|
51751b0…
|
drh
|
157 |
{ "jar", 3, "application/java-archive" }, |
|
2669f49…
|
stephan
|
158 |
{ "jp2", 3, "image/jp2" }, |
|
51751b0…
|
drh
|
159 |
{ "jpe", 3, "image/jpeg" }, |
|
51751b0…
|
drh
|
160 |
{ "jpeg", 4, "image/jpeg" }, |
|
51751b0…
|
drh
|
161 |
{ "jpg", 3, "image/jpeg" }, |
|
7fcb462…
|
stephan
|
162 |
{ "js", 2, "text/javascript" }, |
|
7fcb462…
|
stephan
|
163 |
/* application/javascript is commonly used for JS, but the |
|
7fcb462…
|
stephan
|
164 |
** spec says text/javascript is correct: |
|
7fcb462…
|
stephan
|
165 |
** https://html.spec.whatwg.org/multipage/scripting.html |
|
7fcb462…
|
stephan
|
166 |
** #scriptingLanguages:javascript-mime-type */ |
|
7fcb462…
|
stephan
|
167 |
{ "json", 4, "application/json" }, |
|
51751b0…
|
drh
|
168 |
{ "kar", 3, "audio/midi" }, |
|
51751b0…
|
drh
|
169 |
{ "latex", 5, "application/x-latex" }, |
|
51751b0…
|
drh
|
170 |
{ "lha", 3, "application/octet-stream" }, |
|
51751b0…
|
drh
|
171 |
{ "lsp", 3, "application/x-lisp" }, |
|
51751b0…
|
drh
|
172 |
{ "lzh", 3, "application/octet-stream" }, |
|
51751b0…
|
drh
|
173 |
{ "m", 1, "text/plain" }, |
|
51751b0…
|
drh
|
174 |
{ "m3u", 3, "audio/x-mpegurl" }, |
|
addf43c…
|
drh
|
175 |
{ "man", 3, "text/plain" }, |
|
51751b0…
|
drh
|
176 |
{ "markdown", 8, "text/x-markdown" }, |
|
51751b0…
|
drh
|
177 |
{ "md", 2, "text/x-markdown" }, |
|
51751b0…
|
drh
|
178 |
{ "me", 2, "application/x-troff-me" }, |
|
51751b0…
|
drh
|
179 |
{ "mesh", 4, "model/mesh" }, |
|
51751b0…
|
drh
|
180 |
{ "mid", 3, "audio/midi" }, |
|
51751b0…
|
drh
|
181 |
{ "midi", 4, "audio/midi" }, |
|
51751b0…
|
drh
|
182 |
{ "mif", 3, "application/x-mif" }, |
|
51751b0…
|
drh
|
183 |
{ "mime", 4, "www/mime" }, |
|
95e5814…
|
stephan
|
184 |
{ "mjs", 3, "text/javascript" /*ES6 module*/ }, |
|
51751b0…
|
drh
|
185 |
{ "mkd", 3, "text/x-markdown" }, |
|
51751b0…
|
drh
|
186 |
{ "mov", 3, "video/quicktime" }, |
|
51751b0…
|
drh
|
187 |
{ "movie", 5, "video/x-sgi-movie" }, |
|
51751b0…
|
drh
|
188 |
{ "mp2", 3, "audio/mpeg" }, |
|
51751b0…
|
drh
|
189 |
{ "mp3", 3, "audio/mpeg" }, |
|
51751b0…
|
drh
|
190 |
{ "mp4", 3, "video/mp4" }, |
|
51751b0…
|
drh
|
191 |
{ "mpe", 3, "video/mpeg" }, |
|
51751b0…
|
drh
|
192 |
{ "mpeg", 4, "video/mpeg" }, |
|
51751b0…
|
drh
|
193 |
{ "mpg", 3, "video/mpeg" }, |
|
51751b0…
|
drh
|
194 |
{ "mpga", 4, "audio/mpeg" }, |
|
51751b0…
|
drh
|
195 |
{ "ms", 2, "application/x-troff-ms" }, |
|
51751b0…
|
drh
|
196 |
{ "msh", 3, "model/mesh" }, |
|
addf43c…
|
drh
|
197 |
{ "n", 1, "text/plain" }, |
|
51751b0…
|
drh
|
198 |
{ "nc", 2, "application/x-netcdf" }, |
|
51751b0…
|
drh
|
199 |
{ "oda", 3, "application/oda" }, |
|
04e6a82…
|
jan.nijtmans
|
200 |
{ "odp", 3, "application/vnd.oasis.opendocument.presentation" }, |
|
04e6a82…
|
jan.nijtmans
|
201 |
{ "ods", 3, "application/vnd.oasis.opendocument.spreadsheet" }, |
|
04e6a82…
|
jan.nijtmans
|
202 |
{ "odt", 3, "application/vnd.oasis.opendocument.text" }, |
|
51751b0…
|
drh
|
203 |
{ "ogg", 3, "application/ogg" }, |
|
51751b0…
|
drh
|
204 |
{ "ogm", 3, "application/ogg" }, |
|
422785d…
|
stephan
|
205 |
{ "otf", 3, "font/otf" }, |
|
51751b0…
|
drh
|
206 |
{ "pbm", 3, "image/x-portable-bitmap" }, |
|
51751b0…
|
drh
|
207 |
{ "pdb", 3, "chemical/x-pdb" }, |
|
51751b0…
|
drh
|
208 |
{ "pdf", 3, "application/pdf" }, |
|
51751b0…
|
drh
|
209 |
{ "pgm", 3, "image/x-portable-graymap" }, |
|
51751b0…
|
drh
|
210 |
{ "pgn", 3, "application/x-chess-pgn" }, |
|
51751b0…
|
drh
|
211 |
{ "pgp", 3, "application/pgp" }, |
|
e32214a…
|
drh
|
212 |
{ "pikchr", 6, "text/x-pikchr" }, |
|
51751b0…
|
drh
|
213 |
{ "pl", 2, "application/x-perl" }, |
|
51751b0…
|
drh
|
214 |
{ "pm", 2, "application/x-perl" }, |
|
51751b0…
|
drh
|
215 |
{ "png", 3, "image/png" }, |
|
51751b0…
|
drh
|
216 |
{ "pnm", 3, "image/x-portable-anymap" }, |
|
51751b0…
|
drh
|
217 |
{ "pot", 3, "application/mspowerpoint" }, |
|
51751b0…
|
drh
|
218 |
{ "potx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
219 |
"officedocument.presentationml.template"}, |
|
51751b0…
|
drh
|
220 |
{ "ppm", 3, "image/x-portable-pixmap" }, |
|
51751b0…
|
drh
|
221 |
{ "pps", 3, "application/mspowerpoint" }, |
|
51751b0…
|
drh
|
222 |
{ "ppsx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
223 |
"officedocument.presentationml.slideshow"}, |
|
51751b0…
|
drh
|
224 |
{ "ppt", 3, "application/mspowerpoint" }, |
|
51751b0…
|
drh
|
225 |
{ "pptx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
226 |
"officedocument.presentationml.presentation"}, |
|
51751b0…
|
drh
|
227 |
{ "ppz", 3, "application/mspowerpoint" }, |
|
51751b0…
|
drh
|
228 |
{ "pre", 3, "application/x-freelance" }, |
|
51751b0…
|
drh
|
229 |
{ "prt", 3, "application/pro_eng" }, |
|
51751b0…
|
drh
|
230 |
{ "ps", 2, "application/postscript" }, |
|
51751b0…
|
drh
|
231 |
{ "qt", 2, "video/quicktime" }, |
|
51751b0…
|
drh
|
232 |
{ "ra", 2, "audio/x-realaudio" }, |
|
51751b0…
|
drh
|
233 |
{ "ram", 3, "audio/x-pn-realaudio" }, |
|
51751b0…
|
drh
|
234 |
{ "rar", 3, "application/x-rar-compressed" }, |
|
51751b0…
|
drh
|
235 |
{ "ras", 3, "image/cmu-raster" }, |
|
51751b0…
|
drh
|
236 |
{ "rgb", 3, "image/x-rgb" }, |
|
51751b0…
|
drh
|
237 |
{ "rm", 2, "audio/x-pn-realaudio" }, |
|
51751b0…
|
drh
|
238 |
{ "roff", 4, "application/x-troff" }, |
|
51751b0…
|
drh
|
239 |
{ "rpm", 3, "audio/x-pn-realaudio-plugin" }, |
|
51751b0…
|
drh
|
240 |
{ "rtf", 3, "text/rtf" }, |
|
51751b0…
|
drh
|
241 |
{ "rtx", 3, "text/richtext" }, |
|
51751b0…
|
drh
|
242 |
{ "scm", 3, "application/x-lotusscreencam" }, |
|
51751b0…
|
drh
|
243 |
{ "set", 3, "application/set" }, |
|
51751b0…
|
drh
|
244 |
{ "sgm", 3, "text/sgml" }, |
|
51751b0…
|
drh
|
245 |
{ "sgml", 4, "text/sgml" }, |
|
51751b0…
|
drh
|
246 |
{ "sh", 2, "application/x-sh" }, |
|
51751b0…
|
drh
|
247 |
{ "shar", 4, "application/x-shar" }, |
|
51751b0…
|
drh
|
248 |
{ "silo", 4, "model/mesh" }, |
|
51751b0…
|
drh
|
249 |
{ "sit", 3, "application/x-stuffit" }, |
|
51751b0…
|
drh
|
250 |
{ "skd", 3, "application/x-koan" }, |
|
51751b0…
|
drh
|
251 |
{ "skm", 3, "application/x-koan" }, |
|
51751b0…
|
drh
|
252 |
{ "skp", 3, "application/x-koan" }, |
|
51751b0…
|
drh
|
253 |
{ "skt", 3, "application/x-koan" }, |
|
51751b0…
|
drh
|
254 |
{ "smi", 3, "application/smil" }, |
|
51751b0…
|
drh
|
255 |
{ "smil", 4, "application/smil" }, |
|
51751b0…
|
drh
|
256 |
{ "snd", 3, "audio/basic" }, |
|
51751b0…
|
drh
|
257 |
{ "sol", 3, "application/solids" }, |
|
51751b0…
|
drh
|
258 |
{ "spl", 3, "application/x-futuresplash" }, |
|
7c76c6a…
|
stephan
|
259 |
{ "sql", 3, "application/sql" }, |
|
51751b0…
|
drh
|
260 |
{ "src", 3, "application/x-wais-source" }, |
|
51751b0…
|
drh
|
261 |
{ "step", 4, "application/STEP" }, |
|
51751b0…
|
drh
|
262 |
{ "stl", 3, "application/SLA" }, |
|
51751b0…
|
drh
|
263 |
{ "stp", 3, "application/STEP" }, |
|
51751b0…
|
drh
|
264 |
{ "sv4cpio", 7, "application/x-sv4cpio" }, |
|
51751b0…
|
drh
|
265 |
{ "sv4crc", 6, "application/x-sv4crc" }, |
|
51751b0…
|
drh
|
266 |
{ "svg", 3, "image/svg+xml" }, |
|
51751b0…
|
drh
|
267 |
{ "swf", 3, "application/x-shockwave-flash" }, |
|
51751b0…
|
drh
|
268 |
{ "t", 1, "application/x-troff" }, |
|
51751b0…
|
drh
|
269 |
{ "tar", 3, "application/x-tar" }, |
|
51751b0…
|
drh
|
270 |
{ "tcl", 3, "application/x-tcl" }, |
|
51751b0…
|
drh
|
271 |
{ "tex", 3, "application/x-tex" }, |
|
51751b0…
|
drh
|
272 |
{ "texi", 4, "application/x-texinfo" }, |
|
51751b0…
|
drh
|
273 |
{ "texinfo", 7, "application/x-texinfo" }, |
|
51751b0…
|
drh
|
274 |
{ "tgz", 3, "application/x-tar-gz" }, |
|
51751b0…
|
drh
|
275 |
{ "th1", 3, "application/x-th1" }, |
|
51751b0…
|
drh
|
276 |
{ "tif", 3, "image/tiff" }, |
|
51751b0…
|
drh
|
277 |
{ "tiff", 4, "image/tiff" }, |
|
51751b0…
|
drh
|
278 |
{ "tr", 2, "application/x-troff" }, |
|
51751b0…
|
drh
|
279 |
{ "tsi", 3, "audio/TSP-audio" }, |
|
51751b0…
|
drh
|
280 |
{ "tsp", 3, "application/dsptype" }, |
|
51751b0…
|
drh
|
281 |
{ "tsv", 3, "text/tab-separated-values" }, |
|
51751b0…
|
drh
|
282 |
{ "txt", 3, "text/plain" }, |
|
51751b0…
|
drh
|
283 |
{ "unv", 3, "application/i-deas" }, |
|
51751b0…
|
drh
|
284 |
{ "ustar", 5, "application/x-ustar" }, |
|
5e81f4c…
|
drh
|
285 |
{ "vb", 2, "text/plain" }, |
|
51751b0…
|
drh
|
286 |
{ "vcd", 3, "application/x-cdlink" }, |
|
51751b0…
|
drh
|
287 |
{ "vda", 3, "application/vda" }, |
|
51751b0…
|
drh
|
288 |
{ "viv", 3, "video/vnd.vivo" }, |
|
51751b0…
|
drh
|
289 |
{ "vivo", 4, "video/vnd.vivo" }, |
|
51751b0…
|
drh
|
290 |
{ "vrml", 4, "model/vrml" }, |
|
5c47abd…
|
stephan
|
291 |
{ "wasm", 4, "application/wasm" }, |
|
51751b0…
|
drh
|
292 |
{ "wav", 3, "audio/x-wav" }, |
|
51751b0…
|
drh
|
293 |
{ "wax", 3, "audio/x-ms-wax" }, |
|
5590fb9…
|
stephan
|
294 |
{ "webp", 4, "image/webp" }, |
|
51751b0…
|
drh
|
295 |
{ "wiki", 4, "text/x-fossil-wiki" }, |
|
51751b0…
|
drh
|
296 |
{ "wma", 3, "audio/x-ms-wma" }, |
|
51751b0…
|
drh
|
297 |
{ "wmv", 3, "video/x-ms-wmv" }, |
|
51751b0…
|
drh
|
298 |
{ "wmx", 3, "video/x-ms-wmx" }, |
|
51751b0…
|
drh
|
299 |
{ "wrl", 3, "model/vrml" }, |
|
51751b0…
|
drh
|
300 |
{ "wvx", 3, "video/x-ms-wvx" }, |
|
51751b0…
|
drh
|
301 |
{ "xbm", 3, "image/x-xbitmap" }, |
|
51751b0…
|
drh
|
302 |
{ "xlc", 3, "application/vnd.ms-excel" }, |
|
51751b0…
|
drh
|
303 |
{ "xll", 3, "application/vnd.ms-excel" }, |
|
51751b0…
|
drh
|
304 |
{ "xlm", 3, "application/vnd.ms-excel" }, |
|
51751b0…
|
drh
|
305 |
{ "xls", 3, "application/vnd.ms-excel" }, |
|
51751b0…
|
drh
|
306 |
{ "xlsx", 4, "application/vnd.openxmlformats-" |
|
51751b0…
|
drh
|
307 |
"officedocument.spreadsheetml.sheet"}, |
|
51751b0…
|
drh
|
308 |
{ "xlw", 3, "application/vnd.ms-excel" }, |
|
51751b0…
|
drh
|
309 |
{ "xml", 3, "text/xml" }, |
|
51751b0…
|
drh
|
310 |
{ "xpm", 3, "image/x-xpixmap" }, |
|
c0f0e1d…
|
stephan
|
311 |
{ "xsl", 3, "text/xml" }, |
|
c0f0e1d…
|
stephan
|
312 |
{ "xslt", 4, "text/xml" }, |
|
51751b0…
|
drh
|
313 |
{ "xwd", 3, "image/x-xwindowdump" }, |
|
51751b0…
|
drh
|
314 |
{ "xyz", 3, "chemical/x-pdb" }, |
|
51751b0…
|
drh
|
315 |
{ "zip", 3, "application/zip" }, |
|
51751b0…
|
drh
|
316 |
}; |
|
51751b0…
|
drh
|
317 |
|
|
51751b0…
|
drh
|
318 |
/* |
|
e4c420b…
|
drh
|
319 |
** Verify that all entries in the aMime[] table are in sorted order. |
|
e4c420b…
|
drh
|
320 |
** Abort with a fatal error if any is out-of-order. |
|
e4c420b…
|
drh
|
321 |
*/ |
|
e4c420b…
|
drh
|
322 |
static void mimetype_verify(void){ |
|
e4c420b…
|
drh
|
323 |
int i; |
|
3cb9ba4…
|
andygoth
|
324 |
for(i=1; i<count(aMime); i++){ |
|
e4c420b…
|
drh
|
325 |
if( fossil_strcmp(aMime[i-1].zSuffix,aMime[i].zSuffix)>=0 ){ |
|
3f5ab71…
|
drh
|
326 |
fossil_panic("mimetypes out of sequence: %s before %s", |
|
e4c420b…
|
drh
|
327 |
aMime[i-1].zSuffix, aMime[i].zSuffix); |
|
e4c420b…
|
drh
|
328 |
} |
|
e4c420b…
|
drh
|
329 |
} |
|
e4c420b…
|
drh
|
330 |
} |
|
e4c420b…
|
drh
|
331 |
|
|
e4c420b…
|
drh
|
332 |
/* |
|
009a243…
|
stephan
|
333 |
** Looks in the contents of the "mimetypes" setting for a suffix |
|
009a243…
|
stephan
|
334 |
** matching zSuffix. If found, it returns the configured value |
|
009a243…
|
stephan
|
335 |
** in memory owned by the app (i.e. do not free() it), else it |
|
009a243…
|
stephan
|
336 |
** returns 0. |
|
009a243…
|
stephan
|
337 |
** |
|
009a243…
|
stephan
|
338 |
** The mimetypes setting is expected to be a list of file extensions |
|
009a243…
|
stephan
|
339 |
** and mimetypes, with one such mapping per line. A leading '.' on |
|
009a243…
|
stephan
|
340 |
** extensions is permitted for compatibility with lists imported from |
|
009a243…
|
stephan
|
341 |
** other tools which require them. |
|
009a243…
|
stephan
|
342 |
*/ |
|
009a243…
|
stephan
|
343 |
static const char *mimetype_from_name_custom(const char *zSuffix){ |
|
009a243…
|
stephan
|
344 |
static char * zList = 0; |
|
009a243…
|
stephan
|
345 |
static char const * zEnd = 0; |
|
009a243…
|
stephan
|
346 |
static int once = 0; |
|
009a243…
|
stephan
|
347 |
char * z; |
|
009a243…
|
stephan
|
348 |
int tokenizerState /* 0=expecting a key, 1=skip next token, |
|
009a243…
|
stephan
|
349 |
** 2=accept next token */; |
|
009a243…
|
stephan
|
350 |
if(once==0){ |
|
275da70…
|
danield
|
351 |
once = 1; |
|
009a243…
|
stephan
|
352 |
zList = db_get("mimetypes",0); |
|
009a243…
|
stephan
|
353 |
if(zList==0){ |
|
009a243…
|
stephan
|
354 |
return 0; |
|
009a243…
|
stephan
|
355 |
} |
|
009a243…
|
stephan
|
356 |
/* Transform zList to simplify the main loop: |
|
009a243…
|
stephan
|
357 |
replace non-newline spaces with NUL bytes. */ |
|
009a243…
|
stephan
|
358 |
zEnd = zList + strlen(zList); |
|
009a243…
|
stephan
|
359 |
for(z = zList; z<zEnd; ++z){ |
|
009a243…
|
stephan
|
360 |
if('\n'==*z) continue; |
|
009a243…
|
stephan
|
361 |
else if(fossil_isspace(*z)){ |
|
009a243…
|
stephan
|
362 |
*z = 0; |
|
009a243…
|
stephan
|
363 |
} |
|
009a243…
|
stephan
|
364 |
} |
|
009a243…
|
stephan
|
365 |
}else if(zList==0){ |
|
009a243…
|
stephan
|
366 |
return 0; |
|
009a243…
|
stephan
|
367 |
} |
|
009a243…
|
stephan
|
368 |
tokenizerState = 0; |
|
009a243…
|
stephan
|
369 |
z = zList; |
|
009a243…
|
stephan
|
370 |
while( z<zEnd ){ |
|
009a243…
|
stephan
|
371 |
if(*z==0){ |
|
009a243…
|
stephan
|
372 |
++z; |
|
009a243…
|
stephan
|
373 |
continue; |
|
009a243…
|
stephan
|
374 |
} |
|
009a243…
|
stephan
|
375 |
else if('\n'==*z){ |
|
009a243…
|
stephan
|
376 |
if(2==tokenizerState){ |
|
009a243…
|
stephan
|
377 |
/* We were expecting a value for a successful match |
|
009a243…
|
stephan
|
378 |
here, but got no value. Bail out. */ |
|
009a243…
|
stephan
|
379 |
break; |
|
009a243…
|
stephan
|
380 |
}else{ |
|
009a243…
|
stephan
|
381 |
/* May happen on malformed inputs. Skip this record. */ |
|
009a243…
|
stephan
|
382 |
tokenizerState = 0; |
|
009a243…
|
stephan
|
383 |
++z; |
|
009a243…
|
stephan
|
384 |
continue; |
|
009a243…
|
stephan
|
385 |
} |
|
009a243…
|
stephan
|
386 |
} |
|
009a243…
|
stephan
|
387 |
switch(tokenizerState){ |
|
009a243…
|
stephan
|
388 |
case 0:{ /* This is a file extension */ |
|
009a243…
|
stephan
|
389 |
static char * zCase = 0; |
|
009a243…
|
stephan
|
390 |
if('.'==*z){ |
|
009a243…
|
stephan
|
391 |
/*ignore an optional leading dot, for compatibility |
|
009a243…
|
stephan
|
392 |
with some external mimetype lists*/; |
|
009a243…
|
stephan
|
393 |
if(++z==zEnd){ |
|
009a243…
|
stephan
|
394 |
break; |
|
009a243…
|
stephan
|
395 |
} |
|
009a243…
|
stephan
|
396 |
} |
|
009a243…
|
stephan
|
397 |
if(zCase<z){ |
|
009a243…
|
stephan
|
398 |
/*we have not yet case-folded this section: lower-case it*/ |
|
009a243…
|
stephan
|
399 |
for(zCase = z; zCase<zEnd && *zCase!=0; ++zCase){ |
|
009a243…
|
stephan
|
400 |
if(!(0x80 & *zCase)){ |
|
009a243…
|
stephan
|
401 |
*zCase = (char)fossil_tolower(*zCase); |
|
009a243…
|
stephan
|
402 |
} |
|
009a243…
|
stephan
|
403 |
} |
|
009a243…
|
stephan
|
404 |
} |
|
009a243…
|
stephan
|
405 |
if(strcmp(z,zSuffix)==0){ |
|
009a243…
|
stephan
|
406 |
tokenizerState = 2 /* Match: accept the next value. */; |
|
009a243…
|
stephan
|
407 |
}else{ |
|
009a243…
|
stephan
|
408 |
tokenizerState = 1 /* No match: skip the next value. */; |
|
009a243…
|
stephan
|
409 |
} |
|
009a243…
|
stephan
|
410 |
z += strlen(z); |
|
009a243…
|
stephan
|
411 |
break; |
|
009a243…
|
stephan
|
412 |
} |
|
009a243…
|
stephan
|
413 |
case 1: /* This is a value, but not a match. Skip it. */ |
|
009a243…
|
stephan
|
414 |
z += strlen(z); |
|
009a243…
|
stephan
|
415 |
break; |
|
009a243…
|
stephan
|
416 |
case 2: /* This is the value which matched the previous key. */; |
|
009a243…
|
stephan
|
417 |
return z; |
|
009a243…
|
stephan
|
418 |
default: |
|
009a243…
|
stephan
|
419 |
assert(!"cannot happen - invalid tokenizerState value."); |
|
009a243…
|
stephan
|
420 |
} |
|
009a243…
|
stephan
|
421 |
} |
|
009a243…
|
stephan
|
422 |
return 0; |
|
009a243…
|
stephan
|
423 |
} |
|
009a243…
|
stephan
|
424 |
|
|
009a243…
|
stephan
|
425 |
/* |
|
83f03e9…
|
stephan
|
426 |
** Emit Javascript which applies (or optionally can apply) to both the |
|
83f03e9…
|
stephan
|
427 |
** /doc and /wiki pages. None of this implements required |
|
9b2b6f5…
|
stephan
|
428 |
** functionality, just nice-to-haves. Any calls after the first are |
|
9b2b6f5…
|
stephan
|
429 |
** no-ops. |
|
83f03e9…
|
stephan
|
430 |
*/ |
|
83f03e9…
|
stephan
|
431 |
void document_emit_js(void){ |
|
9b2b6f5…
|
stephan
|
432 |
static int once = 0; |
|
9b2b6f5…
|
stephan
|
433 |
if(0==once++){ |
|
815b4fc…
|
wyoung
|
434 |
builtin_fossil_js_bundle_or("pikchr", NULL); |
|
9b2b6f5…
|
stephan
|
435 |
style_script_begin(__FILE__,__LINE__); |
|
9b2b6f5…
|
stephan
|
436 |
CX("window.addEventListener('load', " |
|
9b2b6f5…
|
stephan
|
437 |
"()=>window.fossil.pikchr.addSrcView(), " |
|
9b2b6f5…
|
stephan
|
438 |
"false);\n"); |
|
9b2b6f5…
|
stephan
|
439 |
style_script_end(); |
|
9b2b6f5…
|
stephan
|
440 |
} |
|
83f03e9…
|
stephan
|
441 |
} |
|
83f03e9…
|
stephan
|
442 |
|
|
83f03e9…
|
stephan
|
443 |
/* |
|
4cb50c4…
|
stephan
|
444 |
** Guess the mimetype of a document based on its name. |
|
5cf1206…
|
drh
|
445 |
*/ |
|
5cf1206…
|
drh
|
446 |
const char *mimetype_from_name(const char *zName){ |
|
5cf1206…
|
drh
|
447 |
const char *z; |
|
5cf1206…
|
drh
|
448 |
int i; |
|
8e66784…
|
drh
|
449 |
int first, last; |
|
8e66784…
|
drh
|
450 |
int len; |
|
5cf1206…
|
drh
|
451 |
char zSuffix[20]; |
|
8e66784…
|
drh
|
452 |
|
|
ea2698e…
|
drh
|
453 |
|
|
ea2698e…
|
drh
|
454 |
#ifdef FOSSIL_DEBUG |
|
ea2698e…
|
drh
|
455 |
/* This is test code to make sure the table above is in the correct |
|
ea2698e…
|
drh
|
456 |
** order |
|
8e66784…
|
drh
|
457 |
*/ |
|
ea2698e…
|
drh
|
458 |
if( fossil_strcmp(zName, "mimetype-test")==0 ){ |
|
e4c420b…
|
drh
|
459 |
mimetype_verify(); |
|
ea2698e…
|
drh
|
460 |
return "ok"; |
|
ea2698e…
|
drh
|
461 |
} |
|
ea2698e…
|
drh
|
462 |
#endif |
|
5cf1206…
|
drh
|
463 |
|
|
5cf1206…
|
drh
|
464 |
z = zName; |
|
5cf1206…
|
drh
|
465 |
for(i=0; zName[i]; i++){ |
|
5cf1206…
|
drh
|
466 |
if( zName[i]=='.' ) z = &zName[i+1]; |
|
5cf1206…
|
drh
|
467 |
} |
|
8e66784…
|
drh
|
468 |
len = strlen(z); |
|
53db40e…
|
drh
|
469 |
if( len<(int)sizeof(zSuffix)-1 ){ |
|
bbbb35a…
|
drh
|
470 |
sqlite3_snprintf(sizeof(zSuffix), zSuffix, "%s", z); |
|
2fac809…
|
drh
|
471 |
for(i=0; zSuffix[i]; i++) zSuffix[i] = fossil_tolower(zSuffix[i]); |
|
009a243…
|
stephan
|
472 |
z = mimetype_from_name_custom(zSuffix); |
|
009a243…
|
stephan
|
473 |
if(z!=0){ |
|
009a243…
|
stephan
|
474 |
return z; |
|
009a243…
|
stephan
|
475 |
} |
|
8e66784…
|
drh
|
476 |
first = 0; |
|
3cb9ba4…
|
andygoth
|
477 |
last = count(aMime) - 1; |
|
8e66784…
|
drh
|
478 |
while( first<=last ){ |
|
8e66784…
|
drh
|
479 |
int c; |
|
8e66784…
|
drh
|
480 |
i = (first+last)/2; |
|
31c52c7…
|
drh
|
481 |
c = fossil_strcmp(zSuffix, aMime[i].zSuffix); |
|
8e66784…
|
drh
|
482 |
if( c==0 ) return aMime[i].zMimetype; |
|
8e66784…
|
drh
|
483 |
if( c<0 ){ |
|
8e66784…
|
drh
|
484 |
last = i-1; |
|
8e66784…
|
drh
|
485 |
}else{ |
|
8e66784…
|
drh
|
486 |
first = i+1; |
|
5cf1206…
|
drh
|
487 |
} |
|
5cf1206…
|
drh
|
488 |
} |
|
5cf1206…
|
drh
|
489 |
} |
|
5cf1206…
|
drh
|
490 |
return "application/x-fossil-artifact"; |
|
5cf1206…
|
drh
|
491 |
} |
|
5cf1206…
|
drh
|
492 |
|
|
5cf1206…
|
drh
|
493 |
/* |
|
26eef7f…
|
rberteig
|
494 |
** COMMAND: test-mimetype |
|
ea2698e…
|
drh
|
495 |
** |
|
ea2698e…
|
drh
|
496 |
** Usage: %fossil test-mimetype FILENAME... |
|
ea2698e…
|
drh
|
497 |
** |
|
ea2698e…
|
drh
|
498 |
** Return the deduced mimetype for each file listed. |
|
ea2698e…
|
drh
|
499 |
** |
|
ea2698e…
|
drh
|
500 |
** If Fossil is compiled with -DFOSSIL_DEBUG then the "mimetype-test" |
|
ea2698e…
|
drh
|
501 |
** filename is special and verifies the integrity of the mimetype table. |
|
ea2698e…
|
drh
|
502 |
** It should return "ok". |
|
ea2698e…
|
drh
|
503 |
*/ |
|
ea2698e…
|
drh
|
504 |
void mimetype_test_cmd(void){ |
|
ea2698e…
|
drh
|
505 |
int i; |
|
e4c420b…
|
drh
|
506 |
mimetype_verify(); |
|
009a243…
|
stephan
|
507 |
db_find_and_open_repository(0, 0); |
|
ea2698e…
|
drh
|
508 |
for(i=2; i<g.argc; i++){ |
|
ea2698e…
|
drh
|
509 |
fossil_print("%-20s -> %s\n", g.argv[i], mimetype_from_name(g.argv[i])); |
|
ea2698e…
|
drh
|
510 |
} |
|
ea2698e…
|
drh
|
511 |
} |
|
ea2698e…
|
drh
|
512 |
|
|
51751b0…
|
drh
|
513 |
/* |
|
51751b0…
|
drh
|
514 |
** WEBPAGE: mimetype_list |
|
51751b0…
|
drh
|
515 |
** |
|
51751b0…
|
drh
|
516 |
** Show the built-in table used to guess embedded document mimetypes |
|
51751b0…
|
drh
|
517 |
** from file suffixes. |
|
51751b0…
|
drh
|
518 |
*/ |
|
51751b0…
|
drh
|
519 |
void mimetype_list_page(void){ |
|
51751b0…
|
drh
|
520 |
int i; |
|
009a243…
|
stephan
|
521 |
char *zCustomList = 0; /* value of the mimetypes setting */ |
|
009a243…
|
stephan
|
522 |
int nCustomEntries = 0; /* number of entries in the mimetypes |
|
009a243…
|
stephan
|
523 |
** setting */ |
|
e4c420b…
|
drh
|
524 |
mimetype_verify(); |
|
51751b0…
|
drh
|
525 |
style_header("Mimetype List"); |
|
c64f28d…
|
drh
|
526 |
@ <p>The Fossil <a href="%R/help/www/doc">/doc</a> page uses filename |
|
009a243…
|
stephan
|
527 |
@ suffixes and the following tables to guess at the appropriate mimetype |
|
009a243…
|
stephan
|
528 |
@ for each document. Mimetypes may be customized and overridden using |
|
c64f28d…
|
drh
|
529 |
@ <a href="%R/help/mimetypes">the mimetypes config setting</a>.</p> |
|
009a243…
|
stephan
|
530 |
zCustomList = db_get("mimetypes",0); |
|
009a243…
|
stephan
|
531 |
if( zCustomList!=0 ){ |
|
009a243…
|
stephan
|
532 |
Blob list, entry, key, val; |
|
009a243…
|
stephan
|
533 |
@ <h1>Repository-specific mimetypes</h1> |
|
009a243…
|
stephan
|
534 |
@ <p>The following extension-to-mimetype mappings are defined via |
|
c64f28d…
|
drh
|
535 |
@ the <a href="%R/help/mimetypes">mimetypes setting</a>.</p> |
|
009a243…
|
stephan
|
536 |
@ <table class='sortable mimetypetable' border=1 cellpadding=0 \ |
|
009a243…
|
stephan
|
537 |
@ data-column-types='tt' data-init-sort='0'> |
|
009a243…
|
stephan
|
538 |
@ <thead> |
|
009a243…
|
stephan
|
539 |
@ <tr><th>Suffix<th>Mimetype |
|
009a243…
|
stephan
|
540 |
@ </thead> |
|
009a243…
|
stephan
|
541 |
@ <tbody> |
|
009a243…
|
stephan
|
542 |
blob_set(&list, zCustomList); |
|
009a243…
|
stephan
|
543 |
while( blob_line(&list, &entry)>0 ){ |
|
009a243…
|
stephan
|
544 |
const char *zKey; |
|
009a243…
|
stephan
|
545 |
if( blob_token(&entry, &key)==0 ) continue; |
|
009a243…
|
stephan
|
546 |
if( blob_token(&entry, &val)==0 ) continue; |
|
009a243…
|
stephan
|
547 |
zKey = blob_str(&key); |
|
009a243…
|
stephan
|
548 |
if( zKey[0]=='.' ) zKey++; |
|
009a243…
|
stephan
|
549 |
@ <tr><td>%h(zKey)<td>%h(blob_str(&val))</tr> |
|
009a243…
|
stephan
|
550 |
nCustomEntries++; |
|
009a243…
|
stephan
|
551 |
} |
|
009a243…
|
stephan
|
552 |
fossil_free(zCustomList); |
|
009a243…
|
stephan
|
553 |
if( nCustomEntries==0 ){ |
|
009a243…
|
stephan
|
554 |
/* This can happen if the option is set to an empty/space-only |
|
009a243…
|
stephan
|
555 |
** value. */ |
|
009a243…
|
stephan
|
556 |
@ <tr><td colspan="2"><em>none</em></tr> |
|
009a243…
|
stephan
|
557 |
} |
|
009a243…
|
stephan
|
558 |
@ </tbody></table> |
|
009a243…
|
stephan
|
559 |
} |
|
009a243…
|
stephan
|
560 |
@ <h1>Default built-in mimetypes</h1> |
|
009a243…
|
stephan
|
561 |
if(nCustomEntries>0){ |
|
009a243…
|
stephan
|
562 |
@ <p>Entries starting with an exclamation mark <em><strong>!</strong></em> |
|
009a243…
|
stephan
|
563 |
@ are overwritten by repository-specific settings.</p> |
|
009a243…
|
stephan
|
564 |
} |
|
6b645d6…
|
drh
|
565 |
@ <table class='sortable mimetypetable' border=1 cellpadding=0 \ |
|
6b645d6…
|
drh
|
566 |
@ data-column-types='tt' data-init-sort='1'> |
|
51751b0…
|
drh
|
567 |
@ <thead> |
|
51751b0…
|
drh
|
568 |
@ <tr><th>Suffix<th>Mimetype |
|
51751b0…
|
drh
|
569 |
@ </thead> |
|
51751b0…
|
drh
|
570 |
@ <tbody> |
|
3cb9ba4…
|
andygoth
|
571 |
for(i=0; i<count(aMime); i++){ |
|
009a243…
|
stephan
|
572 |
const char *zFlag = ""; |
|
009a243…
|
stephan
|
573 |
if(nCustomEntries>0 && |
|
009a243…
|
stephan
|
574 |
mimetype_from_name_custom(aMime[i].zSuffix)!=0){ |
|
009a243…
|
stephan
|
575 |
zFlag = "<em><strong>!</strong></em> "; |
|
009a243…
|
stephan
|
576 |
} |
|
009a243…
|
stephan
|
577 |
@ <tr><td>%s(zFlag)%h(aMime[i].zSuffix)<td>%h(aMime[i].zMimetype)</tr> |
|
51751b0…
|
drh
|
578 |
} |
|
51751b0…
|
drh
|
579 |
@ </tbody></table> |
|
6b645d6…
|
drh
|
580 |
style_table_sorter(); |
|
112c713…
|
drh
|
581 |
style_finish_page(); |
|
51751b0…
|
drh
|
582 |
} |
|
ace8016…
|
drh
|
583 |
|
|
ace8016…
|
drh
|
584 |
/* |
|
ace8016…
|
drh
|
585 |
** Check to see if the file in the pContent blob is "embedded HTML". Return |
|
ace8016…
|
drh
|
586 |
** true if it is, and fill pTitle with the document title. |
|
ace8016…
|
drh
|
587 |
** |
|
ace8016…
|
drh
|
588 |
** An "embedded HTML" file is HTML that lacks a header and a footer. The |
|
ace8016…
|
drh
|
589 |
** standard Fossil header is prepended and the standard Fossil footer is |
|
ace8016…
|
drh
|
590 |
** appended. Otherwise, the file is displayed without change. |
|
ace8016…
|
drh
|
591 |
** |
|
ace8016…
|
drh
|
592 |
** Embedded HTML must be contained in a <div class='fossil-doc'> element. |
|
ace8016…
|
drh
|
593 |
** If that <div> also contains a data-title attribute, then the |
|
ace8016…
|
drh
|
594 |
** value of that attribute is extracted into pTitle and becomes the title |
|
ace8016…
|
drh
|
595 |
** of the document. |
|
ace8016…
|
drh
|
596 |
*/ |
|
ace8016…
|
drh
|
597 |
int doc_is_embedded_html(Blob *pContent, Blob *pTitle){ |
|
ace8016…
|
drh
|
598 |
const char *zIn = blob_str(pContent); |
|
ace8016…
|
drh
|
599 |
const char *zAttr; |
|
ace8016…
|
drh
|
600 |
const char *zValue; |
|
ace8016…
|
drh
|
601 |
int nAttr, nValue; |
|
ace8016…
|
drh
|
602 |
int seenClass = 0; |
|
ace8016…
|
drh
|
603 |
int seenTitle = 0; |
|
5260fbf…
|
jan.nijtmans
|
604 |
|
|
ace8016…
|
drh
|
605 |
while( fossil_isspace(zIn[0]) ) zIn++; |
|
ace8016…
|
drh
|
606 |
if( fossil_strnicmp(zIn,"<div",4)!=0 ) return 0; |
|
ace8016…
|
drh
|
607 |
zIn += 4; |
|
ace8016…
|
drh
|
608 |
while( zIn[0] ){ |
|
ace8016…
|
drh
|
609 |
if( fossil_isspace(zIn[0]) ) zIn++; |
|
3d6a4fd…
|
mistachkin
|
610 |
if( zIn[0]=='>' ) break; |
|
ace8016…
|
drh
|
611 |
zAttr = zIn; |
|
ace8016…
|
drh
|
612 |
while( fossil_isalnum(zIn[0]) || zIn[0]=='-' ) zIn++; |
|
ace8016…
|
drh
|
613 |
nAttr = (int)(zIn - zAttr); |
|
ace8016…
|
drh
|
614 |
while( fossil_isspace(zIn[0]) ) zIn++; |
|
ace8016…
|
drh
|
615 |
if( zIn[0]!='=' ) continue; |
|
ace8016…
|
drh
|
616 |
zIn++; |
|
ace8016…
|
drh
|
617 |
while( fossil_isspace(zIn[0]) ) zIn++; |
|
ace8016…
|
drh
|
618 |
if( zIn[0]=='"' || zIn[0]=='\'' ){ |
|
ace8016…
|
drh
|
619 |
char cDelim = zIn[0]; |
|
ace8016…
|
drh
|
620 |
zIn++; |
|
ace8016…
|
drh
|
621 |
zValue = zIn; |
|
ace8016…
|
drh
|
622 |
while( zIn[0] && zIn[0]!=cDelim ) zIn++; |
|
ace8016…
|
drh
|
623 |
if( zIn[0]==0 ) return 0; |
|
ace8016…
|
drh
|
624 |
nValue = (int)(zIn - zValue); |
|
ace8016…
|
drh
|
625 |
zIn++; |
|
ace8016…
|
drh
|
626 |
}else{ |
|
ace8016…
|
drh
|
627 |
zValue = zIn; |
|
ace8016…
|
drh
|
628 |
while( zIn[0]!=0 && zIn[0]!='>' && zIn[0]!='/' |
|
ace8016…
|
drh
|
629 |
&& !fossil_isspace(zIn[0]) ) zIn++; |
|
ace8016…
|
drh
|
630 |
if( zIn[0]==0 ) return 0; |
|
ace8016…
|
drh
|
631 |
nValue = (int)(zIn - zValue); |
|
ace8016…
|
drh
|
632 |
} |
|
ace8016…
|
drh
|
633 |
if( nAttr==5 && fossil_strnicmp(zAttr,"class",5)==0 ){ |
|
ace8016…
|
drh
|
634 |
if( nValue!=10 || fossil_strnicmp(zValue,"fossil-doc",10)!=0 ) return 0; |
|
ace8016…
|
drh
|
635 |
seenClass = 1; |
|
ace8016…
|
drh
|
636 |
if( seenTitle ) return 1; |
|
ace8016…
|
drh
|
637 |
} |
|
ace8016…
|
drh
|
638 |
if( nAttr==10 && fossil_strnicmp(zAttr,"data-title",10)==0 ){ |
|
54e01c6…
|
drh
|
639 |
/* The text argument to data-title="" will have had any characters that |
|
54e01c6…
|
drh
|
640 |
** are special to HTML encoded. We need to decode these before turning |
|
54e01c6…
|
drh
|
641 |
** the text into a title, as the title text will be reencoded later */ |
|
54e01c6…
|
drh
|
642 |
char *zTitle = mprintf("%.*s", nValue, zValue); |
|
54e01c6…
|
drh
|
643 |
int i; |
|
54e01c6…
|
drh
|
644 |
for(i=0; fossil_isspace(zTitle[i]); i++){} |
|
fd59eb1…
|
drh
|
645 |
html_to_plaintext(zTitle+i, pTitle, 0); |
|
54e01c6…
|
drh
|
646 |
fossil_free(zTitle); |
|
ace8016…
|
drh
|
647 |
seenTitle = 1; |
|
ace8016…
|
drh
|
648 |
if( seenClass ) return 1; |
|
ace8016…
|
drh
|
649 |
} |
|
ace8016…
|
drh
|
650 |
} |
|
ace8016…
|
drh
|
651 |
return seenClass; |
|
5260fbf…
|
jan.nijtmans
|
652 |
} |
|
ace8016…
|
drh
|
653 |
|
|
ace8016…
|
drh
|
654 |
/* |
|
c49030f…
|
drh
|
655 |
** Look for a file named zName in the check-in with RID=vid. Load the content |
|
48e1e18…
|
drh
|
656 |
** of that file into pContent and return the RID for the file. Or return 0 |
|
48e1e18…
|
drh
|
657 |
** if the file is not found or could not be loaded. |
|
48e1e18…
|
drh
|
658 |
*/ |
|
48e1e18…
|
drh
|
659 |
int doc_load_content(int vid, const char *zName, Blob *pContent){ |
|
f8363db…
|
drh
|
660 |
int writable; |
|
48e1e18…
|
drh
|
661 |
int rid; /* The RID of the file being loaded */ |
|
f8363db…
|
drh
|
662 |
if( db_is_protected(PROTECT_READONLY) |
|
f8363db…
|
drh
|
663 |
|| !db_is_writeable("repository") |
|
f8363db…
|
drh
|
664 |
){ |
|
f8363db…
|
drh
|
665 |
writable = 0; |
|
f8363db…
|
drh
|
666 |
}else{ |
|
f8363db…
|
drh
|
667 |
writable = 1; |
|
f8363db…
|
drh
|
668 |
} |
|
0397982…
|
drh
|
669 |
if( writable ){ |
|
0397982…
|
drh
|
670 |
db_end_transaction(0); |
|
0397982…
|
drh
|
671 |
db_begin_write(); |
|
0397982…
|
drh
|
672 |
} |
|
b20f6cb…
|
andygoth
|
673 |
if( !db_table_exists("repository", "vcache") || !writable ){ |
|
48e1e18…
|
drh
|
674 |
db_multi_exec( |
|
95edba6…
|
andygoth
|
675 |
"CREATE %s TABLE IF NOT EXISTS vcache(\n" |
|
c49030f…
|
drh
|
676 |
" vid INTEGER, -- check-in ID\n" |
|
48e1e18…
|
drh
|
677 |
" fname TEXT, -- filename\n" |
|
48e1e18…
|
drh
|
678 |
" rid INTEGER, -- artifact ID\n" |
|
48e1e18…
|
drh
|
679 |
" PRIMARY KEY(vid,fname)\n" |
|
b20f6cb…
|
andygoth
|
680 |
") WITHOUT ROWID", writable ? "" : "TEMPORARY" |
|
48e1e18…
|
drh
|
681 |
); |
|
48e1e18…
|
drh
|
682 |
} |
|
48e1e18…
|
drh
|
683 |
if( !db_exists("SELECT 1 FROM vcache WHERE vid=%d", vid) ){ |
|
48e1e18…
|
drh
|
684 |
db_multi_exec( |
|
48e1e18…
|
drh
|
685 |
"DELETE FROM vcache;\n" |
|
48e1e18…
|
drh
|
686 |
"CREATE VIRTUAL TABLE IF NOT EXISTS temp.foci USING files_of_checkin;\n" |
|
48e1e18…
|
drh
|
687 |
"INSERT INTO vcache(vid,fname,rid)" |
|
48e1e18…
|
drh
|
688 |
" SELECT checkinID, filename, blob.rid FROM foci, blob" |
|
48e1e18…
|
drh
|
689 |
" WHERE blob.uuid=foci.uuid" |
|
48e1e18…
|
drh
|
690 |
" AND foci.checkinID=%d;", |
|
48e1e18…
|
drh
|
691 |
vid |
|
48e1e18…
|
drh
|
692 |
); |
|
48e1e18…
|
drh
|
693 |
} |
|
48e1e18…
|
drh
|
694 |
rid = db_int(0, "SELECT rid FROM vcache" |
|
48e1e18…
|
drh
|
695 |
" WHERE vid=%d AND fname=%Q", vid, zName); |
|
48e1e18…
|
drh
|
696 |
if( rid && content_get(rid, pContent)==0 ){ |
|
48e1e18…
|
drh
|
697 |
rid = 0; |
|
48e1e18…
|
drh
|
698 |
} |
|
48e1e18…
|
drh
|
699 |
return rid; |
|
48e1e18…
|
drh
|
700 |
} |
|
48e1e18…
|
drh
|
701 |
|
|
48e1e18…
|
drh
|
702 |
/* |
|
703e62a…
|
drh
|
703 |
** Check to verify that z[i] is contained within HTML markup. |
|
703e62a…
|
drh
|
704 |
** |
|
703e62a…
|
drh
|
705 |
** This works by looking backwards in the string for the most recent |
|
703e62a…
|
drh
|
706 |
** '<' or '>' character. If a '<' is found first, then we assume that |
|
703e62a…
|
drh
|
707 |
** z[i] is within markup. If a '>' is seen or neither character is seen, |
|
703e62a…
|
drh
|
708 |
** then z[i] is not within markup. |
|
703e62a…
|
drh
|
709 |
*/ |
|
703e62a…
|
drh
|
710 |
static int isWithinHtmlMarkup(const char *z, int i){ |
|
703e62a…
|
drh
|
711 |
while( i>=0 && z[i]!='>' && z[i]!='<' ){ i--; } |
|
703e62a…
|
drh
|
712 |
return z[i]=='<'; |
|
703e62a…
|
drh
|
713 |
} |
|
703e62a…
|
drh
|
714 |
|
|
703e62a…
|
drh
|
715 |
/* |
|
703e62a…
|
drh
|
716 |
** Check to see if z[i] is contained within an href='...' of markup. |
|
703e62a…
|
drh
|
717 |
*/ |
|
703e62a…
|
drh
|
718 |
static int isWithinHref(const char *z, int i){ |
|
703e62a…
|
drh
|
719 |
while( i>5 |
|
703e62a…
|
drh
|
720 |
&& !fossil_isspace(z[i]) |
|
703e62a…
|
drh
|
721 |
&& z[i]!='\'' && z[i]!='"' |
|
703e62a…
|
drh
|
722 |
&& z[i]!='>' |
|
703e62a…
|
drh
|
723 |
){ i--; } |
|
703e62a…
|
drh
|
724 |
if( i<=6 ) return 0; |
|
703e62a…
|
drh
|
725 |
if( z[i]!='\'' && z[i]!='\"' ) return 0; |
|
703e62a…
|
drh
|
726 |
if( strncmp(&z[i-5],"href=",5)!=0 ) return 0; |
|
703e62a…
|
drh
|
727 |
if( !fossil_isspace(z[i-6]) ) return 0; |
|
703e62a…
|
drh
|
728 |
return 1; |
|
703e62a…
|
drh
|
729 |
} |
|
703e62a…
|
drh
|
730 |
|
|
703e62a…
|
drh
|
731 |
/* |
|
e57ab29…
|
drh
|
732 |
** Transfer content to the output. During the transfer, when text of |
|
95edba6…
|
andygoth
|
733 |
** the following form is seen: |
|
95edba6…
|
andygoth
|
734 |
** |
|
c865e1a…
|
drh
|
735 |
** href="$ROOT/..." |
|
c865e1a…
|
drh
|
736 |
** action="$ROOT/..." |
|
45427ae…
|
drh
|
737 |
** href=".../doc/$CURRENT/..." |
|
c865e1a…
|
drh
|
738 |
** |
|
275da70…
|
danield
|
739 |
** Convert $ROOT to the root URI of the repository, and $CURRENT to the |
|
c865e1a…
|
drh
|
740 |
** version number of the /doc/ document currently being displayed (if any). |
|
275da70…
|
danield
|
741 |
** Allow ' in place of " and any case for href or action. |
|
e57ab29…
|
drh
|
742 |
** |
|
c865e1a…
|
drh
|
743 |
** Efforts are made to limit this translation to cases where the text is |
|
c865e1a…
|
drh
|
744 |
** fully contained with an HTML markup element. |
|
e57ab29…
|
drh
|
745 |
*/ |
|
5602385…
|
drh
|
746 |
void convert_href_and_output(Blob *pIn){ |
|
e57ab29…
|
drh
|
747 |
int i, base; |
|
e57ab29…
|
drh
|
748 |
int n = blob_size(pIn); |
|
e57ab29…
|
drh
|
749 |
char *z = blob_buffer(pIn); |
|
e57ab29…
|
drh
|
750 |
for(base=0, i=7; i<n; i++){ |
|
c3b5f1d…
|
jan.nijtmans
|
751 |
if( z[i]=='$' |
|
e57ab29…
|
drh
|
752 |
&& strncmp(&z[i],"$ROOT/", 6)==0 |
|
e57ab29…
|
drh
|
753 |
&& (z[i-1]=='\'' || z[i-1]=='"') |
|
e57ab29…
|
drh
|
754 |
&& i-base>=9 |
|
3e183bf…
|
drh
|
755 |
&& ((fossil_strnicmp(&z[i-6],"href=",5)==0 && fossil_isspace(z[i-7])) || |
|
3e183bf…
|
drh
|
756 |
(fossil_strnicmp(&z[i-8],"action=",7)==0 && fossil_isspace(z[i-9])) ) |
|
703e62a…
|
drh
|
757 |
&& isWithinHtmlMarkup(z, i-6) |
|
e57ab29…
|
drh
|
758 |
){ |
|
e57ab29…
|
drh
|
759 |
blob_append(cgi_output_blob(), &z[base], i-base); |
|
e57ab29…
|
drh
|
760 |
blob_appendf(cgi_output_blob(), "%R"); |
|
e57ab29…
|
drh
|
761 |
base = i+5; |
|
703e62a…
|
drh
|
762 |
}else |
|
703e62a…
|
drh
|
763 |
if( z[i]=='$' |
|
45427ae…
|
drh
|
764 |
&& strncmp(&z[i-5],"/doc/$CURRENT/", 11)==0 |
|
703e62a…
|
drh
|
765 |
&& isWithinHref(z,i-5) |
|
703e62a…
|
drh
|
766 |
&& isWithinHtmlMarkup(z, i-5) |
|
703e62a…
|
drh
|
767 |
&& strncmp(g.zPath, "doc/",4)==0 |
|
703e62a…
|
drh
|
768 |
){ |
|
703e62a…
|
drh
|
769 |
int j; |
|
45427ae…
|
drh
|
770 |
for(j=7; g.zPath[j] && g.zPath[j]!='/'; j++){} |
|
703e62a…
|
drh
|
771 |
blob_append(cgi_output_blob(), &z[base], i-base); |
|
703e62a…
|
drh
|
772 |
blob_appendf(cgi_output_blob(), "%.*s", j-4, g.zPath+4); |
|
45427ae…
|
drh
|
773 |
base = i+8; |
|
e57ab29…
|
drh
|
774 |
} |
|
e57ab29…
|
drh
|
775 |
} |
|
e57ab29…
|
drh
|
776 |
blob_append(cgi_output_blob(), &z[base], i-base); |
|
e57ab29…
|
drh
|
777 |
} |
|
ec56c69…
|
drh
|
778 |
|
|
ec56c69…
|
drh
|
779 |
/* |
|
ec56c69…
|
drh
|
780 |
** Render a document as the reply to the HTTP request. The body |
|
ec56c69…
|
drh
|
781 |
** of the document is contained in pBody. The body might be binary. |
|
ec56c69…
|
drh
|
782 |
** The mimetype is in zMimetype. |
|
ec56c69…
|
drh
|
783 |
*/ |
|
ec56c69…
|
drh
|
784 |
void document_render( |
|
ec56c69…
|
drh
|
785 |
Blob *pBody, /* Document content */ |
|
ec56c69…
|
drh
|
786 |
const char *zMime, /* MIME-type */ |
|
ec56c69…
|
drh
|
787 |
const char *zDefaultTitle, /* Default title */ |
|
ec56c69…
|
drh
|
788 |
const char *zFilename /* Name of the file being rendered */ |
|
ec56c69…
|
drh
|
789 |
){ |
|
ec56c69…
|
drh
|
790 |
Blob title; |
|
36a17f3…
|
drh
|
791 |
int isPopup = P("popup")!=0; |
|
ec56c69…
|
drh
|
792 |
blob_init(&title,0,0); |
|
ec56c69…
|
drh
|
793 |
if( fossil_strcmp(zMime, "text/x-fossil-wiki")==0 ){ |
|
37ae94b…
|
drh
|
794 |
Blob tail = BLOB_INITIALIZER; |
|
ec56c69…
|
drh
|
795 |
style_adunit_config(ADUNIT_RIGHT_OK); |
|
ec56c69…
|
drh
|
796 |
if( wiki_find_title(pBody, &title, &tail) ){ |
|
36a17f3…
|
drh
|
797 |
if( !isPopup ) style_header("%s", blob_str(&title)); |
|
ec56c69…
|
drh
|
798 |
wiki_convert(&tail, 0, WIKI_BUTTONS); |
|
ec56c69…
|
drh
|
799 |
}else{ |
|
36a17f3…
|
drh
|
800 |
if( !isPopup ) style_header("%s", zDefaultTitle); |
|
ec56c69…
|
drh
|
801 |
wiki_convert(pBody, 0, WIKI_BUTTONS); |
|
ec56c69…
|
drh
|
802 |
} |
|
36a17f3…
|
drh
|
803 |
if( !isPopup ){ |
|
36a17f3…
|
drh
|
804 |
document_emit_js(); |
|
36a17f3…
|
drh
|
805 |
style_finish_page(); |
|
36a17f3…
|
drh
|
806 |
} |
|
37ae94b…
|
drh
|
807 |
blob_reset(&tail); |
|
ec56c69…
|
drh
|
808 |
}else if( fossil_strcmp(zMime, "text/x-markdown")==0 ){ |
|
ec56c69…
|
drh
|
809 |
Blob tail = BLOB_INITIALIZER; |
|
ec56c69…
|
drh
|
810 |
markdown_to_html(pBody, &title, &tail); |
|
36a17f3…
|
drh
|
811 |
if( !isPopup ){ |
|
36a17f3…
|
drh
|
812 |
if( blob_size(&title)>0 ){ |
|
0b24a45…
|
drh
|
813 |
markdown_dehtmlize_blob(&title); |
|
36a17f3…
|
drh
|
814 |
style_header("%s", blob_str(&title)); |
|
36a17f3…
|
drh
|
815 |
}else{ |
|
36a17f3…
|
drh
|
816 |
style_header("%s", zDefaultTitle); |
|
36a17f3…
|
drh
|
817 |
} |
|
ec56c69…
|
drh
|
818 |
} |
|
ec56c69…
|
drh
|
819 |
convert_href_and_output(&tail); |
|
36a17f3…
|
drh
|
820 |
if( !isPopup ){ |
|
36a17f3…
|
drh
|
821 |
document_emit_js(); |
|
36a17f3…
|
drh
|
822 |
style_finish_page(); |
|
36a17f3…
|
drh
|
823 |
} |
|
37ae94b…
|
drh
|
824 |
blob_reset(&tail); |
|
ec56c69…
|
drh
|
825 |
}else if( fossil_strcmp(zMime, "text/plain")==0 ){ |
|
ec56c69…
|
drh
|
826 |
style_header("%s", zDefaultTitle); |
|
ec56c69…
|
drh
|
827 |
@ <blockquote><pre> |
|
ec56c69…
|
drh
|
828 |
@ %h(blob_str(pBody)) |
|
ec56c69…
|
drh
|
829 |
@ </pre></blockquote> |
|
83f03e9…
|
stephan
|
830 |
document_emit_js(); |
|
112c713…
|
drh
|
831 |
style_finish_page(); |
|
ec56c69…
|
drh
|
832 |
}else if( fossil_strcmp(zMime, "text/html")==0 |
|
ec56c69…
|
drh
|
833 |
&& doc_is_embedded_html(pBody, &title) ){ |
|
ec56c69…
|
drh
|
834 |
if( blob_size(&title)==0 ) blob_append(&title,zFilename,-1); |
|
36a17f3…
|
drh
|
835 |
if( !isPopup ) style_header("%s", blob_str(&title)); |
|
ec56c69…
|
drh
|
836 |
convert_href_and_output(pBody); |
|
36a17f3…
|
drh
|
837 |
if( !isPopup ){ |
|
36a17f3…
|
drh
|
838 |
document_emit_js(); |
|
36a17f3…
|
drh
|
839 |
style_finish_page(); |
|
36a17f3…
|
drh
|
840 |
} |
|
e32214a…
|
drh
|
841 |
}else if( fossil_strcmp(zMime, "text/x-pikchr")==0 ){ |
|
e32214a…
|
drh
|
842 |
style_adunit_config(ADUNIT_RIGHT_OK); |
|
363f01a…
|
drh
|
843 |
if( !isPopup ) style_header("%s", zDefaultTitle); |
|
e32214a…
|
drh
|
844 |
wiki_render_by_mimetype(pBody, zMime); |
|
363f01a…
|
drh
|
845 |
if( !isPopup ) style_finish_page(); |
|
ec56c69…
|
drh
|
846 |
#ifdef FOSSIL_ENABLE_TH1_DOCS |
|
ec56c69…
|
drh
|
847 |
}else if( Th_AreDocsEnabled() && |
|
ec56c69…
|
drh
|
848 |
fossil_strcmp(zMime, "application/x-th1")==0 ){ |
|
ec56c69…
|
drh
|
849 |
int raw = P("raw")!=0; |
|
ec56c69…
|
drh
|
850 |
if( !raw ){ |
|
ec56c69…
|
drh
|
851 |
Blob tail; |
|
ec56c69…
|
drh
|
852 |
blob_zero(&tail); |
|
ec56c69…
|
drh
|
853 |
if( wiki_find_title(pBody, &title, &tail) ){ |
|
ec56c69…
|
drh
|
854 |
style_header("%s", blob_str(&title)); |
|
ec56c69…
|
drh
|
855 |
Th_Render(blob_str(&tail)); |
|
ec56c69…
|
drh
|
856 |
blob_reset(&tail); |
|
ec56c69…
|
drh
|
857 |
}else{ |
|
19bbd2c…
|
drh
|
858 |
style_header("%h", zFilename); |
|
ec56c69…
|
drh
|
859 |
Th_Render(blob_str(pBody)); |
|
ec56c69…
|
drh
|
860 |
} |
|
ec56c69…
|
drh
|
861 |
}else{ |
|
ec56c69…
|
drh
|
862 |
Th_Render(blob_str(pBody)); |
|
ec56c69…
|
drh
|
863 |
} |
|
ec56c69…
|
drh
|
864 |
if( !raw ){ |
|
83f03e9…
|
stephan
|
865 |
document_emit_js(); |
|
112c713…
|
drh
|
866 |
style_finish_page(); |
|
ec56c69…
|
drh
|
867 |
} |
|
ec56c69…
|
drh
|
868 |
#endif |
|
ec56c69…
|
drh
|
869 |
}else{ |
|
14c81d9…
|
drh
|
870 |
fossil_free(style_csp(1)); |
|
ec56c69…
|
drh
|
871 |
cgi_set_content_type(zMime); |
|
ec56c69…
|
drh
|
872 |
cgi_set_content(pBody); |
|
ec56c69…
|
drh
|
873 |
} |
|
ec56c69…
|
drh
|
874 |
} |
|
ec56c69…
|
drh
|
875 |
|
|
27d743e…
|
drh
|
876 |
|
|
27d743e…
|
drh
|
877 |
/* |
|
27d743e…
|
drh
|
878 |
** WEBPAGE: uv |
|
5cf1206…
|
drh
|
879 |
** WEBPAGE: doc |
|
27d743e…
|
drh
|
880 |
** URL: /uv/FILE |
|
cfcd9b8…
|
drh
|
881 |
** URL: /doc/CHECKIN/FILE |
|
cfcd9b8…
|
drh
|
882 |
** |
|
fd9b7bd…
|
drh
|
883 |
** CHECKIN can be either tag or hash prefix or timestamp identifying a |
|
7dd07b2…
|
drh
|
884 |
** particular check-in, or the name of a branch (meaning the most recent |
|
cfcd9b8…
|
drh
|
885 |
** check-in on that branch) or one of various magic words: |
|
cfcd9b8…
|
drh
|
886 |
** |
|
cfcd9b8…
|
drh
|
887 |
** "tip" means the most recent check-in |
|
cfcd9b8…
|
drh
|
888 |
** |
|
cfcd9b8…
|
drh
|
889 |
** "ckout" means the current check-out, if the server is run from |
|
cfcd9b8…
|
drh
|
890 |
** within a check-out, otherwise it is the same as "tip" |
|
cfcd9b8…
|
drh
|
891 |
** |
|
d08bc9e…
|
drh
|
892 |
** "latest" means use the most recent check-in for the document |
|
d08bc9e…
|
drh
|
893 |
** regardless of what branch it occurs on. |
|
d08bc9e…
|
drh
|
894 |
** |
|
cfcd9b8…
|
drh
|
895 |
** FILE is the name of a file to delivered up as a webpage. FILE is relative |
|
cfcd9b8…
|
drh
|
896 |
** to the root of the source tree of the repository. The FILE must |
|
cfcd9b8…
|
drh
|
897 |
** be a part of CHECKIN, except when CHECKIN=="ckout" when FILE is read |
|
b5ab1eb…
|
drh
|
898 |
** directly from disk and need not be a managed file. For /uv, FILE |
|
b5ab1eb…
|
drh
|
899 |
** can also be the hash of the unversioned file. |
|
cfcd9b8…
|
drh
|
900 |
** |
|
cfcd9b8…
|
drh
|
901 |
** The "ckout" CHECKIN is intended for development - to provide a mechanism |
|
cfcd9b8…
|
drh
|
902 |
** for looking at what a file will look like using the /doc webpage after |
|
dc1121f…
|
drh
|
903 |
** it gets checked in. Some commands like "fossil ui", "fossil server", |
|
dc1121f…
|
drh
|
904 |
** and "fossil http" accept an argument "--ckout-alias NAME" when allows |
|
dc1121f…
|
drh
|
905 |
** NAME to be understood as an alias for "ckout". On a site with many |
|
dc1121f…
|
drh
|
906 |
** embedded hyperlinks to /doc/trunk/... one can run with "--ckout-alias trunk" |
|
dc1121f…
|
drh
|
907 |
** to simulate what the pending changes will look like after they are |
|
dc1121f…
|
drh
|
908 |
** checked in. The NAME alias is stored in g.zCkoutAlias. |
|
cfcd9b8…
|
drh
|
909 |
** |
|
cfcd9b8…
|
drh
|
910 |
** The file extension is used to decide how to render the file. |
|
bdfbbdd…
|
drh
|
911 |
** |
|
f4ceace…
|
mistachkin
|
912 |
** If FILE ends in "/" then the names "FILE/index.html", "FILE/index.wiki", |
|
f4ceace…
|
mistachkin
|
913 |
** and "FILE/index.md" are tried in that order. If the binary was compiled |
|
f4ceace…
|
mistachkin
|
914 |
** with TH1 embedded documentation support and the "th1-docs" setting is |
|
f4ceace…
|
mistachkin
|
915 |
** enabled, the name "FILE/index.th1" is also tried. If none of those are |
|
f4ceace…
|
mistachkin
|
916 |
** found, then FILE is completely replaced by "404.md" and tried. If that |
|
f4ceace…
|
mistachkin
|
917 |
** is not found, then a default 404 screen is generated. |
|
e57ab29…
|
drh
|
918 |
** |
|
26eef7f…
|
rberteig
|
919 |
** If the file's mimetype is "text/x-fossil-wiki" or "text/x-markdown" |
|
26eef7f…
|
rberteig
|
920 |
** then headers and footers are added. If the document has mimetype |
|
26eef7f…
|
rberteig
|
921 |
** text/html then headers and footers are usually not added. However, |
|
26eef7f…
|
rberteig
|
922 |
** if a "text/html" document begins with the following div: |
|
e57ab29…
|
drh
|
923 |
** |
|
e57ab29…
|
drh
|
924 |
** <div class='fossil-doc' data-title='TEXT'> |
|
e57ab29…
|
drh
|
925 |
** |
|
e57ab29…
|
drh
|
926 |
** then headers and footers are supplied. The optional data-title field |
|
e57ab29…
|
drh
|
927 |
** specifies the title of the document in that case. |
|
e57ab29…
|
drh
|
928 |
** |
|
e57ab29…
|
drh
|
929 |
** For fossil-doc documents and for markdown documents, text of the |
|
e57ab29…
|
drh
|
930 |
** form: "href='$ROOT/" or "action='$ROOT" has the $ROOT name expanded |
|
e57ab29…
|
drh
|
931 |
** to the top-level of the repository. |
|
5cf1206…
|
drh
|
932 |
*/ |
|
5cf1206…
|
drh
|
933 |
void doc_page(void){ |
|
5aa3785…
|
mistachkin
|
934 |
const char *zName = 0; /* Argument to the /doc page */ |
|
ef10899…
|
drh
|
935 |
const char *zOrigName = "?"; /* Original document name */ |
|
5cf1206…
|
drh
|
936 |
const char *zMime; /* Document MIME type */ |
|
c49030f…
|
drh
|
937 |
char *zCheckin = "tip"; /* The check-in holding the document */ |
|
956d490…
|
andygoth
|
938 |
char *zPathSuffix = ""; /* Text to append to g.zPath */ |
|
c49030f…
|
drh
|
939 |
int vid = 0; /* Artifact of check-in */ |
|
5cf1206…
|
drh
|
940 |
int rid = 0; /* Artifact of file */ |
|
5cf1206…
|
drh
|
941 |
int i; /* Loop counter */ |
|
5cf1206…
|
drh
|
942 |
Blob filebody; /* Content of the documentation file */ |
|
ace8016…
|
drh
|
943 |
Blob title; /* Document title */ |
|
8b4b424…
|
drh
|
944 |
int nMiss = (-1); /* Failed attempts to find the document */ |
|
27d743e…
|
drh
|
945 |
int isUV = g.zPath[0]=='u'; /* True for /uv. False for /doc */ |
|
27d743e…
|
drh
|
946 |
const char *zDfltTitle; |
|
9586ac1…
|
jan.nijtmans
|
947 |
static const char *const azSuffix[] = { |
|
bdfbbdd…
|
drh
|
948 |
"index.html", "index.wiki", "index.md" |
|
f4ceace…
|
mistachkin
|
949 |
#ifdef FOSSIL_ENABLE_TH1_DOCS |
|
f4ceace…
|
mistachkin
|
950 |
, "index.th1" |
|
a6fd491…
|
jan.nijtmans
|
951 |
#endif |
|
bdfbbdd…
|
drh
|
952 |
}; |
|
cfcd9b8…
|
drh
|
953 |
|
|
cfcd9b8…
|
drh
|
954 |
login_check_credentials(); |
|
653dd40…
|
drh
|
955 |
if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
|
112c713…
|
drh
|
956 |
style_set_current_feature("doc"); |
|
ace8016…
|
drh
|
957 |
blob_init(&title, 0, 0); |
|
37ae94b…
|
drh
|
958 |
blob_init(&filebody, 0, 0); |
|
27d743e…
|
drh
|
959 |
zDfltTitle = isUV ? "" : "Documentation"; |
|
48e1e18…
|
drh
|
960 |
db_begin_transaction(); |
|
3cb9ba4…
|
andygoth
|
961 |
while( rid==0 && (++nMiss)<=count(azSuffix) ){ |
|
c99b4e3…
|
drh
|
962 |
zName = P("name"); |
|
27d743e…
|
drh
|
963 |
if( isUV ){ |
|
4a83785…
|
drh
|
964 |
if( zName==0 ) zName = "index.wiki"; |
|
27d743e…
|
drh
|
965 |
i = 0; |
|
bdfbbdd…
|
drh
|
966 |
}else{ |
|
27d743e…
|
drh
|
967 |
if( zName==0 || zName[0]==0 ) zName = "tip/index.wiki"; |
|
27d743e…
|
drh
|
968 |
for(i=0; zName[i] && zName[i]!='/'; i++){} |
|
27d743e…
|
drh
|
969 |
zCheckin = mprintf("%.*s", i, zName); |
|
27d743e…
|
drh
|
970 |
if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){ |
|
27d743e…
|
drh
|
971 |
zCheckin = "tip"; |
|
d08bc9e…
|
drh
|
972 |
}else if( fossil_strcmp(zCheckin,"latest")==0 ){ |
|
d08bc9e…
|
drh
|
973 |
char *zNewCkin = db_text(0, |
|
d08bc9e…
|
drh
|
974 |
"SELECT uuid FROM blob, mlink, event, filename" |
|
d08bc9e…
|
drh
|
975 |
" WHERE filename.name=%Q" |
|
d08bc9e…
|
drh
|
976 |
" AND mlink.fnid=filename.fnid" |
|
d08bc9e…
|
drh
|
977 |
" AND blob.rid=mlink.mid" |
|
d08bc9e…
|
drh
|
978 |
" AND event.objid=mlink.mid" |
|
d08bc9e…
|
drh
|
979 |
" ORDER BY event.mtime DESC LIMIT 1", |
|
d08bc9e…
|
drh
|
980 |
zName + i + 1); |
|
d08bc9e…
|
drh
|
981 |
if( zNewCkin ) zCheckin = zNewCkin; |
|
27d743e…
|
drh
|
982 |
} |
|
27d743e…
|
drh
|
983 |
} |
|
3cb9ba4…
|
andygoth
|
984 |
if( nMiss==count(azSuffix) ){ |
|
27d743e…
|
drh
|
985 |
zName = "404.md"; |
|
ec56c69…
|
drh
|
986 |
zDfltTitle = "Not Found"; |
|
27d743e…
|
drh
|
987 |
}else if( zName[i]==0 ){ |
|
3cb9ba4…
|
andygoth
|
988 |
assert( nMiss>=0 && nMiss<count(azSuffix) ); |
|
27d743e…
|
drh
|
989 |
zName = azSuffix[nMiss]; |
|
27d743e…
|
drh
|
990 |
}else if( !isUV ){ |
|
bdfbbdd…
|
drh
|
991 |
zName += i; |
|
bdfbbdd…
|
drh
|
992 |
} |
|
bdfbbdd…
|
drh
|
993 |
while( zName[0]=='/' ){ zName++; } |
|
27d743e…
|
drh
|
994 |
if( isUV ){ |
|
956d490…
|
andygoth
|
995 |
zPathSuffix = fossil_strdup(zName); |
|
27d743e…
|
drh
|
996 |
}else{ |
|
956d490…
|
andygoth
|
997 |
zPathSuffix = mprintf("%s/%s", zCheckin, zName); |
|
27d743e…
|
drh
|
998 |
} |
|
bdfbbdd…
|
drh
|
999 |
if( nMiss==0 ) zOrigName = zName; |
|
bdfbbdd…
|
drh
|
1000 |
if( !file_is_simple_pathname(zName, 1) ){ |
|
bdfbbdd…
|
drh
|
1001 |
if( sqlite3_strglob("*/", zName)==0 ){ |
|
3cb9ba4…
|
andygoth
|
1002 |
assert( nMiss>=0 && nMiss<count(azSuffix) ); |
|
bdfbbdd…
|
drh
|
1003 |
zName = mprintf("%s%s", zName, azSuffix[nMiss]); |
|
bdfbbdd…
|
drh
|
1004 |
if( !file_is_simple_pathname(zName, 1) ){ |
|
bdfbbdd…
|
drh
|
1005 |
goto doc_not_found; |
|
bdfbbdd…
|
drh
|
1006 |
} |
|
bdfbbdd…
|
drh
|
1007 |
}else{ |
|
bdfbbdd…
|
drh
|
1008 |
goto doc_not_found; |
|
bdfbbdd…
|
drh
|
1009 |
} |
|
bdfbbdd…
|
drh
|
1010 |
} |
|
27d743e…
|
drh
|
1011 |
if( isUV ){ |
|
7383450…
|
drh
|
1012 |
if( db_table_exists("repository","unversioned") ){ |
|
b5ab1eb…
|
drh
|
1013 |
rid = unversioned_content(zName, &filebody); |
|
b5ab1eb…
|
drh
|
1014 |
if( rid==1 ){ |
|
b5ab1eb…
|
drh
|
1015 |
Stmt q; |
|
b5ab1eb…
|
drh
|
1016 |
db_prepare(&q, "SELECT hash, mtime FROM unversioned" |
|
b5ab1eb…
|
drh
|
1017 |
" WHERE name=%Q", zName); |
|
b5ab1eb…
|
drh
|
1018 |
if( db_step(&q)==SQLITE_ROW ){ |
|
b5ab1eb…
|
drh
|
1019 |
etag_check(ETAG_HASH, db_column_text(&q,0)); |
|
b5ab1eb…
|
drh
|
1020 |
etag_last_modified(db_column_int64(&q,1)); |
|
b5ab1eb…
|
drh
|
1021 |
} |
|
b5ab1eb…
|
drh
|
1022 |
db_finalize(&q); |
|
b5ab1eb…
|
drh
|
1023 |
}else if( rid==2 ){ |
|
b5ab1eb…
|
drh
|
1024 |
zName = db_text(zName, |
|
b5ab1eb…
|
drh
|
1025 |
"SELECT name FROM unversioned WHERE hash=%Q", zName); |
|
b5ab1eb…
|
drh
|
1026 |
g.isConst = 1; |
|
b5ab1eb…
|
drh
|
1027 |
} |
|
b5ab1eb…
|
drh
|
1028 |
zDfltTitle = zName; |
|
b5ab1eb…
|
drh
|
1029 |
} |
|
dc1121f…
|
drh
|
1030 |
}else if( fossil_strcmp(zCheckin,"ckout")==0 |
|
dc1121f…
|
drh
|
1031 |
|| fossil_strcmp(zCheckin,g.zCkoutAlias)==0 |
|
dc1121f…
|
drh
|
1032 |
){ |
|
bc36fdc…
|
danield
|
1033 |
/* Read from the local check-out */ |
|
bdfbbdd…
|
drh
|
1034 |
char *zFullpath; |
|
bdfbbdd…
|
drh
|
1035 |
db_must_be_within_tree(); |
|
bdfbbdd…
|
drh
|
1036 |
zFullpath = mprintf("%s/%s", g.zLocalRoot, zName); |
|
1772357…
|
drh
|
1037 |
if( file_isfile(zFullpath, RepoFILE) |
|
1772357…
|
drh
|
1038 |
&& blob_read_from_file(&filebody, zFullpath, RepoFILE)>0 ){ |
|
cfcd9b8…
|
drh
|
1039 |
rid = 1; /* Fake RID just to get the loop to end */ |
|
cfcd9b8…
|
drh
|
1040 |
} |
|
cfcd9b8…
|
drh
|
1041 |
fossil_free(zFullpath); |
|
bdfbbdd…
|
drh
|
1042 |
}else{ |
|
29cb826…
|
drh
|
1043 |
vid = symbolic_name_to_rid(zCheckin, "ci"); |
|
29cb826…
|
drh
|
1044 |
rid = vid>0 ? doc_load_content(vid, zName, &filebody) : 0; |
|
48e1e18…
|
drh
|
1045 |
} |
|
48e1e18…
|
drh
|
1046 |
} |
|
956d490…
|
andygoth
|
1047 |
g.zPath = mprintf("%s/%s", g.zPath, zPathSuffix); |
|
bdfbbdd…
|
drh
|
1048 |
if( rid==0 ) goto doc_not_found; |
|
1c5b51e…
|
drh
|
1049 |
blob_to_utf8_no_bom(&filebody, 0); |
|
1c5b51e…
|
drh
|
1050 |
|
|
1c5b51e…
|
drh
|
1051 |
/* The file is now contained in the filebody blob. Deliver the |
|
20d02ab…
|
jan.nijtmans
|
1052 |
** file to the user |
|
1c5b51e…
|
drh
|
1053 |
*/ |
|
cfcd9b8…
|
drh
|
1054 |
zMime = nMiss==0 ? P("mimetype") : 0; |
|
f969b6c…
|
drh
|
1055 |
if( zMime==0 ){ |
|
f969b6c…
|
drh
|
1056 |
zMime = mimetype_from_name(zName); |
|
f969b6c…
|
drh
|
1057 |
} |
|
2116238…
|
drh
|
1058 |
Th_StoreUnsafe("doc_name", zName); |
|
27d743e…
|
drh
|
1059 |
if( vid ){ |
|
27d743e…
|
drh
|
1060 |
Th_Store("doc_version", db_text(0, "SELECT '[' || substr(uuid,1,10) || ']'" |
|
27d743e…
|
drh
|
1061 |
" FROM blob WHERE rid=%d", vid)); |
|
27d743e…
|
drh
|
1062 |
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event" |
|
27d743e…
|
drh
|
1063 |
" WHERE objid=%d AND type='ci'", vid)); |
|
27d743e…
|
drh
|
1064 |
} |
|
57f1e87…
|
drh
|
1065 |
cgi_check_for_malice(); |
|
ec56c69…
|
drh
|
1066 |
document_render(&filebody, zMime, zDfltTitle, zName); |
|
3cb9ba4…
|
andygoth
|
1067 |
if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found"); |
|
27d743e…
|
drh
|
1068 |
db_end_transaction(0); |
|
37ae94b…
|
drh
|
1069 |
blob_reset(&title); |
|
37ae94b…
|
drh
|
1070 |
blob_reset(&filebody); |
|
20d02ab…
|
jan.nijtmans
|
1071 |
return; |
|
20d02ab…
|
jan.nijtmans
|
1072 |
|
|
20d02ab…
|
jan.nijtmans
|
1073 |
/* Jump here when unable to locate the document */ |
|
cfcd9b8…
|
drh
|
1074 |
doc_not_found: |
|
20d02ab…
|
jan.nijtmans
|
1075 |
db_end_transaction(0); |
|
2537956…
|
drh
|
1076 |
if( isUV && P("name")==0 ){ |
|
7d12ba5…
|
drh
|
1077 |
uvlist_page(); |
|
0cd96ed…
|
drh
|
1078 |
return; |
|
2537956…
|
drh
|
1079 |
} |
|
cfcd9b8…
|
drh
|
1080 |
cgi_set_status(404, "Not Found"); |
|
cfcd9b8…
|
drh
|
1081 |
style_header("Not Found"); |
|
cfcd9b8…
|
drh
|
1082 |
@ <p>Document %h(zOrigName) not found |
|
cfcd9b8…
|
drh
|
1083 |
if( fossil_strcmp(zCheckin,"ckout")!=0 ){ |
|
cfcd9b8…
|
drh
|
1084 |
@ in %z(href("%R/tree?ci=%T",zCheckin))%h(zCheckin)</a> |
|
cfcd9b8…
|
drh
|
1085 |
} |
|
112c713…
|
drh
|
1086 |
style_finish_page(); |
|
37ae94b…
|
drh
|
1087 |
blob_reset(&title); |
|
37ae94b…
|
drh
|
1088 |
blob_reset(&filebody); |
|
20d02ab…
|
jan.nijtmans
|
1089 |
return; |
|
4348111…
|
drh
|
1090 |
} |
|
4348111…
|
drh
|
1091 |
|
|
4348111…
|
drh
|
1092 |
/* |
|
4348111…
|
drh
|
1093 |
** The default logo. |
|
4348111…
|
drh
|
1094 |
*/ |
|
4348111…
|
drh
|
1095 |
static const unsigned char aLogo[] = { |
|
20d02ab…
|
jan.nijtmans
|
1096 |
71, 73, 70, 56, 55, 97, 62, 0, 71, 0, 244, 0, 0, 85, |
|
20d02ab…
|
jan.nijtmans
|
1097 |
129, 149, 95, 136, 155, 99, 139, 157, 106, 144, 162, 113, 150, 166, |
|
20d02ab…
|
jan.nijtmans
|
1098 |
116, 152, 168, 127, 160, 175, 138, 168, 182, 148, 176, 188, 159, 184, |
|
20d02ab…
|
jan.nijtmans
|
1099 |
195, 170, 192, 202, 180, 199, 208, 184, 202, 210, 191, 207, 215, 201, |
|
20d02ab…
|
jan.nijtmans
|
1100 |
215, 221, 212, 223, 228, 223, 231, 235, 226, 227, 226, 226, 234, 237, |
|
20d02ab…
|
jan.nijtmans
|
1101 |
233, 239, 241, 240, 244, 246, 244, 247, 248, 255, 255, 255, 0, 0, |
|
20d02ab…
|
jan.nijtmans
|
1102 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
|
20d02ab…
|
jan.nijtmans
|
1103 |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, 0, 0, |
|
20d02ab…
|
jan.nijtmans
|
1104 |
0, 0, 62, 0, 71, 0, 0, 5, 255, 96, 100, 141, 100, 105, |
|
20d02ab…
|
jan.nijtmans
|
1105 |
158, 168, 37, 41, 132, 192, 164, 112, 44, 207, 102, 99, 0, 56, |
|
20d02ab…
|
jan.nijtmans
|
1106 |
16, 84, 116, 239, 199, 141, 65, 110, 232, 248, 25, 141, 193, 161, |
|
20d02ab…
|
jan.nijtmans
|
1107 |
82, 113, 108, 202, 32, 55, 229, 210, 73, 61, 41, 164, 88, 102, |
|
20d02ab…
|
jan.nijtmans
|
1108 |
181, 10, 41, 96, 179, 91, 106, 35, 240, 5, 135, 143, 137, 242, |
|
20d02ab…
|
jan.nijtmans
|
1109 |
87, 123, 246, 33, 190, 81, 108, 163, 237, 198, 14, 30, 113, 233, |
|
20d02ab…
|
jan.nijtmans
|
1110 |
131, 78, 115, 72, 11, 115, 87, 101, 19, 124, 51, 66, 74, 8, |
|
20d02ab…
|
jan.nijtmans
|
1111 |
19, 16, 67, 100, 74, 133, 50, 15, 101, 135, 56, 11, 74, 6, |
|
20d02ab…
|
jan.nijtmans
|
1112 |
143, 49, 126, 106, 56, 8, 145, 67, 9, 152, 48, 139, 155, 5, |
|
20d02ab…
|
jan.nijtmans
|
1113 |
22, 13, 74, 115, 161, 41, 147, 101, 13, 130, 57, 132, 170, 40, |
|
20d02ab…
|
jan.nijtmans
|
1114 |
167, 155, 0, 94, 57, 3, 178, 48, 183, 181, 57, 160, 186, 40, |
|
20d02ab…
|
jan.nijtmans
|
1115 |
19, 141, 189, 0, 69, 192, 40, 16, 195, 155, 185, 199, 41, 201, |
|
20d02ab…
|
jan.nijtmans
|
1116 |
189, 191, 205, 193, 188, 131, 210, 49, 175, 88, 209, 214, 38, 19, |
|
20d02ab…
|
jan.nijtmans
|
1117 |
3, 11, 19, 111, 127, 60, 219, 39, 55, 204, 19, 11, 6, 100, |
|
20d02ab…
|
jan.nijtmans
|
1118 |
5, 10, 227, 228, 37, 163, 0, 239, 117, 56, 238, 243, 49, 195, |
|
20d02ab…
|
jan.nijtmans
|
1119 |
177, 247, 48, 158, 56, 251, 50, 216, 254, 197, 56, 128, 107, 158, |
|
20d02ab…
|
jan.nijtmans
|
1120 |
2, 125, 171, 114, 92, 218, 246, 96, 66, 3, 4, 50, 134, 176, |
|
20d02ab…
|
jan.nijtmans
|
1121 |
145, 6, 97, 64, 144, 24, 19, 136, 108, 91, 177, 160, 0, 194, |
|
20d02ab…
|
jan.nijtmans
|
1122 |
19, 253, 0, 216, 107, 214, 224, 192, 129, 5, 16, 83, 255, 244, |
|
20d02ab…
|
jan.nijtmans
|
1123 |
43, 213, 195, 24, 159, 27, 169, 64, 230, 88, 208, 227, 129, 182, |
|
20d02ab…
|
jan.nijtmans
|
1124 |
54, 4, 89, 158, 24, 181, 163, 199, 1, 155, 52, 233, 8, 130, |
|
20d02ab…
|
jan.nijtmans
|
1125 |
176, 83, 24, 128, 137, 50, 18, 32, 48, 48, 114, 11, 173, 137, |
|
20d02ab…
|
jan.nijtmans
|
1126 |
19, 110, 4, 64, 105, 1, 194, 30, 140, 68, 15, 24, 24, 224, |
|
20d02ab…
|
jan.nijtmans
|
1127 |
50, 76, 70, 0, 11, 171, 54, 26, 160, 181, 194, 149, 148, 40, |
|
20d02ab…
|
jan.nijtmans
|
1128 |
174, 148, 122, 64, 180, 208, 161, 17, 207, 112, 164, 1, 128, 96, |
|
20d02ab…
|
jan.nijtmans
|
1129 |
148, 78, 18, 21, 194, 33, 229, 51, 247, 65, 133, 97, 5, 250, |
|
20d02ab…
|
jan.nijtmans
|
1130 |
69, 229, 100, 34, 220, 128, 166, 116, 190, 62, 8, 167, 195, 170, |
|
20d02ab…
|
jan.nijtmans
|
1131 |
47, 163, 0, 130, 90, 152, 11, 160, 173, 170, 27, 154, 26, 91, |
|
20d02ab…
|
jan.nijtmans
|
1132 |
232, 151, 171, 18, 14, 162, 253, 98, 170, 18, 70, 171, 64, 219, |
|
20d02ab…
|
jan.nijtmans
|
1133 |
10, 67, 136, 134, 187, 116, 75, 180, 46, 179, 174, 135, 4, 189, |
|
20d02ab…
|
jan.nijtmans
|
1134 |
229, 231, 78, 40, 10, 62, 226, 164, 172, 64, 240, 167, 170, 10, |
|
20d02ab…
|
jan.nijtmans
|
1135 |
18, 124, 188, 10, 107, 65, 193, 94, 11, 93, 171, 28, 248, 17, |
|
20d02ab…
|
jan.nijtmans
|
1136 |
239, 46, 140, 78, 97, 34, 25, 153, 36, 99, 65, 130, 7, 203, |
|
20d02ab…
|
jan.nijtmans
|
1137 |
183, 168, 51, 34, 136, 25, 140, 10, 6, 16, 28, 255, 145, 241, |
|
20d02ab…
|
jan.nijtmans
|
1138 |
230, 140, 10, 66, 178, 167, 112, 48, 192, 128, 129, 9, 31, 141, |
|
20d02ab…
|
jan.nijtmans
|
1139 |
84, 138, 63, 163, 162, 2, 203, 206, 240, 56, 55, 98, 192, 188, |
|
20d02ab…
|
jan.nijtmans
|
1140 |
15, 185, 50, 160, 6, 0, 125, 62, 33, 214, 195, 33, 5, 24, |
|
20d02ab…
|
jan.nijtmans
|
1141 |
184, 25, 231, 14, 201, 245, 144, 23, 126, 104, 228, 0, 145, 2, |
|
20d02ab…
|
jan.nijtmans
|
1142 |
13, 140, 244, 212, 17, 21, 20, 176, 159, 17, 95, 225, 160, 128, |
|
20d02ab…
|
jan.nijtmans
|
1143 |
16, 1, 32, 224, 142, 32, 227, 125, 87, 64, 0, 16, 54, 129, |
|
20d02ab…
|
jan.nijtmans
|
1144 |
205, 2, 141, 76, 53, 130, 103, 37, 166, 64, 144, 107, 78, 196, |
|
20d02ab…
|
jan.nijtmans
|
1145 |
5, 192, 0, 54, 50, 229, 9, 141, 49, 84, 194, 35, 12, 196, |
|
20d02ab…
|
jan.nijtmans
|
1146 |
153, 48, 192, 137, 57, 84, 24, 7, 87, 159, 249, 240, 215, 143, |
|
20d02ab…
|
jan.nijtmans
|
1147 |
105, 241, 118, 149, 9, 139, 4, 64, 203, 141, 35, 140, 129, 131, |
|
20d02ab…
|
jan.nijtmans
|
1148 |
16, 222, 125, 231, 128, 2, 238, 17, 152, 66, 3, 5, 56, 224, |
|
20d02ab…
|
jan.nijtmans
|
1149 |
159, 103, 16, 76, 25, 75, 5, 11, 164, 215, 96, 9, 14, 16, |
|
20d02ab…
|
jan.nijtmans
|
1150 |
36, 225, 15, 11, 40, 144, 192, 156, 41, 10, 178, 199, 3, 66, |
|
20d02ab…
|
jan.nijtmans
|
1151 |
64, 80, 193, 3, 124, 90, 48, 129, 129, 102, 177, 18, 192, 154, |
|
20d02ab…
|
jan.nijtmans
|
1152 |
49, 84, 240, 208, 92, 22, 149, 96, 39, 9, 31, 74, 17, 94, |
|
20d02ab…
|
jan.nijtmans
|
1153 |
3, 8, 177, 199, 72, 59, 85, 76, 25, 216, 8, 139, 194, 197, |
|
20d02ab…
|
jan.nijtmans
|
1154 |
138, 163, 69, 96, 115, 0, 147, 72, 72, 84, 28, 14, 79, 86, |
|
20d02ab…
|
jan.nijtmans
|
1155 |
233, 230, 23, 113, 26, 160, 128, 3, 10, 58, 129, 103, 14, 159, |
|
20d02ab…
|
jan.nijtmans
|
1156 |
214, 163, 146, 117, 238, 213, 154, 128, 151, 109, 84, 64, 217, 13, |
|
20d02ab…
|
jan.nijtmans
|
1157 |
27, 10, 228, 39, 2, 235, 164, 168, 74, 8, 0, 59, |
|
4348111…
|
drh
|
1158 |
}; |
|
4348111…
|
drh
|
1159 |
|
|
4348111…
|
drh
|
1160 |
/* |
|
4348111…
|
drh
|
1161 |
** WEBPAGE: logo |
|
4348111…
|
drh
|
1162 |
** |
|
4348111…
|
drh
|
1163 |
** Return the logo image. This image is available to anybody who can see |
|
4348111…
|
drh
|
1164 |
** the login page. It is designed for use in the upper left-hand corner |
|
4348111…
|
drh
|
1165 |
** of the header. |
|
4348111…
|
drh
|
1166 |
*/ |
|
4348111…
|
drh
|
1167 |
void logo_page(void){ |
|
4348111…
|
drh
|
1168 |
Blob logo; |
|
4348111…
|
drh
|
1169 |
char *zMime; |
|
4348111…
|
drh
|
1170 |
|
|
7383450…
|
drh
|
1171 |
etag_check(ETAG_CONFIG, 0); |
|
4348111…
|
drh
|
1172 |
zMime = db_get("logo-mimetype", "image/gif"); |
|
4348111…
|
drh
|
1173 |
blob_zero(&logo); |
|
4348111…
|
drh
|
1174 |
db_blob(&logo, "SELECT value FROM config WHERE name='logo-image'"); |
|
4348111…
|
drh
|
1175 |
if( blob_size(&logo)==0 ){ |
|
4348111…
|
drh
|
1176 |
blob_init(&logo, (char*)aLogo, sizeof(aLogo)); |
|
4348111…
|
drh
|
1177 |
} |
|
4348111…
|
drh
|
1178 |
cgi_set_content_type(zMime); |
|
4348111…
|
drh
|
1179 |
cgi_set_content(&logo); |
|
6239845…
|
drh
|
1180 |
} |
|
6239845…
|
drh
|
1181 |
|
|
6239845…
|
drh
|
1182 |
/* |
|
6239845…
|
drh
|
1183 |
** The default background image: a 16x16 white GIF |
|
6239845…
|
drh
|
1184 |
*/ |
|
6239845…
|
drh
|
1185 |
static const unsigned char aBackground[] = { |
|
6239845…
|
drh
|
1186 |
71, 73, 70, 56, 57, 97, 16, 0, 16, 0, |
|
6239845…
|
drh
|
1187 |
240, 0, 0, 255, 255, 255, 0, 0, 0, 33, |
|
6239845…
|
drh
|
1188 |
254, 4, 119, 105, 115, 104, 0, 44, 0, 0, |
|
6239845…
|
drh
|
1189 |
0, 0, 16, 0, 16, 0, 0, 2, 14, 132, |
|
6239845…
|
drh
|
1190 |
143, 169, 203, 237, 15, 163, 156, 180, 218, 139, |
|
6239845…
|
drh
|
1191 |
179, 62, 5, 0, 59, |
|
6239845…
|
drh
|
1192 |
}; |
|
6239845…
|
drh
|
1193 |
|
|
6239845…
|
drh
|
1194 |
|
|
6239845…
|
drh
|
1195 |
/* |
|
6239845…
|
drh
|
1196 |
** WEBPAGE: background |
|
6239845…
|
drh
|
1197 |
** |
|
7ab0328…
|
drh
|
1198 |
** Return the background image. If no background image is defined, a |
|
7ab0328…
|
drh
|
1199 |
** built-in 16x16 pixel white GIF is returned. |
|
6239845…
|
drh
|
1200 |
*/ |
|
6239845…
|
drh
|
1201 |
void background_page(void){ |
|
6239845…
|
drh
|
1202 |
Blob bgimg; |
|
6239845…
|
drh
|
1203 |
char *zMime; |
|
6239845…
|
drh
|
1204 |
|
|
7383450…
|
drh
|
1205 |
etag_check(ETAG_CONFIG, 0); |
|
6239845…
|
drh
|
1206 |
zMime = db_get("background-mimetype", "image/gif"); |
|
6239845…
|
drh
|
1207 |
blob_zero(&bgimg); |
|
6239845…
|
drh
|
1208 |
db_blob(&bgimg, "SELECT value FROM config WHERE name='background-image'"); |
|
6239845…
|
drh
|
1209 |
if( blob_size(&bgimg)==0 ){ |
|
6239845…
|
drh
|
1210 |
blob_init(&bgimg, (char*)aBackground, sizeof(aBackground)); |
|
6239845…
|
drh
|
1211 |
} |
|
6239845…
|
drh
|
1212 |
cgi_set_content_type(zMime); |
|
6239845…
|
drh
|
1213 |
cgi_set_content(&bgimg); |
|
15f0dbd…
|
drh
|
1214 |
} |
|
15f0dbd…
|
drh
|
1215 |
|
|
7383450…
|
drh
|
1216 |
|
|
7383450…
|
drh
|
1217 |
/* |
|
81b3ce3…
|
drh
|
1218 |
** WEBPAGE: favicon.ico |
|
81b3ce3…
|
drh
|
1219 |
** |
|
37262b8…
|
mistachkin
|
1220 |
** Return the configured "favicon.ico" image. If no "favicon.ico" image |
|
37262b8…
|
mistachkin
|
1221 |
** is defined, the returned image is for the Fossil lizard icon. |
|
81b3ce3…
|
drh
|
1222 |
** |
|
37262b8…
|
mistachkin
|
1223 |
** The intended use case here is to supply an icon for the "fossil ui" |
|
81b3ce3…
|
drh
|
1224 |
** command. For a permanent website, the recommended process is for |
|
37262b8…
|
mistachkin
|
1225 |
** the admin to set up a project-specific icon and reference that icon |
|
37262b8…
|
mistachkin
|
1226 |
** in the HTML header using a line like: |
|
81b3ce3…
|
drh
|
1227 |
** |
|
81b3ce3…
|
drh
|
1228 |
** <link rel="icon" href="URL-FOR-YOUR-ICON" type="MIMETYPE"/> |
|
275da70…
|
danield
|
1229 |
** |
|
81b3ce3…
|
drh
|
1230 |
*/ |
|
81b3ce3…
|
drh
|
1231 |
void favicon_page(void){ |
|
37262b8…
|
mistachkin
|
1232 |
Blob icon; |
|
37262b8…
|
mistachkin
|
1233 |
char *zMime; |
|
81b3ce3…
|
drh
|
1234 |
|
|
81b3ce3…
|
drh
|
1235 |
etag_check(ETAG_CONFIG, 0); |
|
37262b8…
|
mistachkin
|
1236 |
zMime = db_get("icon-mimetype", "image/gif"); |
|
37262b8…
|
mistachkin
|
1237 |
blob_zero(&icon); |
|
37262b8…
|
mistachkin
|
1238 |
db_blob(&icon, "SELECT value FROM config WHERE name='icon-image'"); |
|
37262b8…
|
mistachkin
|
1239 |
if( blob_size(&icon)==0 ){ |
|
37262b8…
|
mistachkin
|
1240 |
blob_init(&icon, (char*)aLogo, sizeof(aLogo)); |
|
37262b8…
|
mistachkin
|
1241 |
} |
|
37262b8…
|
mistachkin
|
1242 |
cgi_set_content_type(zMime); |
|
37262b8…
|
mistachkin
|
1243 |
cgi_set_content(&icon); |
|
81b3ce3…
|
drh
|
1244 |
} |
|
81b3ce3…
|
drh
|
1245 |
|
|
81b3ce3…
|
drh
|
1246 |
/* |
|
7ab0328…
|
drh
|
1247 |
** WEBPAGE: docsrch |
|
7ab0328…
|
drh
|
1248 |
** |
|
7ab0328…
|
drh
|
1249 |
** Search for documents that match a user-supplied full-text search pattern. |
|
7ab0328…
|
drh
|
1250 |
** If no pattern is specified (by the s= query parameter) then the user |
|
7ab0328…
|
drh
|
1251 |
** is prompted to enter a search string. |
|
7ab0328…
|
drh
|
1252 |
** |
|
7ab0328…
|
drh
|
1253 |
** Query parameters: |
|
15f0dbd…
|
drh
|
1254 |
** |
|
7ab0328…
|
drh
|
1255 |
** s=PATTERN Search for PATTERN |
|
15f0dbd…
|
drh
|
1256 |
*/ |
|
15f0dbd…
|
drh
|
1257 |
void doc_search_page(void){ |
|
809c010…
|
stephan
|
1258 |
const int isSearch = P("s")!=0; |
|
15f0dbd…
|
drh
|
1259 |
login_check_credentials(); |
|
809c010…
|
stephan
|
1260 |
style_header("Document Search%s", isSearch ? " Results" : ""); |
|
57f1e87…
|
drh
|
1261 |
cgi_check_for_malice(); |
|
c0c0bae…
|
drh
|
1262 |
search_screen(SRCH_DOC, 0); |
|
112c713…
|
drh
|
1263 |
style_finish_page(); |
|
5cf1206…
|
drh
|
1264 |
} |