Logo Search packages:      
Sourcecode: obex-data-server version File versions  Download package

ods-server-session.c

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 *
 * Copyright (C) 2007 Tadas Dailyda <tadas@dailyda.com>
 *
 * Licensed under the GNU General Public License Version 2
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#include <glib.h>
#include <glib/gprintf.h>
#include <glib/gstdio.h>

#include <bluetooth/bluetooth.h>
#include <openobex/obex.h>
#include <openobex/obex_const.h>

#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>

#include "ods-common.h"
#include "ods-error.h"
#include "ods-marshal.h"
#include "ods-obex.h"
#include "ods-server-session.h"
#include "ods-server-session-dbus-glue.h"


static void     ods_server_session_class_init   (OdsServerSessionClass *klass);
static void     ods_server_session_init               (OdsServerSession *server_session);
static GObject* ods_server_session_constructor  (GType type, guint n_construct_params, 
                                                            GObjectConstructParam *construct_params);
static void     ods_server_session_finalize           (GObject          *object);

#define ODS_SERVER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), ODS_TYPE_SERVER_SESSION, OdsServerSessionPrivate))

#define ODS_SERVER_SESSION_LOCK(server_session) g_message ("LOCK"); g_static_mutex_lock (&(server_session)->priv->mutex)
#define ODS_SERVER_SESSION_UNLOCK(server_session) g_message ("UNLOCK"); g_static_mutex_unlock (&(server_session)->priv->mutex)

struct OdsServerSessionPrivate
{
      /* constructor properties */
      gint                          fd; /* rfcomm device */
      guint                         service;
      gchar                         *root_path; /* root folder (constructor "path" property) */
      gchar                         *path; /* current path */
      gchar                         *owner; /* D-Bus client, who initiated this session */
      gboolean                      allow_write; /* Whether to allow changes in file system */
      gboolean                      auto_accept; /* Whether incoming files should be auto-accepted */
      /* state (open or busy) */
      OdsServerSessionState   state; /* ODS_SERVER_SESSION_STATE_OPEN by default */
      /* OBEX connection */
      OdsObexContext                *obex_context;
      GIOChannel                    *io_channel;
      GSource                             *io_source;
      /* other */
      GStaticMutex                  mutex;
      DBusGMethodInvocation   *dbus_context; /* D-Bus context for async methods */
      gchar                         *dbus_path; /* D-Bus path for this object */
};

enum {
      CANCELLED,
      DISCONNECTED,
      TRANSFER_STARTED,
      TRANSFER_PROGRESS,
      TRANSFER_COMPLETED,
      ERROR_OCCURRED,
      LAST_SIGNAL
};

static guint      signals [LAST_SIGNAL] = { 0, };
/* for numbering established sessions */
static guint      iterator = 0;

G_DEFINE_TYPE (OdsServerSession, ods_server_session, G_TYPE_OBJECT)

static gboolean
obex_io_callback (GIOChannel *io_channel, GIOCondition cond, gpointer data)
{
      obex_t                        *obex_handle;
      OdsServerSession  *server_session;
      GError                        *error = NULL;
      gboolean                ret = TRUE;

      obex_handle = (obex_t *) data;
      server_session = ODS_SERVER_SESSION (OBEX_GetUserData (obex_handle));
      
      g_message ("io callback");
      if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_LINK_ERROR, "Connection error");
            /* cleanup transfer data */
            ods_obex_transfer_close (server_session->priv->obex_context);
            server_session->priv->state = ODS_SERVER_SESSION_STATE_NOT_CONNECTED;
            ret = FALSE;
      } else if (OBEX_HandleInput (obex_handle, 1) < 0) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_BAD_DATA, 
                                    "Could not parse incoming data");         
      }
      
      if (error) {
            gchar *error_name;
            /* Get D-Bus name for error */
            error_name = ods_error_get_dbus_name (error);
            /* emit ErrorOccurred signal */
            g_signal_emit (server_session, signals [ERROR_OCCURRED], 0,
                                    error_name, error->message);
            g_free (error_name);
            g_clear_error (&error);
      }
      if (!ret) {
            /* Also emit DISCONNECTED signal, since this session is now defunct */
            g_signal_emit (server_session, signals [DISCONNECTED], 0);
      }

      return ret;
}

