5 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40 #define OBEX_FTP_UUID \
41 "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09"
42 #define OBEX_FTP_UUID_LEN 16
44 #define FTP_INTERFACE "org.openobex.FileTransfer"
45 #define FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
46 #define PCSUITE_UUID "00005005-0000-1000-8000-0002ee000001"
48 static DBusConnection *conn = NULL;
51 struct obc_session *session;
55 static void async_cb(GObex *obex, GError *err, GObexPacket *rsp,
58 DBusMessage *reply, *msg = user_data;
61 reply = g_dbus_create_error(msg, "org.openobex.Error.Failed",
64 reply = dbus_message_new_method_return(msg);
66 g_dbus_send_message(conn, reply);
67 dbus_message_unref(msg);
70 static DBusMessage *change_folder(DBusConnection *connection,
71 DBusMessage *message, void *user_data)
73 struct ftp_data *ftp = user_data;
74 struct obc_session *session = ftp->session;
75 GObex *obex = obc_session_get_obex(session);
79 if (dbus_message_get_args(message, NULL,
80 DBUS_TYPE_STRING, &folder,
81 DBUS_TYPE_INVALID) == FALSE)
82 return g_dbus_create_error(message,
83 "org.openobex.Error.InvalidArguments", NULL);
85 g_obex_setpath(obex, folder, async_cb, message, &err);
88 reply = g_dbus_create_error(message,
89 "org.openobex.Error.Failed",
95 dbus_message_ref(message);
100 static void append_variant(DBusMessageIter *iter, int type, void *val)
102 DBusMessageIter value;
103 char sig[2] = { type, '\0' };
105 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
107 dbus_message_iter_append_basic(&value, type, val);
109 dbus_message_iter_close_container(iter, &value);
112 static void dict_append_entry(DBusMessageIter *dict,
113 const char *key, int type, void *val)
115 DBusMessageIter entry;
117 if (type == DBUS_TYPE_STRING) {
118 const char *str = *((const char **) val);
123 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
126 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
128 append_variant(&entry, type, val);
130 dbus_message_iter_close_container(dict, &entry);
133 static void xml_element(GMarkupParseContext *ctxt,
134 const gchar *element,
136 const gchar **values,
140 DBusMessageIter dict, *iter = user_data;
144 if (strcasecmp("folder", element) != 0 && strcasecmp("file", element) != 0)
147 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
148 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
149 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
150 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
152 dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &element);
154 /* FIXME: User, Group, Other permission must be reviewed */
157 for (key = (gchar *) names[i]; key; key = (gchar *) names[++i]) {
158 key[0] = g_ascii_toupper(key[0]);
159 if (g_str_equal("Size", key) == TRUE) {
161 size = g_ascii_strtoll(values[i], NULL, 10);
162 dict_append_entry(&dict, key, DBUS_TYPE_UINT64, &size);
164 dict_append_entry(&dict, key, DBUS_TYPE_STRING, &values[i]);
167 dbus_message_iter_close_container(iter, &dict);
170 static const GMarkupParser parser = {
178 static void get_file_callback(struct obc_session *session, GError *err,
181 struct ftp_data *ftp = user_data;
188 reply = g_dbus_create_error(ftp->msg,
189 "org.openobex.Error.Failed",
192 reply = dbus_message_new_method_return(ftp->msg);
194 g_dbus_send_message(conn, reply);
196 dbus_message_unref(ftp->msg);
200 static void list_folder_callback(struct obc_session *session,
201 GError *err, void *user_data)
203 struct ftp_data *ftp = user_data;
204 struct obc_transfer *transfer = obc_session_get_transfer(session);
205 GMarkupParseContext *ctxt;
207 DBusMessageIter iter, array;
211 reply = dbus_message_new_method_return(ftp->msg);
213 buf = obc_transfer_get_buffer(transfer, &size);
217 dbus_message_iter_init_append(reply, &iter);
218 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
219 DBUS_TYPE_ARRAY_AS_STRING
220 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
221 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
222 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
223 ctxt = g_markup_parse_context_new(&parser, 0, &array, NULL);
224 g_markup_parse_context_parse(ctxt, buf, strlen(buf) - 1, NULL);
225 g_markup_parse_context_free(ctxt);
226 dbus_message_iter_close_container(&iter, &array);
228 obc_transfer_clear_buffer(transfer);
231 g_dbus_send_message(conn, reply);
232 dbus_message_unref(ftp->msg);
236 static DBusMessage *create_folder(DBusConnection *connection,
237 DBusMessage *message, void *user_data)
239 struct ftp_data *ftp = user_data;
240 struct obc_session *session = ftp->session;
241 GObex *obex = obc_session_get_obex(session);
245 if (dbus_message_get_args(message, NULL,
246 DBUS_TYPE_STRING, &folder,
247 DBUS_TYPE_INVALID) == FALSE)
248 return g_dbus_create_error(message,
249 "org.openobex.Error.InvalidArguments", NULL);
251 g_obex_mkdir(obex, folder, async_cb, message, &err);
254 reply = g_dbus_create_error(message,
255 "org.openobex.Error.Failed",
261 dbus_message_ref(message);
266 static DBusMessage *list_folder(DBusConnection *connection,
267 DBusMessage *message, void *user_data)
269 struct ftp_data *ftp = user_data;
270 struct obc_session *session = ftp->session;
273 return g_dbus_create_error(message,
274 "org.openobex.Error.InProgress",
275 "Transfer in progress");
277 if (obc_session_get(session, "x-obex/folder-listing",
278 NULL, NULL, NULL, 0, list_folder_callback, ftp) < 0)
279 return g_dbus_create_error(message,
280 "org.openobex.Error.Failed",
283 ftp->msg = dbus_message_ref(message);
288 static DBusMessage *get_file(DBusConnection *connection,
289 DBusMessage *message, void *user_data)
291 struct ftp_data *ftp = user_data;
292 struct obc_session *session = ftp->session;
293 const char *target_file, *source_file;
296 return g_dbus_create_error(message,
297 "org.openobex.Error.InProgress",
298 "Transfer in progress");
300 if (dbus_message_get_args(message, NULL,
301 DBUS_TYPE_STRING, &target_file,
302 DBUS_TYPE_STRING, &source_file,
303 DBUS_TYPE_INVALID) == FALSE)
304 return g_dbus_create_error(message,
305 "org.openobex.Error.InvalidArguments", NULL);
307 if (obc_session_get(session, NULL, source_file,
308 target_file, NULL, 0, get_file_callback, ftp) < 0)
309 return g_dbus_create_error(message,
310 "org.openobex.Error.Failed",
313 ftp->msg = dbus_message_ref(message);
318 static DBusMessage *put_file(DBusConnection *connection,
319 DBusMessage *message, void *user_data)
321 struct ftp_data *ftp = user_data;
322 struct obc_session *session = ftp->session;
323 gchar *sourcefile, *targetfile;
325 if (dbus_message_get_args(message, NULL,
326 DBUS_TYPE_STRING, &sourcefile,
327 DBUS_TYPE_STRING, &targetfile,
328 DBUS_TYPE_INVALID) == FALSE)
329 return g_dbus_create_error(message,
330 "org.openobex.Error.InvalidArguments",
331 "Invalid arguments in method call");
333 if (obc_session_send(session, sourcefile, targetfile) < 0)
334 return g_dbus_create_error(message,
335 "org.openobex.Error.Failed",
338 return dbus_message_new_method_return(message);
341 static DBusMessage *copy_file(DBusConnection *connection,
342 DBusMessage *message, void *user_data)
344 struct ftp_data *ftp = user_data;
345 struct obc_session *session = ftp->session;
346 GObex *obex = obc_session_get_obex(session);
347 const char *filename, *destname;
350 if (dbus_message_get_args(message, NULL,
351 DBUS_TYPE_STRING, &filename,
352 DBUS_TYPE_STRING, &destname,
353 DBUS_TYPE_INVALID) == FALSE)
354 return g_dbus_create_error(message,
355 "org.openobex.Error.InvalidArguments", NULL);
357 g_obex_copy(obex, filename, destname, async_cb, message, &err);
360 reply = g_dbus_create_error(message,
361 "org.openobex.Error.Failed",
367 dbus_message_ref(message);
372 static DBusMessage *move_file(DBusConnection *connection,
373 DBusMessage *message, void *user_data)
375 struct ftp_data *ftp = user_data;
376 struct obc_session *session = ftp->session;
377 GObex *obex = obc_session_get_obex(session);
378 const char *filename, *destname;
381 if (dbus_message_get_args(message, NULL,
382 DBUS_TYPE_STRING, &filename,
383 DBUS_TYPE_STRING, &destname,
384 DBUS_TYPE_INVALID) == FALSE)
385 return g_dbus_create_error(message,
386 "org.openobex.Error.InvalidArguments", NULL);
388 g_obex_move(obex, filename, destname, async_cb, message, &err);
391 reply = g_dbus_create_error(message,
392 "org.openobex.Error.Failed",
398 dbus_message_ref(message);
403 static DBusMessage *delete(DBusConnection *connection,
404 DBusMessage *message, void *user_data)
406 struct ftp_data *ftp = user_data;
407 struct obc_session *session = ftp->session;
408 GObex *obex = obc_session_get_obex(session);
412 if (dbus_message_get_args(message, NULL,
413 DBUS_TYPE_STRING, &file,
414 DBUS_TYPE_INVALID) == FALSE)
415 return g_dbus_create_error(message,
416 "org.openobex.Error.InvalidArguments", NULL);
418 g_obex_delete(obex, file, async_cb, message, &err);
421 reply = g_dbus_create_error(message,
422 "org.openobex.Error.Failed",
428 dbus_message_ref(message);
433 static GDBusMethodTable ftp_methods[] = {
434 { "ChangeFolder", "s", "", change_folder,
435 G_DBUS_METHOD_FLAG_ASYNC },
436 { "CreateFolder", "s", "", create_folder,
437 G_DBUS_METHOD_FLAG_ASYNC },
438 { "ListFolder", "", "aa{sv}", list_folder,
439 G_DBUS_METHOD_FLAG_ASYNC },
440 { "GetFile", "ss", "", get_file,
441 G_DBUS_METHOD_FLAG_ASYNC },
442 { "PutFile", "ss", "", put_file,
443 G_DBUS_METHOD_FLAG_ASYNC },
444 { "CopyFile", "ss", "", copy_file,
445 G_DBUS_METHOD_FLAG_ASYNC },
446 { "MoveFile", "ss", "", move_file,
447 G_DBUS_METHOD_FLAG_ASYNC },
448 { "Delete", "s", "", delete,
449 G_DBUS_METHOD_FLAG_ASYNC },
453 static void ftp_free(void *data)
455 struct ftp_data *ftp = data;
457 obc_session_unref(ftp->session);
461 static int ftp_probe(struct obc_session *session)
463 struct ftp_data *ftp;
466 path = obc_session_get_path(session);
470 ftp = g_try_new0(struct ftp_data, 1);
474 ftp->session = obc_session_ref(session);
476 if (!g_dbus_register_interface(conn, path, FTP_INTERFACE, ftp_methods,
477 NULL, NULL, ftp, ftp_free)) {
485 static void ftp_remove(struct obc_session *session)
487 const char *path = obc_session_get_path(session);
491 g_dbus_unregister_interface(conn, path, FTP_INTERFACE);
494 static struct obc_driver ftp = {
497 .target = OBEX_FTP_UUID,
498 .target_len = OBEX_FTP_UUID_LEN,
503 static struct obc_driver pcsuite = {
504 .service = "PCSUITE",
505 .uuid = PCSUITE_UUID,
506 .target = OBEX_FTP_UUID,
507 .target_len = OBEX_FTP_UUID_LEN,
518 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
522 err = obc_driver_register(&ftp);
526 err = obc_driver_register(&pcsuite);
528 obc_driver_unregister(&ftp);
535 dbus_connection_unref(conn);
544 dbus_connection_unref(conn);
547 obc_driver_unregister(&ftp);
548 obc_driver_unregister(&pcsuite);