1 /*
2  * Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
3  *
4  * This file is part of NetSurf, http://www.netsurf-browser.org/
5  *
6  * NetSurf is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; version 2 of the License.
9  *
10  * NetSurf is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /** \file
20  * Generate HTML content for displaying directory listings (implementation).
21  */
22 
23 #include <stdbool.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 
28 #include "utils/nsurl.h"
29 #include "utils/messages.h"
30 #include "utils/nscolour.h"
31 
32 #include "netsurf/types.h"
33 #include "netsurf/plot_style.h"
34 
35 #include "content/dirlist.h"
36 #include "desktop/system_colour.h"
37 
38 static int dirlist_filesize_calculate(unsigned long *bytesize);
39 static int dirlist_filesize_value(unsigned long bytesize);
40 static char* dirlist_filesize_unit(unsigned long bytesize);
41 
42 
43 /**
44  * Generates the top part of an HTML directory listing page
45  *
46  * \return  Top of directory listing HTML
47  *
48  * This is part of a series of functions.  To generate a complete page,
49  * call the following functions in order:
50  *
51  *     dirlist_generate_top()
52  *     dirlist_generate_hide_columns()  -- optional
53  *     dirlist_generate_title()
54  *     dirlist_generate_parent_link()   -- optional
55  *     dirlist_generate_headings()
56  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
57  *     dirlist_generate_bottom()
58  */
59 
dirlist_generate_top(char * buffer,int buffer_length)60 bool dirlist_generate_top(char *buffer, int buffer_length)
61 {
62 	int error = snprintf(buffer, buffer_length,
63 		"<html>\n"
64 		"<head>\n"
65 		"<link rel=\"stylesheet\" title=\"Standard\" "
66 			"type=\"text/css\" href=\"resource:internal.css\">\n"
67 		"<style>\n");
68 	if (error < 0 || error >= buffer_length)
69 		/* Error or buffer too small */
70 		return false;
71 	else
72 		/* OK */
73 		return true;
74 
75 }
76 
77 
78 /**
79  * Generates the part of an HTML directory listing page that can suppress
80  * particular columns
81  *
82  * \param  flags	  flags for which cols to suppress. 0 to suppress none
83  * \param  buffer	  buffer to fill with generated HTML
84  * \param  buffer_length  maximum size of buffer
85  * \return  true iff buffer filled without error
86  *
87  * This is part of a series of functions.  To generate a complete page,
88  * call the following functions in order:
89  *
90  *     dirlist_generate_top()
91  *     dirlist_generate_hide_columns()  -- optional
92  *     dirlist_generate_title()
93  *     dirlist_generate_parent_link()   -- optional
94  *     dirlist_generate_headings()
95  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
96  *     dirlist_generate_bottom()
97  */
98 
dirlist_generate_hide_columns(int flags,char * buffer,int buffer_length)99 bool dirlist_generate_hide_columns(int flags, char *buffer, int buffer_length)
100 {
101 	int error = snprintf(buffer, buffer_length,
102 			"%s\n%s\n%s\n%s\n%s\n",
103 			(flags & DIRLIST_NO_NAME_COLUMN) ?
104 					"span.name { display: none; }\n" : "",
105 			(flags & DIRLIST_NO_TYPE_COLUMN) ?
106 					"span.type { display: none; }\n" : "",
107 			(flags & DIRLIST_NO_SIZE_COLUMN) ?
108 					"span.size { display: none; }\n" : "",
109 			(flags & DIRLIST_NO_DATE_COLUMN) ?
110 					"span.date { display: none; }\n" : "",
111 			(flags & DIRLIST_NO_TIME_COLUMN) ?
112 					"span.time { display: none; }\n" : "");
113 	if (error < 0 || error >= buffer_length)
114 		/* Error or buffer too small */
115 		return false;
116 	else
117 		/* OK */
118 		return true;
119 }
120 
121 
122 /**
123  * Generates the part of an HTML directory listing page that contains the title
124  *
125  * \param  title	  title to use
126  * \param  buffer	  buffer to fill with generated HTML
127  * \param  buffer_length  maximum size of buffer
128  * \return  true iff buffer filled without error
129  *
130  * This is part of a series of functions.  To generate a complete page,
131  * call the following functions in order:
132  *
133  *     dirlist_generate_top()
134  *     dirlist_generate_hide_columns()  -- optional
135  *     dirlist_generate_title()
136  *     dirlist_generate_parent_link()   -- optional
137  *     dirlist_generate_headings()
138  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
139  *     dirlist_generate_bottom()
140  */
141 
dirlist_generate_title(const char * title,char * buffer,int buffer_length)142 bool dirlist_generate_title(const char *title, char *buffer, int buffer_length)
143 {
144 	const char *stylesheet;
145 	nserror err;
146 	int error;
147 
148 	if (title == NULL)
149 		title = "";
150 
151 	err = nscolour_get_stylesheet(&stylesheet);
152 	if (err != NSERROR_OK) {
153 		return false;
154 	}
155 
156 	error = snprintf(buffer, buffer_length,
157 			"</style>\n"
158 			"<title>%s</title>\n"
159 			"<style>\n"
160 			"html {\n"
161 			"\tbackground-color: #%06x;\n"
162 			"}\n"
163 			"%s"
164 			"</style>\n"
165 			"</head>\n"
166 			"<body id=\"dirlist\" class=\"ns-even-bg ns-even-fg ns-border\">\n"
167 			"<h1 class=\"ns-border\">%s</h1>\n",
168 			title,
169 			colour_rb_swap(nscolours[NSCOLOUR_WIN_ODD_BG]),
170 			stylesheet, title);
171 	if (error < 0 || error >= buffer_length)
172 		/* Error or buffer too small */
173 		return false;
174 	else
175 		/* OK */
176 		return true;
177 }
178 
179 
180 /**
181  * Generates the part of an HTML directory listing page that links to the parent
182  * directory
183  *
184  * \param  parent	  url of parent directory
185  * \param  buffer	  buffer to fill with generated HTML
186  * \param  buffer_length  maximum size of buffer
187  * \return  true iff buffer filled without error
188  *
189  * This is part of a series of functions.  To generate a complete page,
190  * call the following functions in order:
191  *
192  *     dirlist_generate_top()
193  *     dirlist_generate_hide_columns()  -- optional
194  *     dirlist_generate_title()
195  *     dirlist_generate_parent_link()   -- optional
196  *     dirlist_generate_headings()
197  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
198  *     dirlist_generate_bottom()
199  */
200 
dirlist_generate_parent_link(const char * parent,char * buffer,int buffer_length)201 bool dirlist_generate_parent_link(const char *parent, char *buffer,
202 		int buffer_length)
203 {
204 	int error = snprintf(buffer, buffer_length,
205 			"<p><a href=\"%s\">%s</a></p>",
206 			parent, messages_get("FileParent"));
207 	if (error < 0 || error >= buffer_length)
208 		/* Error or buffer too small */
209 		return false;
210 	else
211 		/* OK */
212 		return true;
213 }
214 
215 
216 /**
217  * Generates the part of an HTML directory listing page that displays the column
218  * headings
219  *
220  * \param  buffer	  buffer to fill with generated HTML
221  * \param  buffer_length  maximum size of buffer
222  * \return  true iff buffer filled without error
223  *
224  * This is part of a series of functions.  To generate a complete page,
225  * call the following functions in order:
226  *
227  *     dirlist_generate_top()
228  *     dirlist_generate_hide_columns()  -- optional
229  *     dirlist_generate_title()
230  *     dirlist_generate_parent_link()   -- optional
231  *     dirlist_generate_headings()
232  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
233  *     dirlist_generate_bottom()
234  */
235 
dirlist_generate_headings(char * buffer,int buffer_length)236 bool dirlist_generate_headings(char *buffer, int buffer_length)
237 {
238 	int error = snprintf(buffer, buffer_length,
239 			"<div>\n"
240 			"<strong>\n"
241 			"\t<span class=\"name\">%s</span>\n"
242 			"\t<span class=\"type\">%s</span>\n"
243 			"\t<span class=\"size\">%s</span>"
244 			"<span class=\"size\"></span>\n"
245 			"\t<span class=\"date\">%s</span>\n"
246 			"\t<span class=\"time\">%s</span>\n"
247 			"</strong>\n",
248 			messages_get("FileName"), messages_get("FileType"),
249 			messages_get("FileSize"), messages_get("FileDate"),
250 			messages_get("FileTime"));
251 	if (error < 0 || error >= buffer_length)
252 		/* Error or buffer too small */
253 		return false;
254 	else
255 		/* OK */
256 		return true;
257 }
258 
259 
260 /**
261  * Generates the part of an HTML directory listing page that displays a row
262  * in the directory contents table
263  *
264  * \param  even		  evenness of row number, for alternate row colouring
265  * \param  directory	  whether this row is for a directory (or a file)
266  * \param  url		  url for row entry
267  * \param  name		  name of row entry
268  * \param  mimetype	  MIME type of row entry
269  * \param  size		  size of row entry.  If negative, size is left blank
270  * \param  date		  date row entry was last modified
271  * \param  time		  time row entry was last modified
272  * \param  buffer	  buffer to fill with generated HTML
273  * \param  buffer_length  maximum size of buffer
274  * \return  true iff buffer filled without error
275  *
276  * This is part of a series of functions.  To generate a complete page,
277  * call the following functions in order:
278  *
279  *     dirlist_generate_top()
280  *     dirlist_generate_hide_columns()  -- optional
281  *     dirlist_generate_title()
282  *     dirlist_generate_parent_link()   -- optional
283  *     dirlist_generate_headings()
284  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
285  *     dirlist_generate_bottom()
286  */
287 
dirlist_generate_row(bool even,bool directory,nsurl * url,char * name,const char * mimetype,long long size,char * date,char * time,char * buffer,int buffer_length)288 bool dirlist_generate_row(bool even, bool directory, nsurl *url, char *name,
289 		const char *mimetype, long long size, char *date, char *time,
290 		char *buffer, int buffer_length)
291 {
292 	const char *unit;
293 	char size_string[100];
294 	int error;
295 
296 	if (size < 0) {
297 		unit = "";
298 		strncpy(size_string, "", sizeof size_string);
299 	} else {
300 		unit = messages_get(dirlist_filesize_unit((unsigned long)size));
301 		snprintf(size_string, sizeof size_string, "%d",
302 				dirlist_filesize_value((unsigned long)size));
303 	}
304 
305 	error = snprintf(buffer, buffer_length,
306 			"<a href=\"%s\" class=\"%s %s\">\n"
307 			"\t<span class=\"name ns-border\">%s</span>\n"
308 			"\t<span class=\"type ns-border\">%s</span>\n"
309 			"\t<span class=\"size ns-border\">%s</span>"
310 			"<span class=\"size ns-border\">%s</span>\n"
311 			"\t<span class=\"date ns-border\">%s</span>\n"
312 			"\t<span class=\"time ns-border\">%s</span>\n"
313 			"</a>\n", nsurl_access(url),
314 			even ? "even ns-even-bg" : "odd  ns-odd-bg",
315 			directory ? "dir" : "file",
316 			name, mimetype, size_string, unit, date, time);
317 	if (error < 0 || error >= buffer_length)
318 		/* Error or buffer too small */
319 		return false;
320 	else
321 		/* OK */
322 		return true;
323 }
324 
325 
326 /**
327  * Generates the bottom part of an HTML directory listing page
328  *
329  * \return  Bottom of directory listing HTML
330  *
331  * This is part of a series of functions.  To generate a complete page,
332  * call the following functions in order:
333  *
334  *     dirlist_generate_top()
335  *     dirlist_generate_hide_columns()  -- optional
336  *     dirlist_generate_title()
337  *     dirlist_generate_parent_link()   -- optional
338  *     dirlist_generate_headings()
339  *     dirlist_generate_row()           -- call 'n' times for 'n' rows
340  *     dirlist_generate_bottom()
341  */
342 
dirlist_generate_bottom(char * buffer,int buffer_length)343 bool dirlist_generate_bottom(char *buffer, int buffer_length)
344 {
345 	int error = snprintf(buffer, buffer_length,
346 			"</div>\n"
347 			"</body>\n"
348 			"</html>\n");
349 	if (error < 0 || error >= buffer_length)
350 		/* Error or buffer too small */
351 		return false;
352 	else
353 		/* OK */
354 		return true;
355 }
356 
357 
358 /**
359  * Obtain display value and units for filesize after conversion to B/kB/MB/GB,
360  * as appropriate.
361  *
362  * \param  bytesize  file size in bytes, updated to filesize in output units
363  * \return  number of times bytesize has been divided by 1024
364  */
365 
dirlist_filesize_calculate(unsigned long * bytesize)366 int dirlist_filesize_calculate(unsigned long *bytesize)
367 {
368 	int i = 0;
369 	while (*bytesize > 1024 * 4) {
370 		*bytesize /= 1024;
371 		i++;
372 		if (i == 3)
373 			break;
374 	}
375 	return i;
376 }
377 
378 
379 /**
380  * Obtain display value for filesize after conversion to B/kB/MB/GB,
381  * as appropriate
382  *
383  * \param  bytesize  file size in bytes
384  * \return  Value to display for file size, in units given by filesize_unit()
385  */
386 
dirlist_filesize_value(unsigned long bytesize)387 int dirlist_filesize_value(unsigned long bytesize)
388 {
389 	dirlist_filesize_calculate(&bytesize);
390 	return (int)bytesize;
391 }
392 
393 
394 /**
395  * Obtain display units for filesize after conversion to B/kB/MB/GB,
396  * as appropriate
397  *
398  * \param  bytesize  file size in bytes
399  * \return  Units to display for file size, for value given by filesize_value()
400  */
401 
dirlist_filesize_unit(unsigned long bytesize)402 char* dirlist_filesize_unit(unsigned long bytesize)
403 {
404 	const char* units[] = { "Bytes", "kBytes", "MBytes", "GBytes" };
405 	return (char*)units[dirlist_filesize_calculate(&bytesize)];
406 }
407