static void
obex_transfer_data_exchange_done (OdsServerSession *server_session, gint ret)
{
      GError                  *error = NULL;
      gchar             *error_name;
      OdsObexContext    *obex_context;
            
      obex_context = server_session->priv->obex_context;
      if (ret < 0) {
            ods_error_err2gerror (ret, &error);
            /* Get D-Bus name for error */
            error_name = ods_error_get_dbus_name (error);
            /* emit ErrorOccurred Signal */
            g_signal_emit (server_session, signals [ERROR_OCCURRED], 0,
                                    error_name, error->message);
            g_free (error_name);
            g_clear_error (&error);
            /* Reset state */
            server_session->priv->state = ODS_SERVER_SESSION_STATE_OPEN;
      } else if (obex_context->report_progress &&
                        !obex_context->transfer_started_signal_emitted) {
            g_signal_emit (server_session, signals [TRANSFER_STARTED], 0,
                                    obex_context->remote,
                                    obex_context->local,
                                    obex_context->target_size);
            obex_context->transfer_started_signal_emitted = TRUE;
      }
}

static void
obex_event (obex_t *handle, obex_object_t *object, int mode, int event, 
                  int command, int response)
{
      OdsServerSession  *server_session;
      OdsObexContext          *obex_context;
      gchar                   *new_path;
      gint                    ret;
      
      server_session = ODS_SERVER_SESSION (OBEX_GetUserData (handle));
      obex_context = server_session->priv->obex_context;
      g_message ("event: %d", event);
      
      switch (event) {
            case OBEX_EV_PROGRESS:
                  if (obex_context->report_progress) {
                        g_signal_emit (server_session, signals [TRANSFER_PROGRESS], 0,
                                                obex_context->counter);
                  }
                  break;
            case OBEX_EV_LINKERR:
                  /* we will get LINKERR when Cancel was called, but device didn't
                   * send OBEX_RSP_SUCCESS response (might be OBEX_RSP_BAD_REQUEST).
                   * When link error really happens, it is handled in io_callback */
                  g_warning ("EV_LINKERR");
            case OBEX_EV_ABORT:
                  /* Cleanup transfer stuff and reset state */
                  /* If it was PUT operation, remove incomplete file */
                  if (obex_context->obex_cmd == OBEX_CMD_PUT &&
                              obex_context->stream_fd >= 0)
                        g_unlink (obex_context->local);
                  ods_obex_transfer_close (obex_context);
                  server_session->priv->state = ODS_SERVER_SESSION_STATE_OPEN;
                  /* emit CANCELLED signal */
                  g_signal_emit (server_session, signals [CANCELLED], 0);
                  OBEX_ObjectSetRsp (object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
                  
                  /* In case this was trigerred by Cancel method */
                  if (server_session->priv->dbus_context) {
                        dbus_g_method_return (server_session->priv->dbus_context);
                        server_session->priv->dbus_context = NULL;
                        ODS_SERVER_SESSION_UNLOCK (server_session);
                  }
                  break;
            case OBEX_EV_REQDONE:
                  switch (command) {
                        case OBEX_CMD_DISCONNECT:
                              ods_server_session_disconnect_internal (server_session);
                              break;
                        case OBEX_CMD_PUT:
                              if (obex_context->local == NULL) {
                                    /* This is a Delete request */
                                    obex_context->local = g_build_filename (
                                                                              server_session->priv->path, 
                                                                              obex_context->remote, NULL);
                                    g_message ("Deleting: %s", obex_context->local);
                                    if (g_file_test (obex_context->local, G_FILE_TEST_IS_DIR))
                                          ret = rmdir (obex_context->local);
                                    else
                                          ret = g_unlink (obex_context->local);
                                    
                                    if (ret == -1)
                                          OBEX_ObjectSetRsp (object, OBEX_RSP_FORBIDDEN,
                                                                        OBEX_RSP_FORBIDDEN);
                              }
                              /* Transfer complete */
                              ods_obex_transfer_close (obex_context);
                              server_session->priv->state = ODS_SERVER_SESSION_STATE_OPEN;
                              if (obex_context->report_progress)
                                    g_signal_emit (server_session, signals [TRANSFER_COMPLETED], 0);
                              break;
                        case OBEX_CMD_GET:
                              /* Transfer complete */
                              ods_obex_transfer_close (obex_context);
                              server_session->priv->state = ODS_SERVER_SESSION_STATE_OPEN;
                              if (obex_context->report_progress)
                                    g_signal_emit (server_session, signals [TRANSFER_COMPLETED], 0);
                              break;
                        default:
                              break;
                  }
                  break;
            case OBEX_EV_REQHINT:
                  switch (command) {
                        case OBEX_CMD_PUT:
                              if (!server_session->priv->allow_write) {
                                    g_message ("CMD_PUT forbidden");
                                    OBEX_ObjectSetRsp (object, OBEX_RSP_FORBIDDEN, 
                                                                  OBEX_RSP_FORBIDDEN);
                                    return;
                              }
                              OBEX_ObjectReadStream (handle, object, NULL);
                              obex_context->obex_cmd = OBEX_CMD_PUT;
                              /* Initialize transfer and set state */
                              ods_obex_transfer_new (obex_context, NULL, NULL, NULL);
                              obex_context->report_progress = FALSE;/* might be delete operation */
                              server_session->priv->state = ODS_SERVER_SESSION_STATE_BUSY;
                              
                              OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, 
                                                            OBEX_RSP_SUCCESS);
                              break;
                        case OBEX_CMD_GET:
                              obex_context->obex_cmd = OBEX_CMD_GET;
                              /* Initialize transfer and set state */
                              ods_obex_transfer_new (obex_context, NULL, NULL, NULL);
                              server_session->priv->state = ODS_SERVER_SESSION_STATE_BUSY;
                              
                              OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, 
                                                            OBEX_RSP_SUCCESS);
                              break;
                        case OBEX_CMD_CONNECT:
                        case OBEX_CMD_DISCONNECT:
                        case OBEX_CMD_SETPATH:
                              OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, 
                                                            OBEX_RSP_SUCCESS);
                              break;
                        default:
                              OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED,
                                                            OBEX_RSP_NOT_IMPLEMENTED);
                              break;
                  }
                  break;
            case OBEX_EV_REQCHECK:
                  if (command == OBEX_CMD_PUT) {
                        g_message ("CMD_PUT requested at REQCHECK");
                        if (!server_session->priv->allow_write) {
                              g_message ("CMD_PUT forbidden");
                              OBEX_ObjectSetRsp (object, OBEX_RSP_FORBIDDEN, 
                                                            OBEX_RSP_FORBIDDEN);
                              return;
                        }
                        ret = ods_obex_srv_put (obex_context, object, 
                                                            server_session->priv->path);
                        g_message ("ret=%d", ret);
                        /* also emit TransferStarted signal */
                        if (ret == 0 && obex_context->report_progress) {
                              g_signal_emit (server_session, signals [TRANSFER_STARTED],
                                                      0, obex_context->remote,
                                                      obex_context->local,
                                                      obex_context->target_size);
                              obex_context->transfer_started_signal_emitted = TRUE;
                        }
                        if (!server_session->priv->auto_accept && ret == 0)
                              OBEX_SuspendRequest (obex_context->obex_handle, object);
                  }
                  break;
            case OBEX_EV_REQ:
                  switch (command) {
                        case OBEX_CMD_DISCONNECT:
                              OBEX_ObjectSetRsp(object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
                              break;
                                     
                        case OBEX_CMD_CONNECT:
                              g_message ("CMD_CONNECT requested");
                              ods_obex_srv_connect (obex_context, object);
                              break;
                                  
                        case OBEX_CMD_SETPATH:
                              g_message ("CMD_SETPATH requested");
                              g_message ("current path: %s", server_session->priv->path);
                              g_message ("root path: %s", server_session->priv->root_path);
                              if (ods_obex_srv_setpath (obex_context, object, 
                                                                        server_session->priv->root_path,
                                                                        server_session->priv->path,
                                                                        &new_path)) {
                                    g_free (server_session->priv->path);
                                    server_session->priv->path = new_path;
                              }
                              g_message ("new path: %s", server_session->priv->path);
                              break;
                        case OBEX_CMD_GET:
                              g_message ("CMD_GET requested");
                              ret = ods_obex_srv_get (obex_context, object,
                                                                  server_session->priv->path,
                                                                  server_session->priv->root_path,
                                                                  server_session->priv->allow_write);
                              g_message ("ret=%d", ret);
                              if (ret > 0 && obex_context->report_progress) {
                                    g_signal_emit (server_session, signals [TRANSFER_STARTED],
                                                            0, obex_context->remote,
                                                            obex_context->local,
                                                            obex_context->target_size);
                                    obex_context->transfer_started_signal_emitted = TRUE;
                              }
                              break;
                        case OBEX_CMD_PUT:
                              g_message ("CMD_PUT requested");
                              if (!server_session->priv->allow_write) {
                                    g_message ("CMD_PUT forbidden");
                                    OBEX_ObjectSetRsp (object, OBEX_RSP_FORBIDDEN, 
                                                                  OBEX_RSP_FORBIDDEN);
                                    return;
                              }
                              ret = ods_obex_srv_put (obex_context, object, 
                                                                  server_session->priv->path);
                              g_message ("ret=%d", ret);
                              if (ret == 0 && obex_context->report_progress) {
                                    g_signal_emit (server_session, signals [TRANSFER_STARTED],
                                                            0, obex_context->remote,
                                                            obex_context->local,
                                                            obex_context->target_size);
                                    obex_context->transfer_started_signal_emitted = TRUE;
                              }
                              if (!server_session->priv->auto_accept && ret == 0)
                                    OBEX_SuspendRequest (obex_context->obex_handle, object);
                              break;
                        default:
                              OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED, 
                                                            OBEX_RSP_NOT_IMPLEMENTED);
                              break;
                  }
                  break;
            case OBEX_EV_STREAMEMPTY:
                  ret = ods_obex_writestream (obex_context, object);
                  obex_transfer_data_exchange_done (server_session, ret);
                  break;
            case OBEX_EV_STREAMAVAIL:
                  /* This PUT request is definitely not a delete request. Let's
                   * open a file for writing. */
                  if (obex_context->remote && !obex_context->local) {
                        obex_context->report_progress = TRUE;
                        if (!ods_obex_srv_new_file (obex_context, server_session->priv->path))
                              ret = -1;
                  }
                  ret = ods_obex_readstream (obex_context, object);
                  obex_transfer_data_exchange_done (server_session, ret);
                  break;
            case OBEX_EV_PARSEERR:
                  /* Handled in io_callback */
                  break;
            case OBEX_EV_UNEXPECTED:
                  break;
            default:
                  break;
      }
}

