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>
52 #define PCSUITE_CHANNEL 24
53 #define PCSUITE_WHO_SIZE 8
55 #define PCSUITE_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
57 <attribute id=\"0x0001\"> \
59 <uuid value=\"00005005-0000-1000-8000-0002ee000001\"/> \
63 <attribute id=\"0x0004\"> \
66 <uuid value=\"0x0100\"/> \
69 <uuid value=\"0x0003\"/> \
70 <uint8 value=\"%u\" name=\"channel\"/> \
73 <uuid value=\"0x0008\"/> \
78 <attribute id=\"0x0005\"> \
80 <uuid value=\"0x1002\"/> \
84 <attribute id=\"0x0009\"> \
87 <uuid value=\"00005005-0000-1000-8000-0002ee000001\"/> \
88 <uint16 value=\"0x0100\" name=\"version\"/> \
93 <attribute id=\"0x0100\"> \
94 <text value=\"%s\" name=\"name\"/> \
98 #define BACKUP_BUS_NAME "com.nokia.backup.plugin"
99 #define BACKUP_PATH "/com/nokia/backup"
100 #define BACKUP_PLUGIN_INTERFACE "com.nokia.backup.plugin"
101 #define BACKUP_DBUS_TIMEOUT (1000 * 60 * 15)
103 static const uint8_t FTP_TARGET[TARGET_SIZE] = {
104 0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
105 0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
107 static const uint8_t PCSUITE_WHO[PCSUITE_WHO_SIZE] = {
108 'P', 'C', ' ', 'S', 'u', 'i', 't', 'e' };
110 struct pcsuite_session {
111 struct ftp_session *ftp;
116 static void *pcsuite_connect(struct obex_session *os, int *err)
118 struct pcsuite_session *pcsuite;
119 struct ftp_session *ftp;
125 ftp = ftp_connect(os, err);
129 filename = g_build_filename(g_get_home_dir(), ".pcsuite", NULL);
131 fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
132 if (fd < 0 && errno != EEXIST) {
133 error("open(%s): %s(%d)", filename, strerror(errno), errno);
137 /* Try to remove the file before retrying since it could be
138 that some process left/crash without removing it */
140 if (remove(filename) < 0) {
141 error("remove(%s): %s(%d)", filename, strerror(errno),
146 fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
148 error("open(%s): %s(%d)", filename, strerror(errno),
154 DBG("%s created", filename);
156 pcsuite = g_new0(struct pcsuite_session, 1);
158 pcsuite->lock_file = filename;
161 DBG("session %p created", pcsuite);
170 ftp_disconnect(os, ftp);
179 static int pcsuite_get(struct obex_session *os, void *user_data)
181 struct pcsuite_session *pcsuite = user_data;
185 return ftp_get(os, pcsuite->ftp);
188 static int pcsuite_chkput(struct obex_session *os, void *user_data)
190 struct pcsuite_session *pcsuite = user_data;
194 return ftp_chkput(os, pcsuite->ftp);
197 static int pcsuite_put(struct obex_session *os, void *user_data)
199 struct pcsuite_session *pcsuite = user_data;
203 return ftp_put(os, pcsuite->ftp);
206 static int pcsuite_setpath(struct obex_session *os, void *user_data)
208 struct pcsuite_session *pcsuite = user_data;
212 return ftp_setpath(os, pcsuite->ftp);
215 static int pcsuite_action(struct obex_session *os, void *user_data)
217 struct pcsuite_session *pcsuite = user_data;
221 return ftp_action(os, pcsuite->ftp);
224 static void pcsuite_disconnect(struct obex_session *os, void *user_data)
226 struct pcsuite_session *pcsuite = user_data;
230 if (pcsuite->fd >= 0)
233 if (pcsuite->lock_file) {
234 remove(pcsuite->lock_file);
235 g_free(pcsuite->lock_file);
239 ftp_disconnect(os, pcsuite->ftp);
244 static struct obex_service_driver pcsuite = {
245 .name = "Nokia OBEX PC Suite Services",
246 .service = OBEX_PCSUITE,
247 .channel = PCSUITE_CHANNEL,
249 .record = PCSUITE_RECORD,
250 .target = FTP_TARGET,
251 .target_size = TARGET_SIZE,
253 .who_size = PCSUITE_WHO_SIZE,
254 .connect = pcsuite_connect,
257 .chkput = pcsuite_chkput,
258 .setpath = pcsuite_setpath,
259 .action = pcsuite_action,
260 .disconnect = pcsuite_disconnect
263 struct backup_object {
269 DBusPendingCall *pending_call;
270 DBusConnection *conn;
273 static void on_backup_dbus_notify(DBusPendingCall *pending_call,
276 struct backup_object *obj = user_data;
278 const char *filename;
281 DBG("Notification received for pending call - %s", obj->cmd);
283 reply = dbus_pending_call_steal_reply(pending_call);
285 if (reply && dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32,
286 &error_code, DBUS_TYPE_STRING,
287 &filename, DBUS_TYPE_INVALID)) {
289 obj->error_code = error_code;
292 DBG("Notification - file path = %s, error_code = %d",
293 filename, error_code);
295 obj->fd = open(filename,obj->oflag,obj->mode);
299 DBG("Notification timed out or connection got closed");
302 dbus_message_unref(reply);
304 dbus_pending_call_unref(pending_call);
305 obj->pending_call = NULL;
306 dbus_connection_unref(obj->conn);
310 DBG("File opened, setting io flags, cmd = %s",
312 if (obj->oflag == O_RDONLY)
313 obex_object_set_io_flags(user_data, G_IO_IN, 0);
315 obex_object_set_io_flags(user_data, G_IO_OUT, 0);
317 DBG("File open error, setting io error, cmd = %s",
319 obex_object_set_io_flags(user_data, G_IO_ERR, -EPERM);
323 static gboolean send_backup_dbus_message(const char *oper,
324 struct backup_object *obj,
327 DBusConnection *conn;
329 DBusPendingCall *pending_call;
330 gboolean ret = FALSE;
331 dbus_uint32_t file_size;
333 file_size = size ? *size : 0;
335 conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
340 msg = dbus_message_new_method_call(BACKUP_BUS_NAME, BACKUP_PATH,
341 BACKUP_PLUGIN_INTERFACE,
344 dbus_connection_unref(conn);
348 dbus_message_append_args(msg, DBUS_TYPE_STRING, &oper,
349 DBUS_TYPE_STRING, &obj->cmd,
350 DBUS_TYPE_INT32, &file_size,
353 if (strcmp(oper, "open") == 0) {
354 ret = dbus_connection_send_with_reply(conn, msg, &pending_call,
355 BACKUP_DBUS_TIMEOUT);
356 dbus_message_unref(msg);
359 obj->pending_call = pending_call;
360 ret = dbus_pending_call_set_notify(pending_call,
361 on_backup_dbus_notify,
364 dbus_connection_unref(conn);
366 ret = dbus_connection_send(conn, msg, NULL);
367 dbus_message_unref(msg);
368 dbus_connection_unref(conn);
374 static void *backup_open(const char *name, int oflag, mode_t mode,
375 void *context, size_t *size, int *err)
377 struct backup_object *obj = g_new0(struct backup_object, 1);
379 DBG("cmd = %s", name);
381 obj->cmd = g_path_get_basename(name);
385 obj->pending_call = NULL;
389 if (send_backup_dbus_message("open", obj, size) == FALSE) {
400 static int backup_close(void *object)
402 struct backup_object *obj = object;
405 DBG("cmd = %s", obj->cmd);
410 if (obj->pending_call) {
411 dbus_pending_call_cancel(obj->pending_call);
412 dbus_pending_call_unref(obj->pending_call);
413 dbus_connection_unref(obj->conn);
416 send_backup_dbus_message("close", obj, &size);
424 static ssize_t backup_read(void *object, void *buf, size_t count)
426 struct backup_object *obj = object;
429 if (obj->pending_call) {
430 DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
435 DBG("cmd = %s, READING DATA", obj->cmd);
436 ret = read(obj->fd, buf, count);
440 DBG("cmd = %s, PERMANENT FAILURE", obj->cmd);
441 ret = obj->error_code ? -obj->error_code : -ENOENT;
447 static ssize_t backup_write(void *object, const void *buf, size_t count)
449 struct backup_object *obj = object;
452 if (obj->pending_call) {
453 DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
458 ret = write(obj->fd, buf, count);
460 DBG("cmd = %s, WRITTING", obj->cmd);
463 error("backup: cmd = %s", obj->cmd);
467 error("backup: cmd = %s", obj->cmd);
468 ret = obj->error_code ? -obj->error_code : -ENOENT;
474 static int backup_flush(void *object)
481 static struct obex_mime_type_driver backup = {
482 .target = FTP_TARGET,
483 .target_size = TARGET_SIZE,
484 .mimetype = "application/vnd.nokia-backup",
486 .close = backup_close,
488 .write = backup_write,
489 .flush = backup_flush,
492 static int pcsuite_init(void)
496 err = obex_service_driver_register(&pcsuite);
500 err = obex_mime_type_driver_register(&backup);
502 obex_service_driver_unregister(&pcsuite);
507 static void pcsuite_exit(void)
509 obex_mime_type_driver_unregister(&backup);
510 obex_service_driver_unregister(&pcsuite);
513 OBEX_PLUGIN_DEFINE(pcsuite, pcsuite_init, pcsuite_exit)