1 /*
2  * http.c for owhttpd (1-wire web server)
3  * By Paul Alfille 2003, using libow
4  * offshoot of the owfs ( 1wire file system )
5  *
6  * GPL license ( Gnu Public Lincense )
7  *
8  * Based on chttpd. copyright(c) 0x7d0 greg olszewski <noop@nwonknu.org>
9  *
10  */
11 
12 #include "owhttpd.h"
13 
14 // #include <libgen.h>  /* for dirname() */
15 
16 /* --------------- Prototypes---------------- */
17 static void Show(struct OutputControl * oc, const struct parsedname *pn_entry);
18 static void ShowDirectory(struct OutputControl * oc, const struct parsedname *pn_entry);
19 static void ShowReadWrite(struct OutputControl * oc, struct one_wire_query *owq);
20 static void ShowReadonly(struct OutputControl * oc, struct one_wire_query *owq);
21 static void ShowWriteonly(struct OutputControl * oc, struct one_wire_query *owq);
22 static void ShowStructure(struct OutputControl * oc, struct one_wire_query *owq);
23 static void StructureDetail(struct OutputControl * oc, const char * structure_details );
24 static void Upload( struct OutputControl * oc, const struct parsedname * pn ) ;
25 static void Extension( struct OutputControl * oc, const struct parsedname * pn ) ;
26 
27 static void ShowText(struct OutputControl * oc, const struct parsedname *pn_entry);
28 static void ShowTextDirectory(struct OutputControl * oc, const struct parsedname *pn_entry);
29 static void ShowTextReadWrite(struct OutputControl * oc, struct one_wire_query *owq);
30 static void ShowTextReadonly(struct OutputControl * oc, struct one_wire_query *owq);
31 static void ShowTextWriteonly(struct OutputControl * oc, struct one_wire_query *owq);
32 static void ShowTextStructure(struct OutputControl * oc, struct one_wire_query *owq);
33 
34 static void ShowJson(struct OutputControl * oc, const struct parsedname *pn_entry);
35 static void ShowJsonDirectory(struct OutputControl * oc, const struct parsedname *pn_entry);
36 static void ShowJsonReadWrite(struct OutputControl * oc, struct one_wire_query *owq);
37 static void ShowJsonReadonly(struct OutputControl * oc, struct one_wire_query *owq);
38 static void ShowJsonWriteonly(struct OutputControl * oc, struct one_wire_query *owq);
39 static void ShowJsonStructure(struct OutputControl * oc, struct one_wire_query *owq);
40 static void StructureDetailJson(struct OutputControl * oc, const char * structure_details );
41 
42 /* --------------- Functions ---------------- */
43 
44 /* Device entry -- table line for a filetype */
Show(struct OutputControl * oc,const struct parsedname * pn_entry)45 static void Show(struct OutputControl * oc, const struct parsedname *pn_entry)
46 {
47 	FILE * out = oc->out ;
48 	struct one_wire_query *owq = OWQ_create_from_path(pn_entry->path); // for read or dir
49 	struct filetype * ft = pn_entry->selected_filetype ;
50 	/* Left column */
51 	fprintf(out, "<TR><TD><B>%s</B></TD><TD>", FS_DirName(pn_entry));
52 
53 	if (owq == NO_ONE_WIRE_QUERY) {
54 		fprintf(out, "<B>Memory exhausted</B>");
55 	} else if ( BAD( OWQ_allocate_read_buffer(owq)) ) {
56 		fprintf(out, "<B>Memory exhausted</B>");
57 	} else if (ft == NO_FILETYPE) {
58 		ShowDirectory(oc, pn_entry);
59 	} else if (IsStructureDir(pn_entry)) {
60 		ShowStructure(oc, owq);
61 	} else if (ft->format == ft_directory || ft->format == ft_subdir) {
62 		// Directory
63 		ShowDirectory(oc, pn_entry);
64 	} else if ( pn_entry->extension == EXTENSION_UNKNOWN  && ft->ag != NON_AGGREGATE && ft->ag->combined == ag_sparse ) {
65 		Extension(oc, pn_entry ) ; // flag as generic needing an extension chosen
66 	} else if (ft->write == NO_WRITE_FUNCTION || Globals.readonly) {
67 		// Unwritable
68 		if (ft->read != NO_READ_FUNCTION) {
69 			ShowReadonly(oc, owq);
70 		} else {
71 			// Property has no read or write ability
72 		}
73 	} else {					// Writeable
74 		if (ft->read == NO_READ_FUNCTION) {
75 			ShowWriteonly(oc, owq);
76 		} else {
77 			ShowReadWrite(oc, owq);
78 		}
79 	}
80 	fprintf(out, "</TD></TR>\r\n");
81 	OWQ_destroy(owq);
82 }
83 
84 
85 /* Device entry -- table line for a filetype */
ShowReadWrite(struct OutputControl * oc,struct one_wire_query * owq)86 static void ShowReadWrite(struct OutputControl * oc, struct one_wire_query *owq)
87 {
88 	FILE * out = oc->out ;
89 	struct parsedname * pn = PN(owq) ;
90 	const char *file = FS_DirName(pn);
91 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
92 	if (read_return < 0) {
93 		fprintf(out, "Error: %s", strerror(-read_return));
94 		return;
95 	}
96 
97 	switch (pn->selected_filetype->format) {
98 		case ft_binary:
99 			{
100 				int i = 0;
101 				fprintf(out, "<CODE><FORM METHOD='GET' ACTION='http://%s%s'><TEXTAREA NAME='%s' COLS='64' ROWS='%-d'>", oc->host, oc->base_url, file, read_return >> 5);
102 				while (i < read_return) {
103 					fprintf(out, "%.2hhX", OWQ_buffer(owq)[i]);
104 					if (((++i) < read_return) && (i & 0x1F) == 0) {
105 						fprintf(out, "\r\n");
106 					}
107 				}
108 				fprintf(out, "</TEXTAREA><INPUT TYPE='SUBMIT' VALUE='CHANGE'></FORM></CODE>");
109 				Upload( oc, pn ) ;
110 				break;
111 			}
112 		case ft_yesno:
113 		case ft_bitfield:
114 			if (pn->extension >= 0) {
115 				fprintf(out,
116 						"<FORM METHOD='GET' ACTION='http://%s%s'><INPUT TYPE='CHECKBOX' NAME='%s' %s><INPUT TYPE='SUBMIT' VALUE='CHANGE' NAME='%s'></FORM>",oc->host, oc->base_url,
117 						file, (OWQ_buffer(owq)[0] == '0') ? "" : "CHECKED", file);
118 				break;
119 			}
120 			// fall through
121 		default:
122 			fprintf(out,
123 					"<FORM METHOD='GET' ACTION='http://%s%s'><INPUT TYPE='TEXT' NAME='%s' VALUE='%.*s'><INPUT TYPE='SUBMIT' VALUE='CHANGE'></FORM>",oc->host, oc->base_url,
124 					file, read_return, OWQ_buffer(owq));
125 			break;
126 	}
127 }
128 
Upload(struct OutputControl * oc,const struct parsedname * pn)129 static void Upload( struct OutputControl * oc, const struct parsedname * pn )
130 {
131 	FILE * out = oc->out ;
132 	fprintf(out,"<FORM METHOD='POST'  ACTION='http://%s%s' ENCTYPE='multipart/form-data'>Load from file: <INPUT TYPE=FILE NAME='%s' SIZE=30><INPUT TYPE=SUBMIT VALUE='UPLOAD'></FORM>",oc->host, oc->base_url, pn->path);
133 }
134 
Extension(struct OutputControl * oc,const struct parsedname * pn)135 static void Extension( struct OutputControl * oc, const struct parsedname * pn )
136 {
137 	static regex_t rx_extension ;
138 	FILE * out = oc->out ;
139 	const char * file = FS_DirName(pn);
140 	struct ow_regmatch orm ;
141 	orm.number = 0 ;
142 
143 	ow_regcomp( &rx_extension, "\\.", 0 ) ;
144 	if ( ow_regexec( &rx_extension, file, &orm ) == 0 ) {
145 		fprintf(out, "<CODE><FORM METHOD='GET' ACTION='http://%s%s'><INPUT NAME='EXTENSION' TYPE='TEXT' SIZE='30' VALUE='%s.' ID='EXTENSION'><INPUT TYPE='SUBMIT' VALUE='EXTENSION'></FORM>", oc->host, oc->base_url, orm.pre[0] );
146 		ow_regexec_free( &orm ) ;
147 	}
148 }
149 
150 /* Device entry -- table line for a filetype */
ShowReadonly(struct OutputControl * oc,struct one_wire_query * owq)151 static void ShowReadonly(struct OutputControl * oc, struct one_wire_query *owq)
152 {
153 	FILE * out = oc->out ;
154 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
155 	struct parsedname * pn = PN(owq) ;
156 	if (read_return < 0) {
157 		fprintf(out, "Error: %s", strerror(-read_return));
158 		return;
159 	}
160 
161 	switch (pn->selected_filetype->format) {
162 	case ft_binary:
163 		{
164 			int i = 0;
165 			fprintf(out, "<PRE>");
166 			while (i < read_return) {
167 				fprintf(out, "%.2hhX", OWQ_buffer(owq)[i]);
168 				if (((++i) < read_return) && (i & 0x1F) == 0) {
169 					fprintf(out, "\r\n");
170 				}
171 			}
172 			fprintf(out, "</PRE>");
173 			break;
174 		}
175 	case ft_yesno:
176 	case ft_bitfield:
177 		if (pn->extension >= 0) {
178 			switch (OWQ_buffer(owq)[0]) {
179 				case '0':
180 					fprintf(out, "NO  (0)");
181 					break;
182 				case '1':
183 					fprintf(out, "YES (1)");
184 					break;
185 			}
186 			break;
187 		}
188 		// fall through
189 	default:
190 		fprintf(out, "%.*s", read_return, OWQ_buffer(owq));
191 		break;
192 	}
193 }
194 
195 /* Structure entry */
ShowStructure(struct OutputControl * oc,struct one_wire_query * owq)196 static void ShowStructure(struct OutputControl * oc, struct one_wire_query *owq)
197 {
198 	FILE * out = oc->out ;
199 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
200 	if (read_return < 0) {
201 		fprintf(out, "Error: %s", strerror(-read_return));
202 		return;
203 	}
204 
205 	fprintf(out, "%.*s", read_return, OWQ_buffer(owq));
206 
207 	// Optional structure details
208 	StructureDetail(oc,OWQ_buffer(owq)) ;
209 }
210 
211 /* Detailed (parsed) structure entry */
StructureDetail(struct OutputControl * oc,const char * structure_details)212 static void StructureDetail(struct OutputControl * oc, const char * structure_details )
213 {
214 	FILE * out = oc->out ;
215 	char format_type ;
216 	int extension ;
217 	int elements ;
218 	char rw[4] ;
219 	int size ;
220 
221 	if ( sscanf( structure_details, "%c,%d,%d,%2s,%d,", &format_type, &extension, &elements, rw, &size ) < 5 ) {
222 		return ;
223 	}
224 
225 	fprintf(out, "<br>");
226 	switch( format_type ) {
227 		case 'b':
228 			fprintf(out, "Binary string");
229 			break ;
230 		case 'a':
231 			fprintf(out, "Ascii string");
232 			break ;
233 		case 'D':
234 			fprintf(out, "Directory");
235 			break ;
236 		case 'i':
237 			fprintf(out, "Integer value");
238 			break ;
239 		case 'u':
240 			fprintf(out, "Unsigned integer value");
241 			break ;
242 		case 'f':
243 			fprintf(out, "Floating point value");
244 			break ;
245 		case 'l':
246 			fprintf(out, "Alias");
247 			break ;
248 		case 'y':
249 			fprintf(out, "Yes/No value");
250 			break ;
251 		case 'd':
252 			fprintf(out, "Date value");
253 			break ;
254 		case 't':
255 			fprintf(out, "Temperature value");
256 			break ;
257 		case 'g':
258 			fprintf(out, "Delta temperature value");
259 			break ;
260 		case 'p':
261 			fprintf(out, "Pressure value");
262 			break ;
263 		default:
264 			fprintf(out, "Unknown value type");
265 	}
266 
267 	fprintf(out, ", ");
268 
269 	if ( elements == 1 ) {
270 		fprintf(out, "Singleton");
271 	} else if ( extension == EXTENSION_BYTE ) {
272 		fprintf(out, "Array of %d bits as a BYTE",elements);
273 	} else if ( extension == EXTENSION_ALL ) {
274 		fprintf(out, "Array of %d elements combined",elements);
275 	} else {
276 		fprintf(out, "Element %d (of %d)",extension,elements);
277 	}
278 
279 	fprintf(out, ", ");
280 
281 	if ( strncasecmp( rw, "rw", 2 ) == 0 ) {
282 		fprintf(out, "Read/Write");
283 	} else if ( strncasecmp( rw, "ro", 2 ) == 0 ) {
284 		fprintf(out, "Read only");
285 	} else if ( strncasecmp( rw, "wo", 2 ) == 0 ) {
286 		fprintf(out, "Write only");
287 	} else{
288 		fprintf(out, "No access");
289 	}
290 
291 	fprintf(out, ", ");
292 
293 	if ( format_type == 'b' ) {
294 		fprintf(out, "%d bytes",size);
295 	} else {
296 		fprintf(out, "%d characters",size);
297 	}
298 }
299 
300 /* Device entry -- table line for a filetype */
ShowWriteonly(struct OutputControl * oc,struct one_wire_query * owq)301 static void ShowWriteonly(struct OutputControl * oc, struct one_wire_query *owq)
302 {
303 	FILE * out = oc->out ;
304 	struct parsedname * pn = PN(owq) ;
305 	const char *file = FS_DirName(pn);
306 
307 	switch (pn->selected_filetype->format) {
308 		case ft_binary:
309 			fprintf(out,
310 					"<CODE><FORM METHOD='GET' ACTION='http://%s%s'><TEXTAREA NAME='%s' COLS='64' ROWS='%-d'></TEXTAREA><INPUT TYPE='SUBMIT' VALUE='CHANGE'></FORM></CODE>",oc->host, oc->base_url,
311 					file, (int) (OWQ_size(owq) >> 5));
312 			Upload(oc,pn) ;
313 			break;
314 		case ft_yesno:
315 		case ft_bitfield:
316 			if (pn->extension >= 0) {
317 				fprintf(out,
318 						"<FORM METHOD='GET' ACTION='http://%s%s'><INPUT TYPE='SUBMIT' NAME='%s' VALUE='ON'><INPUT TYPE='SUBMIT' NAME='%s' VALUE='OFF'></FORM>", oc->host, oc->base_url, file, file);
319 				break;
320 			}
321 			// fall through
322 		default:
323 			fprintf(out, "<FORM METHOD='GET' ACTION='http://%s%s'><INPUT TYPE='TEXT' NAME='%s'><INPUT TYPE='SUBMIT' VALUE='CHANGE'></FORM>", oc->host, oc->base_url, file);
324 			break;
325 	}
326 }
327 
ShowDirectory(struct OutputControl * oc,const struct parsedname * pn_entry)328 static void ShowDirectory(struct OutputControl * oc, const struct parsedname *pn_entry)
329 {
330 	FILE * out = oc->out ;
331 	fprintf(out, "<A HREF='%s'>%s</A>", pn_entry->path, FS_DirName(pn_entry));
332 }
333 
334 /* Device entry -- table line for a filetype */
ShowText(struct OutputControl * oc,const struct parsedname * pn_entry)335 static void ShowText(struct OutputControl * oc, const struct parsedname *pn_entry)
336 {
337 	FILE * out = oc->out ;
338 	struct one_wire_query *owq = OWQ_create_from_path(pn_entry->path); // for read or dir
339 	struct filetype * ft = pn_entry->selected_filetype ;
340 
341 	/* Left column */
342 	fprintf(out, "%s ", FS_DirName(pn_entry));
343 
344 	if (owq == NO_ONE_WIRE_QUERY) {
345 	} else if ( BAD( OWQ_allocate_read_buffer(owq)) ) {
346 		//fprintf(out, "(memory exhausted)");
347 	} else if (ft == NO_FILETYPE) {
348 		ShowTextDirectory(oc, pn_entry);
349 	} else if (ft->format == ft_directory || ft->format == ft_subdir) {
350 		ShowTextDirectory(oc, pn_entry);
351 	} else if (IsStructureDir(pn_entry)) {
352 		ShowTextStructure(oc, owq);
353 	} else if (ft->write == NO_WRITE_FUNCTION || Globals.readonly) {
354 		// Unwritable
355 		if (ft->read != NO_READ_FUNCTION) {
356 			ShowTextReadonly(oc, owq);
357 		}
358 	} else {					// Writeable
359 		if (ft->read == NO_READ_FUNCTION) {
360 			ShowTextWriteonly(oc, owq);
361 		} else {
362 			ShowTextReadWrite(oc, owq);
363 		}
364 	}
365 	fprintf(out, "\r\n");
366 	OWQ_destroy(owq);
367 }
368 
369 /* Device entry -- table line for a filetype */
ShowTextStructure(struct OutputControl * oc,struct one_wire_query * owq)370 static void ShowTextStructure(struct OutputControl * oc, struct one_wire_query *owq)
371 {
372 	FILE * out = oc->out ;
373 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
374 	if (read_return < 0) {
375 		//fprintf(out, "error: %s", strerror(-read_return));
376 		return;
377 	}
378 
379 	fprintf(out, "%.*s", read_return, OWQ_buffer(owq));
380 }
381 
382 /* Device entry -- table line for a filetype */
ShowTextReadWrite(struct OutputControl * oc,struct one_wire_query * owq)383 static void ShowTextReadWrite(struct OutputControl * oc, struct one_wire_query *owq)
384 {
385 	FILE * out = oc->out ;
386 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
387 	if (read_return < 0) {
388 		//fprintf(out, "error: %s", strerror(-read_return));
389 		return;
390 	}
391 
392 	switch (PN(owq)->selected_filetype->format) {
393 	case ft_binary:
394 		{
395 			int i;
396 			for (i = 0; i < read_return; ++i) {
397 				fprintf(out, "%.2hhX", OWQ_buffer(owq)[i]);
398 			}
399 			break;
400 		}
401 	case ft_yesno:
402 	case ft_bitfield:
403 		if (PN(owq)->extension >= 0) {
404 			fprintf(out, "%c", OWQ_buffer(owq)[0]);
405 			break;
406 		}
407 		// fall through
408 	default:
409 		fprintf(out, "%.*s", read_return, OWQ_buffer(owq));
410 		break;
411 	}
412 }
413 
414 /* Device entry -- table line for a filetype */
ShowTextReadonly(struct OutputControl * oc,struct one_wire_query * owq)415 static void ShowTextReadonly(struct OutputControl * oc, struct one_wire_query *owq)
416 {
417 	ShowTextReadWrite(oc, owq);
418 }
419 
420 /* Device entry -- table line for a filetype */
ShowTextWriteonly(struct OutputControl * oc,struct one_wire_query * owq)421 static void ShowTextWriteonly(struct OutputControl * oc, struct one_wire_query *owq)
422 {
423 	FILE * out = oc->out ;
424 	(void) owq;
425 	fprintf(out, "(writeonly)");
426 }
427 
ShowTextDirectory(struct OutputControl * oc,const struct parsedname * pn_entry)428 static void ShowTextDirectory(struct OutputControl * oc, const struct parsedname *pn_entry)
429 {
430 	(void) oc;
431 	(void) pn_entry;
432 }
433 
434 /* Now show the device */
ShowDeviceTextCallback(void * v,const struct parsedname * pn_entry)435 static void ShowDeviceTextCallback(void *v, const struct parsedname * pn_entry)
436 {
437 	struct OutputControl * oc = v;
438 	ShowText(oc, pn_entry);
439 }
440 
ShowDeviceCallback(void * v,const struct parsedname * pn_entry)441 static void ShowDeviceCallback(void *v, const struct parsedname * pn_entry)
442 {
443 	struct OutputControl * oc = v;
444 	Show(oc, pn_entry);
445 }
446 
ShowDeviceText(struct OutputControl * oc,struct parsedname * pn)447 static void ShowDeviceText(struct OutputControl * oc, struct parsedname *pn)
448 {
449 	HTTPstart(oc, "200 OK", ct_text);
450 
451 	if (pn->selected_filetype == NO_DEVICE) {	/* whole device */
452 		//printf("whole directory path=%s \n", pn->path);
453 		FS_dir(ShowDeviceTextCallback, oc, pn);
454 	} else {					/* Single item */
455 		//printf("single item path=%s\n", pn->path);
456 		ShowText(oc, pn);
457 	}
458 }
459 
460 /* Device entry -- table line for a filetype */
ShowJson(struct OutputControl * oc,const struct parsedname * pn_entry)461 static void ShowJson(struct OutputControl * oc, const struct parsedname *pn_entry)
462 {
463 	FILE * out = oc->out ;
464 	struct one_wire_query *owq = OWQ_create_from_path(pn_entry->path); // for read or dir
465 	struct filetype * ft = pn_entry->selected_filetype ;
466 
467 	if (owq == NO_ONE_WIRE_QUERY) {
468 		fprintf(out, "null");
469 	} else if ( BAD( OWQ_allocate_read_buffer(owq)) ) {
470 		fprintf(out, "null");
471 	} else if (ft == NO_FILETYPE) {
472 		ShowJsonDirectory(oc, pn_entry);
473 	} else if (IsStructureDir(pn_entry)) {
474 		ShowJsonStructure(oc, owq);
475 	} else if (ft->format == ft_directory || ft->format == ft_subdir) {
476 		ShowJsonDirectory(oc, pn_entry);
477 	} else if (ft->write == NO_WRITE_FUNCTION || Globals.readonly) {
478 		// Unwritable
479 		if (ft->read != NO_READ_FUNCTION) {
480 			ShowJsonReadonly(oc, owq);
481 		}
482 	} else {					// Writeable
483 		if (ft->read == NO_READ_FUNCTION) {
484 			ShowJsonWriteonly(oc, owq);
485 		} else {
486 			ShowJsonReadWrite(oc, owq);
487 		}
488 	}
489 	OWQ_destroy(owq);
490 }
491 
492 /* Device entry -- table line for a filetype */
ShowJsonStructure(struct OutputControl * oc,struct one_wire_query * owq)493 static void ShowJsonStructure(struct OutputControl * oc, struct one_wire_query *owq)
494 {
495 	FILE * out = oc->out ;
496 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
497 	if (read_return < 0) {
498 		fprintf(out, "null");
499 		return;
500 	}
501 	fprintf(out, "\"%.*s\":", read_return, OWQ_buffer(owq));
502 	StructureDetailJson( oc, OWQ_buffer(owq) ) ;
503 }
504 
505 /* Detailed (parsed) structure entry */
StructureDetailJson(struct OutputControl * oc,const char * structure_details)506 static void StructureDetailJson(struct OutputControl * oc, const char * structure_details )
507 {
508 	FILE * out = oc->out ;
509 	char format_type ;
510 	int extension ;
511 	int elements ;
512 	char rw[4] ;
513 	int size ;
514 
515 	if ( sscanf( structure_details, "[\"%c\",\"%d\",\"%d\",\"%2s\",\"%d\",", &format_type, &extension, &elements, rw, &size ) < 5 ) {
516 		return ;
517 	}
518 
519 	fprintf(out, "\"");
520 	switch( format_type ) {
521 		case 'b':
522 			fprintf(out, "Binary string");
523 			break ;
524 		case 'a':
525 			fprintf(out, "Ascii string");
526 			break ;
527 		case 'D':
528 			fprintf(out, "Directory");
529 			break ;
530 		case 'i':
531 			fprintf(out, "Integer value");
532 			break ;
533 		case 'u':
534 			fprintf(out, "Unsigned integer value");
535 			break ;
536 		case 'f':
537 			fprintf(out, "Floating point value");
538 			break ;
539 		case 'l':
540 			fprintf(out, "Alias");
541 			break ;
542 		case 'y':
543 			fprintf(out, "Yes/No value");
544 			break ;
545 		case 'd':
546 			fprintf(out, "Date value");
547 			break ;
548 		case 't':
549 			fprintf(out, "Temperature value");
550 			break ;
551 		case 'g':
552 			fprintf(out, "Delta temperature value");
553 			break ;
554 		case 'p':
555 			fprintf(out, "Pressure value");
556 			break ;
557 		default:
558 			fprintf(out, "Unknown value type");
559 	}
560 
561 	fprintf(out, "\", \"");
562 
563 	if ( elements == 1 ) {
564 		fprintf(out, "Singleton");
565 	} else if ( extension == EXTENSION_BYTE ) {
566 		fprintf(out, "Array of %d bits as a BYTE",elements);
567 	} else if ( extension == EXTENSION_ALL ) {
568 		fprintf(out, "Array of %d elements combined",elements);
569 	} else {
570 		fprintf(out, "Element %d (of %d)",extension,elements);
571 	}
572 
573 	fprintf(out, "\", \"");
574 
575 	if ( strncasecmp( rw, "rw", 2 ) == 0 ) {
576 		fprintf(out, "Read/Write");
577 	} else if ( strncasecmp( rw, "ro", 2 ) == 0 ) {
578 		fprintf(out, "Read only");
579 	} else if ( strncasecmp( rw, "wo", 2 ) == 0 ) {
580 		fprintf(out, "Write only");
581 	} else{
582 		fprintf(out, "No access");
583 	}
584 
585 	fprintf(out, "\", \"");
586 
587 	if ( format_type == 'b' ) {
588 		fprintf(out, "%d bytes",size);
589 	} else {
590 		fprintf(out, "%d characters",size);
591 	}
592 	fprintf( out, "\"]" );
593 }
594 
595 /* Device entry -- table line for a filetype */
ShowJsonReadWrite(struct OutputControl * oc,struct one_wire_query * owq)596 static void ShowJsonReadWrite(struct OutputControl * oc, struct one_wire_query *owq)
597 {
598 	FILE * out = oc->out ;
599 	struct parsedname * pn = PN(owq) ;
600 	SIZE_OR_ERROR read_return = FS_read_postparse(owq);
601 
602 	if (read_return < 0) {
603 		fprintf(out, "null");
604 		return;
605 	}
606 
607 	switch (pn->selected_filetype->format) {
608 	case ft_binary:
609 		{
610 			int i;
611 			fprintf(out,"\"");
612 			for (i = 0; i < read_return; ++i) {
613 				fprintf(out, "%.2hhX", OWQ_buffer(owq)[i]);
614 			}
615 			fprintf(out,"\"");
616 			break;
617 		}
618 	case ft_yesno:
619 	case ft_bitfield:
620 		if (pn->extension >= 0) {
621 			fprintf(out, "\"%s\"", OWQ_buffer(owq)[0]=='0'?"false":"true");
622 			break;
623 		}
624 		// fall through
625 	default:
626 		fprintf(out, "\"%.*s\"", read_return, OWQ_buffer(owq));
627 		break;
628 	}
629 }
630 
631 /* Device entry -- table line for a filetype */
ShowJsonReadonly(struct OutputControl * oc,struct one_wire_query * owq)632 static void ShowJsonReadonly(struct OutputControl * oc, struct one_wire_query *owq)
633 {
634 	ShowJsonReadWrite(oc, owq);
635 }
636 
637 /* Device entry -- table line for a filetype */
ShowJsonWriteonly(struct OutputControl * oc,struct one_wire_query * owq)638 static void ShowJsonWriteonly(struct OutputControl * oc, struct one_wire_query *owq)
639 {
640 	FILE * out = oc->out ;
641 	(void) owq ;
642 	fprintf(out,"null") ;
643 }
ShowJsonDirectory(struct OutputControl * oc,const struct parsedname * pn_entry)644 static void ShowJsonDirectory(struct OutputControl * oc, const struct parsedname *pn_entry)
645 {
646 	FILE * out = oc->out ;
647 	(void) pn_entry;
648 	fprintf(out,"[]") ;
649 }
650 
651 /* Now show the device */
ShowDeviceJsonCallback(void * v,const struct parsedname * pn_entry)652 static void ShowDeviceJsonCallback(void *v, const struct parsedname * pn_entry)
653 {
654 	struct OutputControl * oc = v ;
655 	JSON_dir_entry(oc, "\"%s\":",FS_DirName(pn_entry) ) ;
656 	ShowJson(oc, pn_entry);
657 }
658 
ShowDeviceJson(struct OutputControl * oc,struct parsedname * pn)659 static void ShowDeviceJson(struct OutputControl * oc, struct parsedname *pn)
660 {
661 	FILE * out = oc->out ;
662 
663 	HTTPstart(oc, "200 OK", ct_json);
664 
665 	if (pn->selected_filetype == NO_DEVICE) {	/* whole device */
666 		JSON_dir_init( oc ) ;
667 		fprintf(out, "{\n" ) ;
668 		FS_dir(ShowDeviceJsonCallback, oc, pn);
669 		JSON_dir_finish(oc) ;
670 		fprintf(out, "}" );
671 	} else {					/* Single item */
672 		//printf("single item path=%s\n", pn->path);
673 		fprintf(out, "[ " ) ;
674 		ShowJson(oc, pn);
675 		fprintf(out, " ]" ) ;
676 	}
677 }
678 
679 
ShowDevice(struct OutputControl * oc,struct parsedname * pn)680 void ShowDevice(struct OutputControl * oc, struct parsedname *pn)
681 {
682 	FILE * out = oc->out ;
683 	if (pn->state & ePS_text) {
684 		ShowDeviceText(oc, pn);
685 		return;
686 	} else if (pn->state & ePS_json) {
687 		ShowDeviceJson(oc, pn);
688 		return;
689 	}
690 
691 	HTTPstart(oc, "200 OK", ct_html);
692 
693 	HTTPtitle(oc, &pn->path[1]);
694 	HTTPheader(oc, &pn->path[1]);
695 
696 	if (NotUncachedDir(pn) && IsRealDir(pn)) {
697 		fprintf(out, "<BR><small><A href='/uncached%s'>uncached version</A></small>", pn->path);
698 	}
699 	fprintf(out, "<TABLE BGCOLOR=\"#DDDDDD\" BORDER=1>");
700 	fprintf(out, "<TR><TD><A HREF='%.*s'><CODE><B><BIG>up</BIG></B></CODE></A></TD><TD>directory</TD></TR>", Backup(pn->path), pn->path);
701 
702 
703 	if (pn->selected_filetype == NO_FILETYPE) {	/* whole device */
704 		FS_dir(ShowDeviceCallback, oc, pn);
705 	} else {					/* single item */
706 		Show(oc, pn);
707 	}
708 	fprintf(out, "</TABLE>");
709 	HTTPfoot(oc);
710 }
711