static void
ods_server_session_set_property (GObject      *object,
                                          guint         property_id,
                                          const GValue *value,
                                          GParamSpec   *pspec)
{
      OdsServerSession *self = ODS_SERVER_SESSION (object);

      switch (property_id) {
            case ODS_SERVER_SESSION_FD:
                  self->priv->fd = g_value_get_int (value);
                  break;
            case ODS_SERVER_SESSION_SERVICE:
                  self->priv->service = g_value_get_int (value);
                  break;
            case ODS_SERVER_SESSION_PATH:
                  self->priv->root_path = g_value_dup_string (value);
                  self->priv->path = g_value_dup_string (value);
                  g_warning ("Session path: %s", self->priv->path);
                  break;
            case ODS_SERVER_SESSION_ALLOW_WRITE:
                  self->priv->allow_write = g_value_get_boolean (value);
                  break;
            case ODS_SERVER_SESSION_AUTO_ACCEPT:
                  self->priv->auto_accept = g_value_get_boolean (value);
                  break;
            case ODS_SERVER_SESSION_OWNER:
                  self->priv->owner = g_value_dup_string (value);
                  break;
            default:
                  /* We don't have any other property... */
                  G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
                  break;
      }
}

static void
ods_server_session_get_property (GObject      *object,
                                          guint         property_id,
                                          GValue       *value,
                                          GParamSpec   *pspec)
{
      OdsServerSession *self = ODS_SERVER_SESSION (object);

      switch (property_id) {
            case ODS_SERVER_SESSION_FD:
                  g_value_set_int (value, self->priv->fd);
                  break;
            case ODS_SERVER_SESSION_SERVICE:
                  g_value_set_int (value, self->priv->service);
                  break;
            case ODS_SERVER_SESSION_PATH:
                  g_value_set_string (value, self->priv->path);
                  break;
            case ODS_SERVER_SESSION_ALLOW_WRITE:
                  g_value_set_boolean (value, self->priv->allow_write);
                  break;
            case ODS_SERVER_SESSION_AUTO_ACCEPT:
                  g_value_set_boolean (value, self->priv->auto_accept);
                  break;
            case ODS_SERVER_SESSION_OWNER:
                  g_value_set_string (value, self->priv->owner);
                  break;
            case ODS_SERVER_SESSION_DBUS_PATH:
                  g_value_set_string (value, self->priv->dbus_path);
                  break;
            default:
                  /* We don't have any other property... */
                  G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
                  break;
      }
}

