5 * Copyright (C) 2007-2010 Nokia Corporation
6 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <sys/types.h>
51 #include "filesystem.h"
53 #define LST_TYPE "x-obex/folder-listing"
54 #define CAP_TYPE "x-obex/capability"
56 #define FTP_CHANNEL 10
57 #define FTP_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
59 <attribute id=\"0x0001\"> \
61 <uuid value=\"0x1106\"/> \
65 <attribute id=\"0x0004\"> \
68 <uuid value=\"0x0100\"/> \
71 <uuid value=\"0x0003\"/> \
72 <uint8 value=\"%u\" name=\"channel\"/> \
75 <uuid value=\"0x0008\"/> \
80 <attribute id=\"0x0009\"> \
83 <uuid value=\"0x1106\"/> \
84 <uint16 value=\"0x0102\" name=\"version\"/> \
89 <attribute id=\"0x0100\"> \
90 <text value=\"%s\" name=\"name\"/> \
92 <attribute id=\"0x0200\"> \
93 <uint16 value=\"%u\" name=\"psm\"/> \
97 static const uint8_t FTP_TARGET[TARGET_SIZE] = {
98 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
99 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
102 struct obex_session *os;
106 static void set_folder(struct ftp_session *ftp, const char *new_folder)
108 DBG("%p folder %s", ftp, new_folder);
112 ftp->folder = new_folder ? g_strdup(new_folder) : NULL;
115 static int get_by_type(struct ftp_session *ftp, const char *type)
117 struct obex_session *os = ftp->os;
118 const char *capability = obex_option_capability();
119 const char *name = obex_get_name(os);
123 DBG("%p name %s type %s", ftp, name, type);
125 if (type == NULL && name == NULL)
128 if (type != NULL && g_ascii_strcasecmp(type, CAP_TYPE) == 0)
129 return obex_get_stream_start(os, capability);
131 if (name != NULL && !is_filename(name))
134 path = g_build_filename(ftp->folder, name, NULL);
135 err = obex_get_stream_start(os, path);
142 void *ftp_connect(struct obex_session *os, int *err)
144 struct ftp_session *ftp;
145 const char *root_folder;
149 root_folder = obex_option_root_folder();
151 manager_register_session(os);
153 ftp = g_new0(struct ftp_session, 1);
154 set_folder(ftp, root_folder);
160 DBG("session %p created", ftp);
165 int ftp_get(struct obex_session *os, void *user_data)
167 struct ftp_session *ftp = user_data;
168 const char *type = obex_get_type(os);
173 if (ftp->folder == NULL)
176 ret = get_by_type(ftp, type);
183 static int ftp_delete(struct ftp_session *ftp, const char *name)
188 DBG("%p name %s", ftp, name);
190 if (!(ftp->folder && name))
193 path = g_build_filename(ftp->folder, name, NULL);
195 if (obex_remove(ftp->os, path) < 0)
203 int ftp_chkput(struct obex_session *os, void *user_data)
205 struct ftp_session *ftp = user_data;
206 const char *name = obex_get_name(os);
210 DBG("%p name %s", ftp, name);
215 if (!is_filename(name))
218 if (obex_get_size(os) == OBJECT_SIZE_DELETE)
221 path = g_build_filename(ftp->folder, name, NULL);
223 ret = obex_put_stream_start(os, path);
230 int ftp_put(struct obex_session *os, void *user_data)
232 struct ftp_session *ftp = user_data;
233 const char *name = obex_get_name(os);
234 ssize_t size = obex_get_size(os);
236 DBG("%p name %s size %zd", ftp, name, size);
238 if (ftp->folder == NULL)
244 if (!is_filename(name))
247 if (size == OBJECT_SIZE_DELETE)
248 return ftp_delete(ftp, name);
253 int ftp_setpath(struct obex_session *os, void *user_data)
255 struct ftp_session *ftp = user_data;
256 const char *root_folder, *name;
257 const uint8_t *nonhdr;
263 if (obex_get_non_header_data(os, &nonhdr) != 2) {
264 error("Set path failed: flag and constants not found!");
268 name = obex_get_name(os);
269 root_folder = obex_option_root_folder();
270 root = g_str_equal(root_folder, ftp->folder);
272 DBG("%p name %s", ftp, name);
274 /* Check flag "Backup" */
275 if ((nonhdr[0] & 0x01) == 0x01) {
276 DBG("Set to parent path");
281 fullname = g_path_get_dirname(ftp->folder);
282 set_folder(ftp, fullname);
285 DBG("Set to parent path: %s", ftp->folder);
291 DBG("Set path failed: name missing!");
295 if (strlen(name) == 0) {
297 set_folder(ftp, root_folder);
301 /* Check and set to name path */
302 if (!is_filename(name)) {
303 error("Set path failed: name incorrect!");
307 fullname = g_build_filename(ftp->folder, name, NULL);
309 DBG("Fullname: %s", fullname);
311 err = verify_path(fullname);
316 err = stat(fullname, &dstat);
324 DBG("stat: %s(%d)", strerror(-err), -err);
329 if (S_ISDIR(dstat.st_mode) && (dstat.st_mode & S_IRUSR) &&
330 (dstat.st_mode & S_IXUSR)) {
331 set_folder(ftp, fullname);
339 if (nonhdr[0] != 0) {
344 if (mkdir(fullname, 0755) < 0) {
346 DBG("mkdir: %s(%d)", strerror(-err), -err);
351 set_folder(ftp, fullname);
358 static gboolean is_valid_path(const char *path)
360 gchar **elements, **cur;
363 elements = g_strsplit(path, "/", 0);
365 for (cur = elements; *cur != NULL; cur++) {
366 if (**cur == '\0' || strcmp(*cur, ".") == 0)
369 if (strcmp(*cur, "..") == 0) {
379 g_strfreev(elements);
387 static char *ftp_build_filename(struct ftp_session *ftp, const char *destname)
391 /* DestName can either be relative or absolute (FTP style) */
392 if (destname[0] == '/')
393 filename = g_build_filename(obex_option_root_folder(),
396 filename = g_build_filename(ftp->folder, destname, NULL);
398 if (is_valid_path(filename + strlen(obex_option_root_folder())))
406 static int ftp_copy(struct ftp_session *ftp, const char *name,
407 const char *destname)
409 char *source, *destination, *destdir;
412 DBG("%p name %s destination %s", ftp, name, destname);
414 if (ftp->folder == NULL) {
415 error("No folder set");
419 if (name == NULL || destname == NULL)
422 destination = ftp_build_filename(ftp, destname);
424 if (destination == NULL)
427 destdir = g_path_get_dirname(destination);
428 ret = verify_path(destdir);
434 source = g_build_filename(ftp->folder, name, NULL);
436 ret = obex_copy(ftp->os, source, destination);
444 static int ftp_move(struct ftp_session *ftp, const char *name,
445 const char *destname)
447 char *source, *destination, *destdir;
450 DBG("%p name %s destname %s", ftp, name, destname);
452 if (ftp->folder == NULL) {
453 error("No folder set");
457 if (name == NULL || destname == NULL)
460 destination = ftp_build_filename(ftp, destname);
462 if (destination == NULL)
465 destdir = g_path_get_dirname(destination);
466 ret = verify_path(destdir);
472 source = g_build_filename(ftp->folder, name, NULL);
474 ret = obex_move(ftp->os, source, destination);
482 int ftp_action(struct obex_session *os, void *user_data)
484 struct ftp_session *ftp = user_data;
485 const char *name, *destname;
488 name = obex_get_name(os);
489 if (name == NULL || !is_filename(name))
492 destname = obex_get_destname(os);
493 action_id = obex_get_action_id(os);
495 DBG("%p action 0x%x", ftp, action_id);
498 case 0x00: /* Copy Object */
499 return ftp_copy(ftp, name, destname);
500 case 0x01: /* Move/Rename Object */
501 return ftp_move(ftp, name, destname);
507 void ftp_disconnect(struct obex_session *os, void *user_data)
509 struct ftp_session *ftp = user_data;
513 manager_unregister_session(os);
519 static struct obex_service_driver ftp = {
520 .name = "File Transfer server",
522 .channel = FTP_CHANNEL,
523 .port = OBEX_PORT_RANDOM,
525 .record = FTP_RECORD,
526 .target = FTP_TARGET,
527 .target_size = TARGET_SIZE,
528 .connect = ftp_connect,
531 .chkput = ftp_chkput,
532 .setpath = ftp_setpath,
533 .action = ftp_action,
534 .disconnect = ftp_disconnect
537 static int ftp_init(void)
539 return obex_service_driver_register(&ftp);
542 static void ftp_exit(void)
544 obex_service_driver_unregister(&ftp);
547 OBEX_PLUGIN_DEFINE(ftp, ftp_init, ftp_exit)