1#include "base.h"
2#include "log.h"
3#include "buffer.h"
4#include "response.h"
5
6#include "plugin.h"
7
8#include "stream.h"
9#include "stat_cache.h"
10
11#include "sys-mmap.h"
12
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <ctype.h>
16#include <stdlib.h>
17#include <string.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <stdio.h>
21#include <assert.h>
22
23#include <unistd.h>
24#include <dirent.h>
25#include <dlinklist.h>
26//#include <sys/socket.h>
27
28//#define USE_LIBEXIF
29#ifdef USE_LIBEXIF
30#include <libexif/exif-loader.h>
31#endif
32
33#if EMBEDDED_EANBLE
34#ifndef APP_IPKG
35#include "disk_share.h"
36#endif
37#endif
38
39#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H)
40#define USE_PROPPATCH
41#define USE_MINIDLNA_DB
42#include <libxml/tree.h>
43#include <libxml/parser.h>
44#include <sqlite3.h>
45#endif
46
47#include <stdarg.h>
48
49#include <curl/curl.h>
50#include <openssl/md5.h>
51
52//#include "sql.h"
53/*
54#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_UUID_H)
55#define USE_LOCKS
56#include <uuid/uuid.h>
57#endif
58*/
59
60#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H)
61#define USE_LOCKS
62#endif
63
64#define MUSIC_ID		"1"
65#define MUSIC_ALL_ID		"1$4"
66#define MUSIC_GENRE_ID		"1$5"
67#define MUSIC_ARTIST_ID		"1$6"
68#define MUSIC_ALBUM_ID		"1$7"
69#define MUSIC_PLIST_ID		"1$F"
70#define MUSIC_DIR_ID		"1$14"
71#define MUSIC_CONTRIB_ARTIST_ID	"1$100"
72#define MUSIC_ALBUM_ARTIST_ID	"1$107"
73#define MUSIC_COMPOSER_ID	"1$108"
74#define MUSIC_RATING_ID		"1$101"
75
76#define VIDEO_ID		"2"
77#define VIDEO_ALL_ID		"2$8"
78#define VIDEO_GENRE_ID		"2$9"
79#define VIDEO_ACTOR_ID		"2$A"
80#define VIDEO_SERIES_ID		"2$E"
81#define VIDEO_PLIST_ID		"2$10"
82#define VIDEO_DIR_ID		"2$15"
83#define VIDEO_RATING_ID		"2$200"
84
85#define IMAGE_ID		"3"
86#define IMAGE_ALL_ID		"3$B"
87#define IMAGE_DATE_ID		"3$C"
88#define IMAGE_ALBUM_ID		"3$D"
89#define IMAGE_CAMERA_ID		"3$D2" // PlaysForSure == Keyword
90#define IMAGE_PLIST_ID		"3$11"
91#define IMAGE_DIR_ID		"3$16"
92#define IMAGE_RATING_ID		"3$300"
93
94/**
95 * this is a webdav for a lighttpd plugin
96 *
97 * at least a very basic one.
98 * - for now it is read-only and we only support PROPFIND
99 *
100 */
101
102#define WEBDAV_FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH
103#define WEBDAV_DIR_MODE  S_IRWXU | S_IRWXG | S_IRWXO
104
105#define DBG_ENABLE_MOD_SMBDAV 1
106#define DBE	DBG_ENABLE_MOD_SMBDAV
107
108/* plugin config for all request/connections */
109
110typedef struct {
111	unsigned short enabled;
112	unsigned short is_readonly;
113	unsigned short log_xml;
114
115	buffer *sqlite_db_name;
116	array  *alias_url;
117#ifdef USE_PROPPATCH
118	sqlite3 *sql;
119	sqlite3_stmt *stmt_update_prop;
120	sqlite3_stmt *stmt_delete_prop;
121	sqlite3_stmt *stmt_select_prop;
122	sqlite3_stmt *stmt_select_propnames;
123
124	sqlite3_stmt *stmt_delete_uri;
125	sqlite3_stmt *stmt_move_uri;
126	sqlite3_stmt *stmt_copy_uri;
127
128	sqlite3_stmt *stmt_remove_lock;
129	sqlite3_stmt *stmt_create_lock;
130	sqlite3_stmt *stmt_read_lock;
131	sqlite3_stmt *stmt_read_lock_by_uri;
132	sqlite3_stmt *stmt_refresh_lock;
133#endif
134} plugin_config;
135
136typedef struct {
137	PLUGIN_DATA;
138
139	buffer *tmp_buf;
140	request_uri uri;
141	physical physical;
142
143	plugin_config **config_storage;
144
145	plugin_config conf;
146
147	//- 20130304 Sungmin add
148	buffer *minidlna_db_dir;
149	buffer *minidlna_db_file;
150	buffer *minidlna_media_dir;
151	buffer *mnt_path;
152
153} plugin_data;
154
155/* init the plugin data */
156INIT_FUNC(mod_webdav_init) {
157
158	plugin_data *p;
159
160	p = calloc(1, sizeof(*p));
161
162	p->tmp_buf = buffer_init();
163
164	p->uri.scheme = buffer_init();
165	p->uri.path_raw = buffer_init();
166	p->uri.path = buffer_init();
167	p->uri.authority = buffer_init();
168
169	p->physical.path = buffer_init();
170	p->physical.rel_path = buffer_init();
171	p->physical.doc_root = buffer_init();
172	p->physical.basedir = buffer_init();
173
174	//- 20130304 Sungmin add
175	p->minidlna_db_dir = buffer_init();
176	p->minidlna_db_file = buffer_init();
177	p->minidlna_media_dir = buffer_init();
178	p->mnt_path = buffer_init();
179
180	return p;
181}
182
183/* detroy the plugin data */
184FREE_FUNC(mod_webdav_free) {
185	plugin_data *p = p_d;
186
187	UNUSED(srv);
188
189	if (!p) return HANDLER_GO_ON;
190
191	if (p->config_storage) {
192		size_t i;
193		for (i = 0; i < srv->config_context->used; i++) {
194			plugin_config *s = p->config_storage[i];
195
196			if (NULL == s) continue;
197
198			array_free(s->alias_url);
199			buffer_free(s->sqlite_db_name);
200#ifdef USE_PROPPATCH
201			if (s->sql) {
202				sqlite3_finalize(s->stmt_delete_prop);
203				sqlite3_finalize(s->stmt_delete_uri);
204				sqlite3_finalize(s->stmt_copy_uri);
205				sqlite3_finalize(s->stmt_move_uri);
206				sqlite3_finalize(s->stmt_update_prop);
207				sqlite3_finalize(s->stmt_select_prop);
208				sqlite3_finalize(s->stmt_select_propnames);
209
210				sqlite3_finalize(s->stmt_read_lock);
211				sqlite3_finalize(s->stmt_read_lock_by_uri);
212				sqlite3_finalize(s->stmt_create_lock);
213				sqlite3_finalize(s->stmt_remove_lock);
214				sqlite3_finalize(s->stmt_refresh_lock);
215				sqlite3_close(s->sql);
216			}
217#endif
218			free(s);
219		}
220		free(p->config_storage);
221	}
222
223	buffer_free(p->uri.scheme);
224	buffer_free(p->uri.path_raw);
225	buffer_free(p->uri.path);
226	buffer_free(p->uri.authority);
227
228	buffer_free(p->physical.path);
229	buffer_free(p->physical.rel_path);
230	buffer_free(p->physical.doc_root);
231	buffer_free(p->physical.basedir);
232
233	buffer_free(p->tmp_buf);
234
235	//- 20130304 Sungmin add
236	buffer_free(p->minidlna_db_dir);
237	buffer_free(p->minidlna_db_file);
238	buffer_free(p->minidlna_media_dir);
239	buffer_free(p->mnt_path);
240
241	free(p);
242
243	return HANDLER_GO_ON;
244}
245
246/* handle plugin config and check values */
247
248SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
249
250	plugin_data *p = p_d;
251	size_t i = 0;
252
253	config_values_t cv[] = {
254		{ "webdav.activate",            NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
255		{ "webdav.is-readonly",         NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 1 */
256		{ "webdav.sqlite-db-name",      NULL, T_CONFIG_STRING,  T_CONFIG_SCOPE_CONNECTION },       /* 2 */
257		{ "webdav.log-xml",             NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },       /* 3 */
258		{ "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },         /* 4 */
259
260		{ NULL,                         NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
261	};
262
263	if (!p) return HANDLER_ERROR;
264
265	p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
266
267	for (i = 0; i < srv->config_context->used; i++) {
268		data_config const* config = (data_config const*)srv->config_context->data[i];
269		plugin_config *s;
270
271		s = calloc(1, sizeof(plugin_config));
272		s->sqlite_db_name = buffer_init();
273		s->alias_url = array_init();
274
275		cv[0].destination = &(s->enabled);
276		cv[1].destination = &(s->is_readonly);
277		cv[2].destination = s->sqlite_db_name;
278		cv[3].destination = &(s->log_xml);
279		cv[4].destination = s->alias_url;
280
281		p->config_storage[i] = s;
282
283		if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
284			return HANDLER_ERROR;
285		}
286
287#if EMBEDDED_EANBLE
288		char *usbdiskname = nvram_get_productid();
289#else
290		char *usbdiskname = "usbdisk";
291#endif
292
293		for (size_t j = 0; j < s->alias_url->used; j++) {
294			data_string *ds = (data_string *)s->alias_url->data[j];
295			if(strstr(ds->key->ptr, usbdiskname)!=NULL){
296				buffer_copy_buffer(p->mnt_path, ds->value);
297
298				if(strcmp( p->mnt_path->ptr + (p->mnt_path->used -1 ), "/" )!=0)
299					buffer_append_string(p->mnt_path, "/");
300			}
301		}
302#if EMBEDDED_EANBLE
303#ifdef APP_IPKG
304		free(usbdiskname);
305#endif
306#endif
307
308		if (!buffer_string_is_empty(s->sqlite_db_name)) {
309#ifdef USE_PROPPATCH
310			const char *next_stmt;
311			char *err;
312
313			if (SQLITE_OK != sqlite3_open(s->sqlite_db_name->ptr, &(s->sql))) {
314				log_error_write(srv, __FILE__, __LINE__, "sbs", "sqlite3_open failed for",
315						s->sqlite_db_name,
316						sqlite3_errmsg(s->sql));
317				return HANDLER_ERROR;
318			}
319
320			if (SQLITE_OK != sqlite3_exec(s->sql,
321					"CREATE TABLE properties ("
322					"  resource TEXT NOT NULL,"
323					"  prop TEXT NOT NULL,"
324					"  ns TEXT NOT NULL,"
325					"  value TEXT NOT NULL,"
326					"  PRIMARY KEY(resource, prop, ns))",
327					NULL, NULL, &err)) {
328
329				if (0 != strcmp(err, "table properties already exists")) {
330					log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
331					sqlite3_free(err);
332
333					return HANDLER_ERROR;
334				}
335				sqlite3_free(err);
336			}
337
338			if (SQLITE_OK != sqlite3_prepare(s->sql,
339				CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
340				&(s->stmt_select_prop), &next_stmt)) {
341				/* prepare failed */
342
343				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
344				return HANDLER_ERROR;
345			}
346
347			if (SQLITE_OK != sqlite3_prepare(s->sql,
348				CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
349				&(s->stmt_select_propnames), &next_stmt)) {
350				/* prepare failed */
351
352				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
353				return HANDLER_ERROR;
354			}
355
356
357			if (SQLITE_OK != sqlite3_prepare(s->sql,
358				CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
359				&(s->stmt_update_prop), &next_stmt)) {
360				/* prepare failed */
361
362				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
363				return HANDLER_ERROR;
364			}
365
366			if (SQLITE_OK != sqlite3_prepare(s->sql,
367				CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
368				&(s->stmt_delete_prop), &next_stmt)) {
369				/* prepare failed */
370				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
371
372				return HANDLER_ERROR;
373			}
374
375			if (SQLITE_OK != sqlite3_prepare(s->sql,
376				CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
377				&(s->stmt_delete_uri), &next_stmt)) {
378				/* prepare failed */
379				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
380
381				return HANDLER_ERROR;
382			}
383
384			if (SQLITE_OK != sqlite3_prepare(s->sql,
385				CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
386				&(s->stmt_copy_uri), &next_stmt)) {
387				/* prepare failed */
388				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
389
390				return HANDLER_ERROR;
391			}
392
393			if (SQLITE_OK != sqlite3_prepare(s->sql,
394				CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
395				&(s->stmt_move_uri), &next_stmt)) {
396				/* prepare failed */
397				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
398
399				return HANDLER_ERROR;
400			}
401
402			/* LOCKS */
403
404			if (SQLITE_OK != sqlite3_exec(s->sql,
405					"CREATE TABLE locks ("
406					"  locktoken TEXT NOT NULL,"
407					"  resource TEXT NOT NULL,"
408					"  lockscope TEXT NOT NULL,"
409					"  locktype TEXT NOT NULL,"
410					"  owner TEXT NOT NULL,"
411					"  depth INT NOT NULL,"
412					"  timeout TIMESTAMP NOT NULL,"
413					"  PRIMARY KEY(locktoken))",
414					NULL, NULL, &err)) {
415
416				if (0 != strcmp(err, "table locks already exists")) {
417					log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
418					sqlite3_free(err);
419
420					return HANDLER_ERROR;
421				}
422				sqlite3_free(err);
423			}
424
425			if (SQLITE_OK != sqlite3_prepare(s->sql,
426				CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
427				&(s->stmt_create_lock), &next_stmt)) {
428				/* prepare failed */
429				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
430
431				return HANDLER_ERROR;
432			}
433
434			if (SQLITE_OK != sqlite3_prepare(s->sql,
435				CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
436				&(s->stmt_remove_lock), &next_stmt)) {
437				/* prepare failed */
438				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
439
440				return HANDLER_ERROR;
441			}
442
443			if (SQLITE_OK != sqlite3_prepare(s->sql,
444				CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
445				&(s->stmt_read_lock), &next_stmt)) {
446				/* prepare failed */
447				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
448
449				return HANDLER_ERROR;
450			}
451
452			if (SQLITE_OK != sqlite3_prepare(s->sql,
453				CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
454				&(s->stmt_read_lock_by_uri), &next_stmt)) {
455				/* prepare failed */
456				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
457
458				return HANDLER_ERROR;
459			}
460
461			if (SQLITE_OK != sqlite3_prepare(s->sql,
462				CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
463				&(s->stmt_refresh_lock), &next_stmt)) {
464				/* prepare failed */
465				log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
466
467				return HANDLER_ERROR;
468			}
469
470
471#else
472			log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
473			return HANDLER_ERROR;
474#endif
475		}
476	}
477
478	return HANDLER_GO_ON;
479}
480
481#define PATCH_OPTION(x) \
482	p->conf.x = s->x;
483static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
484	size_t i, j;
485	plugin_config *s = p->config_storage[0];
486
487	PATCH_OPTION(enabled);
488	PATCH_OPTION(is_readonly);
489	PATCH_OPTION(log_xml);
490
491#ifdef USE_PROPPATCH
492	PATCH_OPTION(sql);
493	PATCH_OPTION(stmt_update_prop);
494	PATCH_OPTION(stmt_delete_prop);
495	PATCH_OPTION(stmt_select_prop);
496	PATCH_OPTION(stmt_select_propnames);
497
498	PATCH_OPTION(stmt_delete_uri);
499	PATCH_OPTION(stmt_move_uri);
500	PATCH_OPTION(stmt_copy_uri);
501
502	PATCH_OPTION(stmt_remove_lock);
503	PATCH_OPTION(stmt_refresh_lock);
504	PATCH_OPTION(stmt_create_lock);
505	PATCH_OPTION(stmt_read_lock);
506	PATCH_OPTION(stmt_read_lock_by_uri);
507#endif
508	/* skip the first, the global context */
509	for (i = 1; i < srv->config_context->used; i++) {
510		data_config *dc = (data_config *)srv->config_context->data[i];
511		s = p->config_storage[i];
512
513		/* condition didn't match */
514		if (!config_check_cond(srv, con, dc)) continue;
515
516		/* merge config */
517		for (j = 0; j < dc->value->used; j++) {
518			data_unset *du = dc->value->data[j];
519
520			if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
521				PATCH_OPTION(enabled);
522			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
523				PATCH_OPTION(is_readonly);
524			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
525				PATCH_OPTION(log_xml);
526			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
527#ifdef USE_PROPPATCH
528				PATCH_OPTION(sql);
529				PATCH_OPTION(stmt_update_prop);
530				PATCH_OPTION(stmt_delete_prop);
531				PATCH_OPTION(stmt_select_prop);
532				PATCH_OPTION(stmt_select_propnames);
533
534				PATCH_OPTION(stmt_delete_uri);
535				PATCH_OPTION(stmt_move_uri);
536				PATCH_OPTION(stmt_copy_uri);
537
538				PATCH_OPTION(stmt_remove_lock);
539				PATCH_OPTION(stmt_refresh_lock);
540				PATCH_OPTION(stmt_create_lock);
541				PATCH_OPTION(stmt_read_lock);
542				PATCH_OPTION(stmt_read_lock_by_uri);
543#endif
544			}
545		}
546	}
547
548	return 0;
549}
550
551URIHANDLER_FUNC(mod_webdav_uri_handler) {
552	plugin_data *p = p_d;
553
554	UNUSED(srv);
555
556	if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
557
558	mod_webdav_patch_connection(srv, con, p);
559
560	if (!p->conf.enabled) return HANDLER_GO_ON;
561
562	switch (con->request.http_method) {
563	case HTTP_METHOD_OPTIONS:
564		/* we fake a little bit but it makes MS W2k happy and it let's us mount the volume */
565		response_header_overwrite(srv, con, CONST_STR_LEN("DAV"), CONST_STR_LEN("1,2"));
566		response_header_overwrite(srv, con, CONST_STR_LEN("MS-Author-Via"), CONST_STR_LEN("DAV"));
567
568		if (p->conf.is_readonly) {
569			response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
570		} else {
571			response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
572		}
573		break;
574	default:
575		break;
576	}
577
578	/* not found */
579	return HANDLER_GO_ON;
580}
581
582static size_t curl_write_callback_func(void *ptr, size_t size, size_t count, void *stream)
583{
584   	/* ptr - your string variable.
585     	stream - data chuck you received */
586	char **response_ptr =  (char**)stream;
587
588    /* assuming the response is a string */
589    *response_ptr = strndup(ptr, (size_t)(size *count));
590
591  	//printf("%.*s", size, (char*)stream));
592   	//Cdbg(1, "callback_func.... %s", (char*)ptr);
593}
594#if 0
595
596/* md5sum:
597 * Concatenates a series of strings together then generates an md5
598 * message digest. Writes the result directly into 'output', which
599 * MUST be large enough to accept the result. (Size ==
600 * 128 + null terminator.)
601 */
602char secret[100] = "804b51d14d840d6e";
603/* sprint_hex:
604 * print a long hex value into a string buffer. This function will
605 * write 'len' bytes of data from 'char_buf' into 2*len bytes of space
606 * in 'output'. (Each hex value is 4 bytes.) Space in output must be
607 * pre-allocated. */
608void sprint_hex(char* output, unsigned char* char_buf, int len)
609{
610	int i;
611	for (i=0; i < len; i++) {
612		sprintf(output + i*2, "%02x", char_buf[i]);
613	}
614}
615
616void md5sum(char* output, int counter, ...)
617{
618	va_list argp;
619	unsigned char temp[MD5_DIGEST_LENGTH];
620	char* md5_string;
621	int full_len;
622	int i, str_len;
623	int buffer_size = 10;
624
625	md5_string = (char*)malloc(buffer_size);
626	md5_string[0] = '\0';
627
628	full_len = 0;
629	va_start(argp, secret);
630	for (i = 0; i < counter; i++) {
631		char* string = va_arg(argp, char*);
632		int len = strlen(string);
633
634		/* If the buffer is not large enough, expand until it is. */
635		while (len + full_len > buffer_size - 1) {
636			buffer_size += buffer_size;
637			md5_string = realloc(md5_string, buffer_size);
638		}
639
640		strncat(md5_string, string, len);
641
642		full_len += len;
643		md5_string[full_len] = '\0';
644	}
645	va_end(argp);
646
647	str_len = strlen(md5_string);
648	MD5((const unsigned char*)md5_string, (unsigned int)str_len, temp);
649
650	free(md5_string);
651
652	sprint_hex(output, temp, MD5_DIGEST_LENGTH);
653	output[129] = '\0';
654}
655#endif
656
657static int get_minidlna_db_path(plugin_data *p){
658
659	if(is_dms_enabled()==0){
660		return 0;
661	}
662
663	//- 20130603 JerryLin add
664	int bOpenConfigFle = 1;
665#if EMBEDDED_EANBLE
666	char* db_dir = nvram_get_dms_dbcwd();
667	if(db_dir){
668		buffer_copy_string_len(p->minidlna_db_dir, db_dir, strlen(db_dir));
669		buffer_copy_string_len(p->minidlna_db_file, db_dir, strlen(db_dir));
670		buffer_append_string(p->minidlna_db_file, "/files.db");
671		bOpenConfigFle = 0;
672	}
673
674	char* media_dir = nvram_get_dms_dir();
675	if(media_dir){
676		buffer_copy_string_len(p->minidlna_media_dir, media_dir, strlen(media_dir));
677		bOpenConfigFle = 0;
678	}
679#endif
680	if(bOpenConfigFle==1){
681		FILE* fp2;
682		char line[128];
683		char* minidla_config_file = NULL;
684		char* minidla_config_file_tmp = "/etc/minidlna.conf";
685		if(access(minidla_config_file_tmp,R_OK) == 0)
686			minidla_config_file = "/etc/minidlna.conf";
687		else
688			minidla_config_file = "/opt/etc/minidlna.conf";
689
690		if((fp2 = fopen(minidla_config_file, "r")) != NULL){
691			memset(line, 0, sizeof(line));
692			while(fgets(line, 128, fp2) != NULL){
693				if(strncmp(line, "db_dir=", 7)==0){
694					char tmp[100] = "\0";
695					strncpy(tmp, line + 7, strlen(line)-7);
696					tmp[strlen(tmp)-1]='\0';
697
698					buffer_copy_string_len(p->minidlna_db_dir, tmp, strlen(tmp) );
699
700					strcat(tmp, "/files.db");
701					buffer_copy_string_len(p->minidlna_db_file, tmp, strlen(tmp) );
702				}
703				else if(strncmp(line, "media_dir=", 10)==0){
704					char tmp[100] = "\0";
705					strncpy(tmp, line + 10, strlen(line)-10);
706					tmp[strlen(tmp)-1]='\0';
707
708					buffer_copy_string_len(p->minidlna_media_dir, tmp, strlen(tmp) );
709				}
710			}
711			fclose(fp2);
712		}
713	}
714
715#if EMBEDDED_EANBLE
716#ifdef APP_IPKG
717	if(db_dir)
718		free(db_dir);
719
720	if(media_dir)
721		free(media_dir);
722#endif
723#endif
724	//Cdbg(DBE, ".............................minidlna_db_dir=%s", p->minidlna_db_dir->ptr);
725	//Cdbg(DBE, ".............................minidlna_db_file=%s", p->minidlna_db_file->ptr);
726	//Cdbg(DBE, ".............................minidlna_media_dir=%s", p->minidlna_media_dir->ptr);
727
728}
729
730static int get_thumb_image(char* path, plugin_data *p, unsigned char **out){
731	if(is_dms_enabled()==0){
732		return 0;
733	}
734
735#if EMBEDDED_EANBLE
736	char* thumb_dir = (char *)malloc(PATH_MAX);
737	if(!thumb_dir) return 0;
738
739	if (buffer_is_empty(p->minidlna_db_dir))
740		get_minidlna_db_path(p);
741
742	strcpy(thumb_dir, p->minidlna_db_dir->ptr);
743	strcat(thumb_dir, "/art_cache/tmp");
744
745	char* filename = NULL;
746	extract_filename(path, &filename);
747	const char *dot = strrchr(filename, '.');
748	int len = dot - filename;
749
750	char* filepath = NULL;
751	extract_filepath(path, &filepath);
752
753	strcat(thumb_dir, filepath);
754	strncat(thumb_dir, filename, len);
755	strcat(thumb_dir, ".jpg");
756
757	free(filename);
758	free(filepath);
759#else
760	char* db_dir = "/var/lib/minidlna/";
761	char* thumb_dir = (char *)malloc(PATH_MAX);
762
763	if(!thumb_dir){
764		return 0;
765	}
766	strcpy(thumb_dir, db_dir);
767	strcat(thumb_dir, "art_cache");
768
769	char* filename = NULL;
770	extract_filename(path, &filename);
771	const char *dot = strrchr(filename, '.');
772	int index = dot - filename;
773	//Cdbg(DBE,"dot = %s, index=%d", dot, index);
774
775	char* filepath = NULL;
776	extract_filepath(path, &filepath);
777
778	Cdbg(DBE,"filepath=%s, filename=%s", filepath, filename);
779
780	strcat(thumb_dir, filepath);
781	strncat(thumb_dir, filename, index);
782	strcat(thumb_dir, ".jpg");
783
784	free(filename);
785	free(filepath);
786
787#endif
788	Cdbg(DBE,"thumb_dir=%s", thumb_dir);
789
790	int result = 0;
791
792	FILE* fp = fopen(thumb_dir, "rb");
793
794	if(fp!=NULL){
795		Cdbg(DBE, "success to open thumb_dir=%s", thumb_dir);
796		//Get file length
797       	fseek(fp, 0, SEEK_END);
798       	int fileLen = ftell(fp);
799       	fseek(fp, 0, SEEK_SET);
800
801		char* buffer = (char *)malloc(fileLen+1);
802		if(buffer){
803			fread( buffer, fileLen, sizeof(unsigned char), fp );
804
805			unsigned char* tmp = ldb_base64_encode(buffer, fileLen);
806			uint32 olen = strlen(tmp) + 1;
807			*out = (char*)malloc(olen);
808			memcpy(*out, tmp, olen);
809
810			free(tmp);
811			free(buffer);
812
813			fclose(fp);
814
815			result = 1;
816		}
817	}
818
819	free(thumb_dir);
820	return result;
821}
822
823static int get_album_cover_image(sqlite3 *sql_minidlna, sqlite_int64 plAlbumArt, unsigned char **out){
824	if(is_dms_enabled()==0){
825		return 0;
826	}
827
828	if(plAlbumArt<=0){
829		return 0;
830	}
831
832	int rows2;
833	char **result2;
834	char* base64_image = NULL;
835	char sql_query[2048] = "\0";
836
837	sprintf(sql_query, "SELECT PATH FROM ALBUM_ART WHERE ID = '%lld'", plAlbumArt );
838	if( sql_get_table(sql_minidlna, sql_query, &result2, &rows2, NULL) == SQLITE_OK ){
839		//Cdbg(DBE, "get_album_cover_image, album cover path=%s", result2[1]);
840
841		char* album_cover_file = result2[1];
842
843		FILE* fp = fopen(album_cover_file, "rb");
844
845		if(fp!=NULL){
846			//Get file length
847	       	fseek(fp, 0, SEEK_END);
848	       	int fileLen = ftell(fp);
849	       	fseek(fp, 0, SEEK_SET);
850
851			char* buffer = (char *)malloc(fileLen+1);
852			if(!buffer){
853				return 0;
854			}
855			char* aa = get_filename_ext(album_cover_file);
856			int len = strlen(aa)+1;
857			char* file_ext = (char*)malloc(len);
858			memset(file_ext,'\0', len);
859			strcpy(file_ext, aa);
860			for (int i = 0; file_ext[i]; i++)
861				file_ext[i] = tolower(file_ext[i]);
862
863			fread( buffer, fileLen, sizeof(unsigned char), fp );
864
865			unsigned char* tmp = ldb_base64_encode(buffer, fileLen);
866			uint32 olen = strlen(tmp) + 1;
867			*out = (char*)malloc(olen);
868			memcpy(*out, tmp, olen);
869
870			free(tmp);
871			free(file_ext);
872			free(buffer);
873
874			fclose(fp);
875		}
876
877	}
878	sqlite3_free_table(result2);
879
880	return 1;
881}
882
883static int webdav_gen_prop_tag(server *srv, connection *con,
884		char *prop_name,
885		char *prop_ns,
886		char *value,
887		buffer *b) {
888
889	UNUSED(srv);
890	UNUSED(con);
891
892	if (value) {
893		buffer_append_string_len(b,CONST_STR_LEN("<"));
894		buffer_append_string(b, prop_name);
895		buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
896		buffer_append_string(b, prop_ns);
897		buffer_append_string_len(b, CONST_STR_LEN("\">"));
898
899		buffer_append_string(b, value);
900
901		buffer_append_string_len(b,CONST_STR_LEN("</"));
902		buffer_append_string(b, prop_name);
903		buffer_append_string_len(b, CONST_STR_LEN(">"));
904	} else {
905		buffer_append_string_len(b,CONST_STR_LEN("<"));
906		buffer_append_string(b, prop_name);
907		buffer_append_string_len(b, CONST_STR_LEN(" xmlns=\""));
908		buffer_append_string(b, prop_ns);
909		buffer_append_string_len(b, CONST_STR_LEN("\"/>"));
910	}
911
912	return 0;
913}
914
915
916static int webdav_gen_response_status_tag(server *srv, connection *con, physical *dst, int status, buffer *b) {
917	UNUSED(srv);
918
919	buffer_append_string_len(b,CONST_STR_LEN("<D:response xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
920
921	buffer_append_string_len(b,CONST_STR_LEN("<D:href>\n"));
922	buffer_append_string_buffer(b, dst->rel_path);
923	buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
924	buffer_append_string_len(b,CONST_STR_LEN("<D:status>\n"));
925
926	if (con->request.http_version == HTTP_VERSION_1_1) {
927		buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 "));
928	} else {
929		buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 "));
930	}
931	buffer_append_int(b, status);
932	buffer_append_string_len(b, CONST_STR_LEN(" "));
933	buffer_append_string(b, get_http_status_name(status));
934
935	buffer_append_string_len(b,CONST_STR_LEN("</D:status>\n"));
936	buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
937
938	return 0;
939}
940
941static int webdav_delete_file(server *srv, connection *con, plugin_data *p, physical *dst, buffer *b) {
942	int status = 0;
943
944	/* try to unlink it */
945	if (-1 == unlink(dst->path->ptr)) {
946		switch(errno) {
947		case EACCES:
948		case EPERM:
949			/* 403 */
950			status = 403;
951			break;
952		default:
953			status = 501;
954			break;
955		}
956		webdav_gen_response_status_tag(srv, con, dst, status, b);
957	} else {
958#ifdef USE_PROPPATCH
959		sqlite3_stmt *stmt = p->conf.stmt_delete_uri;
960
961		if (!stmt) {
962			status = 403;
963			webdav_gen_response_status_tag(srv, con, dst, status, b);
964		} else {
965			sqlite3_reset(stmt);
966
967			/* bind the values to the insert */
968
969			sqlite3_bind_text(stmt, 1,
970				CONST_BUF_LEN(dst->rel_path),
971				SQLITE_TRANSIENT);
972
973			if (SQLITE_DONE != sqlite3_step(stmt)) {
974				/* */
975			}
976		}
977#else
978		UNUSED(p);
979#endif
980	}
981
982	return (status != 0);
983}
984
985static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physical *dst, buffer *b) {
986	DIR *dir;
987	int have_multi_status = 0;
988	physical d;
989
990	d.path = buffer_init();
991	d.rel_path = buffer_init();
992
993	if (NULL != (dir = opendir(dst->path->ptr))) {
994		struct dirent *de;
995
996		while(NULL != (de = readdir(dir))) {
997			struct stat st;
998			int status = 0;
999
1000			if ((de->d_name[0] == '.' && de->d_name[1] == '\0')  ||
1001			  (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
1002				continue;
1003				/* ignore the parent dir */
1004			}
1005
1006			buffer_copy_buffer(d.path, dst->path);
1007			buffer_append_slash(d.path);
1008			buffer_append_string(d.path, de->d_name);
1009
1010			buffer_copy_buffer(d.rel_path, dst->rel_path);
1011			buffer_append_slash(d.rel_path);
1012			buffer_append_string(d.rel_path, de->d_name);
1013
1014			/* stat and unlink afterwards */
1015			if (-1 == stat(d.path->ptr, &st)) {
1016				/* don't about it yet, rmdir will fail too */
1017			} else if (S_ISDIR(st.st_mode)) {
1018				have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
1019
1020				/* try to unlink it */
1021				if (-1 == rmdir(d.path->ptr)) {
1022					switch(errno) {
1023					case EACCES:
1024					case EPERM:
1025						/* 403 */
1026						status = 403;
1027						break;
1028					default:
1029						status = 501;
1030						break;
1031					}
1032					have_multi_status = 1;
1033
1034					webdav_gen_response_status_tag(srv, con, &d, status, b);
1035				} else {
1036#ifdef USE_PROPPATCH
1037					sqlite3_stmt *stmt = p->conf.stmt_delete_uri;
1038
1039					status = 0;
1040
1041					if (stmt) {
1042						sqlite3_reset(stmt);
1043
1044						/* bind the values to the insert */
1045
1046						sqlite3_bind_text(stmt, 1,
1047							CONST_BUF_LEN(d.rel_path),
1048							SQLITE_TRANSIENT);
1049
1050						if (SQLITE_DONE != sqlite3_step(stmt)) {
1051							/* */
1052						}
1053					}
1054#endif
1055				}
1056			} else {
1057				have_multi_status = webdav_delete_file(srv, con, p, &d, b);
1058			}
1059		}
1060		closedir(dir);
1061
1062		buffer_free(d.path);
1063		buffer_free(d.rel_path);
1064	}
1065
1066	return have_multi_status;
1067}
1068
1069static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {
1070	stream s;
1071	int status = 0, ofd;
1072	UNUSED(srv);
1073	UNUSED(con);
1074
1075	if (stream_open(&s, src->path)) {
1076		return 403;
1077	}
1078
1079	if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), WEBDAV_FILE_MODE))) {
1080		/* opening the destination failed for some reason */
1081		switch(errno) {
1082		case EEXIST:
1083			status = 412;
1084			break;
1085		case EISDIR:
1086			status = 409;
1087			break;
1088		case ENOENT:
1089			/* at least one part in the middle wasn't existing */
1090			status = 409;
1091			break;
1092		default:
1093			status = 403;
1094			break;
1095		}
1096		stream_close(&s);
1097		return status;
1098	}
1099
1100	if (-1 == write(ofd, s.start, s.size)) {
1101		switch(errno) {
1102		case ENOSPC:
1103			status = 507;
1104			break;
1105		default:
1106			status = 403;
1107			break;
1108		}
1109	}
1110
1111	stream_close(&s);
1112	close(ofd);
1113
1114#ifdef USE_PROPPATCH
1115	if (0 == status) {
1116		/* copy worked fine, copy connected properties */
1117		sqlite3_stmt *stmt = p->conf.stmt_copy_uri;
1118
1119		if (stmt) {
1120			sqlite3_reset(stmt);
1121
1122			/* bind the values to the insert */
1123			sqlite3_bind_text(stmt, 1,
1124				CONST_BUF_LEN(dst->rel_path),
1125				SQLITE_TRANSIENT);
1126
1127			sqlite3_bind_text(stmt, 2,
1128				CONST_BUF_LEN(src->rel_path),
1129				SQLITE_TRANSIENT);
1130
1131			if (SQLITE_DONE != sqlite3_step(stmt)) {
1132				/* */
1133			}
1134		}
1135	}
1136#else
1137	UNUSED(p);
1138#endif
1139	return status;
1140}
1141
1142static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) {
1143	DIR *srcdir;
1144	int status = 0;
1145
1146	if (NULL != (srcdir = opendir(src->path->ptr))) {
1147		struct dirent *de;
1148		physical s, d;
1149
1150		s.path = buffer_init();
1151		s.rel_path = buffer_init();
1152
1153		d.path = buffer_init();
1154		d.rel_path = buffer_init();
1155
1156		while (NULL != (de = readdir(srcdir))) {
1157			struct stat st;
1158
1159			if ((de->d_name[0] == '.' && de->d_name[1] == '\0')
1160				|| (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
1161				continue;
1162			}
1163
1164			buffer_copy_buffer(s.path, src->path);
1165			buffer_append_slash(s.path);
1166			buffer_append_string(s.path, de->d_name);
1167
1168			buffer_copy_buffer(d.path, dst->path);
1169			buffer_append_slash(d.path);
1170			buffer_append_string(d.path, de->d_name);
1171
1172			buffer_copy_buffer(s.rel_path, src->rel_path);
1173			buffer_append_slash(s.rel_path);
1174			buffer_append_string(s.rel_path, de->d_name);
1175
1176			buffer_copy_buffer(d.rel_path, dst->rel_path);
1177			buffer_append_slash(d.rel_path);
1178			buffer_append_string(d.rel_path, de->d_name);
1179
1180			if (-1 == stat(s.path->ptr, &st)) {
1181				/* why ? */
1182			} else if (S_ISDIR(st.st_mode)) {
1183				/* a directory */
1184				if (-1 == mkdir(d.path->ptr, WEBDAV_DIR_MODE) &&
1185				    errno != EEXIST) {
1186					/* WTH ? */
1187				} else {
1188#ifdef USE_PROPPATCH
1189					sqlite3_stmt *stmt = p->conf.stmt_copy_uri;
1190
1191					if (0 != (status = webdav_copy_dir(srv, con, p, &s, &d, overwrite))) {
1192						break;
1193					}
1194					/* directory is copied, copy the properties too */
1195
1196					if (stmt) {
1197						sqlite3_reset(stmt);
1198
1199						/* bind the values to the insert */
1200						sqlite3_bind_text(stmt, 1,
1201							CONST_BUF_LEN(dst->rel_path),
1202							SQLITE_TRANSIENT);
1203
1204						sqlite3_bind_text(stmt, 2,
1205							CONST_BUF_LEN(src->rel_path),
1206							SQLITE_TRANSIENT);
1207
1208						if (SQLITE_DONE != sqlite3_step(stmt)) {
1209							/* */
1210						}
1211					}
1212#endif
1213				}
1214			} else if (S_ISREG(st.st_mode)) {
1215				/* a plain file */
1216				if (0 != (status = webdav_copy_file(srv, con, p, &s, &d, overwrite))) {
1217					break;
1218				}
1219			}
1220		}
1221
1222		buffer_free(s.path);
1223		buffer_free(s.rel_path);
1224		buffer_free(d.path);
1225		buffer_free(d.rel_path);
1226
1227		closedir(srcdir);
1228	}
1229
1230	return status;
1231}
1232
1233static int webdav_get_live_property(server *srv, connection *con, plugin_data *p, physical *dst, char *prop_name, buffer *b) {
1234	stat_cache_entry *sce = NULL;
1235	int found = 0;
1236
1237	UNUSED(p);
1238
1239	if (HANDLER_ERROR != (stat_cache_get_entry(srv, con, dst->path, &sce))) {
1240		char ctime_buf[] = "2005-08-18T07:27:16Z";
1241		char mtime_buf[] = "Thu, 18 Aug 2005 07:27:16 GMT";
1242		size_t k;
1243
1244		if (0 == strcmp(prop_name, "resourcetype")) {
1245			if (S_ISDIR(sce->st.st_mode)) {
1246				buffer_append_string_len(b, CONST_STR_LEN("<D:resourcetype><D:collection/></D:resourcetype>"));
1247				found = 1;
1248			}
1249		} else if (0 == strcmp(prop_name, "getcontenttype")) {
1250			if (S_ISDIR(sce->st.st_mode)) {
1251				buffer_append_string_len(b, CONST_STR_LEN("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));
1252				found = 1;
1253			} else if(S_ISREG(sce->st.st_mode)) {
1254				for (k = 0; k < con->conf.mimetypes->used; k++) {
1255					data_string *ds = (data_string *)con->conf.mimetypes->data[k];
1256
1257					if (buffer_is_empty(ds->key)) continue;
1258
1259					if (buffer_is_equal_right_len(dst->path, ds->key, buffer_string_length(ds->key))) {
1260						buffer_append_string_len(b,CONST_STR_LEN("<D:getcontenttype>"));
1261						buffer_append_string_buffer(b, ds->value);
1262						buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
1263						found = 1;
1264
1265						break;
1266					}
1267				}
1268			}
1269		} else if (0 == strcmp(prop_name, "creationdate")) {
1270			//buffer_append_string_len(b, CONST_STR_LEN("<D:creationdate ns0:dt=\"dateTime.tz\">"));
1271                        buffer_append_string_len(b, CONST_STR_LEN("<D:creationdate>"));
1272			strftime(ctime_buf, sizeof(ctime_buf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&(sce->st.st_ctime)));
1273			buffer_append_string(b, ctime_buf);
1274			buffer_append_string_len(b, CONST_STR_LEN("</D:creationdate>"));
1275			found = 1;
1276		} else if (0 == strcmp(prop_name, "getlastmodified")) {
1277			//buffer_append_string_len(b,CONST_STR_LEN("<D:getlastmodified ns0:dt=\"dateTime.rfc1123\">"));
1278			buffer_append_string_len(b,CONST_STR_LEN("<D:getlastmodified>"));
1279			strftime(mtime_buf, sizeof(mtime_buf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(sce->st.st_mtime)));
1280			//strftime(mtime_buf, sizeof(mtime_buf), "%Y/%m/%d %H:%M:%S", localtime(&(sce->st.st_mtime)));
1281			buffer_append_string(b, mtime_buf);
1282			buffer_append_string_len(b, CONST_STR_LEN("</D:getlastmodified>"));
1283			found = 1;
1284		} else if (0 == strcmp(prop_name, "getcontentlength")) {
1285			buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlength>"));
1286			buffer_append_int(b, sce->st.st_size);
1287			buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlength>"));
1288			found = 1;
1289		} else if (0 == strcmp(prop_name, "getcontentlanguage")) {
1290			buffer_append_string_len(b,CONST_STR_LEN("<D:getcontentlanguage>"));
1291			buffer_append_string_len(b, CONST_STR_LEN("en"));
1292			buffer_append_string_len(b, CONST_STR_LEN("</D:getcontentlanguage>"));
1293			found = 1;
1294		}else if (0 == strcmp(prop_name, "getmac")) {
1295			//- 20111124 Jerry add
1296			buffer_append_string_len(b,CONST_STR_LEN("<D:getmac>"));
1297			buffer_append_string_len(b, CONST_STR_LEN("</D:getmac>"));
1298			found = 1;
1299		}else if (0 == strcmp(prop_name, "getonline")) {
1300			//- 20111219 Jerry add
1301			buffer_append_string_len(b,CONST_STR_LEN("<D:getonline>"));
1302			buffer_append_string_len(b, CONST_STR_LEN("1"));
1303			buffer_append_string_len(b, CONST_STR_LEN("</D:getonline>"));
1304			found = 1;
1305		}else if (0 == strcmp(prop_name, "getuniqueid")) {
1306			//- 20120104 Jerry add
1307			buffer_append_string_len(b,CONST_STR_LEN("<D:getuniqueid>"));
1308			char* result;
1309			md5String(dst->rel_path->ptr, NULL, &result);
1310			buffer_append_string(b, result);
1311			free(result);
1312			buffer_append_string_len(b, CONST_STR_LEN("</D:getuniqueid>"));
1313			found = 1;
1314		}else if (0 == strcmp(prop_name, "getattr")) {
1315			//- 20120302 Jerry add
1316			buffer_append_string_len(b,CONST_STR_LEN("<D:getattr>"));
1317
1318			int permission = -1;
1319		#if EMBEDDED_EANBLE
1320			char* usbdisk_rel_sub_path = NULL;
1321			char* usbdisk_sub_share_folder = NULL;
1322
1323			smbc_parse_mnt_path(dst->path->ptr,
1324				                p->mnt_path->ptr,
1325				                p->mnt_path->used-1,
1326				                &usbdisk_rel_sub_path,
1327				                &usbdisk_sub_share_folder);
1328
1329			permission = smbc_get_usbdisk_permission(con->aidisk_username->ptr, usbdisk_rel_sub_path, usbdisk_sub_share_folder);
1330
1331			free(usbdisk_rel_sub_path);
1332			free(usbdisk_sub_share_folder);
1333
1334			buffer_append_string_len(b, CONST_STR_LEN("<D:readonly>"));
1335			if( permission == 3 )
1336				buffer_append_string_len(b, CONST_STR_LEN("false"));
1337			else
1338				buffer_append_string_len(b, CONST_STR_LEN("true"));
1339			buffer_append_string_len(b, CONST_STR_LEN("</D:readonly>"));
1340		#else
1341			buffer_append_string_len(b, CONST_STR_LEN("<D:readonly>"));
1342			buffer_append_string_len(b, CONST_STR_LEN("true"));
1343			buffer_append_string_len(b, CONST_STR_LEN("</D:readonly>"));
1344		#endif
1345
1346			buffer_append_string_len(b, CONST_STR_LEN("<D:hidden>"));
1347			buffer_append_string_len(b, CONST_STR_LEN("false"));
1348			buffer_append_string_len(b, CONST_STR_LEN("</D:hidden>"));
1349
1350			buffer_append_string_len(b, CONST_STR_LEN("</D:getattr>"));
1351
1352			found = 1;
1353		}
1354		else if (0 == strcmp(prop_name, "gettype")) {
1355			//- 20120208 Jerry add
1356			buffer_append_string_len(b,CONST_STR_LEN("<D:gettype>"));
1357			buffer_append_string(b, "usbdisk");
1358			buffer_append_string_len(b, CONST_STR_LEN("</D:gettype>"));
1359			found = 1;
1360		}
1361		else if (0 == strcmp(prop_name, "getuseragent")) {
1362			//- 20121205 Jerry add
1363			buffer_append_string_len(b,CONST_STR_LEN("<D:getuseragent>"));
1364			if(con->smb_info){
1365				buffer_append_string_buffer(b, con->smb_info->user_agent);
1366			}
1367			buffer_append_string_len(b, CONST_STR_LEN("</D:getuseragent>"));
1368			found = 1;
1369		}
1370		else if (0 == strcmp(prop_name, "getroutersync")) {
1371			//- 20121206 Jerry add
1372			buffer_append_string_len(b,CONST_STR_LEN("<D:getroutersync>"));
1373
1374			share_link_info_t* c;
1375			int is_router_sync_folder = 0;
1376			buffer* temp = buffer_init();
1377
1378			for (c = share_link_info_list; c; c = c->next) {
1379
1380				if(c->toshare != 2)
1381					continue;
1382
1383				buffer_append_string_buffer(temp, c->realpath);
1384				buffer_append_string(temp, "/");
1385				buffer_append_string_buffer(temp, c->filename);
1386
1387				if(buffer_is_equal(temp,dst->rel_path)){
1388					is_router_sync_folder = 1;
1389					break;
1390				}
1391			}
1392
1393			buffer_free(temp);
1394
1395			if(is_router_sync_folder==1)
1396				buffer_append_string(b, "1");
1397			else
1398				buffer_append_string(b, "0");
1399
1400			buffer_append_string_len(b, CONST_STR_LEN("</D:getroutersync>"));
1401			found = 1;
1402		}
1403		else if (0 == strcmp(prop_name, "getmetadata")) {
1404#if 1
1405			buffer_append_string_len(b,CONST_STR_LEN("<D:getmetadata>"));
1406
1407			if(is_dms_enabled()==1){
1408
1409				int rows, i;
1410				sqlite3 *sql_minidlna = NULL;
1411				char **result;
1412				char sql_query[2048] = "\0";
1413
1414				get_minidlna_db_path(p);
1415
1416				if (!buffer_is_empty(p->minidlna_db_file)) {
1417					if (SQLITE_OK != sqlite3_open(p->minidlna_db_file->ptr, &(sql_minidlna))) {
1418						Cdbg(DBE, "Fail to open minidlna db %s", p->minidlna_db_file->ptr);
1419					}
1420				}
1421
1422				if (sql_minidlna) {
1423
1424					int column_count = 11;
1425					sprintf(sql_query, "SELECT ID, TITLE, SIZE, TIMESTAMP, THUMBNAIL, RESOLUTION, CREATOR, ARTIST, MIME, ALBUM, ALBUM_ART from DETAILS");
1426
1427					#if EMBEDDED_EANBLE
1428					if (0 == strcmp(dst->path->ptr, "/tmp"))
1429						sprintf(sql_query, "%s WHERE PATH = '%s'", sql_query, dst->path->ptr);
1430					else
1431						sprintf(sql_query, "%s WHERE PATH = '/tmp%s'", sql_query, dst->path->ptr);
1432					#else
1433					sprintf(sql_query, "%s WHERE PATH = '%s'", sql_query, dst->path->ptr);
1434					#endif
1435
1436					//Cdbg(DBE, "sql_query=%s", sql_query);
1437
1438					if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
1439						if( rows ){
1440							sqlite_int64 plID = strtoll(result[column_count], NULL, 10);
1441							char* plname = result[column_count+1];
1442							char* thumbnail = result[column_count+4];
1443							char* resolution = result[column_count+5];
1444							char* creator = result[column_count+6];
1445							char* artist = result[column_count+7];
1446							char* mime = result[column_count+8];
1447							char* album = result[column_count+9];
1448							char* album_art = result[column_count+10];
1449
1450							if(plname){
1451								int thumb = atoi(thumbnail);
1452
1453								buffer_append_string_len(b, CONST_STR_LEN("<D:title>"));
1454								buffer_append_string(b, plname);
1455								buffer_append_string_len(b, CONST_STR_LEN("</D:title>"));
1456
1457								buffer_append_string_len(b, CONST_STR_LEN("<D:resolution>"));
1458								buffer_append_string(b, resolution);
1459								buffer_append_string_len(b, CONST_STR_LEN("</D:resolution>"));
1460
1461								buffer_append_string_len(b, CONST_STR_LEN("<D:creator><![CDATA["));
1462								buffer_append_string(b, creator);
1463								buffer_append_string_len(b, CONST_STR_LEN("]]></D:creator>"));
1464
1465								buffer_append_string_len(b, CONST_STR_LEN("<D:artist><![CDATA["));
1466								buffer_append_string(b, artist);
1467								buffer_append_string_len(b, CONST_STR_LEN("]]></D:artist>"));
1468
1469								buffer_append_string_len(b, CONST_STR_LEN("<D:mime>"));
1470								buffer_append_string(b, mime);
1471								buffer_append_string_len(b, CONST_STR_LEN("</D:mime>"));
1472
1473								buffer_append_string_len(b, CONST_STR_LEN("<D:thumb>"));
1474								//buffer_append_string(b, thumbnail);
1475								buffer_append_string_len(b, CONST_STR_LEN("1"));
1476								buffer_append_string_len(b, CONST_STR_LEN("</D:thumb>"));
1477
1478								//Cdbg(DBE, "plname=%s, thumb=%d, resolution=%s, creator=%s, artist=%s, mime=%s, album_art=%s", plname, thumb, resolution, creator, artist, mime, album_art);
1479
1480								#if 0
1481								char* image = NULL;
1482								if(thumb==1){
1483									if(get_thumb_image(dst->path->ptr, &image)==1){
1484										buffer_append_string_len(b, CONST_STR_LEN("<D:thumb_image>"));
1485										buffer_append_string(b, image);
1486										buffer_append_string_len(b, CONST_STR_LEN("</D:thumb_image>"));
1487										free(image);
1488									}
1489								}
1490								else{
1491									sqlite_int64 plAlbumArt = (album_art ? strtoll(album_art, NULL, 10) : 0);
1492									if(get_album_cover_image(sql_minidlna, plAlbumArt, &image)==1){
1493										buffer_append_string_len(b, CONST_STR_LEN("<D:thumb_image>"));
1494										buffer_append_string(b, image);
1495										buffer_append_string_len(b, CONST_STR_LEN("</D:thumb_image>"));
1496										free(image);
1497									}
1498								}
1499								#endif
1500							}
1501						}
1502
1503						sqlite3_free_table(result);
1504					}
1505
1506					sqlite3_close(sql_minidlna);
1507				}
1508			}
1509
1510#if 0
1511			//- http request test
1512			struct sockaddr_in their_addr; /* connector's address information */
1513			int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
1514			if (serverSocket == -1)
1515				Cdbg(DBE, "serverSocket == -1" );
1516
1517			bzero(&(their_addr), sizeof(their_addr)); /* zero the rest of the struct */
1518    		their_addr.sin_family = AF_INET; /* host byte order */
1519    		their_addr.sin_port = htons(8082); /* short, network byte order */
1520   	 		their_addr.sin_addr.s_addr = htonl(INADDR_ANY);
1521
1522			bzero(&(their_addr.sin_zero), sizeof(their_addr.sin_zero)); /* zero the rest of the struct */
1523		    if (connect(serverSocket, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) {
1524
1525		        Cdbg(DBE, "connect error");
1526		    }
1527
1528			//- http://imdbapi.org/?title=Batman Begins&type=xml
1529			char request[1024]="\0";
1530			sprintf(request, "GET %s HTTP/1.0\r\nHOST:%s \r\n", "/?title=Batman&type=xml", "http://imdbapi.org/");
1531
1532			Cdbg(DBE, "request = %s", request );
1533
1534			if( send(serverSocket, &request, sizeof(request), 0) < 0 )
1535    			Cdbg(DBE, "send()");
1536
1537			int numbytes;
1538			char buf[1024];
1539			if ((numbytes=recv(serverSocket, buf, 1024, 0)) == -1) {
1540        		Cdbg(DBE, "recv error");
1541			}
1542
1543    		buf[numbytes] = '\0';
1544
1545			close(serverSocket);
1546			Cdbg(DBE, "buf=%s", buf);
1547			////////////////////////////////////
1548#endif
1549
1550#if 0
1551
1552			char url[1024]="\0";
1553			sprintf(url, "%s", "http://imdbapi.org/?title=Batman&type=xml");
1554
1555			char init_upload_xml[1024]="/tmp/aaa.xml";
1556			int status = sendRequest(init_upload_xml,url,NULL,NULL,NULL);
1557#endif
1558
1559			buffer_append_string_len(b, CONST_STR_LEN("</D:getmetadata>"));
1560
1561			found = 1;
1562#endif
1563		}
1564		/*else if (0 == strcmp(prop_name, "getname")) {
1565			//- 20120920 Jerry add
1566			buffer_append_string_len(b,CONST_STR_LEN("<D:getname>"));
1567			buffer_append_string_len(b,CONST_STR_LEN("sda"));
1568			buffer_append_string_len(b, CONST_STR_LEN("</D:getname>"));
1569			found = 1;
1570		}else if (0 == strcmp(prop_name, "getpath")) {
1571			//- 20120920 Jerry add
1572			buffer_append_string_len(b,CONST_STR_LEN("<D:getpath>"));
1573			buffer_append_string_buffer(b,dst->rel_path);
1574			buffer_append_string_len(b, CONST_STR_LEN("</D:getpath>"));
1575			found = 1;
1576		}*/
1577	}
1578
1579	return found ? 0 : -1;
1580}
1581
1582static int webdav_get_property(server *srv, connection *con, plugin_data *p, physical *dst, char *prop_name, char *prop_ns, buffer *b) {
1583	if (0 == strcmp(prop_ns, "DAV:")) {
1584		/* a local 'live' property */
1585		return webdav_get_live_property(srv, con, p, dst, prop_name, b);
1586	} else {
1587		int found = 0;
1588#ifdef USE_PROPPATCH
1589		sqlite3_stmt *stmt = p->conf.stmt_select_prop;
1590
1591		if (stmt) {
1592			/* perhaps it is in sqlite3 */
1593			sqlite3_reset(stmt);
1594
1595			/* bind the values to the insert */
1596
1597			sqlite3_bind_text(stmt, 1,
1598				CONST_BUF_LEN(dst->rel_path),
1599				SQLITE_TRANSIENT);
1600			sqlite3_bind_text(stmt, 2,
1601				prop_name,
1602				strlen(prop_name),
1603				SQLITE_TRANSIENT);
1604			sqlite3_bind_text(stmt, 3,
1605				prop_ns,
1606				strlen(prop_ns),
1607				SQLITE_TRANSIENT);
1608
1609			/* it is the PK */
1610			while (SQLITE_ROW == sqlite3_step(stmt)) {
1611				/* there is a row for us, we only expect a single col 'value' */
1612				webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
1613				found = 1;
1614			}
1615		}
1616#endif
1617		return found ? 0 : -1;
1618	}
1619
1620	/* not found */
1621	return -1;
1622}
1623
1624typedef struct {
1625	char *ns;
1626	char *prop;
1627} webdav_property;
1628
1629static webdav_property live_properties[] = {
1630	{ "DAV:", "creationdate" },
1631	{ "DAV:", "displayname" },
1632	{ "DAV:", "getcontentlanguage" },
1633	{ "DAV:", "getcontentlength" },
1634	{ "DAV:", "getcontenttype" },
1635	{ "DAV:", "getetag" },
1636	{ "DAV:", "getlastmodified" },
1637	{ "DAV:", "resourcetype" },
1638	{ "DAV:", "lockdiscovery" },
1639	{ "DAV:", "source" },
1640	{ "DAV:", "supportedlock" },
1641	{ "DAV:", "getmac" },
1642	{ "DAV:", "getonline" },
1643	{ "DAV:", "getuniqueid" },
1644	{ "DAV:", "gettype" },
1645	{ "DAV:", "getattr" },
1646	{ "DAV:", "getname" },
1647	{ "DAV:", "getpath" },
1648	{ "DAV:", "getuseragent" },
1649	{ "DAV:", "getroutersync" },
1650	{ "DAV:", "getmetadata" },
1651
1652	{ NULL, NULL }
1653};
1654
1655typedef struct {
1656	webdav_property **ptr;
1657
1658	size_t used;
1659	size_t size;
1660} webdav_properties;
1661
1662static int webdav_get_props(server *srv, connection *con, plugin_data *p, physical *dst, webdav_properties *props, buffer *b_200, buffer *b_404) {
1663	size_t i;
1664
1665	if (props) {
1666		for (i = 0; i < props->used; i++) {
1667			webdav_property *prop;
1668
1669			prop = props->ptr[i];
1670
1671			if (0 != webdav_get_property(srv, con, p,
1672				dst, prop->prop, prop->ns, b_200)) {
1673				webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
1674			}
1675		}
1676	} else {
1677		for (i = 0; live_properties[i].prop; i++) {
1678			/* a local 'live' property */
1679			webdav_get_live_property(srv, con, p, dst, live_properties[i].prop, b_200);
1680		}
1681	}
1682
1683	return 0;
1684}
1685
1686#ifdef USE_PROPPATCH
1687static int webdav_parse_chunkqueue(server *srv, connection *con, plugin_data *p, chunkqueue *cq, xmlDoc **ret_xml) {
1688	xmlParserCtxtPtr ctxt;
1689	xmlDoc *xml;
1690	int res;
1691	int err;
1692
1693	chunk *c;
1694
1695	UNUSED(con);
1696
1697	/* read the chunks in to the XML document */
1698	ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
1699
1700	for (c = cq->first; cq->bytes_out != cq->bytes_in; c = cq->first) {
1701		size_t weWant = cq->bytes_out - cq->bytes_in;
1702		size_t weHave;
1703
1704		switch(c->type) {
1705		case FILE_CHUNK:
1706			weHave = c->file.length - c->offset;
1707
1708			if (weHave > weWant) weHave = weWant;
1709
1710			/* xml chunks are always memory, mmap() is our friend */
1711			if (c->file.mmap.start == MAP_FAILED) {
1712				if (-1 == c->file.fd &&  /* open the file if not already open */
1713				    -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
1714					log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
1715
1716					return -1;
1717				}
1718
1719				if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
1720					log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
1721							strerror(errno), c->file.name,  c->file.fd);
1722					close(c->file.fd);
1723					c->file.fd = -1;
1724
1725					return -1;
1726				}
1727
1728				close(c->file.fd);
1729				c->file.fd = -1;
1730
1731				c->file.mmap.length = c->file.length;
1732
1733				/* chunk_reset() or chunk_free() will cleanup for us */
1734			}
1735
1736			if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
1737				log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
1738			}
1739
1740			chunkqueue_mark_written(cq, weHave);
1741
1742			break;
1743		case MEM_CHUNK:
1744			/* append to the buffer */
1745			weHave = buffer_string_length(c->mem) - c->offset;
1746
1747			if (weHave > weWant) weHave = weWant;
1748
1749			if (p->conf.log_xml) {
1750				log_error_write(srv, __FILE__, __LINE__, "ss", "XML-request-body:", c->mem->ptr + c->offset);
1751			}
1752
1753			if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
1754				log_error_write(srv, __FILE__, __LINE__, "sodd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
1755			}
1756
1757			chunkqueue_mark_written(cq, weHave);
1758
1759			break;
1760		}
1761	}
1762
1763	switch ((err = xmlParseChunk(ctxt, 0, 0, 1))) {
1764	case XML_ERR_DOCUMENT_END:
1765	case XML_ERR_OK:
1766		break;
1767	default:
1768		log_error_write(srv, __FILE__, __LINE__, "sd", "xmlParseChunk failed at final packet:", err);
1769		break;
1770	}
1771
1772	xml = ctxt->myDoc;
1773	res = ctxt->wellFormed;
1774	xmlFreeParserCtxt(ctxt);
1775
1776	if (res == 0) {
1777		xmlFreeDoc(xml);
1778	} else {
1779		*ret_xml = xml;
1780	}
1781
1782	return res;
1783}
1784#endif
1785
1786#ifdef USE_LOCKS
1787static int webdav_lockdiscovery(server *srv, connection *con,
1788		buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
1789
1790	buffer *b = buffer_init();
1791
1792	response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
1793
1794	response_header_overwrite(srv, con,
1795		CONST_STR_LEN("Content-Type"),
1796		CONST_STR_LEN("text/xml; charset=\"utf-8\""));
1797
1798	buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
1799
1800	buffer_append_string_len(b,CONST_STR_LEN("<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
1801	buffer_append_string_len(b,CONST_STR_LEN("<D:lockdiscovery>\n"));
1802	buffer_append_string_len(b,CONST_STR_LEN("<D:activelock>\n"));
1803
1804	buffer_append_string_len(b,CONST_STR_LEN("<D:lockscope>"));
1805	buffer_append_string_len(b,CONST_STR_LEN("<D:"));
1806	buffer_append_string(b, lockscope);
1807	buffer_append_string_len(b, CONST_STR_LEN("/>"));
1808	buffer_append_string_len(b,CONST_STR_LEN("</D:lockscope>\n"));
1809
1810	buffer_append_string_len(b,CONST_STR_LEN("<D:locktype>"));
1811	buffer_append_string_len(b,CONST_STR_LEN("<D:"));
1812	buffer_append_string(b, locktype);
1813	buffer_append_string_len(b, CONST_STR_LEN("/>"));
1814	buffer_append_string_len(b,CONST_STR_LEN("</D:locktype>\n"));
1815
1816	buffer_append_string_len(b,CONST_STR_LEN("<D:depth>"));
1817	buffer_append_string(b, depth == 0 ? "0" : "infinity");
1818	buffer_append_string_len(b,CONST_STR_LEN("</D:depth>\n"));
1819
1820	buffer_append_string_len(b,CONST_STR_LEN("<D:timeout>"));
1821	buffer_append_string_len(b, CONST_STR_LEN("Second-600"));
1822	buffer_append_string_len(b,CONST_STR_LEN("</D:timeout>\n"));
1823
1824	buffer_append_string_len(b,CONST_STR_LEN("<D:owner>"));
1825	buffer_append_string_len(b,CONST_STR_LEN("</D:owner>\n"));
1826
1827	buffer_append_string_len(b,CONST_STR_LEN("<D:locktoken>"));
1828	buffer_append_string_len(b, CONST_STR_LEN("<D:href>"));
1829	buffer_append_string_buffer(b, locktoken);
1830	buffer_append_string_len(b, CONST_STR_LEN("</D:href>"));
1831	buffer_append_string_len(b,CONST_STR_LEN("</D:locktoken>\n"));
1832
1833	buffer_append_string_len(b,CONST_STR_LEN("</D:activelock>\n"));
1834	buffer_append_string_len(b,CONST_STR_LEN("</D:lockdiscovery>\n"));
1835	buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
1836
1837	chunkqueue_append_buffer(con->write_queue, b);
1838	buffer_free(b);
1839
1840	return 0;
1841}
1842#endif
1843
1844/**
1845 * check if resource is having the right locks to access to resource
1846 *
1847 *
1848 *
1849 */
1850static int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
1851	int has_lock = 1;
1852
1853#ifdef USE_LOCKS
1854	data_string *ds;
1855	UNUSED(srv);
1856
1857	/**
1858	 * This implementation is more fake than real
1859	 * we need a parser for the If: header to really handle the full scope
1860	 *
1861	 * X-Litmus: locks: 11 (owner_modify)
1862	 * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
1863	 * - a tagged check:
1864	 *   if http://127.0.0.1:1025/dav/litmus/lockme is locked with
1865	 *   opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1, go on
1866	 *
1867	 * X-Litmus: locks: 16 (fail_cond_put)
1868	 * If: (<DAV:no-lock> ["-1622396671"])
1869	 * - untagged:
1870	 *   go on if the resource has the etag [...] and the lock
1871	 */
1872	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
1873		/* Ooh, ooh. A if tag, now the fun begins.
1874		 *
1875		 * this can only work with a real parser
1876		 **/
1877	} else {
1878		/* we didn't provided a lock-token -> */
1879		/* if the resource is locked -> 423 */
1880
1881		sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
1882
1883		sqlite3_reset(stmt);
1884
1885		sqlite3_bind_text(stmt, 1,
1886			CONST_BUF_LEN(uri),
1887			SQLITE_TRANSIENT);
1888
1889		while (SQLITE_ROW == sqlite3_step(stmt)) {
1890			has_lock = 0;
1891		}
1892	}
1893#else
1894	UNUSED(srv);
1895	UNUSED(con);
1896	UNUSED(p);
1897	UNUSED(uri);
1898#endif
1899
1900	return has_lock;
1901}
1902
1903//- 20111209 Sungmin add
1904static const char* change_webdav_file_path(server *srv, connection *con, const char* source)
1905{
1906	UNUSED(con);
1907
1908	config_values_t cv[] = {
1909		{ "alias.url",                  NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
1910		{ NULL,                         NULL, T_CONFIG_UNSET,  T_CONFIG_SCOPE_UNSET }
1911	};
1912
1913	size_t i, j;
1914	for (i = 1; i < srv->config_context->used; i++) {
1915		array* alias = array_init();
1916		cv[0].destination = alias;
1917
1918		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
1919			continue;
1920		}
1921
1922		for (j = 0; j < alias->used; j++) {
1923
1924			data_string *ds = (data_string *)alias->data[j];
1925			if( strncmp(source, ds->key->ptr, ds->key->used-1) == 0 ){
1926				char buff[4096];
1927				replace_str(source, ds->key->ptr, ds->value->ptr, buff );
1928				array_free(alias);
1929				return buff;
1930			}
1931		}
1932
1933		array_free(alias);
1934	}
1935
1936	return source;
1937}
1938
1939URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
1940	plugin_data *p = p_d;
1941	buffer *b;
1942	DIR *dir;
1943	data_string *ds;
1944	int depth = -1;
1945	struct stat st;
1946	buffer *prop_200;
1947	buffer *prop_404;
1948	webdav_properties *req_props;
1949	stat_cache_entry *sce = NULL;
1950
1951	UNUSED(srv);
1952
1953	if (!p->conf.enabled) return HANDLER_GO_ON;
1954	/* physical path is setup */
1955	if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
1956
1957	/* PROPFIND need them */
1958	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Depth"))) {
1959		depth = strtol(ds->value->ptr, NULL, 10);
1960	}
1961
1962#if EMBEDDED_EANBLE
1963	if( !con->srv_socket->is_ssl ){
1964		if(srv->is_streaming_port_opend && con->request.http_method==HTTP_METHOD_GET){
1965		}
1966		else{
1967			con->http_status = 403;
1968			return HANDLER_FINISHED;
1969		}
1970	}
1971#endif
1972
1973
1974	Cdbg(DBE, "http_method=[%d][%s], depth=[%d], con->url->path=[%s]",
1975		con->request.http_method, get_http_method_name(con->request.http_method),
1976		depth, con->url.path->ptr);
1977
1978	switch (con->request.http_method) {
1979	case HTTP_METHOD_PROPFIND:
1980
1981		/* they want to know the properties of the directory */
1982		req_props = NULL;
1983
1984		/* is there a content-body ? */
1985
1986		switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
1987		case HANDLER_ERROR:
1988			if (errno == ENOENT) {
1989				con->http_status = 404;
1990				return HANDLER_FINISHED;
1991			}
1992			break;
1993		default:
1994			break;
1995		}
1996
1997
1998#ifdef USE_PROPPATCH
1999		/* any special requests or just allprop ? */
2000		if (con->request.content_length) {
2001			xmlDocPtr xml;
2002
2003			if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
2004				xmlNode *rootnode = xmlDocGetRootElement(xml);
2005
2006				force_assert(rootnode);
2007
2008				if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propfind")) {
2009					xmlNode *cmd;
2010
2011					req_props = calloc(1, sizeof(*req_props));
2012
2013					for (cmd = rootnode->children; cmd; cmd = cmd->next) {
2014
2015						if (0 == xmlStrcmp(cmd->name, BAD_CAST "prop")) {
2016							/* get prop by name */
2017							xmlNode *prop;
2018
2019							for (prop = cmd->children; prop; prop = prop->next) {
2020								if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */
2021
2022								if (prop->ns &&
2023								  (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
2024								    (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
2025									size_t i;
2026									log_error_write(srv, __FILE__, __LINE__, "ss",
2027											"no name space for:",
2028											prop->name);
2029
2030									xmlFreeDoc(xml);
2031
2032									for (i = 0; i < req_props->used; i++) {
2033										free(req_props->ptr[i]->ns);
2034										free(req_props->ptr[i]->prop);
2035										free(req_props->ptr[i]);
2036									}
2037									free(req_props->ptr);
2038									free(req_props);
2039
2040									con->http_status = 400;
2041									return HANDLER_FINISHED;
2042								}
2043
2044								/* add property to requested list */
2045								if (req_props->size == 0) {
2046									req_props->size = 16;
2047									req_props->ptr = malloc(sizeof(*(req_props->ptr)) * req_props->size);
2048								} else if (req_props->used == req_props->size) {
2049									req_props->size += 16;
2050									req_props->ptr = realloc(req_props->ptr, sizeof(*(req_props->ptr)) * req_props->size);
2051								}
2052
2053								req_props->ptr[req_props->used] = malloc(sizeof(webdav_property));
2054								req_props->ptr[req_props->used]->ns = (char *)xmlStrdup(prop->ns ? prop->ns->href : (xmlChar *)"");
2055								req_props->ptr[req_props->used]->prop = (char *)xmlStrdup(prop->name);
2056								req_props->used++;
2057							}
2058						} else if (0 == xmlStrcmp(cmd->name, BAD_CAST "propname")) {
2059							sqlite3_stmt *stmt = p->conf.stmt_select_propnames;
2060
2061							if (stmt) {
2062								/* get all property names (EMPTY) */
2063								sqlite3_reset(stmt);
2064								/* bind the values to the insert */
2065
2066								sqlite3_bind_text(stmt, 1,
2067									CONST_BUF_LEN(con->uri.path),
2068									SQLITE_TRANSIENT);
2069
2070								if (SQLITE_DONE != sqlite3_step(stmt)) {
2071								}
2072							}
2073						} else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
2074							/* get all properties (EMPTY) */
2075							req_props = NULL;
2076						}
2077					}
2078				}
2079
2080				xmlFreeDoc(xml);
2081			} else {
2082				con->http_status = 400;
2083				return HANDLER_FINISHED;
2084			}
2085		}
2086#endif
2087		con->http_status = 207;
2088
2089		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
2090
2091		b = buffer_init();
2092
2093		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
2094
2095		//buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n"));
2096		buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\" "));
2097
2098		char usbdisk_path[50] = "/usbdisk";
2099
2100#if EMBEDDED_EANBLE
2101		buffer_append_string_len(b, CONST_STR_LEN(" readonly=\""));
2102		#ifndef APP_IPKG
2103		strcpy(usbdisk_path, "/");
2104		strcat(usbdisk_path, nvram_get_productid());
2105		#else
2106		char *productid = nvram_get_productid();
2107		strcpy(usbdisk_path, "/");
2108        strcat(usbdisk_path, productid);
2109        free(productid);
2110		#endif
2111		char* usbdisk_rel_path=NULL;
2112		char* usbdisk_share_folder=NULL;
2113		int qry_type=0;
2114		Cdbg(1, "con->physical.path->ptr=%s", con->physical.path->ptr);
2115		smbc_parse_mnt_path(con->physical.path->ptr,
2116						    p->mnt_path->ptr,
2117						    p->mnt_path->used-1,
2118						    &usbdisk_rel_path,
2119						    &usbdisk_share_folder);
2120
2121		if(usbdisk_share_folder!=NULL){
2122
2123			int perm = smbc_get_usbdisk_permission(con->aidisk_username->ptr, usbdisk_rel_path, usbdisk_share_folder);
2124
2125			if(perm==3)
2126				buffer_append_string(b, "0");
2127			else
2128				buffer_append_string(b, "1");
2129
2130			qry_type = 0;
2131		}
2132		else{
2133			buffer_append_string(b, "1");
2134			qry_type = 1;
2135		}
2136
2137		//- Query Type
2138		buffer_append_string_len(b, CONST_STR_LEN("\" qtype=\""));
2139		if(qry_type==1)
2140			buffer_append_string(b, "1");
2141		else
2142			buffer_append_string(b, "0");
2143
2144		//- Computer Name
2145		#ifndef APP_IPKG
2146		buffer_append_string_len(b, CONST_STR_LEN("\" computername=\""));
2147		buffer_append_string(b, nvram_get_computer_name());
2148		#else
2149		char *computer_name = nvram_get_computer_name();
2150		buffer_append_string_len(b, CONST_STR_LEN("\" computername=\""));
2151        buffer_append_string(b, computer_name);
2152        //buffer_append_string(b, nvram_get_computer_name());
2153        free(computer_name);
2154		#endif
2155#else
2156		buffer_append_string_len(b, CONST_STR_LEN(" readonly=\"0"));
2157
2158		//- Query Type
2159		buffer_append_string_len(b, CONST_STR_LEN("\" qtype=\""));
2160		if(strcmp(con->uri.path->ptr, usbdisk_path)==0)
2161			buffer_append_string(b, "1");
2162		else
2163			buffer_append_string(b, "0");
2164
2165		//- Computer Name
2166		buffer_append_string_len(b, CONST_STR_LEN("\" computername=\"WebDAV"));
2167#endif
2168
2169		buffer_append_string_len(b, CONST_STR_LEN("\" isusb=\"1"));
2170
2171		buffer_append_string_len(b,CONST_STR_LEN("\">\n"));
2172
2173		/* allprop */
2174
2175		prop_200 = buffer_init();
2176		prop_404 = buffer_init();
2177
2178		switch(depth) {
2179		case 0:
2180			/* Depth: 0 */
2181			webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
2182
2183			buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
2184			buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
2185			buffer_append_string_buffer(b, con->uri.scheme);
2186			buffer_append_string_len(b,CONST_STR_LEN("://"));
2187			buffer_append_string_buffer(b, con->uri.authority);
2188			buffer_append_string_encoded(b, CONST_BUF_LEN(con->uri.path), ENCODING_REL_URI);
2189			buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
2190
2191			if (!buffer_string_is_empty(prop_200)) {
2192				buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
2193				buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
2194
2195				buffer_append_string_buffer(b, prop_200);
2196
2197				buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
2198
2199				buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
2200
2201				buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
2202			}
2203			if (!buffer_string_is_empty(prop_404)) {
2204				buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
2205				buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
2206
2207				buffer_append_string_buffer(b, prop_404);
2208
2209				buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
2210
2211				buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
2212
2213				buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
2214			}
2215
2216			buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
2217
2218			break;
2219		case 1:
2220			if (NULL != (dir = opendir(con->physical.path->ptr))) {
2221				struct dirent *de;
2222				physical d;
2223				physical *dst = &(con->physical);
2224
2225				d.path = buffer_init();
2226				d.rel_path = buffer_init();
2227
2228				while(NULL != (de = readdir(dir))) {
2229					if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
2230						continue;
2231						/* ignore the parent dir */
2232					}
2233
2234					if ( de->d_name[0] == '.' ) {
2235						continue;
2236						//- ignore the hidden file
2237					}
2238
2239					if ( check_skip_folder_name(de->d_name) == 1 ) {
2240						continue;
2241					}
2242
2243					buffer_copy_buffer(d.path, dst->path);
2244					buffer_append_slash(d.path);
2245
2246					buffer_copy_buffer(d.rel_path, dst->rel_path);
2247					buffer_append_slash(d.rel_path);
2248
2249					if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
2250						/* don't append the . */
2251					} else {
2252						buffer_append_string(d.path, de->d_name);
2253						buffer_append_string(d.rel_path, de->d_name);
2254					}
2255
2256#if EMBEDDED_EANBLE
2257					int permission = -1;
2258					char* usbdisk_rel_sub_path = NULL;
2259					char* usbdisk_sub_share_folder = NULL;
2260					smbc_parse_mnt_path(d.path->ptr,
2261										p->mnt_path->ptr,
2262										p->mnt_path->used-1,
2263										&usbdisk_rel_sub_path,
2264										&usbdisk_sub_share_folder);
2265
2266					if( usbdisk_sub_share_folder != NULL ){
2267						permission = smbc_get_usbdisk_permission(con->aidisk_username->ptr, usbdisk_rel_sub_path, usbdisk_sub_share_folder);
2268
2269						free(usbdisk_rel_sub_path);
2270						free(usbdisk_sub_share_folder);
2271
2272						if(permission!=1 && permission!=3)
2273							continue;
2274					}
2275					else
2276						free(usbdisk_rel_sub_path);
2277#endif
2278
2279					buffer_reset(prop_200);
2280					buffer_reset(prop_404);
2281
2282					webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
2283
2284					buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
2285					buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
2286					buffer_append_string_buffer(b, con->uri.scheme);
2287					buffer_append_string_len(b,CONST_STR_LEN("://"));
2288					buffer_append_string_buffer(b, con->uri.authority);
2289
2290					if(con->share_link_shortpath->used){
2291						char buff[4096];
2292						char* tmp = replace_str(&d.rel_path->ptr[0],
2293							                    (char*)con->share_link_realpath->ptr,
2294							                    (char*)con->share_link_shortpath->ptr,
2295							                    (char *)&buff[0]);
2296
2297						buffer_append_string(b, "/");
2298						buffer_append_string_encoded(b, tmp, strlen(tmp), ENCODING_REL_URI);
2299					}
2300					else{
2301						//Cdbg(DBE, "d.rel_path=%s", d.rel_path->ptr);
2302						buffer_append_string_encoded(b, CONST_BUF_LEN(d.rel_path), ENCODING_REL_URI);
2303					}
2304
2305					buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
2306
2307					if (!buffer_string_is_empty(prop_200)) {
2308						buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
2309						buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
2310
2311						buffer_append_string_buffer(b, prop_200);
2312
2313						buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
2314
2315						buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
2316
2317						buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
2318					}
2319					if (!buffer_string_is_empty(prop_404)) {
2320						buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
2321						buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
2322
2323						buffer_append_string_buffer(b, prop_404);
2324
2325						buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
2326
2327						buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
2328
2329						buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
2330					}
2331
2332					buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
2333				}
2334				closedir(dir);
2335				buffer_free(d.path);
2336				buffer_free(d.rel_path);
2337			}
2338			break;
2339		}
2340
2341		if (req_props) {
2342			size_t i;
2343			for (i = 0; i < req_props->used; i++) {
2344				free(req_props->ptr[i]->ns);
2345				free(req_props->ptr[i]->prop);
2346				free(req_props->ptr[i]);
2347			}
2348			free(req_props->ptr);
2349			free(req_props);
2350		}
2351
2352		buffer_free(prop_200);
2353		buffer_free(prop_404);
2354
2355		buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
2356
2357		if (p->conf.log_xml) {
2358			log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
2359		}
2360
2361		chunkqueue_append_buffer(con->write_queue, b);
2362		buffer_free(b);
2363
2364		con->file_finished = 1;
2365
2366		return HANDLER_FINISHED;
2367	case HTTP_METHOD_MKCOL:
2368		if (p->conf.is_readonly) {
2369			con->http_status = 403;
2370			return HANDLER_FINISHED;
2371		}
2372
2373		if (con->request.content_length != 0) {
2374			/* we don't support MKCOL with a body */
2375			con->http_status = 415;
2376
2377			return HANDLER_FINISHED;
2378		}
2379
2380		/* let's create the directory */
2381
2382		if (-1 == mkdir(con->physical.path->ptr, WEBDAV_DIR_MODE)) {
2383			switch(errno) {
2384			case EPERM:
2385				con->http_status = 403;
2386				break;
2387			case ENOENT:
2388			case ENOTDIR:
2389				con->http_status = 409;
2390				break;
2391			case EEXIST:
2392			default:
2393				con->http_status = 405; /* not allowed */
2394				break;
2395			}
2396		} else {
2397			log_sys_write(srv, "sbss", "Create folder", con->url.rel_path, "from ip", con->dst_addr_buf->ptr);
2398			con->http_status = 201;
2399			con->file_finished = 1;
2400		}
2401
2402		return HANDLER_FINISHED;
2403	case HTTP_METHOD_DELETE:
2404		if (p->conf.is_readonly) {
2405			con->http_status = 403;
2406			return HANDLER_FINISHED;
2407		}
2408
2409		/* does the client have a lock for this connection ? */
2410		if (!webdav_has_lock(srv, con, p, con->uri.path)) {
2411			con->http_status = 423;
2412			return HANDLER_FINISHED;
2413		}
2414
2415		/* stat and unlink afterwards */
2416		if (-1 == stat(con->physical.path->ptr, &st)) {
2417			/* don't about it yet, unlink will fail too */
2418			switch(errno) {
2419			case ENOENT:
2420				 con->http_status = 404;
2421				 break;
2422			default:
2423				 con->http_status = 403;
2424				 break;
2425			}
2426		} else if (S_ISDIR(st.st_mode)) {
2427			buffer *multi_status_resp = buffer_init();
2428
2429			if (webdav_delete_dir(srv, con, p, &(con->physical), multi_status_resp)) {
2430				/* we got an error somewhere in between, build a 207 */
2431				response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
2432
2433				b = buffer_init();
2434
2435				buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
2436
2437				buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\">\n"));
2438
2439				buffer_append_string_buffer(b, multi_status_resp);
2440
2441				buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
2442
2443				if (p->conf.log_xml) {
2444					log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
2445				}
2446
2447				chunkqueue_append_buffer(con->write_queue, b);
2448				buffer_free(b);
2449
2450				con->http_status = 207;
2451				con->file_finished = 1;
2452			} else {
2453				/* everything went fine, remove the directory */
2454
2455				if (-1 == rmdir(con->physical.path->ptr)) {
2456					switch(errno) {
2457					case ENOENT:
2458						con->http_status = 404;
2459						break;
2460					default:
2461						con->http_status = 501;
2462						break;
2463					}
2464				} else {
2465					log_sys_write(srv, "sbss", "Delete folder", con->url.rel_path, "from ip", con->dst_addr_buf->ptr);
2466					con->http_status = 204;
2467				}
2468			}
2469
2470			buffer_free(multi_status_resp);
2471		} else if (-1 == unlink(con->physical.path->ptr)) {
2472			switch(errno) {
2473			case EPERM:
2474				con->http_status = 403;
2475				break;
2476			case ENOENT:
2477				con->http_status = 404;
2478				break;
2479			default:
2480				con->http_status = 501;
2481				break;
2482			}
2483		} else {
2484			log_sys_write(srv, "sbss", "Delete file", con->url.rel_path, "from ip", con->dst_addr_buf->ptr);
2485			con->http_status = 204;
2486		}
2487		return HANDLER_FINISHED;
2488	case HTTP_METHOD_PUT: {
2489		int fd;
2490		chunkqueue *cq = con->request_content_queue;
2491		chunk *c;
2492		data_string *ds_range;
2493
2494		if (p->conf.is_readonly) {
2495			con->http_status = 403;
2496			return HANDLER_FINISHED;
2497		}
2498
2499		/* is a exclusive lock set on the source */
2500		if (!webdav_has_lock(srv, con, p, con->uri.path)) {
2501			con->http_status = 423;
2502			return HANDLER_FINISHED;
2503		}
2504
2505		//- Sungmin add
2506		int autoCreateFolder = 0;
2507		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Auto-CreateFolder"))) {
2508			if (ds->value->used != 2 ||
2509			    (ds->value->ptr[0] != 'F' &&
2510			     ds->value->ptr[0] != 'T') )  {
2511				con->http_status = 400;
2512				return HANDLER_FINISHED;
2513			}
2514			autoCreateFolder = (ds->value->ptr[0] == 'F' ? 0 : 1);
2515		}
2516
2517		if(autoCreateFolder){
2518			char* file_path = NULL;
2519			extract_filepath(con->physical.path->ptr, &file_path);
2520			createDirectory(file_path);
2521			free(file_path);
2522		}
2523		////////////////////////////////
2524
2525		assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
2526
2527		/* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
2528		 * - most important Content-Range
2529		 *
2530		 *
2531		 * Example: Content-Range: bytes 100-1037/1038 */
2532
2533		if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
2534			const char *num = ds_range->value->ptr;
2535			off_t offset;
2536			char *err = NULL;
2537
2538			if (0 != strncmp(num, "bytes ", 6)) {
2539				con->http_status = 501; /* not implemented */
2540
2541				return HANDLER_FINISHED;
2542			}
2543
2544			/* we only support <num>- ... */
2545
2546			num += 6;
2547
2548			/* skip WS */
2549			while (*num == ' ' || *num == '\t') num++;
2550
2551			if (*num == '\0') {
2552				con->http_status = 501; /* not implemented */
2553
2554				return HANDLER_FINISHED;
2555			}
2556
2557			offset = strtoll(num, &err, 10);
2558
2559			if (*err != '-' || offset < 0) {
2560				con->http_status = 501; /* not implemented */
2561
2562				return HANDLER_FINISHED;
2563			}
2564
2565			//- Sungmin modify if offset is zero, we create a new file.
2566			if(offset==0){
2567				if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, WEBDAV_FILE_MODE))) {
2568					if (errno == ENOENT &&
2569					    -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, WEBDAV_FILE_MODE))) {
2570						/* we can't open the file */
2571						switch(errno) {
2572						case EEXIST:
2573							con->http_status = 412;
2574							break;
2575						case EISDIR:
2576							con->http_status = 427;
2577							break;
2578						case ENOENT:
2579							/* at least one part in the middle wasn't existing */
2580							con->http_status = 427;
2581							break;
2582						default:
2583							con->http_status = 403;
2584							break;
2585						}
2586
2587						return HANDLER_FINISHED;
2588					}
2589					else {
2590						con->http_status = 201; /* created */
2591					}
2592				}
2593				else {
2594					con->http_status = 200; /* modified */
2595				}
2596			}
2597			else{
2598				if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, WEBDAV_FILE_MODE))) {
2599					switch (errno) {
2600					case ENOENT:
2601						con->http_status = 404; /* not found */
2602						break;
2603					default:
2604						con->http_status = 403; /* not found */
2605						break;
2606					}
2607					return HANDLER_FINISHED;
2608				}
2609			}
2610
2611			if (-1 == lseek(fd, offset, SEEK_SET)) {
2612				con->http_status = 501; /* not implemented */
2613
2614				close(fd);
2615
2616				return HANDLER_FINISHED;
2617			}
2618			con->http_status = 200; /* modified */
2619		}
2620		else {
2621			/* take what we have in the request-body and write it to a file */
2622
2623			/* if the file doesn't exist, create it */
2624			if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, WEBDAV_FILE_MODE))) {
2625				if (errno != ENOENT ||
2626				    -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, WEBDAV_FILE_MODE))) {
2627					/* we can't open the file */
2628					con->http_status = 403;
2629
2630					return HANDLER_FINISHED;
2631				}
2632				else {
2633					con->http_status = 201; /* created */
2634				}
2635			}
2636			else {
2637				con->http_status = 200; /* modified */
2638			}
2639		}
2640
2641		con->file_finished = 1;
2642
2643		for (c = cq->first; c; c = cq->first) {
2644			int r = 0;
2645
2646			/* copy all chunks */
2647			switch(c->type) {
2648			case FILE_CHUNK:
2649
2650				if (c->file.mmap.start == MAP_FAILED) {
2651					if (-1 == c->file.fd &&  /* open the file if not already open */
2652					    -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
2653						log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
2654						close(fd);
2655						return HANDLER_ERROR;
2656					}
2657
2658					if (MAP_FAILED == (c->file.mmap.start = mmap(NULL, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
2659						log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
2660								strerror(errno), c->file.name,  c->file.fd);
2661						close(c->file.fd);
2662						c->file.fd = -1;
2663						close(fd);
2664						return HANDLER_ERROR;
2665					}
2666
2667					c->file.mmap.length = c->file.length;
2668
2669					close(c->file.fd);
2670					c->file.fd = -1;
2671
2672					/* chunk_reset() or chunk_free() will cleanup for us */
2673				}
2674
2675				if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
2676					switch(errno) {
2677					case ENOSPC:
2678						con->http_status = 507;
2679
2680						break;
2681					default:
2682						con->http_status = 403;
2683						break;
2684					}
2685				}
2686				break;
2687			case MEM_CHUNK:
2688				if ((r = write(fd, c->mem->ptr + c->offset, buffer_string_length(c->mem) - c->offset)) < 0) {
2689					switch(errno) {
2690					case ENOSPC:
2691						con->http_status = 507;
2692
2693						break;
2694					default:
2695						con->http_status = 403;
2696						break;
2697					}
2698				}
2699				break;
2700			}
2701
2702			if (r > 0) {
2703				chunkqueue_mark_written(cq, r);
2704			} else {
2705				break;
2706			}
2707		}
2708		close(fd);
2709
2710		return HANDLER_FINISHED;
2711	}
2712	case HTTP_METHOD_MOVE:
2713	case HTTP_METHOD_COPY: {
2714		buffer *destination = NULL;
2715		char *sep, *sep2, *start;
2716		int overwrite = 1;
2717
2718		if (p->conf.is_readonly) {
2719			con->http_status = 403;
2720			return HANDLER_FINISHED;
2721		}
2722
2723		/* is a exclusive lock set on the source */
2724		if (con->request.http_method == HTTP_METHOD_MOVE) {
2725			if (!webdav_has_lock(srv, con, p, con->uri.path)) {
2726				con->http_status = 423;
2727				return HANDLER_FINISHED;
2728			}
2729		}
2730
2731		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
2732			destination = ds->value;
2733		} else {
2734			con->http_status = 400;
2735			return HANDLER_FINISHED;
2736		}
2737
2738		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Overwrite"))) {
2739			if (buffer_string_length(ds->value) != 1 ||
2740			    (ds->value->ptr[0] != 'F' &&
2741			     ds->value->ptr[0] != 'T') )  {
2742				con->http_status = 400;
2743				return HANDLER_FINISHED;
2744			}
2745			overwrite = (ds->value->ptr[0] == 'F' ? 0 : 1);
2746		}
2747		/* let's parse the Destination
2748		 *
2749		 * http://127.0.0.1:1025/dav/litmus/copydest
2750		 *
2751		 * - host has to be the same as the Host: header we got
2752		 * - we have to stay inside the document root
2753		 * - the query string is thrown away
2754		 *  */
2755
2756		buffer_reset(p->uri.scheme);
2757		buffer_reset(p->uri.path_raw);
2758		buffer_reset(p->uri.authority);
2759
2760		start = destination->ptr;
2761
2762		if (NULL == (sep = strstr(start, "://"))) {
2763			con->http_status = 400;
2764			return HANDLER_FINISHED;
2765		}
2766		buffer_copy_string_len(p->uri.scheme, start, sep - start);
2767
2768		start = sep + 3;
2769
2770		if (NULL == (sep = strchr(start, '/'))) {
2771			con->http_status = 400;
2772			return HANDLER_FINISHED;
2773		}
2774		if (NULL != (sep2 = memchr(start, '@', sep - start))) {
2775			/* skip login information */
2776			start = sep2 + 1;
2777		}
2778		buffer_copy_string_len(p->uri.authority, start, sep - start);
2779
2780		start = sep + 1;
2781
2782		if (NULL == (sep = strchr(start, '?'))) {
2783			/* no query string, good */
2784			buffer_copy_string(p->uri.path_raw, start);
2785		} else {
2786			buffer_copy_string_len(p->uri.path_raw, start, sep - start);
2787		}
2788
2789		if (!buffer_is_equal(p->uri.authority, con->uri.authority)) {
2790			/* not the same host */
2791			con->http_status = 502;
2792			return HANDLER_FINISHED;
2793		}
2794
2795		buffer_copy_buffer(p->tmp_buf, p->uri.path_raw);
2796		buffer_urldecode_path(p->tmp_buf);
2797		buffer_path_simplify(p->uri.path, p->tmp_buf);
2798
2799		//- 20121115 Sungmin add for router sync.
2800		if(con->share_link_shortpath->used){
2801
2802			char* a;
2803			if (NULL != ( a = strstr(p->uri.path->ptr, con->share_link_shortpath->ptr))){
2804				char buff[4096];
2805				replace_str( a,
2806					         con->share_link_shortpath->ptr,
2807					         con->share_link_realpath->ptr,
2808					         buff );
2809				buffer_copy_string( p->uri.path, buff );
2810			}
2811			else{
2812				con->http_status = 502;
2813				return HANDLER_FINISHED;
2814			}
2815		}
2816
2817		//- 20111209 Sungmin add
2818		buffer_copy_string(p->uri.path, change_webdav_file_path(srv, con, p->uri.path->ptr));
2819
2820		/* we now have a URI which is clean. transform it into a physical path */
2821		buffer_copy_buffer(p->physical.doc_root, con->physical.doc_root);
2822		buffer_copy_buffer(p->physical.rel_path, p->uri.path);
2823
2824		if (con->conf.force_lowercase_filenames) {
2825			buffer_to_lower(p->physical.rel_path);
2826		}
2827
2828		buffer_copy_buffer(p->physical.path, p->physical.doc_root);
2829		buffer_append_slash(p->physical.path);
2830		buffer_copy_buffer(p->physical.basedir, p->physical.path);
2831
2832		/* don't add a second / */
2833		if (p->physical.rel_path->ptr[0] == '/') {
2834			buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, buffer_string_length(p->physical.rel_path) - 1);
2835		} else {
2836			buffer_append_string_buffer(p->physical.path, p->physical.rel_path);
2837		}
2838
2839		/* let's see if the source is a directory
2840		 * if yes, we fail with 501 */
2841
2842		if (-1 == stat(con->physical.path->ptr, &st)) {
2843			/* don't about it yet, unlink will fail too */
2844			switch(errno) {
2845			case ENOENT:
2846				 con->http_status = 404;
2847				 break;
2848			default:
2849				 con->http_status = 403;
2850				 break;
2851			}
2852		} else if (S_ISDIR(st.st_mode)) {
2853			int r;
2854			/* src is a directory */
2855
2856			if (-1 == stat(p->physical.path->ptr, &st)) {
2857				//- dst is not exist.
2858				if(in_the_same_folder(con->physical.path, p->physical.path)) {
2859					if( rename(con->physical.path->ptr, p->physical.path->ptr) ) {
2860						con->http_status = 403;
2861					} else {
2862						con->http_status = 201; //Created
2863						log_sys_write(srv, "sbsbss", "Move", con->physical.rel_path, "to", p->physical.rel_path ,"from ip", con->dst_addr_buf->ptr);
2864					}
2865
2866					con->file_finished = 1;
2867					return HANDLER_FINISHED;
2868				} else if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
2869					con->http_status = 403;
2870					return HANDLER_FINISHED;
2871				}
2872			}
2873			else if (!S_ISDIR(st.st_mode)) {
2874				//- dst is not folder.
2875				if (overwrite == 0) {
2876					/* copying into a non-dir ? */
2877					con->http_status = 409;
2878					return HANDLER_FINISHED;
2879				} else {
2880					unlink(p->physical.path->ptr);
2881					if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) {
2882						con->http_status = 403;
2883						return HANDLER_FINISHED;
2884					}
2885				}
2886			}
2887			else if (S_ISDIR(st.st_mode)) {
2888				//- dst folder is exist.
2889				if (overwrite == 0) {
2890					/* copying into a non-dir ? */
2891					con->http_status = 412;
2892					return HANDLER_FINISHED;
2893				}
2894			}
2895
2896			/* copy the content of src to dest */
2897			if (0 != (r = webdav_copy_dir(srv, con, p, &(con->physical), &(p->physical), overwrite))) {
2898				con->http_status = r;
2899				return HANDLER_FINISHED;
2900			}
2901			if (con->request.http_method == HTTP_METHOD_MOVE) {
2902				b = buffer_init();
2903				webdav_delete_dir(srv, con, p, &(con->physical), b); /* content */
2904				buffer_free(b);
2905				Cdbg(DBE, "Move %s to %s from ip", con->url.rel_path->ptr, p->physical.rel_path->ptr);
2906				rmdir(con->physical.path->ptr);
2907
2908				log_sys_write(srv, "sbsbss", "Move", con->url.rel_path, "to", p->physical.rel_path ,"from ip", con->dst_addr_buf->ptr);
2909			}
2910			con->http_status = 201;
2911			con->file_finished = 1;
2912		} else {
2913			/* it is just a file, good */
2914			int r;
2915
2916			/* does the client have a lock for this connection ? */
2917			if (!webdav_has_lock(srv, con, p, p->uri.path)) {
2918				con->http_status = 423;
2919				return HANDLER_FINISHED;
2920			}
2921
2922			/* destination exists */
2923			if (0 == (r = stat(p->physical.path->ptr, &st))) {
2924				if (S_ISDIR(st.st_mode)) {
2925					if (overwrite == 0) {
2926						/* copying into a non-dir ? */
2927						con->http_status = 409;
2928						return HANDLER_FINISHED;
2929					}
2930
2931					/* file to dir/
2932					 * append basename to physical path */
2933
2934					if (NULL != (sep = strrchr(con->physical.path->ptr, '/'))) {
2935						buffer_append_string(p->physical.path, sep);
2936						r = stat(p->physical.path->ptr, &st);
2937					}
2938				}
2939			}
2940
2941			if (-1 == r) {
2942				con->http_status = 201; /* we will create a new one */
2943				con->file_finished = 1;
2944
2945				switch(errno) {
2946				case ENOTDIR:
2947					con->http_status = 409;
2948					return HANDLER_FINISHED;
2949				}
2950			} else if (overwrite == 0) {
2951				/* destination exists, but overwrite is not set */
2952				con->http_status = 412;
2953				return HANDLER_FINISHED;
2954			} else {
2955				con->http_status = 204; /* resource already existed */
2956			}
2957
2958			if (con->request.http_method == HTTP_METHOD_MOVE) {
2959				/* try a rename */
2960
2961				if (0 == rename(con->physical.path->ptr, p->physical.path->ptr)) {
2962#ifdef USE_PROPPATCH
2963					sqlite3_stmt *stmt;
2964
2965					stmt = p->conf.stmt_delete_uri;
2966					if (stmt) {
2967
2968						sqlite3_reset(stmt);
2969
2970						/* bind the values to the insert */
2971						sqlite3_bind_text(stmt, 1,
2972							CONST_BUF_LEN(con->uri.path),
2973							SQLITE_TRANSIENT);
2974
2975						if (SQLITE_DONE != sqlite3_step(stmt)) {
2976							log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move(delete old) failed:", sqlite3_errmsg(p->conf.sql));
2977						}
2978					}
2979
2980					stmt = p->conf.stmt_move_uri;
2981					if (stmt) {
2982
2983						sqlite3_reset(stmt);
2984
2985						/* bind the values to the insert */
2986						sqlite3_bind_text(stmt, 1,
2987							CONST_BUF_LEN(p->uri.path),
2988							SQLITE_TRANSIENT);
2989
2990						sqlite3_bind_text(stmt, 2,
2991							CONST_BUF_LEN(con->uri.path),
2992							SQLITE_TRANSIENT);
2993
2994						if (SQLITE_DONE != sqlite3_step(stmt)) {
2995							log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
2996						}
2997					}
2998#endif
2999					log_sys_write(srv, "sbsbss", "Move", con->url.rel_path, "to", p->physical.rel_path ,"from ip", con->dst_addr_buf->ptr);
3000
3001					return HANDLER_FINISHED;
3002				}
3003
3004				/* rename failed, fall back to COPY + DELETE */
3005			}
3006
3007			if (0 != (r = webdav_copy_file(srv, con, p, &(con->physical), &(p->physical), overwrite))) {
3008				con->http_status = r;
3009
3010				return HANDLER_FINISHED;
3011			}
3012
3013			if (con->request.http_method == HTTP_METHOD_MOVE) {
3014				b = buffer_init();
3015				webdav_delete_file(srv, con, p, &(con->physical), b);
3016				buffer_free(b);
3017
3018				log_sys_write(srv, "sbsbss", "Move", con->url.rel_path, "to", p->physical.rel_path ,"from ip", con->dst_addr_buf->ptr);
3019			}
3020		}
3021
3022		return HANDLER_FINISHED;
3023	}
3024	case HTTP_METHOD_PROPPATCH:
3025		if (p->conf.is_readonly) {
3026			con->http_status = 403;
3027			return HANDLER_FINISHED;
3028		}
3029
3030		if (!webdav_has_lock(srv, con, p, con->uri.path)) {
3031			con->http_status = 423;
3032			return HANDLER_FINISHED;
3033		}
3034
3035		/* check if destination exists */
3036		if (-1 == stat(con->physical.path->ptr, &st)) {
3037			switch(errno) {
3038			case ENOENT:
3039				con->http_status = 404;
3040				break;
3041			}
3042		}
3043
3044#ifdef USE_PROPPATCH
3045		if (con->request.content_length) {
3046			xmlDocPtr xml;
3047
3048			if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
3049				xmlNode *rootnode = xmlDocGetRootElement(xml);
3050
3051				if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propertyupdate")) {
3052					xmlNode *cmd;
3053					char *err = NULL;
3054					int empty_ns = 0; /* send 400 on a empty namespace attribute */
3055
3056					/* start response */
3057
3058					if (SQLITE_OK != sqlite3_exec(p->conf.sql, "BEGIN TRANSACTION", NULL, NULL, &err)) {
3059						log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
3060						sqlite3_free(err);
3061
3062						goto propmatch_cleanup;
3063					}
3064
3065					/* a UPDATE request, we know 'set' and 'remove' */
3066					for (cmd = rootnode->children; cmd; cmd = cmd->next) {
3067						xmlNode *props;
3068						/* either set or remove */
3069
3070						if ((0 == xmlStrcmp(cmd->name, BAD_CAST "set")) ||
3071						    (0 == xmlStrcmp(cmd->name, BAD_CAST "remove"))) {
3072
3073							sqlite3_stmt *stmt;
3074
3075							stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
3076								p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
3077
3078							for (props = cmd->children; props; props = props->next) {
3079								if (0 == xmlStrcmp(props->name, BAD_CAST "prop")) {
3080									xmlNode *prop;
3081									int r;
3082
3083									prop = props->children;
3084
3085									if (prop->ns &&
3086									    (0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
3087									    (0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
3088										log_error_write(srv, __FILE__, __LINE__, "ss",
3089												"no name space for:",
3090												prop->name);
3091
3092										empty_ns = 1;
3093										break;
3094									}
3095
3096									sqlite3_reset(stmt);
3097
3098									/* bind the values to the insert */
3099
3100									sqlite3_bind_text(stmt, 1,
3101										CONST_BUF_LEN(con->uri.path),
3102										SQLITE_TRANSIENT);
3103									sqlite3_bind_text(stmt, 2,
3104										(char *)prop->name,
3105										strlen((char *)prop->name),
3106										SQLITE_TRANSIENT);
3107									if (prop->ns) {
3108										sqlite3_bind_text(stmt, 3,
3109											(char *)prop->ns->href,
3110											strlen((char *)prop->ns->href),
3111											SQLITE_TRANSIENT);
3112									} else {
3113										sqlite3_bind_text(stmt, 3,
3114											"",
3115											0,
3116											SQLITE_TRANSIENT);
3117									}
3118									if (stmt == p->conf.stmt_update_prop) {
3119										sqlite3_bind_text(stmt, 4,
3120											(char *)xmlNodeGetContent(prop),
3121											strlen((char *)xmlNodeGetContent(prop)),
3122											SQLITE_TRANSIENT);
3123									}
3124
3125									if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
3126										log_error_write(srv, __FILE__, __LINE__, "ss",
3127												"sql-set failed:", sqlite3_errmsg(p->conf.sql));
3128									}
3129								}
3130							}
3131							if (empty_ns) break;
3132						}
3133					}
3134
3135					if (empty_ns) {
3136						if (SQLITE_OK != sqlite3_exec(p->conf.sql, "ROLLBACK", NULL, NULL, &err)) {
3137							log_error_write(srv, __FILE__, __LINE__, "ss", "can't rollback transaction:", err);
3138							sqlite3_free(err);
3139
3140							goto propmatch_cleanup;
3141						}
3142
3143						con->http_status = 400;
3144					} else {
3145						if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
3146							log_error_write(srv, __FILE__, __LINE__, "ss", "can't commit transaction:", err);
3147							sqlite3_free(err);
3148
3149							goto propmatch_cleanup;
3150						}
3151						con->http_status = 200;
3152					}
3153					con->file_finished = 1;
3154
3155					return HANDLER_FINISHED;
3156				}
3157
3158propmatch_cleanup:
3159
3160				xmlFreeDoc(xml);
3161			} else {
3162				con->http_status = 400;
3163				return HANDLER_FINISHED;
3164			}
3165		}
3166#endif
3167		con->http_status = 501;
3168		return HANDLER_FINISHED;
3169	case HTTP_METHOD_LOCK:
3170		/**
3171		 * a mac wants to write
3172		 *
3173		 * LOCK /dav/expire.txt HTTP/1.1\r\n
3174		 * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
3175		 * Accept: * / *\r\n
3176		 * Depth: 0\r\n
3177		 * Timeout: Second-600\r\n
3178		 * Content-Type: text/xml; charset=\"utf-8\"\r\n
3179		 * Content-Length: 229\r\n
3180		 * Connection: keep-alive\r\n
3181		 * Host: 192.168.178.23:1025\r\n
3182		 * \r\n
3183		 * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
3184		 * <D:lockinfo xmlns:D=\"DAV:\">\n
3185		 *  <D:lockscope><D:exclusive/></D:lockscope>\n
3186		 *  <D:locktype><D:write/></D:locktype>\n
3187		 *  <D:owner>\n
3188		 *   <D:href>http://www.apple.com/webdav_fs/</D:href>\n
3189		 *  </D:owner>\n
3190		 * </D:lockinfo>\n
3191		 */
3192
3193		if (depth != 0 && depth != -1) {
3194			con->http_status = 400;
3195
3196			return HANDLER_FINISHED;
3197		}
3198
3199#ifdef USE_LOCKS
3200		if (con->request.content_length) {
3201			xmlDocPtr xml;
3202			buffer *hdr_if = NULL;
3203
3204			if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
3205				hdr_if = ds->value;
3206			}
3207
3208			/* we don't support Depth: Infinity on locks */
3209			if (hdr_if == NULL && depth == -1) {
3210				con->http_status = 409; /* Conflict */
3211
3212				return HANDLER_FINISHED;
3213			}
3214
3215			if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
3216				xmlNode *rootnode = xmlDocGetRootElement(xml);
3217
3218				force_assert(rootnode);
3219
3220				if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
3221					xmlNode *lockinfo;
3222					const xmlChar *lockscope = NULL, *locktype = NULL; /* TODO: compiler says unused: *owner = NULL; */
3223
3224					for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
3225						if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
3226							xmlNode *value;
3227							for (value = lockinfo->children; value; value = value->next) {
3228								if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
3229								    (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
3230									lockscope = value->name;
3231								} else {
3232									con->http_status = 400;
3233
3234									xmlFreeDoc(xml);
3235									return HANDLER_FINISHED;
3236								}
3237							}
3238						} else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
3239							xmlNode *value;
3240							for (value = lockinfo->children; value; value = value->next) {
3241								if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
3242									locktype = value->name;
3243								} else {
3244									con->http_status = 400;
3245
3246									xmlFreeDoc(xml);
3247									return HANDLER_FINISHED;
3248								}
3249							}
3250
3251						} else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
3252						}
3253					}
3254
3255					if (lockscope && locktype) {
3256						sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
3257
3258						/* is this resourse already locked ? */
3259
3260						/* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
3261						 *   FROM locks
3262						 *  WHERE resource = ? */
3263
3264						if (stmt) {
3265
3266							sqlite3_reset(stmt);
3267
3268							sqlite3_bind_text(stmt, 1,
3269								CONST_BUF_LEN(p->uri.path),
3270								SQLITE_TRANSIENT);
3271
3272							/* it is the PK */
3273							while (SQLITE_ROW == sqlite3_step(stmt)) {
3274								/* we found a lock
3275								 * 1. is it compatible ?
3276								 * 2. is it ours */
3277								char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
3278
3279								if (strcmp(sql_lockscope, "exclusive")) {
3280									con->http_status = 423;
3281								} else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
3282									/* resourse is locked with a shared lock
3283									 * client wants exclusive */
3284									con->http_status = 423;
3285								}
3286							}
3287							if (con->http_status == 423) {
3288								xmlFreeDoc(xml);
3289								return HANDLER_FINISHED;
3290							}
3291						}
3292
3293						stmt = p->conf.stmt_create_lock;
3294						if (stmt) {
3295							/* create a lock-token */
3296							//uuid_t id;
3297							char uuid[37] /* 36 + \0 */;
3298
3299							sprintf( uuid, "%d", rand() );
3300
3301							//uuid_generate(id);
3302							//uuid_unparse(id, uuid);
3303
3304							buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("opaquelocktoken:"));
3305							buffer_append_string(p->tmp_buf, uuid);
3306
3307							/* "CREATE TABLE locks ("
3308							 * "  locktoken TEXT NOT NULL,"
3309							 * "  resource TEXT NOT NULL,"
3310							 * "  lockscope TEXT NOT NULL,"
3311							 * "  locktype TEXT NOT NULL,"
3312							 * "  owner TEXT NOT NULL,"
3313							 * "  depth INT NOT NULL,"
3314							 */
3315
3316							sqlite3_reset(stmt);
3317
3318							/* locktoken */
3319							sqlite3_bind_text(stmt, 1,
3320									CONST_BUF_LEN(p->tmp_buf),
3321									SQLITE_TRANSIENT);
3322
3323							/* resource */
3324							sqlite3_bind_text(stmt, 2,
3325									CONST_BUF_LEN(con->uri.path),
3326									SQLITE_TRANSIENT);
3327
3328							/* lockscope */
3329							sqlite3_bind_text(stmt, 3,
3330									(const char *)lockscope,
3331									xmlStrlen(lockscope),
3332									SQLITE_TRANSIENT);
3333
3334							/* locktype */
3335							sqlite3_bind_text(stmt, 4,
3336									(const char *)locktype,
3337									xmlStrlen(locktype),
3338									SQLITE_TRANSIENT);
3339
3340							/* owner */
3341							sqlite3_bind_text(stmt, 5,
3342									"",
3343									0,
3344									SQLITE_TRANSIENT);
3345
3346							/* depth */
3347							sqlite3_bind_int(stmt, 6,
3348									depth);
3349
3350
3351							if (SQLITE_DONE != sqlite3_step(stmt)) {
3352								log_error_write(srv, __FILE__, __LINE__, "ss",
3353										"create lock:", sqlite3_errmsg(p->conf.sql));
3354							}
3355
3356							/* looks like we survived */
3357							webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth);
3358
3359							con->http_status = 201;
3360							con->file_finished = 1;
3361						}
3362					}
3363				}
3364
3365				xmlFreeDoc(xml);
3366				return HANDLER_FINISHED;
3367			} else {
3368				con->http_status = 400;
3369				return HANDLER_FINISHED;
3370			}
3371		} else {
3372
3373			if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
3374				buffer *locktoken = ds->value;
3375				sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
3376
3377				/* remove the < > around the token */
3378				if (buffer_string_length(locktoken) < 5) {
3379					con->http_status = 400;
3380
3381					return HANDLER_FINISHED;
3382				}
3383
3384				buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, buffer_string_length(locktoken) - 4);
3385
3386				sqlite3_reset(stmt);
3387
3388				sqlite3_bind_text(stmt, 1,
3389					CONST_BUF_LEN(p->tmp_buf),
3390					SQLITE_TRANSIENT);
3391
3392				if (SQLITE_DONE != sqlite3_step(stmt)) {
3393					log_error_write(srv, __FILE__, __LINE__, "ss",
3394						"refresh lock:", sqlite3_errmsg(p->conf.sql));
3395				}
3396
3397				webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
3398
3399				con->http_status = 200;
3400				con->file_finished = 1;
3401				return HANDLER_FINISHED;
3402			} else {
3403				/* we need a lock-token to refresh */
3404				con->http_status = 400;
3405
3406				return HANDLER_FINISHED;
3407			}
3408		}
3409		break;
3410#else
3411		con->http_status = 501;
3412		return HANDLER_FINISHED;
3413#endif
3414	case HTTP_METHOD_UNLOCK:
3415#ifdef USE_LOCKS
3416		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
3417			buffer *locktoken = ds->value;
3418			sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
3419
3420			/* remove the < > around the token */
3421			if (buffer_string_length(locktoken) < 3) {
3422				con->http_status = 400;
3423
3424				return HANDLER_FINISHED;
3425			}
3426
3427			/**
3428			 * FIXME:
3429			 *
3430			 * if the resourse is locked:
3431			 * - by us: unlock
3432			 * - by someone else: 401
3433			 * if the resource is not locked:
3434			 * - 412
3435			 *  */
3436
3437			buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, buffer_string_length(locktoken) - 2);
3438
3439			sqlite3_reset(stmt);
3440
3441			sqlite3_bind_text(stmt, 1,
3442				CONST_BUF_LEN(p->tmp_buf),
3443				SQLITE_TRANSIENT);
3444
3445			sqlite3_bind_text(stmt, 2,
3446				CONST_BUF_LEN(con->uri.path),
3447				SQLITE_TRANSIENT);
3448
3449			if (SQLITE_DONE != sqlite3_step(stmt)) {
3450				log_error_write(srv, __FILE__, __LINE__, "ss",
3451					"remove lock:", sqlite3_errmsg(p->conf.sql));
3452			}
3453
3454			if (0 == sqlite3_changes(p->conf.sql)) {
3455				con->http_status = 401;
3456			} else {
3457				con->http_status = 204;
3458			}
3459			return HANDLER_FINISHED;
3460		} else {
3461			/* we need a lock-token to unlock */
3462			con->http_status = 400;
3463
3464			return HANDLER_FINISHED;
3465		}
3466		break;
3467#else
3468		con->http_status = 501;
3469		return HANDLER_FINISHED;
3470#endif
3471
3472	case HTTP_METHOD_WOL:{
3473		con->http_status = 200;
3474		return HANDLER_FINISHED;
3475	}
3476
3477	case HTTP_METHOD_GSL:{
3478#if EMBEDDED_EANBLE
3479		if(!con->srv_socket->is_ssl){
3480			con->http_status = 403;
3481			return HANDLER_FINISHED;
3482		}
3483#endif
3484		buffer *buffer_url = NULL;
3485		buffer *buffer_filename = NULL;
3486		buffer *buffer_result_share_link = NULL;
3487		int expire = 1;
3488		int toShare = 1;
3489		Cdbg(DBE, "do HTTP_METHOD_GSL....................");
3490
3491		if (p->conf.is_readonly) {
3492			con->http_status = 403;
3493			return HANDLER_FINISHED;
3494		}
3495
3496		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "URL"))) {
3497			buffer_url = ds->value;
3498		} else {
3499			con->http_status = 400;
3500			return HANDLER_FINISHED;
3501		}
3502
3503		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
3504			buffer_filename = ds->value;
3505		} else {
3506			con->http_status = 400;
3507			return HANDLER_FINISHED;
3508		}
3509
3510		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "EXPIRE"))) {
3511			expire = atoi(ds->value->ptr);
3512		} else {
3513			con->http_status = 400;
3514			return HANDLER_FINISHED;
3515		}
3516
3517		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TOSHARE"))) {
3518			toShare = atoi(ds->value->ptr);
3519		}
3520
3521		int sharelink_save_count = get_sharelink_save_count();
3522		int file_count = 0;
3523
3524		char* tmp_filename = strdup(buffer_filename->ptr);
3525		char *pch = strtok(tmp_filename, ";");
3526		while(pch!=NULL){
3527			file_count++;
3528			pch = strtok(NULL,";");
3529		}
3530		free(tmp_filename);
3531
3532		if(toShare==1&&sharelink_save_count+file_count>srv->srvconf.max_sharelink){
3533			con->http_status = 405;
3534			return HANDLER_FINISHED;
3535		}
3536
3537		char auth[100]="\0";
3538		if(con->aidisk_username->used && con->aidisk_passwd->used)
3539			sprintf(auth, "%s:%s", con->aidisk_username->ptr, con->aidisk_passwd->ptr);
3540		else{
3541			con->http_status = 400;
3542			return HANDLER_FINISHED;
3543		}
3544
3545		char* base64_auth = ldb_base64_encode(auth, strlen(auth));
3546
3547		if( generate_sharelink(srv,
3548			                   con,
3549			                   buffer_filename->ptr,
3550			                   buffer_url->ptr,
3551			                   base64_auth,
3552			                   expire,
3553			                   toShare,
3554			                   &buffer_result_share_link) == 0){
3555			free(base64_auth);
3556			con->http_status = 400;
3557			return HANDLER_FINISHED;
3558		}
3559
3560		con->http_status = 200;
3561
3562		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
3563
3564		b = buffer_init();
3565
3566		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
3567		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
3568		buffer_append_string_len(b,CONST_STR_LEN("<sharelink>"));
3569		buffer_append_string_buffer(b,buffer_result_share_link);
3570		buffer_append_string_len(b,CONST_STR_LEN("</sharelink>"));
3571		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
3572
3573		chunkqueue_append_buffer(con->write_queue, b);
3574		buffer_free(b);
3575
3576		con->file_finished = 1;
3577
3578		buffer_free(buffer_result_share_link);
3579		free(base64_auth);
3580
3581		if(toShare==1)
3582			save_sharelink_list(srv);
3583
3584		return HANDLER_FINISHED;
3585	}
3586
3587	case HTTP_METHOD_GETSRVTIME:{
3588#if EMBEDDED_EANBLE
3589		if(!con->srv_socket->is_ssl){
3590			con->http_status = 403;
3591			return HANDLER_FINISHED;
3592		}
3593#endif
3594
3595		char stime[1024]="\0";
3596		time_t server_time = time(NULL);
3597		sprintf(stime, "%ld", server_time);
3598		Cdbg(DBE, "do HTTP_METHOD_GETSRVTIME....................%s", stime);
3599
3600		con->http_status = 200;
3601
3602		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
3603
3604		b = buffer_init();
3605
3606		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
3607		buffer_append_string_len(b,CONST_STR_LEN("<result>\n"));
3608		buffer_append_string_len(b,CONST_STR_LEN("<servertime>\n"));
3609		buffer_append_string(b,stime);
3610		buffer_append_string_len(b,CONST_STR_LEN("</servertime>\n"));
3611		buffer_append_string_len(b,CONST_STR_LEN("</result>\n"));
3612
3613		chunkqueue_append_buffer(con->write_queue, b);
3614		buffer_free(b);
3615
3616		con->file_finished = 1;
3617		return HANDLER_FINISHED;
3618	}
3619
3620	case HTTP_METHOD_GETROUTERMAC:{
3621
3622#if EMBEDDED_EANBLE
3623		char* router_mac = nvram_get_router_mac();
3624#else
3625		char router_mac[20]="\0";
3626		get_mac_address("eth0", &router_mac);
3627#endif
3628
3629		con->http_status = 200;
3630
3631		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
3632
3633		b = buffer_init();
3634
3635		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
3636		buffer_append_string_len(b,CONST_STR_LEN("<result>\n"));
3637		buffer_append_string_len(b,CONST_STR_LEN("<mac>\n"));
3638		buffer_append_string(b,router_mac);
3639		buffer_append_string_len(b,CONST_STR_LEN("</mac>\n"));
3640		buffer_append_string_len(b,CONST_STR_LEN("</result>\n"));
3641
3642		chunkqueue_append_buffer(con->write_queue, b);
3643		buffer_free(b);
3644
3645		con->file_finished = 1;
3646#if EMBEDDED_EANBLE
3647#ifdef APP_IPKG
3648		free(router_mac);
3649#endif
3650#endif
3651		return HANDLER_FINISHED;
3652	}
3653
3654	case HTTP_METHOD_GETFIRMVER:{
3655
3656#if EMBEDDED_EANBLE
3657		if(!con->srv_socket->is_ssl){
3658			con->http_status = 403;
3659			return HANDLER_FINISHED;
3660		}
3661#endif
3662
3663#if EMBEDDED_EANBLE
3664		char* firmware_version = nvram_get_firmware_version();
3665		char* build_no = nvram_get_build_no();
3666#else
3667		char* firmware_version = "1.0.0";
3668		char* build_no = "0";
3669#endif
3670
3671		con->http_status = 200;
3672
3673		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
3674
3675		b = buffer_init();
3676
3677		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
3678		buffer_append_string_len(b,CONST_STR_LEN("<result>\n"));
3679		buffer_append_string_len(b,CONST_STR_LEN("<version>\n"));
3680		buffer_append_string(b,firmware_version);
3681		buffer_append_string(b,".");
3682		buffer_append_string(b,build_no);
3683		buffer_append_string_len(b,CONST_STR_LEN("</version>\n"));
3684		buffer_append_string_len(b,CONST_STR_LEN("</result>\n"));
3685
3686		chunkqueue_append_buffer(con->write_queue, b);
3687		buffer_free(b);
3688
3689		con->file_finished = 1;
3690#if EMBEDDED_EANBLE
3691#ifdef APP_IPKG
3692        free(firmware_version);
3693        free(build_no);
3694#endif
3695#endif
3696		return HANDLER_FINISHED;
3697	}
3698
3699#if 0
3700	case HTTP_METHOD_GETROUTERINFO:{
3701#if EMBEDDED_EANBLE
3702		if(!con->srv_socket->is_ssl){
3703			con->http_status = 403;
3704			return HANDLER_FINISHED;
3705		}
3706#endif
3707
3708		Cdbg(DBE, "do HTTP_METHOD_GETROUTERINFO....................");
3709
3710		char stime[1024]="\0";
3711		time_t server_time = time(NULL);
3712		sprintf(stime, "%ld", server_time);
3713
3714#if EMBEDDED_EANBLE
3715		char* router_mac = nvram_get_router_mac();
3716
3717		char* firmware_version = nvram_get_firmware_version();
3718		char* build_no = nvram_get_build_no();
3719
3720		char* modal_name = nvram_get_productid();
3721
3722		//- Computer Name
3723		char* computer_name = nvram_get_computer_name();
3724		char* st_webdav_mode = nvram_get_st_webdav_mode();
3725		char* webdav_http_port = nvram_get_webdav_http_port();
3726		char* webdav_https_port = nvram_get_webdav_https_port();
3727		char* http_enable = nvram_get_http_enable();
3728		char* lan_http_port = "80";
3729		char* lan_https_port = nvram_get_lan_https_port();
3730		char* misc_http_x = nvram_get_misc_http_x();
3731		char* misc_http_port = nvram_get_misc_http_port();
3732		char* misc_https_port = nvram_get_misc_https_port();
3733		char* ddns_host_name = nvram_get_ddns_host_name();
3734		char* disk_path = "/mnt/";
3735		char* wan_ip = nvram_get_wan_ip();
3736		char *usbdiskname = nvram_get_productid();
3737
3738		//- Get aicloud version
3739		#ifdef APP_IPKG
3740		char* aicloud_version_file = "/opt/lib/ipkg/info/aicloud.control";
3741		char* aicloud_app_type = "install";
3742		char* smartsync_version_file = "/opt/lib/ipkg/info/smartsync.control";
3743		#else
3744		char* aicloud_version_file = "/usr/lighttpd/control";
3745		char* aicloud_app_type = "embed";
3746		char* smartsync_version_file = "/usr/lighttpd/smartsync_control";
3747		#endif
3748		char aicloud_version[30]="\0";
3749		char smartsync_version[30]="\0";
3750		char *swpjverno = nvram_get_swpjverno();
3751		char *extendno = nvram_get_extendno();
3752
3753		char *https_crt_cn = nvram_get_https_crt_cn();
3754
3755		char *apps_sq = nvram_get_apps_sq();
3756#ifdef USE_TCAPI
3757		char *is_dsl_platform = "1";
3758#else
3759		char *is_dsl_platform = "0";
3760#endif
3761
3762#else
3763		char router_mac[20]="\0";
3764		get_mac_address("eth0", &router_mac);
3765
3766		char* firmware_version = "1.0.0";
3767		char* build_no = "0";
3768
3769		char* modal_name = "WebDAV";
3770
3771		//- Computer Name
3772		char* computer_name = "WebDAV";
3773		char* st_webdav_mode = "0";
3774		char* webdav_http_port = "8082";
3775		char* webdav_https_port = "443";
3776		char* http_enable = "2";
3777		char* lan_http_port = "80";
3778		char* lan_https_port = "8443";
3779		char* misc_http_x = "0";
3780		char* misc_http_port = "8080";
3781		char* misc_https_port = "8443";
3782		char* ddns_host_name = "";
3783		char* disk_path = "/mnt/";
3784		char* wan_ip = "192.168.1.10";
3785		char *usbdiskname = "usbdisk";
3786
3787		//- Get aicloud version
3788		char* aicloud_version_file = "/usr/css/control";
3789		char* smartsync_version_file = "/usr/css/smartsync_control";
3790		char aicloud_version[30]="\0";
3791		char smartsync_version[30]="\0";
3792		char *swpjverno = "";
3793		char *extendno = "";
3794		char* aicloud_app_type = "embed";
3795
3796		char *https_crt_cn = "192.168.1.1";
3797
3798		char *apps_sq = "0";
3799		char *is_dsl_platform = "0";
3800#endif
3801		int sharelink_save_count = get_sharelink_save_count();
3802		int dms_enable = is_dms_enabled();
3803		int jffs_supported = is_jffs_supported();
3804
3805		if(buffer_is_empty(srv->srvconf.aicloud_version)){
3806			//- Parser version file
3807			FILE* fp2;
3808			char line[128];
3809			if((fp2 = fopen(aicloud_version_file, "r")) != NULL){
3810				memset(line, 0, sizeof(line));
3811				while(fgets(line, 128, fp2) != NULL){
3812					if(strncmp(line, "Version:", 8)==0){
3813						strncpy(aicloud_version, line + 9, strlen(line)-8);
3814					}
3815				}
3816				fclose(fp2);
3817			}
3818		}
3819		else{
3820			strcpy(aicloud_version, srv->srvconf.aicloud_version->ptr);
3821		}
3822
3823		if(buffer_is_empty(srv->srvconf.smartsync_version)){
3824			//- Parser version file
3825			FILE* fp2;
3826			char line[128];
3827			if((fp2 = fopen(smartsync_version_file, "r")) != NULL){
3828				memset(line, 0, sizeof(line));
3829				while(fgets(line, 128, fp2) != NULL){
3830					if(strncmp(line, "Version:", 8)==0){
3831						strncpy(smartsync_version, line + 9, strlen(line)-8);
3832					}
3833				}
3834				fclose(fp2);
3835			}
3836		}
3837		else{
3838			strcpy(smartsync_version, srv->srvconf.smartsync_version->ptr);
3839		}
3840
3841#ifndef APP_IPKG
3842		if( swpjverno!=NULL && strncmp(swpjverno,"", 1)!=0){
3843			strcpy(aicloud_version, swpjverno);
3844			if(extendno!=NULL && strncmp(extendno,"", 1)!=0)
3845			{
3846				strcat(aicloud_version, "_");
3847				strcat(aicloud_version, extendno);
3848			}
3849		}
3850#endif
3851		con->http_status = 200;
3852
3853		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
3854
3855		b = buffer_init();
3856
3857		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
3858		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
3859		buffer_append_string_len(b,CONST_STR_LEN("<servertime>"));
3860		buffer_append_string(b,stime);
3861		buffer_append_string_len(b,CONST_STR_LEN("</servertime>"));
3862		buffer_append_string_len(b,CONST_STR_LEN("<mac>"));
3863		buffer_append_string(b,router_mac);
3864		buffer_append_string_len(b,CONST_STR_LEN("</mac>"));
3865		buffer_append_string_len(b,CONST_STR_LEN("<version>"));
3866		buffer_append_string(b,firmware_version);
3867		buffer_append_string(b,".");
3868		buffer_append_string(b,build_no);
3869		buffer_append_string_len(b,CONST_STR_LEN("</version>"));
3870		buffer_append_string_len(b,CONST_STR_LEN("<aicloud_version>"));
3871		buffer_append_string(b,aicloud_version);
3872		buffer_append_string_len(b,CONST_STR_LEN("</aicloud_version>"));
3873		buffer_append_string_len(b,CONST_STR_LEN("<extendno>"));
3874		if(extendno!=NULL && strncmp(extendno,"", 1)!=0) buffer_append_string(b,extendno);
3875		buffer_append_string_len(b,CONST_STR_LEN("</extendno>"));
3876		buffer_append_string_len(b,CONST_STR_LEN("<aicloud_app_type>"));
3877		buffer_append_string(b,aicloud_app_type);
3878		buffer_append_string_len(b,CONST_STR_LEN("</aicloud_app_type>"));
3879		buffer_append_string_len(b,CONST_STR_LEN("<smartsync_version>"));
3880		buffer_append_string(b,smartsync_version);
3881		buffer_append_string_len(b,CONST_STR_LEN("</smartsync_version>"));
3882		buffer_append_string_len(b,CONST_STR_LEN("<modalname>"));
3883		buffer_append_string(b,modal_name);
3884		buffer_append_string_len(b,CONST_STR_LEN("</modalname>"));
3885		buffer_append_string_len(b,CONST_STR_LEN("<computername>"));
3886		buffer_append_string(b,computer_name);
3887		buffer_append_string_len(b,CONST_STR_LEN("</computername>"));
3888		buffer_append_string_len(b,CONST_STR_LEN("<usbdiskname>"));
3889		buffer_append_string(b,usbdiskname);
3890		buffer_append_string_len(b,CONST_STR_LEN("</usbdiskname>"));
3891		buffer_append_string_len(b,CONST_STR_LEN("<webdav_mode>"));
3892		buffer_append_string(b,st_webdav_mode);
3893		buffer_append_string_len(b,CONST_STR_LEN("</webdav_mode>"));
3894		buffer_append_string_len(b,CONST_STR_LEN("<http_port>"));
3895		buffer_append_string(b,webdav_http_port);
3896		buffer_append_string_len(b,CONST_STR_LEN("</http_port>"));
3897		buffer_append_string_len(b,CONST_STR_LEN("<https_port>"));
3898		buffer_append_string(b,webdav_https_port);
3899		buffer_append_string_len(b,CONST_STR_LEN("</https_port>"));
3900		buffer_append_string_len(b,CONST_STR_LEN("<http_enable>"));
3901		buffer_append_string(b,http_enable);
3902		buffer_append_string_len(b,CONST_STR_LEN("</http_enable>"));
3903		buffer_append_string_len(b,CONST_STR_LEN("<lan_http_port>"));
3904		buffer_append_string(b,lan_http_port);
3905		buffer_append_string_len(b,CONST_STR_LEN("</lan_http_port>"));
3906		buffer_append_string_len(b,CONST_STR_LEN("<lan_https_port>"));
3907		buffer_append_string(b,lan_https_port);
3908		buffer_append_string_len(b,CONST_STR_LEN("</lan_https_port>"));
3909		buffer_append_string_len(b,CONST_STR_LEN("<misc_http_enable>"));
3910		buffer_append_string(b,misc_http_x);
3911		buffer_append_string_len(b,CONST_STR_LEN("</misc_http_enable>"));
3912		buffer_append_string_len(b,CONST_STR_LEN("<misc_http_port>"));
3913		buffer_append_string(b,misc_http_port);
3914		buffer_append_string_len(b,CONST_STR_LEN("</misc_http_port>"));
3915		buffer_append_string_len(b,CONST_STR_LEN("<misc_https_port>"));
3916		buffer_append_string(b,misc_https_port);
3917		buffer_append_string_len(b,CONST_STR_LEN("</misc_https_port>"));
3918		buffer_append_string_len(b,CONST_STR_LEN("<last_login_info>"));
3919		if(buffer_is_empty(srv->last_login_info))
3920			buffer_append_string(b,"");
3921		else
3922			buffer_append_string(b,srv->last_login_info->ptr);
3923		buffer_append_string_len(b,CONST_STR_LEN("</last_login_info>"));
3924		buffer_append_string_len(b,CONST_STR_LEN("<ddns_host_name>"));
3925		buffer_append_string(b,ddns_host_name);
3926		buffer_append_string_len(b,CONST_STR_LEN("</ddns_host_name>"));
3927		buffer_append_string_len(b,CONST_STR_LEN("<wan_ip>"));
3928		buffer_append_string(b,wan_ip);
3929		buffer_append_string_len(b,CONST_STR_LEN("</wan_ip>"));
3930		buffer_append_string_len(b,CONST_STR_LEN("<dms_enable>"));
3931		buffer_append_string(b, ((dms_enable==1) ? "1" : "0"));
3932		buffer_append_string_len(b,CONST_STR_LEN("</dms_enable>"));
3933		buffer_append_string_len(b,CONST_STR_LEN("<account_manager_enable>"));
3934		buffer_append_string(b, "0");
3935		buffer_append_string_len(b,CONST_STR_LEN("</account_manager_enable>"));
3936		buffer_append_string_len(b,CONST_STR_LEN("<https_crt_cn>"));
3937		buffer_append_string(b,https_crt_cn);
3938		buffer_append_string_len(b,CONST_STR_LEN("</https_crt_cn>"));
3939		buffer_append_string_len(b,CONST_STR_LEN("<app_installation_url>"));
3940		buffer_append_string(b, buffer_is_empty(srv->srvconf.app_installation_url) ? "" : srv->srvconf.app_installation_url->ptr);
3941		buffer_append_string_len(b,CONST_STR_LEN("</app_installation_url>"));
3942		buffer_append_string_len(b,CONST_STR_LEN("<apps_sq>"));
3943		buffer_append_string(b,apps_sq);
3944		buffer_append_string_len(b,CONST_STR_LEN("</apps_sq>"));
3945		buffer_append_string_len(b,CONST_STR_LEN("<is_dsl_platform>"));
3946		buffer_append_string(b,is_dsl_platform);
3947		buffer_append_string_len(b,CONST_STR_LEN("</is_dsl_platform>"));
3948		buffer_append_string_len(b,CONST_STR_LEN("<used_sharelink>"));
3949		char used_sharelink[5] = "\0";
3950		sprintf(used_sharelink, "%d", sharelink_save_count);
3951		buffer_append_string(b, used_sharelink);
3952		buffer_append_string_len(b,CONST_STR_LEN("</used_sharelink>"));
3953		buffer_append_string_len(b,CONST_STR_LEN("<max_sharelink>"));
3954		char max_sharelink[5] = "\0";
3955		sprintf(max_sharelink, "%d", srv->srvconf.max_sharelink);
3956		buffer_append_string(b, max_sharelink);
3957		buffer_append_string_len(b,CONST_STR_LEN("</max_sharelink>"));
3958
3959		//DIR *dir;
3960		if (NULL != (dir = opendir(disk_path))) {
3961
3962			buffer_append_string_len(b,CONST_STR_LEN("<disk_space>"));
3963
3964			struct dirent *de;
3965
3966			while(NULL != (de = readdir(dir))) {
3967
3968				if ( de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0' ) {
3969					continue;
3970					//- ignore the parent dir
3971				}
3972
3973				if ( de->d_name[0] == '.' ) {
3974					continue;
3975					//- ignore the hidden file
3976				}
3977
3978				buffer_append_string_len(b,CONST_STR_LEN("<item>"));
3979
3980				char querycmd[100] = "\0";
3981
3982				sprintf(querycmd, "df|grep -i '%s%s'", disk_path, de->d_name);
3983
3984				buffer_append_string_len(b,CONST_STR_LEN("<DiskName>"));
3985				buffer_append_string(b,de->d_name);
3986				buffer_append_string_len(b,CONST_STR_LEN("</DiskName>"));
3987
3988				char mybuffer[BUFSIZ]="\0";
3989				FILE* fp = popen( querycmd, "r");
3990				if(fp){
3991					int len = fread(mybuffer, sizeof(char), BUFSIZ, fp);
3992					mybuffer[len-1]="\0";
3993					pclose(fp);
3994
3995					char * pch;
3996					pch = strtok(mybuffer, " ");
3997					int count=1;
3998					while(pch!=NULL){
3999						if(count==3){
4000							buffer_append_string_len(b,CONST_STR_LEN("<DiskUsed>"));
4001							buffer_append_string(b,pch);
4002							buffer_append_string_len(b,CONST_STR_LEN("</DiskUsed>"));
4003						}
4004						else if(count==4){
4005							buffer_append_string_len(b,CONST_STR_LEN("<DiskAvailable>"));
4006							buffer_append_string(b,pch);
4007							buffer_append_string_len(b,CONST_STR_LEN("</DiskAvailable>"));
4008						}
4009						else if(count==5){
4010							buffer_append_string_len(b,CONST_STR_LEN("<DiskUsedPercent>"));
4011							buffer_append_string(b,pch);
4012							buffer_append_string_len(b,CONST_STR_LEN("</DiskUsedPercent>"));
4013						}
4014
4015						//- Next
4016						pch = strtok(NULL," ");
4017						count++;
4018					}
4019
4020				}
4021
4022				buffer_append_string_len(b,CONST_STR_LEN("</item>"));
4023			}
4024
4025			buffer_append_string_len(b,CONST_STR_LEN("</disk_space>"));
4026
4027			closedir(dir);
4028		}
4029
4030		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
4031
4032		chunkqueue_append_buffer(con->write_queue, b);
4033		buffer_free(b);
4034
4035		con->file_finished = 1;
4036#if EMBEDDED_EANBLE
4037#ifdef APP_IPKG
4038        free(router_mac);
4039        free(firmware_version);
4040        free(build_no);
4041        free(modal_name);
4042        free(computer_name);
4043        free(st_webdav_mode);
4044        free(webdav_http_port);
4045        free(webdav_https_port);
4046        free(misc_http_x);
4047        free(misc_http_port);
4048		free(ddns_host_name);
4049		free(wan_ip);
4050		free(http_enable);
4051		free(misc_https_port);
4052		if(swpjverno!=NULL)
4053			free(swpjverno);
4054		if(extendno!=NULL)
4055			free(extendno);
4056		free(https_crt_cn);
4057#endif
4058#endif
4059		return HANDLER_FINISHED;
4060	}
4061#endif
4062
4063	case HTTP_METHOD_RESCANSMBPC:{
4064#if EMBEDDED_EANBLE
4065		if(!con->srv_socket->is_ssl){
4066			con->http_status = 403;
4067			return HANDLER_FINISHED;
4068		}
4069#endif
4070		Cdbg(DBE, "do HTTP_METHOD_RESCANSMBPC");
4071
4072		stop_arpping_process();
4073
4074		#if EMBEDDED_EANBLE
4075		nvram_set_smbdav_str("");
4076		#else
4077		unlink("/tmp/arpping_list");
4078		#endif
4079
4080		con->http_status = 200;
4081		con->file_finished = 1;
4082		return HANDLER_FINISHED;
4083	}
4084
4085	case HTTP_METHOD_PROPFINDMEDIALIST:{
4086#if EMBEDDED_EANBLE
4087		if(!con->srv_socket->is_ssl){
4088			con->http_status = 403;
4089			return HANDLER_FINISHED;
4090		}
4091#endif
4092
4093		int dms_enable = is_dms_enabled();
4094
4095		if(dms_enable == 0){
4096			//- Service Not Available
4097			con->http_status = 503;
4098			return HANDLER_FINISHED;
4099		}
4100
4101		/* they want to know the properties of the directory */
4102		req_props = NULL;
4103
4104		/* is there a content-body ? */
4105		switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
4106			case HANDLER_ERROR:
4107				if (errno == ENOENT) {
4108					con->http_status = 404;
4109					return HANDLER_FINISHED;
4110				}
4111				break;
4112			default:
4113				break;
4114		}
4115
4116#ifdef USE_PROPPATCH
4117		/* any special requests or just allprop ? */
4118		if (con->request.content_length) {
4119			xmlDocPtr xml;
4120
4121			if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
4122				xmlNode *rootnode = xmlDocGetRootElement(xml);
4123
4124				assert(rootnode);
4125
4126				if (0 == xmlStrcmp(rootnode->name, BAD_CAST "propfind")) {
4127					xmlNode *cmd;
4128
4129					req_props = calloc(1, sizeof(*req_props));
4130
4131					for (cmd = rootnode->children; cmd; cmd = cmd->next) {
4132
4133						if (0 == xmlStrcmp(cmd->name, BAD_CAST "prop")) {
4134							/* get prop by name */
4135							xmlNode *prop;
4136							for (prop = cmd->children; prop; prop = prop->next) {
4137								if (prop->type == XML_TEXT_NODE) continue; /* ignore WS */
4138								if (prop->ns &&
4139									(0 == xmlStrcmp(prop->ns->href, BAD_CAST "")) &&
4140									(0 != xmlStrcmp(prop->ns->prefix, BAD_CAST ""))) {
4141									size_t i;
4142									log_error_write(srv, __FILE__, __LINE__, "ss",
4143											"no name space for:",
4144											prop->name);
4145
4146									xmlFreeDoc(xml);
4147
4148									for (i = 0; i < req_props->used; i++) {
4149										free(req_props->ptr[i]->ns);
4150										free(req_props->ptr[i]->prop);
4151										free(req_props->ptr[i]);
4152									}
4153									free(req_props->ptr);
4154									free(req_props);
4155									con->http_status = 400;
4156									return HANDLER_FINISHED;
4157								}
4158
4159								/* add property to requested list */
4160								if (req_props->size == 0) {
4161									req_props->size = 16;
4162									req_props->ptr = malloc(sizeof(*(req_props->ptr)) * req_props->size);
4163								} else if (req_props->used == req_props->size) {
4164									req_props->size += 16;
4165									req_props->ptr = realloc(req_props->ptr, sizeof(*(req_props->ptr)) * req_props->size);
4166								}
4167
4168								req_props->ptr[req_props->used] = malloc(sizeof(webdav_property));
4169								req_props->ptr[req_props->used]->ns = (char *)xmlStrdup(prop->ns ? prop->ns->href : (xmlChar *)"");
4170								req_props->ptr[req_props->used]->prop = (char *)xmlStrdup(prop->name);
4171								req_props->used++;
4172							}
4173						} else if (0 == xmlStrcmp(cmd->name, BAD_CAST "propname")) {
4174							sqlite3_stmt *stmt = p->conf.stmt_select_propnames;
4175
4176							if (stmt) {
4177								/* get all property names (EMPTY) */
4178								sqlite3_reset(stmt);
4179								/* bind the values to the insert */
4180
4181								sqlite3_bind_text(stmt, 1,
4182												  con->uri.path->ptr,
4183												  con->uri.path->used - 1,
4184												  SQLITE_TRANSIENT);
4185
4186								if (SQLITE_DONE != sqlite3_step(stmt)) {
4187								}
4188							}
4189						} else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
4190							/* get all properties (EMPTY) */
4191							req_props = NULL;
4192						}
4193					}
4194				}
4195
4196				xmlFreeDoc(xml);
4197			} else {
4198				con->http_status = 400;
4199				return HANDLER_FINISHED;
4200			}
4201		}
4202#endif
4203
4204#ifdef USE_MINIDLNA_DB
4205		Cdbg(DBE, "do HTTP_METHOD_PROPFINDMEDIALIST");
4206
4207		sqlite3 *sql_minidlna = NULL;
4208		buffer* media_type = NULL;  //- 0: All(default), 1: Image, 2:Audio, 3:Video
4209		buffer* start = NULL;       //- start query index
4210		buffer* end = NULL;         //- end query index
4211		buffer* keyword = NULL;     //- query keyword
4212		buffer* orderby = NULL;     //- query sortby
4213		buffer* orderrule = NULL;   //- sort rule: DESC, ASC
4214		buffer* parentid = NULL;   //- parentid
4215
4216		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "MediaType"))) {
4217		 	media_type = ds->value;
4218		}
4219		else{
4220			Cdbg(DBE, "No value 'MediaType' specified!");
4221			con->http_status = 207;
4222			con->file_finished = 1;
4223			return HANDLER_FINISHED;
4224		}
4225
4226		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Start"))) {
4227			start = ds->value;
4228		}
4229
4230		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "End"))) {
4231			end = ds->value;
4232		}
4233
4234		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Keyword"))) {
4235			keyword = ds->value;
4236		}
4237
4238		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Orderby"))) {
4239			orderby = ds->value;
4240		}
4241
4242		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Orderrule"))) {
4243			orderrule = ds->value;
4244		}
4245
4246		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Parentid"))) {
4247			parentid = ds->value;
4248		}
4249
4250		get_minidlna_db_path(p);
4251
4252		if (!buffer_is_empty(p->minidlna_db_file)) {
4253			if (SQLITE_OK != sqlite3_open(p->minidlna_db_file->ptr, &(sql_minidlna))) {
4254				Cdbg(DBE, "Fail to open minidlna db %s", p->minidlna_db_file->ptr);
4255			}
4256		}
4257
4258		if (!sql_minidlna) {
4259			Cdbg(DBE, "NULL value 'sql_minidlna'!");
4260			con->http_status = 207;
4261			con->file_finished = 1;
4262			return HANDLER_FINISHED;
4263		}
4264
4265		int rows, i;
4266		char **result;
4267		sqlite_int64 plID;
4268		char *plpath, *plname, *thumbnail, *resolution;
4269		char sql_query[2048] = "\0";
4270
4271		int column_count = 7;
4272		sprintf(sql_query, "SELECT d.ID as ID, "
4273		                   "d.PATH as PATH, "
4274		                   "d.TITLE as TITLE, "
4275		                   "d.SIZE as SIZE, "
4276		                   "d.TIMESTAMP as TIMESTAMP, "
4277		                   "d.THUMBNAIL as THUMBNAIL, "
4278		                   "d.RESOLUTION as RESOLUTION "
4279			               "from DETAILS d ");
4280
4281		if(!buffer_is_empty(parentid)){
4282			sprintf(sql_query, "%s left join OBJECTS o on (o.DETAIL_ID = d.ID)", sql_query);
4283		}
4284
4285		if( buffer_is_equal_string(media_type, CONST_STR_LEN("1")) ){
4286			sprintf(sql_query, "%s where d.MIME glob 'i*'", sql_query);
4287		}
4288		else if( buffer_is_equal_string(media_type, CONST_STR_LEN("2")) ){
4289			sprintf(sql_query, "%s where d.MIME glob 'a*'", sql_query);
4290		}
4291		else if( buffer_is_equal_string(media_type, CONST_STR_LEN("3")) ){
4292			sprintf(sql_query, "%s where d.MIME glob 'v*'", sql_query);
4293		}
4294		else if( buffer_is_equal_string(media_type, CONST_STR_LEN("0")) ){
4295			sprintf(sql_query, "%s where d.MIME glob 'i*' or d.MIME glob 'a*' or d.MIME glob 'v*'", sql_query);
4296		}
4297
4298		#if 0
4299		if(!buffer_is_empty(keyword)){
4300			buffer_urldecode_path(keyword);
4301			sprintf(sql_query, "%s and ( PATH LIKE '%s%s%s' or TITLE LIKE '%s%s%s' )", sql_query, "%", keyword->ptr, "%", "%", keyword->ptr, "%");
4302		}
4303		#else
4304		if(!buffer_is_empty(keyword)){
4305			buffer_urldecode_path(keyword);
4306
4307			if(strstr(keyword->ptr, "*")||strstr(keyword->ptr, "?")){
4308				char buff[4096];
4309				char* tmp = replace_str(keyword->ptr, "*", "%", (char *)&buff[0]);
4310				tmp = replace_str(tmp, "?", "_", (char *)&buff[0]);
4311
4312				sprintf(sql_query, "%s and ( PATH LIKE '%s' or TITLE LIKE '%s' )", sql_query, tmp, tmp);
4313			}
4314			else
4315				sprintf(sql_query, "%s and ( PATH LIKE '%s%s%s' or TITLE LIKE '%s%s%s' )", sql_query, "%", keyword->ptr, "%", "%", keyword->ptr, "%");
4316		}
4317		#endif
4318
4319		if(!buffer_is_empty(parentid)){
4320			sprintf(sql_query, "%s and o.PARENT_ID='%s'", sql_query, parentid->ptr );
4321		}
4322
4323#if EMBEDDED_EANBLE
4324		//- Get mount partition
4325		char* disk_path = "/mnt/";
4326		//DIR *dir;
4327		if (NULL != (dir = opendir(disk_path))) {
4328			struct dirent *de;
4329			while(NULL != (de = readdir(dir))) {
4330				if ( de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0' ) {
4331					continue;
4332					//- ignore the parent dir
4333				}
4334
4335				if ( de->d_name[0] == '.' ) {
4336					continue;
4337					//- ignore the hidden file
4338				}
4339
4340				char partion_path[100] = "\0";
4341				sprintf(partion_path, "%s%s", disk_path, de->d_name);
4342
4343				//if(strstr( con->physical.path->ptr, partion_path ) && buffer_is_empty(parentid)){
4344				if(strstr( con->physical.path->ptr, partion_path )){
4345					sprintf(sql_query, "%s and PATH LIKE '%s%s/%s'", sql_query, "%", partion_path, "%");
4346					break;
4347				}
4348			}
4349			closedir(dir);
4350		}
4351#endif
4352
4353		Cdbg(DBE, "1. sql_query=%s", sql_query);
4354		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) != SQLITE_OK ){
4355			sqlite3_close(sql_minidlna);
4356			con->http_status = 207;
4357			con->file_finished = 1;
4358			Cdbg(DBE, "Fail to sql_get_table");
4359			return HANDLER_FINISHED;
4360		}
4361		#if 0
4362		if( !rows ){
4363			sqlite3_free_table(result);
4364			sqlite3_close(sql_minidlna);
4365			con->http_status = 207;
4366			con->file_finished = 1;
4367			Cdbg(DBE, "rows = 0!");
4368			return HANDLER_FINISHED;
4369		}
4370		#endif
4371		////////////////////////////////////////////////////////////////////////////////////
4372
4373		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
4374
4375		b = buffer_init();
4376
4377		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
4378		buffer_append_string_len(b,CONST_STR_LEN("<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\" "));
4379
4380		//- Total count
4381		buffer_append_string_len(b, CONST_STR_LEN(" qcount=\""));
4382		char qcount[1024]="\0";
4383		sprintf(qcount, "%d", rows);
4384		buffer_append_string(b, qcount);
4385		buffer_append_string_len(b, CONST_STR_LEN("\""));
4386
4387		buffer_append_string_len(b, CONST_STR_LEN(" scan_status=\""));
4388#if EMBEDDED_EANBLE
4389		//- Get scan status
4390		char dms_scanfile[64];
4391    	FILE *fp;
4392
4393		if (!buffer_is_empty(p->minidlna_db_dir)) {
4394	        sprintf(dms_scanfile, "%s/scantag", p->minidlna_db_dir->ptr);
4395
4396	        fp = fopen(dms_scanfile, "r");
4397
4398	        if(fp) {
4399				buffer_append_string(b, "Scanning");
4400	            fclose(fp);
4401	        }
4402			else
4403				buffer_append_string(b, "Idle");
4404	    }
4405#else
4406		buffer_append_string(b, "Scanning");
4407#endif
4408		buffer_append_string_len(b, CONST_STR_LEN("\""));
4409
4410		int query_again = 0;
4411		if(!buffer_is_empty(orderby)){
4412			if(!buffer_is_empty(orderrule))
4413				sprintf(sql_query, "%s ORDER BY %s %s", sql_query, orderby->ptr, orderrule->ptr);
4414			else
4415				sprintf(sql_query, "%s ORDER BY %s ASC", sql_query, orderby->ptr);
4416
4417			query_again = 1;
4418		}
4419
4420		if(!buffer_is_empty(start) && !buffer_is_empty(end)){
4421			sprintf(sql_query, "%s LIMIT %s, %s", sql_query, start->ptr, end->ptr);
4422			query_again = 1;
4423
4424			//- Start Index
4425			buffer_append_string_len(b, CONST_STR_LEN(" qstart=\""));
4426			buffer_append_string_buffer(b, start);
4427			buffer_append_string_len(b, CONST_STR_LEN("\""));
4428
4429			//- End Index
4430			int query_end = atoi(end->ptr);
4431			if( query_end > rows) query_end = rows;
4432			buffer_append_string_len(b, CONST_STR_LEN(" qend=\""));
4433			char qend[1024]="\0";
4434			sprintf(qend, "%d", query_end);
4435			buffer_append_string(b, qend);
4436			buffer_append_string_len(b, CONST_STR_LEN("\""));
4437		}
4438
4439		Cdbg(DBE, "sql_query=%s, qcount=%s", sql_query, qcount);
4440
4441		buffer_append_string_len(b,CONST_STR_LEN(">\n"));
4442
4443		if(query_again==1){
4444			sqlite3_free_table(result);
4445			if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) != SQLITE_OK ){
4446				sqlite3_close(sql_minidlna);
4447				con->http_status = 207;
4448				con->file_finished = 1;
4449				Cdbg(DBE, "Fail to sql_get_table 2");
4450				return HANDLER_FINISHED;
4451			}
4452		}
4453
4454		Cdbg(DBE, "rows=%d", rows);
4455
4456		rows++;
4457
4458		char* usbdisk_name;
4459#if EMBEDDED_EANBLE
4460		char *a = nvram_get_productid();
4461		int l = strlen(a)+1;
4462		usbdisk_name = (char*)malloc(l);
4463		memset(usbdisk_name,'\0', l);
4464		strcpy(usbdisk_name, a);
4465		#ifdef APP_IPKG
4466		free(a);
4467		#endif
4468#else
4469		usbdisk_name = (char*)malloc(8);
4470		memset(usbdisk_name,'\0', 8);
4471		strcpy(usbdisk_name, "usbdisk");
4472#endif
4473
4474		/* allprop */
4475		prop_200 = buffer_init();
4476		prop_404 = buffer_init();
4477		physical d;
4478		d.path = buffer_init();
4479		d.rel_path = buffer_init();
4480
4481		for( i=column_count; i<rows*column_count; i+=column_count ){
4482
4483			//- ID, PATH, TITLE, SIZE, TIMESTAMP, THUMBNAIL
4484			plID = strtoll(result[i], NULL, 10);
4485			plpath = result[i+1];
4486			plname = result[i+2];
4487			thumbnail = result[i+5];
4488			resolution = result[i+6];
4489
4490			if(!plpath)
4491				continue;
4492
4493			int thumb = atoi(thumbnail);
4494
4495			if(thumb){
4496				//Cdbg(DBE, "plpath=%s, thumbnail = %d, resolution = %s", plpath, atoi(thumbnail), resolution);
4497
4498				#ifdef USE_LIBEXIF
4499				ExifLoader *l = exif_loader_new();
4500				exif_loader_write_file(l, plpath);
4501				ExifData *ed = exif_loader_get_data(l);
4502				exif_loader_unref(l);
4503
4504				if( ed ){
4505					//Cdbg(DBE, "success");
4506
4507					#if 0
4508					/* Make sure the image had a thumbnail before trying to write it */
4509		            if (ed->data && ed->size) {
4510		                FILE *thumb;
4511		                char thumb_name[1024];
4512
4513		                /* Try to create a unique name for the thumbnail file */
4514		                snprintf(thumb_name, sizeof(thumb_name),
4515		                         "%s_thumb.jpg", plpath);
4516
4517		                thumb = fopen(thumb_name, "wb");
4518		                if (thumb) {
4519		                    /* Write the thumbnail image to the file */
4520		                    fwrite(ed->data, 1, ed->size, thumb);
4521		                    fclose(thumb);
4522		                    Cdbg(DBE, "Wrote thumbnail to %s\n", thumb_name);
4523		                } else {
4524		                    Cdbg(DBE, "Could not create file %s\n", thumb_name);
4525		                }
4526		            } else {
4527		                Cdbg(DBE, "No EXIF thumbnail in file\n");
4528		            }
4529					#endif
4530
4531		            /* Free the EXIF data */
4532		            exif_data_unref(ed);
4533				}
4534				#endif
4535			}
4536
4537			char buff[4096];
4538			#if EMBEDDED_EANBLE
4539			char* tmp = replace_str(&plpath[0],
4540			                    	"tmp/mnt",
4541			                    	usbdisk_name,
4542				                	(char *)&buff[0]);
4543			#else
4544			char* tmp = replace_str(&plpath[0],
4545			                    	"mnt",
4546			                    	usbdisk_name,
4547				                	(char *)&buff[0]);
4548
4549			#endif
4550
4551			//Cdbg(DBE, "tmp=%s, con->url.path=%s", tmp, con->url.path->ptr);
4552
4553			buffer_copy_string(d.path, plpath);
4554			buffer_copy_string(d.rel_path, plpath);
4555
4556			buffer_reset(prop_200);
4557			buffer_reset(prop_404);
4558
4559			//Cdbg(DBE, "d.path=%s", d.path->ptr);
4560			//Cdbg(DBE, "d.rel_path=%s", d.rel_path->ptr);
4561
4562			webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
4563
4564			buffer_append_string_len(b,CONST_STR_LEN("<D:response>\n"));
4565			buffer_append_string_len(b,CONST_STR_LEN("<D:href>"));
4566			buffer_append_string_buffer(b, con->uri.scheme);
4567			buffer_append_string_len(b,CONST_STR_LEN("://"));
4568			buffer_append_string_buffer(b, con->uri.authority);
4569			buffer_append_string_encoded(b, tmp, strlen(tmp), ENCODING_REL_URI);
4570			buffer_append_string_len(b,CONST_STR_LEN("</D:href>\n"));
4571
4572			if (!buffer_is_empty(prop_200)) {
4573				buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
4574				buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
4575				buffer_append_string_buffer(b, prop_200);
4576				buffer_append_string_len(b, CONST_STR_LEN("<D:title>"));
4577				buffer_append_string(b, plname);
4578				buffer_append_string_len(b, CONST_STR_LEN("</D:title>"));
4579				buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
4580				buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 200 OK</D:status>\n"));
4581				buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
4582			}
4583			if (!buffer_is_empty(prop_404)) {
4584				buffer_append_string_len(b,CONST_STR_LEN("<D:propstat>\n"));
4585				buffer_append_string_len(b,CONST_STR_LEN("<D:prop>\n"));
4586				buffer_append_string_buffer(b, prop_404);
4587
4588				//- for test
4589				buffer_append_string_len(b, CONST_STR_LEN("<D:mtitle>"));
4590				buffer_append_string(b, plname);
4591				buffer_append_string_len(b, CONST_STR_LEN("</D:mtitle>"));
4592
4593				buffer_append_string_len(b,CONST_STR_LEN("</D:prop>\n"));
4594				buffer_append_string_len(b,CONST_STR_LEN("<D:status>HTTP/1.1 404 Not Found</D:status>\n"));
4595				buffer_append_string_len(b,CONST_STR_LEN("</D:propstat>\n"));
4596			}
4597
4598			buffer_append_string_len(b,CONST_STR_LEN("</D:response>\n"));
4599
4600		}
4601
4602		buffer_free(d.path);
4603		buffer_free(d.rel_path);
4604
4605		buffer_free(prop_200);
4606		buffer_free(prop_404);
4607
4608		buffer_append_string_len(b,CONST_STR_LEN("</D:multistatus>\n"));
4609
4610		sqlite3_free_table(result);
4611		/*
4612		//- test
4613		Cdbg(DBE, "------------------------------");
4614
4615		//- �M��
4616		column_count = 4;
4617		//sprintf(sql_query, "SELECT PATH, TITLE, ALBUM_ART, ARTIST from DETAILS where TITLE='- All Albums -'");
4618		sprintf(sql_query, "SELECT d.PATH as PATH, "
4619		                   "d.TITLE as TITLE, "
4620		                   "d.ALBUM_ART as ALBUM_ART, "
4621		                   "d.ARTIST as ARTIST "
4622		                   "from OBJECTS o "
4623						   "left join DETAILS d on (o.DETAIL_ID = d.ID)"
4624						   " where o.CLASS = 'container.album.musicAlbum'");
4625
4626		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
4627			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows);
4628			int i=0;
4629			for( i=column_count; i<rows*column_count; i+=column_count ){
4630
4631				Cdbg(DBE, "1, i=%d, PATH=%s, TITLE=%s, ALBUM_ART=%s, ARTIST=%s",
4632					i, result[i], result[i+1], result[i+2], result[i+3]);
4633			}
4634
4635			sqlite3_free_table(result);
4636		}
4637
4638		//- �t����
4639		column_count = 4;
4640		//sprintf(sql_query, "SELECT PATH, TITLE, ALBUM_ART, ARTIST from DETAILS where TITLE='- All Albums -'");
4641		sprintf(sql_query, "SELECT d.PATH as PATH, d.TITLE as TITLE, d.ALBUM_ART as ALBUM_ART, d.ARTIST as ARTIST from OBJECTS o "
4642								   "left join DETAILS d on (o.DETAIL_ID = d.ID)"
4643								   " where o.CLASS = 'container.person.musicArtist'");
4644
4645		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
4646			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows);
4647			int i=0;
4648			for( i=column_count; i<rows*column_count; i+=column_count ){
4649
4650				Cdbg(DBE, "2, i=%d, PATH=%s, TITLE=%s, ALBUM_ART=%s, ARTIST=%s",
4651					i, result[i], result[i+1], result[i+2], result[i+3]);
4652			}
4653
4654			sqlite3_free_table(result);
4655		}
4656
4657		column_count = 4;
4658		sprintf(sql_query, "SELECT PATH, TITLE, ALBUM_ART, ARTIST from DETAILS");
4659		Cdbg(DBE, "sql_query=%s", sql_query);
4660
4661		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
4662
4663			int i=0;
4664			for( i=column_count; i<rows*column_count; i+=column_count ){
4665
4666
4667				Cdbg(DBE, "nbbb, i=%d, PATH=%s, TITLE=%s, ALBUM_ART=%s, ARTIST=%s",
4668					i, result[i], result[i+1], result[i+2], result[i+3]);
4669			}
4670
4671			sqlite3_free_table(result);
4672		}
4673
4674
4675		column_count = 5;
4676		sprintf(sql_query, "SELECT NAME, CLASS, OBJECT_ID, PARENT_ID, REF_ID from OBJECTS");
4677
4678		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
4679			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows);
4680			int i=0;
4681			for( i=column_count; i<rows*column_count; i+=column_count ){
4682				Cdbg(DBE, "nccc, i=%d, NAME=%s, OBJECT_ID=%s, PARENT_ID=%s, REF_ID=%s",
4683					i, result[i], result[i+2], result[i+3], result[i+4]);
4684			}
4685
4686			sqlite3_free_table(result);
4687		}
4688
4689
4690		column_count = 1;
4691		sprintf(sql_query, "SELECT PATH from ALBUM_ART");
4692		if( sql_get_table(sql_minidlna, sql_query, &result2, &rows2, NULL) == SQLITE_OK ){
4693			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows2);
4694			int i=0;
4695			for( i=column_count; i<rows2*column_count; i+=column_count ){
4696				//sqlite_int64 plID = strtoll(result[i], NULL, 10);
4697				//char* plpath = result[i+1];
4698				//Cdbg(DBE, "nddd, i=%d, ID=%lld, PATH=%s", i, plID, plpath);
4699
4700				char* plpath = result2[i];
4701				Cdbg(DBE, "nddd, i=%d, PATH=%s", i, plpath);
4702			}
4703		}
4704
4705		sqlite3_free_table(result2);
4706		//sqlite3_close(sql_minidlna);
4707
4708
4709		Cdbg(DBE, "------------------------------");
4710		*/
4711
4712		sqlite3_close(sql_minidlna);
4713#endif
4714		chunkqueue_append_buffer(con->write_queue, b);
4715		buffer_free(b);
4716
4717		con->http_status = 207;
4718		con->file_finished = 1;
4719		return HANDLER_FINISHED;
4720	}
4721
4722	case HTTP_METHOD_GETMUSICCLASSIFICATION:{
4723		Cdbg(DBE, "do HTTP_METHOD_GETMUSICCLASSIFICATION");
4724
4725#if EMBEDDED_EANBLE
4726		if(!con->srv_socket->is_ssl){
4727			con->http_status = 403;
4728			return HANDLER_FINISHED;
4729		}
4730#endif
4731
4732		if(is_dms_enabled() == 0){
4733			//- Service Not Available
4734			con->http_status = 503;
4735			return HANDLER_FINISHED;
4736		}
4737
4738		buffer* classify = NULL;
4739
4740		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Classify"))) {
4741			classify = ds->value;
4742		}
4743		else{
4744			con->http_status = 400;
4745			con->file_finished = 1;
4746			return HANDLER_FINISHED;
4747		}
4748
4749#ifdef USE_MINIDLNA_DB
4750		sqlite3 *sql_minidlna = NULL;
4751		if (!buffer_is_empty(p->minidlna_db_file)) {
4752			if (SQLITE_OK != sqlite3_open(p->minidlna_db_file->ptr, &(sql_minidlna))) {
4753				Cdbg(DBE, "Fail to open minidlna db %s", p->minidlna_db_file->ptr);
4754			}
4755		}
4756
4757		if (!sql_minidlna) {
4758			Cdbg(DBE, "NULL value 'sql_minidlna'!");
4759			con->http_status = 207;
4760			con->file_finished = 1;
4761			return HANDLER_FINISHED;
4762		}
4763
4764		int column_count = 5;
4765		int rows, i;
4766		char **result;
4767		char sql_query[2048] = "\0";
4768
4769		if(buffer_is_equal_string(classify, CONST_STR_LEN("album"))){
4770			sprintf(sql_query, "SELECT d.TITLE as TITLE, "
4771						   	   "d.ALBUM_ART as ALBUM_ART, "
4772						   	   "d.ARTIST as ARTIST, "
4773						   	   "o.PARENT_ID as PARENT_ID, "
4774						       "o.OBJECT_ID as OBJECT_ID "
4775						       "from OBJECTS o "
4776						       "left join DETAILS d on (o.DETAIL_ID = d.ID) "
4777						       "where o.CLASS = 'container.album.musicAlbum' "
4778						       "and o.PARENT_ID = '%s'", MUSIC_ALBUM_ID);
4779		}
4780		else if(buffer_is_equal_string(classify, CONST_STR_LEN("artist"))){
4781			sprintf(sql_query, "SELECT d.TITLE as TITLE, "
4782							   "d.ALBUM_ART as ALBUM_ART, "
4783							   "d.ARTIST as ARTIST, "
4784							   "o.PARENT_ID as PARENT_ID, "
4785                               "o.OBJECT_ID as OBJECT_ID "
4786						       "from OBJECTS o "
4787						       "left join DETAILS d on (o.DETAIL_ID = d.ID) "
4788						       "where o.CLASS = 'container.person.musicArtist'"
4789						       "and o.PARENT_ID = '%s'", MUSIC_ARTIST_ID);
4790		}
4791		else{
4792			con->http_status = 400;
4793			con->file_finished = 1;
4794			sqlite3_close(sql_minidlna);
4795			return HANDLER_FINISHED;
4796		}
4797
4798		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
4799
4800		b = buffer_init();
4801
4802		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
4803		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
4804
4805		Cdbg(DBE, "do HTTP_METHOD_GETMUSICCLASSIFICATION, sql_query=%s", sql_query);
4806
4807		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
4808			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows);
4809			int i=0;
4810
4811			for( i=column_count; i<=rows*column_count; i+=column_count ){
4812
4813				char* title = result[i];
4814				char* album_art = result[i+1];
4815				char* artist = result[i+2];
4816				char* parent_id = result[i+3];
4817				char* object_id = result[i+4];
4818
4819				buffer* id = buffer_init();
4820				buffer_copy_string(id,object_id);
4821				if(buffer_is_equal_string(classify, CONST_STR_LEN("artist")))
4822					buffer_append_string(id,"$0");
4823
4824				Cdbg(DBE, "1, TITLE=%s, ALBUM_ART=%s, ARTIST=%s", title, album_art, artist);
4825
4826#if 1
4827				int column_count2 = 1;
4828				int rows2, j;
4829				char **result2;
4830				int partion_count = 0;
4831
4832				sprintf(sql_query, "SELECT COUNT(*) as COUNT from DETAILS d "
4833					"LEFT JOIN OBJECTS o on (o.DETAIL_ID = d.ID) "
4834					"WHERE d.MIME glob 'a*' AND o.PARENT_ID='%s' ", id->ptr);
4835
4836#if EMBEDDED_EANBLE
4837				//- Get mount partition
4838				char* disk_path = "/mnt/";
4839				char partion_path[100] = "\0";
4840				//DIR *dir;
4841				if (NULL != (dir = opendir(disk_path))) {
4842					struct dirent *de;
4843					while(NULL != (de = readdir(dir))) {
4844						if ( de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0' ) {
4845							continue;
4846							//- ignore the parent dir
4847						}
4848
4849						if ( de->d_name[0] == '.' ) {
4850							continue;
4851							//- ignore the hidden file
4852						}
4853
4854						sprintf(partion_path, "%s%s", disk_path, de->d_name);
4855
4856						if(strstr( con->physical.path->ptr, partion_path )){
4857							sprintf(sql_query, "%s AND PATH LIKE '%s%s/%s'", sql_query, "%", partion_path, "%");
4858						}
4859
4860						partion_count++;
4861					}
4862					closedir(dir);
4863				}
4864#else
4865				char partion_path[100] = "/mnt/sda";
4866				sprintf(sql_query, "%s AND PATH LIKE '%s%s/%s'", sql_query, "%", partion_path, "%");
4867				partion_count = 1;
4868#endif
4869				if(partion_count>1){
4870					Cdbg(1, "sql_query=%s", sql_query);
4871					int count = 0;
4872					if( sql_get_table(sql_minidlna, sql_query, &result2, &rows2, NULL) == SQLITE_OK ){
4873						Cdbg(DBE, "aaaaaaaaaaaaaa rows2=%d", rows2);
4874
4875						for( j=column_count2; j<=rows2*column_count2; j+=column_count2 ){
4876							count = atoi(result2[j]);
4877						}
4878
4879						sqlite3_free_table(result2);
4880					}
4881
4882					Cdbg(DBE, "bbbbbbbbbbbbb count=%d", count);
4883
4884					if(count==0){
4885						buffer_free(id);
4886						continue;
4887					}
4888				}
4889#endif
4890
4891				buffer_append_string_len(b,CONST_STR_LEN("<item>"));
4892				buffer_append_string_len(b,CONST_STR_LEN("<id>"));
4893				//buffer_append_string(b,object_id);
4894				//if(buffer_is_equal_string(classify, CONST_STR_LEN("artist")))
4895				//	buffer_append_string(b,"$0");
4896				buffer_append_string_buffer(b, id);
4897				buffer_append_string_len(b,CONST_STR_LEN("</id>"));
4898				buffer_append_string_len(b,CONST_STR_LEN("<title>"));
4899				buffer_append_string(b,title);
4900				buffer_append_string_len(b,CONST_STR_LEN("</title>"));
4901				buffer_append_string_len(b,CONST_STR_LEN("<artist>"));
4902				buffer_append_string(b,artist);
4903				buffer_append_string_len(b,CONST_STR_LEN("</artist>"));
4904
4905				char* image = NULL;
4906				sqlite_int64 plAlbumArt = (album_art ? strtoll(album_art, NULL, 10) : 0);
4907				if(get_album_cover_image(sql_minidlna, plAlbumArt, &image)==1){
4908					buffer_append_string_len(b, CONST_STR_LEN("<thumb_image>"));
4909					buffer_append_string(b, image);
4910					buffer_append_string_len(b, CONST_STR_LEN("</thumb_image>"));
4911					free(image);
4912				}
4913
4914				buffer_append_string_len(b,CONST_STR_LEN("</item>"));
4915
4916				buffer_free(id);
4917			}
4918
4919			sqlite3_free_table(result);
4920		}
4921
4922		sqlite3_close(sql_minidlna);
4923		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
4924#endif
4925
4926		chunkqueue_append_buffer(con->write_queue, b);
4927		buffer_free(b);
4928
4929		con->http_status = 200;
4930		con->file_finished = 1;
4931		return HANDLER_FINISHED;
4932	}
4933
4934	case HTTP_METHOD_GETMUSICPLAYLIST:{
4935		Cdbg(DBE, "do HTTP_METHOD_GETMUSICPLAYLIST");
4936#if EMBEDDED_EANBLE
4937		if(!con->srv_socket->is_ssl){
4938			con->http_status = 403;
4939			return HANDLER_FINISHED;
4940		}
4941#endif
4942
4943		if(is_dms_enabled() == 0){
4944			//- Service Not Available
4945			con->http_status = 503;
4946			return HANDLER_FINISHED;
4947		}
4948
4949		buffer* play_id = NULL;
4950
4951		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "id"))) {
4952			play_id = ds->value;
4953		}
4954		else{
4955			con->http_status = 400;
4956			con->file_finished = 1;
4957			return HANDLER_FINISHED;
4958		}
4959#ifdef USE_MINIDLNA_DB
4960		sqlite3 *sql_minidlna = NULL;
4961		if (!buffer_is_empty(p->minidlna_db_file)) {
4962			if (SQLITE_OK != sqlite3_open(p->minidlna_db_file->ptr, &(sql_minidlna))) {
4963				Cdbg(DBE, "Fail to open minidlna db %s", p->minidlna_db_file->ptr);
4964			}
4965		}
4966
4967		if (!sql_minidlna) {
4968			Cdbg(DBE, "NULL value 'sql_minidlna'!");
4969			con->http_status = 207;
4970			con->file_finished = 1;
4971			return HANDLER_FINISHED;
4972		}
4973
4974		int column_count = 2;
4975		int rows, i;
4976		char **result;
4977		char sql_query[2048] = "\0";
4978
4979		sprintf(sql_query, "SELECT d.TITLE as TITLE, "
4980						   "d.PATH as PATH "
4981						   "from OBJECTS o "
4982						   "left join DETAILS d on (o.DETAIL_ID = d.ID) "
4983						   "where o.PARENT_ID = '%s'", play_id->ptr);
4984
4985		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
4986
4987		b = buffer_init();
4988
4989		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
4990		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
4991
4992		Cdbg(DBE, "do HTTP_METHOD_GETMUSICPLAYLIST, sql_query=%s", sql_query);
4993
4994		char auth[100]="\0";
4995		if(con->aidisk_username->used && con->aidisk_passwd->used)
4996			sprintf(auth, "%s:%s", con->aidisk_username->ptr, con->aidisk_passwd->ptr);
4997		else{
4998			con->http_status = 400;
4999			sqlite3_close(sql_minidlna);
5000			return HANDLER_FINISHED;
5001		}
5002
5003		char* base64_auth = ldb_base64_encode(auth, strlen(auth));
5004
5005		if( sql_get_table(sql_minidlna, sql_query, &result, &rows, NULL) == SQLITE_OK ){
5006			Cdbg(DBE, "sql_query=%s, rows=%d", sql_query, rows);
5007			int i=0;
5008
5009			for( i=column_count; i<=rows*column_count; i+=column_count ){
5010
5011				char* title = result[i];
5012				char* path = result[i+1];
5013				Cdbg(DBE, "title=%s", title);
5014				Cdbg(DBE, "path=%s", path);
5015				buffer_append_string_len(b,CONST_STR_LEN("<item>"));
5016				buffer_append_string_len(b,CONST_STR_LEN("<title>"));
5017				if(title) buffer_append_string(b,title);
5018				buffer_append_string_len(b,CONST_STR_LEN("</title>"));
5019				buffer_append_string_len(b,CONST_STR_LEN("<path>"));
5020				if(path) buffer_append_string(b,path);
5021				buffer_append_string_len(b,CONST_STR_LEN("</path>"));
5022
5023				if(path){
5024					char* filename = NULL;
5025					buffer* buffer_filename = buffer_init();
5026					extract_filename(path, &filename);
5027					buffer_copy_string(buffer_filename, "");
5028					buffer_append_string_encoded(buffer_filename,filename,strlen(filename),ENCODING_REL_URI);
5029					free(filename);
5030
5031					char* filepath = NULL;
5032					extract_filepath(path, &filepath);
5033
5034					char buff[4096];
5035					char* usbdisk_name;
5036
5037					#if EMBEDDED_EANBLE
5038					char *a = nvram_get_productid();
5039					int l = strlen(a)+1;
5040					usbdisk_name = (char*)malloc(l);
5041					memset(usbdisk_name,'\0', l);
5042					strcpy(usbdisk_name, a);
5043					#ifdef APP_IPKG
5044					free(a);
5045					#endif
5046					char* tmp = replace_str(&filepath[0],
5047					                    	"tmp/mnt",
5048					                    	usbdisk_name,
5049						                	(char *)&buff[0]);
5050					#else
5051					usbdisk_name = (char*)malloc(8);
5052					memset(usbdisk_name,'\0', 8);
5053					strcpy(usbdisk_name, "usbdisk");
5054					char* tmp = replace_str(&filepath[0],
5055					                    	"mnt",
5056					                    	usbdisk_name,
5057						                	(char *)&buff[0]);
5058
5059					#endif
5060
5061					buffer* buffer_filepath = buffer_init();
5062					buffer_copy_string(buffer_filepath, "");
5063					buffer_append_string_encoded(buffer_filepath,tmp,strlen(tmp),ENCODING_REL_URI);
5064
5065					Cdbg(DBE, "filename=%s, filepath=%s", buffer_filename->ptr, buffer_filepath->ptr);
5066
5067					buffer* buffer_result_share_link;
5068					if( generate_sharelink(srv,
5069						                   con,
5070						                   buffer_filename->ptr,
5071						                   buffer_filepath->ptr,
5072						                   base64_auth, 0, 0,
5073						                   &buffer_result_share_link) == 1){
5074						buffer_append_string_len(b,CONST_STR_LEN("<sharelink>"));
5075						Cdbg(DBE, "sharelink=%s", buffer_result_share_link->ptr);
5076						buffer_append_string_buffer(b,buffer_result_share_link);
5077						buffer_append_string_len(b,CONST_STR_LEN("</sharelink>"));
5078					}
5079
5080					free(usbdisk_name);
5081					free(filepath);
5082					buffer_free(buffer_filename);
5083					buffer_free(buffer_filepath);
5084					buffer_free(buffer_result_share_link);
5085				}
5086
5087				buffer_append_string_len(b,CONST_STR_LEN("</item>"));
5088			}
5089
5090			sqlite3_free_table(result);
5091		}
5092
5093		sqlite3_close(sql_minidlna);
5094		free(base64_auth);
5095
5096		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
5097#endif
5098
5099		//Cdbg(DBE, "b=%s", b->ptr);
5100		chunkqueue_append_buffer(con->write_queue, b);
5101		buffer_free(b);
5102
5103		con->http_status = 200;
5104		con->file_finished = 1;
5105		return HANDLER_FINISHED;
5106	}
5107
5108	case HTTP_METHOD_GETTHUMBIMAGE:{
5109		Cdbg(DBE, "do HTTP_METHOD_GETTHUMBIMAGE");
5110
5111#if EMBEDDED_EANBLE
5112		if(!con->srv_socket->is_ssl){
5113			con->http_status = 403;
5114			return HANDLER_FINISHED;
5115		}
5116#endif
5117
5118		if(is_dms_enabled() == 0){
5119			//- Service Not Available
5120			con->http_status = 503;
5121			return HANDLER_FINISHED;
5122		}
5123
5124		buffer* file = NULL;
5125
5126		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "File"))) {
5127			file = ds->value;
5128		}
5129		else{
5130			con->http_status = 400;
5131			con->file_finished = 1;
5132			return HANDLER_FINISHED;
5133		}
5134
5135		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
5136
5137		b = buffer_init();
5138
5139		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
5140		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
5141
5142		buffer* file_path = buffer_init();
5143		buffer_copy_buffer(file_path, con->physical.path);
5144		buffer_append_string_len(file_path, CONST_STR_LEN("/"));
5145		buffer_append_string_buffer(file_path, file);
5146
5147		char* image = NULL;
5148		Cdbg(1, "file_path = %s", file_path->ptr);
5149		if(get_thumb_image(file_path->ptr, p, &image)==1){
5150			buffer_append_string_len(b, CONST_STR_LEN("<thumb_image>"));
5151			buffer_append_string(b, image);
5152			buffer_append_string_len(b, CONST_STR_LEN("</thumb_image>"));
5153			free(image);
5154		}
5155
5156		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
5157
5158		buffer_free(file_path);
5159
5160		chunkqueue_append_buffer(con->write_queue, b);
5161		buffer_free(b);
5162
5163		con->http_status = 200;
5164		con->file_finished = 1;
5165		return HANDLER_FINISHED;
5166	}
5167
5168	case HTTP_METHOD_GETVIDEOSUBTITLE:{
5169#if EMBEDDED_EANBLE
5170		if(!con->srv_socket->is_ssl){
5171			con->http_status = 403;
5172			return HANDLER_FINISHED;
5173		}
5174#endif
5175
5176		buffer* filename = NULL;
5177
5178		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
5179			filename = ds->value;
5180		} else {
5181			con->http_status = 400;
5182			return HANDLER_FINISHED;
5183		}
5184
5185		Cdbg(DBE, "do HTTP_METHOD_GETVIDEOSUBTITLE %s, filename=%s", con->physical.path->ptr, filename->ptr);
5186
5187		char auth[100]="\0";
5188		if(con->aidisk_username->used && con->aidisk_passwd->used)
5189			sprintf(auth, "%s:%s", con->aidisk_username->ptr, con->aidisk_passwd->ptr);
5190		else{
5191			con->http_status = 400;
5192			return HANDLER_FINISHED;
5193		}
5194
5195		char* base64_auth = ldb_base64_encode(auth, strlen(auth));
5196
5197		response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
5198
5199		b = buffer_init();
5200
5201		buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
5202		buffer_append_string_len(b,CONST_STR_LEN("<result>"));
5203
5204		if (NULL != (dir = opendir(con->physical.path->ptr))) {
5205			struct dirent *de;
5206
5207			while(NULL != (de = readdir(dir))) {
5208				struct stat st;
5209				int status = 0;
5210
5211				if ((de->d_name[0] == '.' && de->d_name[1] == '\0')  ||
5212				    (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
5213					continue;
5214					/* ignore the parent dir */
5215				}
5216
5217				char* aa = get_filename_ext(de->d_name);
5218				int len = strlen(aa)+1;
5219				char* file_ext = (char*)malloc(len);
5220				memset(file_ext,'\0', len);
5221				strcpy(file_ext, aa);
5222				for (int i = 0; file_ext[i]; i++)
5223					file_ext[i] = tolower(file_ext[i]);
5224
5225				if( strcmp(file_ext, "srt")==0 &&
5226					strstr(de->d_name, filename->ptr)){
5227
5228				#if 0
5229					#define BUF_LEN 256
5230					//char utf[1024] = "���������r��";
5231					unsigned long uni2[BUF_LEN] = {
5232				        0x8BF7, 0x4FDD, 0x8BC1, 0x8BE5, 0x6587, 0x4EF6, 0x662F, 0x4EE5,
5233				        0x20, 0x75, 0x74, 0x66, 0x2D, 0x38, 0x20, 0x683C, 0x5F0F,
5234				        0x5B58, 0x50A8, 0x7684, 0x21, 0x0
5235				    };
5236					char utf2[BUF_LEN];
5237					int utflen2 = BUF_LEN;
5238					int ret2 = enc_unicode_to_utf8_str(uni2, (unsigned char *)utf2, &utflen2);
5239					if ( ret2 == 1 ){
5240				    	Cdbg(DBE, "Ooooooooooooooooooooooooooooooooooook!");
5241				        utf2[utflen2] = '\0';
5242				        Cdbg(DBE, "utf2=%s", utf2);
5243				    }
5244				#endif
5245#if 0
5246					#define BUF_LEN 1024
5247					buffer* srt_file = buffer_init();
5248					buffer_copy_buffer(srt_file, con->physical.path);
5249					buffer_append_string(srt_file, "/");
5250					buffer_append_string(srt_file, de->d_name);
5251					Cdbg(DBE, "srt_file=%s", srt_file->ptr);
5252
5253					if(!is_utf8_file(srt_file->ptr)){
5254
5255						buffer* new_srt_file = buffer_init();
5256
5257						buffer_copy_buffer(new_srt_file, con->physical.path);
5258						buffer_append_string(new_srt_file, "/");
5259						buffer_append_string_buffer(new_srt_file, filename);
5260						buffer_append_string(new_srt_file, "_utf8.srt");
5261
5262						//buffer_append_string(new_srt_file, "/tmp/out.srt");
5263
5264						Cdbg(DBE, "new_srt_file=%s", new_srt_file->ptr);
5265
5266						FILE* fp3, *fp4;
5267						char line[BUF_LEN];
5268
5269						fp4 = fopen(new_srt_file->ptr, "w");
5270
5271						//- write utf-8 file header
5272						unsigned char utf8_header[3] = {0xEF, 0xBB, 0xBF};
5273						fputs(utf8_header,fp4);
5274
5275						if((fp3 = fopen(srt_file->ptr, "r")) != NULL){
5276
5277							#if 1
5278							memset(line, 0, sizeof(line));
5279							while(fgets(line, BUF_LEN, fp3) != NULL){
5280
5281								//Cdbg(1, "line=%s", line);
5282								//- ANSI to UTF-8
5283								char *iconv_buf = (char*)calloc(BUF_LEN, sizeof(char));
5284
5285								int rc = do_iconv("UTF-8", "CP950",
5286														   line,
5287														   strlen(line),
5288														   iconv_buf,
5289														   BUF_LEN);
5290								//Cdbg(1, "iconv_buf=%s", iconv_buf);
5291								fputs(iconv_buf,fp4);
5292
5293								free(iconv_buf);
5294							}
5295							#else
5296							setlocale(LC_ALL, "");
5297							char line2[BUF_LEN];
5298							while(fgets(line2, BUF_LEN, fp3) != NULL){
5299
5300								//Cdbg(DBE, "line2=%s", line2);
5301
5302								char utf2[BUF_LEN];
5303								int utflen2 = BUF_LEN;
5304								//char uni2[BUF_LEN] = "���������r��";
5305								/*
5306								unsigned long uni2[BUF_LEN] = {
5307								        0x8BF7, 0x4FDD, 0x8BC1, 0x8BE5, 0x6587, 0x4EF6, 0x662F, 0x4EE5,
5308								        0x20, 0x75, 0x74, 0x66, 0x2D, 0x38, 0x20, 0x683C, 0x5F0F,
5309								        0x5B58, 0x50A8, 0x7684, 0x21, 0x0
5310								};
5311								*/
5312
5313								#if 0
5314								wchar_t wt1[BUF_LEN];
5315								int size4 = ansiToWCHAR(wt1, BUF_LEN, line2 ,BUF_LEN+1, "en_ZW.utf8");
5316								if(size4>0){
5317									int ret2 = enc_unicode_to_utf8_str(wt1, (unsigned char *)utf2, &utflen2);
5318									if ( ret2 == 1 ){
5319								    	utf2[utflen2] = '\0';
5320								        Cdbg(DBE, "utf2=%s", utf2);
5321										fputs(utf2,fp4);
5322								    }
5323								}
5324								#else
5325								int ret2 = enc_unicode_to_utf8_str((unsigned long *)m2w(line2), (unsigned char *)utf2, &utflen2);
5326								if ( ret2 == 1 ){
5327								   	utf2[utflen2] = '\0';
5328								    Cdbg(DBE, "utf2=%s", utf2);
5329									fputs(utf2,fp4);
5330								}
5331								#endif
5332							}
5333							#endif
5334
5335							fclose(fp3);
5336						}
5337
5338						physical s, d;
5339
5340						s.path = buffer_init();
5341						s.rel_path = buffer_init();
5342						buffer_copy_buffer(s.path, new_srt_file);
5343
5344						d.path = buffer_init();
5345						d.rel_path = buffer_init();
5346						buffer_copy_buffer(d.path,srt_file);
5347
5348						Cdbg(DBE, "copy=%s -> %s", new_srt_file->ptr, srt_file->ptr);
5349
5350						//webdav_copy_file(srv, con, p, &s, &d, 1);
5351
5352						fclose(fp4);
5353						buffer_free(srt_file);
5354						buffer_free(new_srt_file);
5355					}
5356
5357#endif
5358					buffer* buffer_filepath = buffer_init();
5359					buffer_copy_string(buffer_filepath, "");
5360					buffer_append_string_encoded(buffer_filepath, con->url.path->ptr, strlen(con->url.path->ptr), ENCODING_REL_URI);
5361
5362					buffer* buffer_result_share_link;
5363					if( generate_sharelink(srv,
5364						                   con,
5365						                   de->d_name,
5366						                   buffer_filepath->ptr,
5367						                   base64_auth, 0, 0,
5368						                   &buffer_result_share_link) == 1){
5369						buffer_append_string_len(b,CONST_STR_LEN("<file>"));
5370						buffer_append_string_len(b,CONST_STR_LEN("<name>"));
5371						buffer_append_string(b,de->d_name);
5372						buffer_append_string_len(b,CONST_STR_LEN("</name>"));
5373						buffer_append_string_len(b,CONST_STR_LEN("<sharelink>"));
5374						buffer_append_string_buffer(b,buffer_result_share_link);
5375						buffer_append_string_len(b,CONST_STR_LEN("</sharelink>"));
5376						buffer_append_string_len(b,CONST_STR_LEN("</file>"));
5377					}
5378
5379					buffer_free(buffer_filepath);
5380					buffer_free(buffer_result_share_link);
5381				}
5382
5383				free(file_ext);
5384			}
5385
5386			closedir(dir);
5387		}
5388
5389		buffer_append_string_len(b,CONST_STR_LEN("</result>"));
5390
5391		chunkqueue_append_buffer(con->write_queue, b);
5392		buffer_free(b);
5393
5394		con->http_status = 200;
5395		con->file_finished = 1;
5396		return HANDLER_FINISHED;
5397	}
5398
5399	case HTTP_METHOD_UPLOADTOFACEBOOK:{
5400		Cdbg(1, "do HTTP_METHOD_UPLOADTOFACEBOOK");
5401
5402#if EMBEDDED_EANBLE
5403		if(!con->srv_socket->is_ssl){
5404			con->http_status = 403;
5405			return HANDLER_FINISHED;
5406		}
5407#endif
5408
5409		buffer* filename = NULL;
5410		buffer* title = NULL;
5411		buffer* album = NULL;
5412		buffer* auth_token = NULL;
5413
5414		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
5415			filename = ds->value;
5416			buffer_urldecode_path(filename);
5417		} else {
5418			con->http_status = 400;
5419			return HANDLER_FINISHED;
5420		}
5421
5422		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TITLE"))) {
5423			title = ds->value;
5424			buffer_urldecode_path(title);
5425		} else {
5426			con->http_status = 400;
5427			return HANDLER_FINISHED;
5428		}
5429
5430		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TOKEN"))) {
5431			auth_token = ds->value;
5432		} else {
5433			con->http_status = 400;
5434			return HANDLER_FINISHED;
5435		}
5436
5437		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "ALBUM"))) {
5438			album = ds->value;
5439		} else {
5440			con->http_status = 400;
5441			return HANDLER_FINISHED;
5442		}
5443
5444		CURL *curl;
5445		CURLcode rt;
5446		struct curl_httppost *formpost = NULL;
5447		struct curl_httppost *lastptr = NULL;
5448		char md5[129];
5449		char* response_str;
5450		char url_upload_facebook[1024] = "\0";
5451		curl = curl_easy_init();
5452
5453		strcpy(url_upload_facebook, "https://graph.facebook.com/");
5454		strcat(url_upload_facebook, album->ptr);
5455		strcat(url_upload_facebook, "/photos");
5456
5457		Cdbg(1, "url_upload_facebook=%s", url_upload_facebook);
5458
5459		if(curl) {
5460			Cdbg(1, "curl_easy_init OK");
5461
5462			/* Set Host to target in HTTP header, and set response handler
5463		 	* function */
5464			curl_easy_setopt(curl, CURLOPT_URL, url_upload_facebook);
5465
5466
5467			/* Build the form post */
5468			curl_formadd(&formpost, &lastptr,
5469			             CURLFORM_COPYNAME, "access_token",
5470			             CURLFORM_COPYCONTENTS, auth_token->ptr, CURLFORM_END);
5471
5472			curl_formadd(&formpost, &lastptr,
5473			             CURLFORM_COPYNAME, "message",
5474			             CURLFORM_COPYCONTENTS, title->ptr, CURLFORM_END);
5475
5476			curl_formadd(&formpost, &lastptr,
5477			             CURLFORM_COPYNAME, "status",
5478			             CURLFORM_COPYCONTENTS, "success", CURLFORM_END);
5479
5480			char photo_path[1024] = "\0";
5481			sprintf(photo_path, "%s/%s", con->physical.path->ptr, filename->ptr);
5482			Cdbg(1, "photo_path=%s", photo_path);
5483
5484			//- check file exists
5485			if(!file_exist(photo_path)){
5486				curl_easy_cleanup(curl);
5487				curl_formfree(formpost);
5488				con->http_status = 404;
5489				return HANDLER_FINISHED;
5490			}
5491
5492			curl_formadd(&formpost, &lastptr,
5493			             CURLFORM_COPYNAME, "source",
5494			             CURLFORM_FILE, photo_path, CURLFORM_END);
5495
5496			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
5497			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
5498
5499			curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
5500			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func);
5501			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_str);
5502
5503			Cdbg(1, "Uploading...");
5504			rt = curl_easy_perform(curl);
5505
5506			#if 1
5507			/* now extract transfer info */
5508			double speed_upload, total_time;
5509      		curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
5510      		curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
5511
5512      		Cdbg(1, "Speed: %.3f bytes/sec during %.3f seconds, response_str=%s",
5513              		speed_upload, total_time, response_str);
5514
5515			free(response_str);
5516			#else
5517			if (rt) {
5518				Cdbg(1, "An error occurred during upload! %s", curl_easy_strerror(rt));
5519			}
5520			else{
5521				/* now extract transfer info */
5522				double speed_upload, total_time;
5523      			curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
5524      			curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
5525
5526      			Cdbg(1, "Speed: %.3f bytes/sec during %.3f seconds",
5527              		speed_upload, total_time);
5528			}
5529			#endif
5530
5531			/* Done. Cleanup. */
5532			curl_easy_cleanup(curl);
5533			curl_formfree(formpost);
5534		}
5535
5536		con->http_status = 200;
5537		con->file_finished = 1;
5538		return HANDLER_FINISHED;
5539	}
5540
5541	case HTTP_METHOD_UPLOADTOPICASA:{
5542		Cdbg(DBE, "do HTTP_METHOD_UPLOADTOPICASA");
5543
5544#if EMBEDDED_EANBLE
5545		if(!con->srv_socket->is_ssl){
5546			con->http_status = 403;
5547			return HANDLER_FINISHED;
5548		}
5549#endif
5550
5551		buffer* filename = NULL;
5552		buffer* title = NULL;
5553		buffer* auth_token = NULL;
5554		buffer* user_id = NULL;
5555		buffer* album_id = NULL;
5556		long response_result = 0;
5557
5558		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
5559			filename = ds->value;
5560			buffer_urldecode_path(filename);
5561		} else {
5562			con->http_status = 400;
5563			return HANDLER_FINISHED;
5564		}
5565
5566		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TITLE"))) {
5567			title = ds->value;
5568			buffer_urldecode_path(title);
5569		} else {
5570			con->http_status = 400;
5571			return HANDLER_FINISHED;
5572		}
5573
5574		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "UID"))) {
5575			user_id = ds->value;
5576		} else {
5577			con->http_status = 400;
5578			return HANDLER_FINISHED;
5579		}
5580
5581		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "AID"))) {
5582			album_id = ds->value;
5583		} else {
5584			con->http_status = 400;
5585			return HANDLER_FINISHED;
5586		}
5587
5588		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TOKEN"))) {
5589			auth_token = ds->value;
5590		} else {
5591			con->http_status = 400;
5592			return HANDLER_FINISHED;
5593		}
5594
5595		CURL *curl;
5596		CURLcode rt;
5597
5598		#if 0
5599		_buffer_t upload_response;
5600		#endif
5601
5602		buffer* buffer_photoid;
5603
5604		curl = curl_easy_init();
5605		if(curl) {
5606			Cdbg(DBE, "curl_easy_init OK");
5607
5608			char request_url[1024] = "\0";
5609			sprintf(request_url, "https://picasaweb.google.com/data/feed/api/user/%s/albumid/%s", user_id->ptr, album_id->ptr);
5610			curl_easy_setopt(curl, CURLOPT_URL, request_url);
5611
5612			char photo_path[1024] = "\0";
5613			sprintf(photo_path, "%s/%s", con->physical.path->ptr, filename->ptr);
5614
5615			FILE *fd;
5616 			fd = fopen(photo_path, "rb"); /* open file to upload */
5617		  	if(!fd) {
5618				curl_easy_cleanup(curl);
5619		    	con->http_status = 404;
5620				return HANDLER_FINISHED;
5621		 	}
5622
5623			/* to get the file size */
5624			struct stat file_info;
5625  			if(fstat(fileno(fd), &file_info) != 0) {
5626				fclose(fd);
5627				curl_easy_cleanup(curl);
5628		    	con->http_status = 404;
5629				return HANDLER_FINISHED;
5630			}
5631
5632			long file_size = file_info.st_size;
5633			char* file_data = (char*) malloc (sizeof(char)*file_size);
5634  			if(file_data == NULL) {
5635				fclose(fd);
5636				curl_easy_cleanup(curl);
5637		    	con->http_status = 400;
5638				return HANDLER_FINISHED;
5639			}
5640
5641  			// copy the file into the buffer:
5642		  	size_t result = fread( file_data, 1, file_size, fd );
5643
5644			if (result != file_size) {
5645				free(file_data);
5646				fclose(fd);
5647				curl_easy_cleanup(curl);
5648		    	con->http_status = 400;
5649				return HANDLER_FINISHED;
5650			}
5651
5652			char mpart1[4096] = "\0";
5653  			sprintf(mpart1, "\nMedia multipart posting\n"
5654				"--END_OF_PART\n"
5655				"Content-Type: application/atom+xml\n\n"
5656				"<entry xmlns='http://www.w3.org/2005/Atom'>\n"
5657				"<title>%s</title>\n"
5658                "<summary></summary>\n"
5659                "<category scheme=\"http://schemas.google.com/g/2005#kind\"\n"
5660                " term=\"http://schemas.google.com/photos/2007#photo\"/>"
5661				"</entry>\n"
5662				"--END_OF_PART\n"
5663				"Content-Type: image/jpeg\n\n", title->ptr);
5664
5665			int mpart1size = strlen(mpart1);
5666			int postdata_length = mpart1size + file_size + strlen("\n--END_OF_PART--");
5667  			char *postdata = (char*)malloc(sizeof(char)*postdata_length);
5668
5669			if(postdata == NULL) {
5670				free(file_data);
5671				fclose(fd);
5672				curl_easy_cleanup(curl);
5673		    	con->http_status = 400;
5674				return HANDLER_FINISHED;
5675			}
5676
5677			memcpy( postdata, mpart1, mpart1size);
5678			memcpy( postdata + mpart1size, file_data, file_size);
5679			memcpy( postdata + mpart1size + file_size, "\n--END_OF_PART--", strlen("\n--END_OF_PART--") );
5680
5681			free(file_data);
5682			fclose(fd);
5683
5684			struct curl_slist *headers = NULL;
5685			headers = curl_slist_append(headers,"Content-Type: multipart/related; boundary=\"END_OF_PART\"");
5686			headers = curl_slist_append(headers,"MIME-version: 1.0");
5687			headers = curl_slist_append(headers,"Expect:");
5688			headers = curl_slist_append(headers,"GData-Version: 2");
5689
5690			char authHeader[1024] = "\0";
5691			sprintf(authHeader, "Authorization: OAuth %s", auth_token->ptr);
5692			headers = curl_slist_append(headers, authHeader);
5693
5694			char content_length[1024] = "\0";
5695			sprintf(content_length, "Content-Length=%d", file_size);
5696			headers = curl_slist_append(headers, content_length);
5697
5698			curl_easy_setopt(curl, CURLOPT_VERBOSE, 2);
5699			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
5700			curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
5701			curl_easy_setopt(curl, CURLOPT_POST, 1);
5702			curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
5703
5704			curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
5705  			curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postdata_length);
5706
5707			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
5708			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
5709
5710			#if 0
5711			memset(&upload_response,0,sizeof(_buffer_t));
5712			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _picasa_api_buffer_write_func);
5713			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &upload_response);
5714			#endif
5715
5716			Cdbg(DBE, "Uploading...");
5717			rt = curl_easy_perform(curl);
5718
5719			curl_slist_free_all(headers);
5720
5721			curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_result);
5722
5723			#if 0
5724			if( response_result == 201 ){
5725				Cdbg(DBE, "complete upload...%s", upload_response.data);
5726
5727				xmlDocPtr xml = xmlParseDoc((xmlChar *)upload_response.data);
5728				if(xml){
5729					xmlNode *rootnode = xmlDocGetRootElement(xml);
5730					Cdbg(1, "rootnode->name=%s", rootnode->name);
5731					if (0 == xmlStrcmp(rootnode->name, BAD_CAST "entry")) {
5732
5733						xmlNodePtr entryChilds = rootnode->xmlChildrenNode;
5734
5735						if( entryChilds != NULL ){
5736				        	do{
5737								if ((!xmlStrcmp(entryChilds->name, BAD_CAST "id")) ){
5738						        	// Get the photo id used in uri for update
5739						            xmlChar *id= xmlNodeListGetString(xml, entryChilds->xmlChildrenNode, 1);
5740						            if( xmlStrncmp(id, BAD_CAST "http://", 7) ){
5741						            	buffer_photoid = buffer_init();
5742										buffer_copy_string( buffer_photoid, id );
5743										Cdbg(DBE, "buffer_photoid=%s", buffer_photoid->ptr);
5744						            }
5745						            xmlFree(id);
5746
5747									break;
5748					          	}
5749							}while( (entryChilds = entryChilds->next)!=NULL );
5750      					}
5751					}
5752
5753					xmlFreeDoc(xml);
5754				}
5755			}
5756			#endif
5757
5758			/* Done. Cleanup. */
5759			free(postdata);
5760
5761			#if 0
5762			free(upload_response.data);
5763			#endif
5764
5765			curl_easy_cleanup(curl);
5766		}
5767
5768		con->http_status = ( response_result == 201 ) ? 200 : 501;
5769		con->file_finished = 1;
5770		return HANDLER_FINISHED;
5771	}
5772
5773	case HTTP_METHOD_UPLOADTOFLICKR:{
5774		Cdbg(1, "do HTTP_METHOD_UPLOADTOFLICKR");
5775
5776#if EMBEDDED_EANBLE
5777		if(!con->srv_socket->is_ssl){
5778			con->http_status = 403;
5779			return HANDLER_FINISHED;
5780		}
5781#endif
5782
5783		buffer* filename = NULL;
5784		buffer* title = NULL;
5785		buffer* auth_token = NULL;
5786
5787		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
5788			filename = ds->value;
5789			buffer_urldecode_path(filename);
5790		} else {
5791			con->http_status = 400;
5792			return HANDLER_FINISHED;
5793		}
5794
5795		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TITLE"))) {
5796			title = ds->value;
5797			buffer_urldecode_path(title);
5798		} else {
5799			con->http_status = 400;
5800			return HANDLER_FINISHED;
5801		}
5802
5803		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TOKEN"))) {
5804			auth_token = ds->value;
5805		} else {
5806			con->http_status = 400;
5807			return HANDLER_FINISHED;
5808		}
5809#if 0
5810		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "PHOTOSET"))) {
5811			photoset = ds->value;
5812		} else {
5813			con->http_status = 400;
5814			return HANDLER_FINISHED;
5815		}
5816#endif
5817		//char api_key[100] = "37140360286c5cd9952023fa8b662a64";
5818		//char secret[100] = "804b51d14d840d6e";
5819		char api_key[100] = "c0466d7736e0275d062ce64aefaacfe0";
5820		char secret[100] = "228e160cf8805246";
5821
5822		CURL *curl;
5823		CURLcode rt;
5824		struct curl_httppost *formpost = NULL;
5825		struct curl_httppost *lastptr = NULL;
5826		char md5[129];
5827		char* response_str;
5828		buffer* buffer_photoid = buffer_init();
5829
5830		curl = curl_easy_init();
5831		if(curl) {
5832			Cdbg(1, "curl_easy_init OK");
5833
5834			/* Set Host to target in HTTP header, and set response handler
5835		 	* function */
5836			curl_easy_setopt(curl, CURLOPT_URL, "https://api.flickr.com/services/upload/");
5837			/* curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); */
5838
5839			/*
5840			char input_string[1024] = "\0";
5841			sprintf(input_string, "api_key%sauth_token%sdescription%stags%stitle%s", api_key, auth_token->ptr, description, tags, title);
5842			Cdbg(1, "input_string=%s", input_string);
5843			md5String(secret, input_string, md5);
5844			*/
5845
5846			md5sum(md5, 7, secret, "api_key", api_key, "auth_token", auth_token->ptr, "title", title->ptr);
5847			Cdbg(1, "md5=%s", md5);
5848
5849			/* Build the form post */
5850			curl_formadd(&formpost, &lastptr,
5851			             CURLFORM_COPYNAME, "api_key",
5852			             CURLFORM_COPYCONTENTS, api_key, CURLFORM_END);
5853
5854			curl_formadd(&formpost, &lastptr,
5855			             CURLFORM_COPYNAME, "auth_token",
5856			             CURLFORM_COPYCONTENTS, auth_token->ptr, CURLFORM_END);
5857
5858			curl_formadd(&formpost, &lastptr,
5859			             CURLFORM_COPYNAME, "api_sig",
5860			             CURLFORM_COPYCONTENTS, md5, CURLFORM_END);
5861
5862			curl_formadd(&formpost, &lastptr,
5863			             CURLFORM_COPYNAME, "title",
5864			             CURLFORM_COPYCONTENTS, title->ptr, CURLFORM_END);
5865
5866			char photo_path[1024] = "\0";
5867			sprintf(photo_path, "%s/%s", con->physical.path->ptr, filename->ptr);
5868			Cdbg(1, "photo_path=%s", photo_path);
5869
5870			//- check file exists
5871			if(!file_exist(photo_path)){
5872				curl_easy_cleanup(curl);
5873				curl_formfree(formpost);
5874				buffer_free(buffer_photoid);
5875				con->http_status = 404;
5876				return HANDLER_FINISHED;
5877			}
5878
5879			curl_formadd(&formpost, &lastptr,
5880			             CURLFORM_COPYNAME, "photo",
5881			             CURLFORM_FILE, photo_path, CURLFORM_END);
5882
5883			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
5884			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
5885
5886			curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
5887			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func);
5888			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_str);
5889
5890			Cdbg(1, "Uploading...");
5891			rt = curl_easy_perform(curl);
5892
5893			#if 0
5894			/* now extract transfer info */
5895			double speed_upload, total_time;
5896      		curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
5897      		curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
5898
5899      		Cdbg(1, "Speed: %.3f bytes/sec during %.3f seconds, response_str=%s",
5900              		speed_upload, total_time, response_str);
5901			#endif
5902
5903			xmlDocPtr xml = xmlParseMemory(response_str, strlen(response_str));
5904			if(xml){
5905				xmlNode *rootnode = xmlDocGetRootElement(xml);
5906
5907				if (0 == xmlStrcmp(rootnode->name, BAD_CAST "rsp")) {
5908
5909					xmlChar *stat = xmlGetProp(rootnode,(const xmlChar*) "stat");
5910
5911					if (0 == xmlStrcmp(stat, BAD_CAST "ok")) {
5912
5913						xmlNode *childnode;
5914						for (childnode = rootnode->children; childnode; childnode = childnode->next) {
5915							if (0 == xmlStrcmp(childnode->name, BAD_CAST "photoid")) {
5916								xmlChar *photoid = xmlNodeGetContent(childnode);
5917								buffer_copy_string( buffer_photoid, photoid );
5918								break;
5919							}
5920						}
5921					}
5922				}
5923
5924				xmlFreeDoc(xml);
5925			}
5926
5927			free(response_str);
5928
5929			/* Done. Cleanup. */
5930			curl_easy_cleanup(curl);
5931			curl_formfree(formpost);
5932		}
5933
5934		if(!buffer_is_empty(buffer_photoid)){
5935
5936			Cdbg(1, "buffer_photoid=%s", buffer_photoid->ptr);
5937#if 0
5938
5939			//- set photo to photoset
5940			//if(!buffer_is_empty(photoset)){
5941			if(buffer_is_empty(photoset)){
5942
5943				char* response_str2;
5944				struct curl_httppost *formpost2 = NULL;
5945				struct curl_httppost *lastptr2 = NULL;
5946				curl = curl_easy_init();
5947				if(curl) {
5948					curl_easy_setopt(curl, CURLOPT_URL, "http://api.flickr.com/services/rest/");
5949
5950					md5sum(md5, 11, secret, "method", "flickr.photosets.addPhoto", "api_key", api_key, "auth_token", auth_token->ptr, "photoset_id", photoset->ptr, "photo_id", buffer_photoid->ptr);
5951					Cdbg(1, "md5=%s, photoset=%s", md5, photoset->ptr);
5952
5953					/* Build the form post */
5954					curl_formadd(&formpost2, &lastptr2,
5955								 CURLFORM_COPYNAME, "method",
5956								 CURLFORM_COPYCONTENTS, "flickr.photosets.addPhoto", CURLFORM_END);
5957
5958					curl_formadd(&formpost2, &lastptr2,
5959								 CURLFORM_COPYNAME, "api_key",
5960								 CURLFORM_COPYCONTENTS, api_key, CURLFORM_END);
5961
5962					curl_formadd(&formpost2, &lastptr2,
5963								 CURLFORM_COPYNAME, "photoset_id",
5964								 CURLFORM_COPYCONTENTS, photoset->ptr, CURLFORM_END);
5965
5966					curl_formadd(&formpost2, &lastptr2,
5967								 CURLFORM_COPYNAME, "photo_id",
5968								 CURLFORM_COPYCONTENTS, buffer_photoid->ptr, CURLFORM_END);
5969
5970					curl_formadd(&formpost2, &lastptr2,
5971								 CURLFORM_COPYNAME, "auth_token",
5972								 CURLFORM_COPYCONTENTS, auth_token->ptr, CURLFORM_END);
5973
5974					curl_formadd(&formpost2, &lastptr2,
5975								 CURLFORM_COPYNAME, "api_sig",
5976								 CURLFORM_COPYCONTENTS, md5, CURLFORM_END);
5977
5978					curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost2);
5979
5980					#if 1
5981					rt = curl_easy_perform(curl);
5982
5983					if (rt) {
5984						Cdbg(1, "An error occurred during upload! %s", curl_easy_strerror(rt));
5985					}
5986					#else
5987					curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func);
5988					curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_str2);
5989					Cdbg(1, "2", md5);
5990
5991					rt = curl_easy_perform(curl);
5992
5993					Cdbg(1, "2, response_str2=%s", response_str2);
5994					xmlDocPtr xml = xmlParseMemory(response_str2, strlen(response_str2));
5995					if(xml){
5996						xmlNode *rootnode = xmlDocGetRootElement(xml);
5997
5998						if (0 == xmlStrcmp(rootnode->name, BAD_CAST "rsp")) {
5999
6000							xmlChar *stat = xmlGetProp(rootnode,(const xmlChar*) "stat");
6001
6002							if (0 == xmlStrcmp(stat, BAD_CAST "ok")) {
6003								Cdbg(1, "set photoset OK...");
6004							}
6005
6006							xmlFreeDoc(xml);
6007						}
6008					}
6009
6010					free(response_str2);
6011					#endif
6012
6013					/* Done. Cleanup. */
6014					curl_easy_cleanup(curl);
6015					curl_formfree(formpost2);
6016				}
6017
6018			}
6019#endif
6020			response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
6021
6022			b = buffer_init();
6023
6024			buffer_copy_string_len(b, CONST_STR_LEN("<?xml version=\"1.0\" encoding=\"utf-8\"?>"));
6025			buffer_append_string_len(b,CONST_STR_LEN("<result>"));
6026			buffer_append_string_len(b,CONST_STR_LEN("<photoid>"));
6027			buffer_append_string_buffer(b,buffer_photoid);
6028			buffer_append_string_len(b,CONST_STR_LEN("</photoid>"));
6029			buffer_append_string_len(b,CONST_STR_LEN("</result>"));
6030
6031			chunkqueue_append_buffer(con->write_queue, b);
6032			buffer_free(b);
6033
6034			con->http_status = 200;
6035		}
6036		else
6037			con->http_status = 501;
6038
6039		buffer_free(buffer_photoid);
6040
6041		con->file_finished = 1;
6042		return HANDLER_FINISHED;
6043	}
6044
6045	case HTTP_METHOD_UPLOADTOTWITTER:{
6046		Cdbg(DBE, "do HTTP_METHOD_UPLOADTOTWITTER");
6047
6048#if EMBEDDED_EANBLE
6049		if(!con->srv_socket->is_ssl){
6050			con->http_status = 403;
6051			return HANDLER_FINISHED;
6052		}
6053#endif
6054
6055		buffer* filename = NULL;
6056		buffer* title = NULL;
6057		buffer* auth_token = NULL;
6058		buffer* auth_secret = NULL;
6059		buffer* nonce = NULL;
6060		buffer* timestamp = NULL;
6061		buffer* signature = NULL;
6062		buffer* photo_size_limit = NULL;
6063
6064		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "FILENAME"))) {
6065			filename = ds->value;
6066			buffer_urldecode_path(filename);
6067		} else {
6068			con->http_status = 400;
6069			return HANDLER_FINISHED;
6070		}
6071
6072		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TITLE"))) {
6073			title = ds->value;
6074			buffer_urldecode_path(title);
6075		} else {
6076			con->http_status = 400;
6077			return HANDLER_FINISHED;
6078		}
6079
6080		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TOKEN"))) {
6081			auth_token = ds->value;
6082		} else {
6083			con->http_status = 400;
6084			return HANDLER_FINISHED;
6085		}
6086
6087		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "SECRET"))) {
6088			auth_secret = ds->value;
6089		} else {
6090			con->http_status = 400;
6091			return HANDLER_FINISHED;
6092		}
6093
6094		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "NONCE"))) {
6095			nonce = ds->value;
6096		} else {
6097			con->http_status = 400;
6098			return HANDLER_FINISHED;
6099		}
6100
6101		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "TIMESTAMP"))) {
6102			timestamp = ds->value;
6103		} else {
6104			con->http_status = 400;
6105			return HANDLER_FINISHED;
6106		}
6107
6108		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "SIGNATURE"))) {
6109			signature = ds->value;
6110		} else {
6111			con->http_status = 400;
6112			return HANDLER_FINISHED;
6113		}
6114
6115		if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "PHOTOSIZELIMIT"))) {
6116			photo_size_limit = ds->value;
6117		} else {
6118			con->http_status = 400;
6119			return HANDLER_FINISHED;
6120		}
6121
6122		char consumer_key[100] = "hBQrdHdHClXylEI6by40DTMVA";
6123		//char consumer_secret[100] = "2PlfH4Bx9XVZTYjOz3hoeqAY31aPUx916hU0R4gu0D0uCZ4Y4L";
6124
6125		CURL *curl;
6126		CURLcode rt;
6127		struct curl_httppost *formpost = NULL;
6128		struct curl_httppost *lastptr = NULL;
6129		char* response_str = NULL;
6130		long response_code = 0;
6131
6132		curl = curl_easy_init();
6133		if(curl) {
6134			Cdbg(DBE, "curl_easy_init OK");
6135
6136			/* Set Host to target in HTTP header, and set response handler
6137		 	* function */
6138		 	//curl_easy_setopt(curl, CURLOPT_URL, "https://upload.twitter.com/1.1/statuses/update_with_media.json");
6139			curl_easy_setopt(curl, CURLOPT_URL, "https://api.twitter.com/1.1/statuses/update_with_media.json");
6140
6141			struct curl_slist *headers = NULL;
6142			char authHeader[1024] = "\0";
6143			sprintf(authHeader, "Authorization: OAuth"
6144				" oauth_consumer_key=\"%s\","
6145				" oauth_nonce=\"%s\","
6146				" oauth_signature_method=\"HMAC-SHA1\","
6147				" oauth_timestamp=\"%s\","
6148				" oauth_token=\"%s\","
6149				" oauth_version=\"1.0\","
6150				" oauth_signature=\"%s\"",
6151				consumer_key,
6152				nonce->ptr,
6153				timestamp->ptr,
6154				auth_token->ptr,
6155				signature->ptr);
6156			headers = curl_slist_append(headers, authHeader);
6157
6158			headers = curl_slist_append(headers,"Content-Type: multipart/form-data");
6159
6160			char photo_path[1024] = "\0";
6161			sprintf(photo_path, "%s/%s", con->physical.path->ptr, filename->ptr);
6162			Cdbg(DBE, "photo_path=%s", photo_path);
6163
6164			FILE *fd;
6165 			fd = fopen(photo_path, "rb"); /* open file to upload */
6166		  	if(!fd) {
6167				curl_easy_cleanup(curl);
6168		    	con->http_status = 404;
6169				return HANDLER_FINISHED;
6170		 	}
6171
6172			/* to get the file size */
6173			struct stat file_info;
6174  			if(fstat(fileno(fd), &file_info) != 0) {
6175				fclose(fd);
6176				curl_easy_cleanup(curl);
6177		    	con->http_status = 404;
6178				return HANDLER_FINISHED;
6179			}
6180
6181			long file_size = file_info.st_size;
6182			long l_photo_size_limit = atol(photo_size_limit->ptr);
6183			fclose(fd);
6184
6185			if(file_size>=l_photo_size_limit){
6186				curl_easy_cleanup(curl);
6187		    	con->http_status = 501;
6188				return HANDLER_FINISHED;
6189			}
6190
6191			curl_formadd(&formpost, &lastptr,
6192			             CURLFORM_COPYNAME, "status",
6193			             CURLFORM_COPYCONTENTS, title->ptr, CURLFORM_END);
6194
6195			curl_formadd(&formpost, &lastptr,
6196			             CURLFORM_COPYNAME, "media[]",
6197			             CURLFORM_FILE, photo_path, CURLFORM_END);
6198
6199			curl_easy_setopt(curl, CURLOPT_VERBOSE, 2);
6200			curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
6201			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
6202			curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
6203
6204			curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
6205
6206			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback_func);
6207			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_str);
6208
6209			Cdbg(DBE, "Uploading...");
6210			rt = curl_easy_perform(curl);
6211
6212			curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
6213
6214			Cdbg(DBE, "response_code=%d, response_str = %s", response_code, response_str);
6215
6216			free(response_str);
6217
6218			/* Done. Cleanup. */
6219			curl_easy_cleanup(curl);
6220			curl_formfree(formpost);
6221		}
6222
6223
6224		if(response_code==200){
6225			con->http_status = 200;
6226		}
6227		else
6228			con->http_status = 501;
6229
6230		con->file_finished = 1;
6231		return HANDLER_FINISHED;
6232	}
6233
6234	default:
6235		break;
6236	}
6237
6238	/* not found */
6239	return HANDLER_GO_ON;
6240}
6241
6242
6243/* this function is called at dlopen() time and inits the callbacks */
6244#ifndef APP_IPKG
6245int mod_webdav_plugin_init(plugin *p);
6246int mod_webdav_plugin_init(plugin *p) {
6247	p->version     = LIGHTTPD_VERSION_ID;
6248	p->name        = buffer_init_string("webdav");
6249
6250	p->init        = mod_webdav_init;
6251	p->handle_uri_clean  = mod_webdav_uri_handler;
6252	p->handle_physical   = mod_webdav_subrequest_handler;
6253	p->set_defaults  = mod_webdav_set_defaults;
6254	p->cleanup     = mod_webdav_free;
6255
6256	p->data        = NULL;
6257
6258	return 0;
6259}
6260#else
6261int aicloud_mod_webdav_plugin_init(plugin *p);
6262int aicloud_mod_webdav_plugin_init(plugin *p) {
6263	p->version     = LIGHTTPD_VERSION_ID;
6264	p->name        = buffer_init_string("webdav");
6265
6266	p->init        = mod_webdav_init;
6267	p->handle_uri_clean  = mod_webdav_uri_handler;
6268	p->handle_physical   = mod_webdav_subrequest_handler;
6269	p->set_defaults  = mod_webdav_set_defaults;
6270	p->cleanup     = mod_webdav_free;
6271
6272	p->data        = NULL;
6273
6274	return 0;
6275}
6276#endif
6277