/**
 * ods_server_session_class_init:
 * @klass: The OdsServerSessionClass
 **/
static void
ods_server_session_class_init (OdsServerSessionClass *klass)
{
      GObjectClass *object_class = G_OBJECT_CLASS (klass);
      
      object_class->constructor = ods_server_session_constructor;
      object_class->finalize = ods_server_session_finalize;
      
      object_class->set_property = ods_server_session_set_property;
      object_class->get_property = ods_server_session_get_property;

      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_FD,
                                                      g_param_spec_int ("fd",
                                                            "", "",
                                                            0, G_MAXINT, /* min, max values */
                                                            0 /* default value */,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
                                                            
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_SERVICE,
                                                      g_param_spec_int ("service",
                                                            "", "",
                                                            0, G_MAXINT, /* min, max values */
                                                            0 /* default value */,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
      
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_PATH,
                                                      g_param_spec_string ("path",
                                                            "", "",
                                                            "" /* default value */,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
                                                            
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_OWNER,
                                                      g_param_spec_string ("owner",
                                                            "", "",
                                                            "" /* default value */,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
                                                            
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_ALLOW_WRITE,
                                                      g_param_spec_boolean("allow-write",
                                                            "", "",
                                                            FALSE,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
      
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_AUTO_ACCEPT,
                                                      g_param_spec_boolean("auto-accept",
                                                            "", "",
                                                            TRUE,
                                                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
                                                            
      g_object_class_install_property (object_class,
                                                      ODS_SERVER_SESSION_DBUS_PATH,
                                                      g_param_spec_string ("dbus-path",
                                                            "", "",
                                                            "" /* default value */,
                                                            G_PARAM_READABLE));
      
      signals [CANCELLED] =
            g_signal_new ("cancelled",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, cancelled),
                        NULL, 
                        NULL, 
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);
      signals [DISCONNECTED] =
            g_signal_new ("disconnected",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, disconnected),
                        NULL, 
                        NULL, 
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);
      signals [TRANSFER_STARTED] =
            g_signal_new ("transfer-started",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, transfer_started),
                        NULL, 
                        NULL,
                        ods_marshal_VOID__STRING_STRING_UINT64,
                        G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64);
      signals [TRANSFER_PROGRESS] =
            g_signal_new ("transfer-progress",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, transfer_progress),
                        NULL, 
                        NULL, 
                        ods_marshal_VOID__UINT64,
                        G_TYPE_NONE, 1, G_TYPE_UINT64);
      signals [TRANSFER_COMPLETED] =
            g_signal_new ("transfer-completed",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, transfer_completed),
                        NULL, 
                        NULL, 
                        g_cclosure_marshal_VOID__VOID,
                        G_TYPE_NONE, 0);
      signals [ERROR_OCCURRED] =
            g_signal_new ("error-occurred",
                        G_TYPE_FROM_CLASS (object_class), 
                        G_SIGNAL_RUN_LAST,
                        G_STRUCT_OFFSET (OdsServerSessionClass, error_occurred),
                        NULL, 
                        NULL,
                        ods_marshal_VOID__STRING_STRING,
                        G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
      
      g_type_class_add_private (klass, sizeof (OdsServerSessionPrivate));
      
      GError *error = NULL;

      /* Init the DBus connection, per-klass */
      klass->connection = dbus_g_bus_get (ODS_DBUS_BUS, &error);
      if (klass->connection == NULL)
      {
            g_warning("Unable to connect to dbus: %s", error->message);
            g_clear_error (&error);
            return;
      }

      /* &dbus_glib_ods_server_session_object_info is provided in the 
       * dbus/ods-server-session-dbus-glue.h file */
      dbus_g_object_type_install_info (ODS_TYPE_SERVER_SESSION, &dbus_glib_ods_server_session_object_info);
}

/**
 * ods_server_session_init:
 * @server_session: This class instance
 **/
static void
ods_server_session_init (OdsServerSession *server_session)
{
      OdsServerSessionClass *klass = ODS_SERVER_SESSION_GET_CLASS (server_session);
      server_session->priv = ODS_SERVER_SESSION_GET_PRIVATE (server_session);
      
      server_session->priv->obex_context = ods_obex_context_new ();
      
      /* figure out DBus object path for this instance */
      server_session->priv->state = ODS_SERVER_SESSION_STATE_OPEN;
      server_session->priv->dbus_path = (gchar *)g_malloc0 (
                                                            ODS_SERVER_SESSION_DBUS_PATH_MAX_LENGTH);
      g_sprintf (server_session->priv->dbus_path, 
                        ODS_SERVER_SESSION_DBUS_PATH_PATTERN, 
                        iterator);
      iterator++;
      
      /* create mutex */
      g_static_mutex_init (&server_session->priv->mutex);
      
      dbus_g_connection_register_g_object (klass->connection, 
                                          server_session->priv->dbus_path, 
                                          G_OBJECT (server_session));
}

static GObject*
ods_server_session_constructor (GType type, guint n_construct_params, 
                                                GObjectConstructParam *construct_params)
{
      GObject *object;
      OdsServerSession *server_session;
      OdsObexContext *obex_context;
      gint ret;
      /*GError *error = NULL;*/
      g_message ("Creating server session");
      
      object = G_OBJECT_CLASS (ods_server_session_parent_class)->constructor (type,
                                                           n_construct_params,
                                                           construct_params);
      
      server_session = ODS_SERVER_SESSION (object);
      obex_context = server_session->priv->obex_context;
      
      /* call OBEX_Init, setup FD Transport here */
      obex_context->obex_handle = OBEX_Init (OBEX_TRANS_FD, obex_event, 0);
      if (obex_context->obex_handle == NULL) {
            /* error (out of memory) */
            g_warning ("error out of memory");
            return NULL;
      }
      OBEX_SetUserData (obex_context->obex_handle, server_session);

      OBEX_SetTransportMTU (obex_context->obex_handle, 
                                          ODS_OBEX_RX_MTU, 
                                          ODS_OBEX_TX_MTU);

      ret = FdOBEX_TransportSetup (obex_context->obex_handle, 
                                                      server_session->priv->fd, 
                                                      server_session->priv->fd, 
                                                      0);
      if (ret < 0) {
            OBEX_Cleanup (obex_context->obex_handle);
            /* error (transport error or smth) */
            g_warning ("error transport setup fail");
            return NULL;
      }

      server_session->priv->io_channel = g_io_channel_unix_new (
                                                                              server_session->priv->fd);
      
      server_session->priv->io_source = g_io_create_watch (
                                                      server_session->priv->io_channel,
                                                      G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL);
    g_source_set_callback (server_session->priv->io_source, 
                                          (GSourceFunc)obex_io_callback, 
                                          obex_context->obex_handle, NULL);
    (void) g_source_attach (server_session->priv->io_source, NULL);
      g_source_unref (server_session->priv->io_source);
      
      return object;
}

/**
 * ods_server_session_finalize:
 * @object: The object to finalize
 *
 * Finalize the session
 **/
static void
ods_server_session_finalize (GObject *object)
{
      OdsServerSession *server_session;

      g_return_if_fail (object != NULL);
      g_return_if_fail (ODS_IS_SERVER_SESSION (object));

      server_session = ODS_SERVER_SESSION (object);

      g_return_if_fail (server_session->priv != NULL);

      /* close connection, free obex_context */
      g_message ("closing connection");
      OBEX_TransportDisconnect (server_session->priv->obex_context->obex_handle);
      OBEX_Cleanup (server_session->priv->obex_context->obex_handle);
      g_free (server_session->priv->obex_context);
      g_io_channel_shutdown (server_session->priv->io_channel, FALSE, NULL);
      g_io_channel_unref (server_session->priv->io_channel);
      g_source_destroy (server_session->priv->io_source);
      /* free other private variables */
      g_free (server_session->priv->root_path);
      g_free (server_session->priv->path);
      g_free (server_session->priv->owner);
      g_free (server_session->priv->dbus_path);
      g_static_mutex_free (&server_session->priv->mutex);

      G_OBJECT_CLASS (ods_server_session_parent_class)->finalize (object);
}

/**
 * ods_server_session_new:
 *
 * Return value: a new OdsServerSession object.
 **/
OdsServerSession *
ods_server_session_new (gint fd, gint service, const gchar *path, 
                                    gboolean allow_write, gboolean auto_accept,
                                    const gchar *owner)
{
      OdsServerSession *server_session;
      server_session = g_object_new (ODS_TYPE_SERVER_SESSION, 
                                                      "fd", fd,
                                                      "service", service,
                                                      "path", path,
                                                      "allow-write", allow_write,
                                                      "auto-accept", auto_accept,
                                                      "owner", owner,
                                                      NULL);
      return ODS_SERVER_SESSION (server_session);
}

gboolean
ods_server_session_accept (OdsServerSession *server_session,
                                          DBusGMethodInvocation *context)
{
      GError      *error = NULL;
      
      ODS_SERVER_SESSION_LOCK (server_session);
      /* do checks */
      if (!ods_check_caller (context, server_session->priv->owner)) {
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      if (server_session->priv->state != ODS_SERVER_SESSION_STATE_BUSY) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_FAILED,
                                    "There is no transfer in progress");
            dbus_g_method_return_error (context, error);
            g_clear_error (&error);
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      
      /* Accept file */
      OBEX_ResumeRequest (server_session->priv->obex_context->obex_handle);
      
      dbus_g_method_return (context);
      ODS_SERVER_SESSION_UNLOCK (server_session);
      return TRUE;
}

gboolean
ods_server_session_reject (OdsServerSession *server_session,
                                          DBusGMethodInvocation *context)
{
      GError      *error = NULL;
            
      ODS_SERVER_SESSION_LOCK (server_session);
      /* do checks */
      if (!ods_check_caller (context, server_session->priv->owner)) {
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      if (server_session->priv->state != ODS_SERVER_SESSION_STATE_BUSY) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_FAILED,
                                    "There is no transfer in progress");
            dbus_g_method_return_error (context, error);
            g_clear_error (&error);
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      
      /* Reject file */
      ods_server_session_cancel_internal (server_session);
      
      dbus_g_method_return (context);
      ODS_SERVER_SESSION_UNLOCK (server_session);
      return TRUE;
}

void
ods_server_session_disconnect_internal (OdsServerSession *server_session)
{
      if (server_session->priv->state == ODS_SERVER_SESSION_STATE_OPEN) {
            OBEX_TransportDisconnect (server_session->priv->obex_context->obex_handle);
            server_session->priv->state = ODS_SERVER_SESSION_STATE_NOT_CONNECTED;
      }
      g_signal_emit (server_session, signals [DISCONNECTED], 0);
}

gboolean
ods_server_session_disconnect (OdsServerSession *server_session,
                                                DBusGMethodInvocation *context)
{
      GError      *error = NULL;
      
      ODS_SERVER_SESSION_LOCK (server_session);
      /* do checks */
      if (!ods_check_caller (context, server_session->priv->owner)) {
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      if (server_session->priv->state == ODS_SERVER_SESSION_STATE_BUSY) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_BUSY,
                                    "Operations in progress need to be cancelled first");
            dbus_g_method_return_error (context, error);
            g_clear_error (&error);
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      
      ods_server_session_disconnect_internal (server_session);
      dbus_g_method_return (context);

      ODS_SERVER_SESSION_UNLOCK (server_session);
      return TRUE;
}

GHashTable *
ods_server_session_get_transfer_info (OdsServerSession *server_session)
{
      GHashTable *info;
      
      gchar *time_str = (gchar *)g_malloc (17);
      
      info = g_hash_table_new ((GHashFunc)g_str_hash, (GEqualFunc)g_str_equal);
      g_hash_table_insert (info, "LocalPath", 
                                          g_strdup (server_session->priv->obex_context->local));
      g_hash_table_insert (info, "RemoteFilename",
                                          g_strdup (server_session->priv->obex_context->remote));
      g_hash_table_insert (info, "Size",
                                          g_strdup_printf ("%" G_GUINT64_FORMAT, 
                                                server_session->priv->obex_context->target_size));
      if (server_session->priv->obex_context->modtime != -1)
            ods_make_iso8601 (server_session->priv->obex_context->modtime, time_str, 
                                          sizeof (time_str));
      else
            time_str = "";
      g_hash_table_insert (info, "Time", time_str);
      return info;
}

gint
ods_server_session_cancel_internal (OdsServerSession *server_session)
{
      if (server_session->priv->state != ODS_SERVER_SESSION_STATE_BUSY) {
            /* emit CANCELLED signal now */
            g_signal_emit (server_session, signals[CANCELLED], 0);
            return 1;
      }
      /* Send CMD_ABORT; cleanup will be done in obex_event */
      return OBEX_CancelRequest (server_session->priv->obex_context->obex_handle, TRUE);
}

gboolean
ods_server_session_cancel (OdsServerSession *server_session,
                                          DBusGMethodInvocation *context)
{
      GError *error = NULL;
      
      ODS_SERVER_SESSION_LOCK (server_session);
      /* do checks */
      if (!ods_check_caller (context, server_session->priv->owner)) {
            ODS_SERVER_SESSION_UNLOCK (server_session);
            return FALSE;
      }
      
      if (ods_server_session_cancel_internal (server_session) == -1) {
            g_set_error (&error, ODS_ERROR, ODS_ERROR_OUT_OF_MEMORY, "Out of memory");
            dbus_g_method_return_error (context, error);
            g_clear_error (&error);
            ODS_SERVER_SESSION_UNLOCK (server_session);
      } else {
            /* set dbus context */
            g_assert (!server_session->priv->dbus_context);
            server_session->priv->dbus_context = context;
            /* will return at obex_event{EV_ABORT} */
      }
      return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index