empathy-call-factory.c 8.47 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * empathy-call-factory.c - Source for EmpathyCallFactory
 * Copyright (C) 2008 Collabora Ltd.
 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

21
#include "config.h"
22
#include "empathy-client-factory.h"
23 24 25

#include "empathy-call-factory.h"
#include "empathy-call-handler.h"
26
#include "empathy-request-util.h"
27 28

#define DEBUG_FLAG EMPATHY_DEBUG_VOIP
29
#include "empathy-debug.h"
30

31
G_DEFINE_TYPE(EmpathyCallFactory, empathy_call_factory, TP_TYPE_BASE_CLIENT)
32

33
static void handle_channels (TpBaseClient *client,
34 35 36 37 38
    TpAccount *account,
    TpConnection *connection,
    GList *channels,
    GList *requests_satisfied,
    gint64 user_action_time,
39
    TpHandleChannelsContext *context);
40

41 42 43 44 45 46 47
static void approve_channels (TpBaseClient *client,
    TpAccount *account,
    TpConnection *connection,
    GList *channels,
    TpChannelDispatchOperation *dispatch_operation,
    TpAddDispatchOperationContext *context);

48 49 50 51
/* signal enum */
enum
{
    NEW_CALL_HANDLER,
52
    INCOMING_CALL,
53 54 55 56 57 58 59 60 61 62
    LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = {0};

static GObject *call_factory = NULL;

static void
empathy_call_factory_init (EmpathyCallFactory *obj)
{
63
  TpBaseClient *client = (TpBaseClient *) obj;
64

65 66
  tp_base_client_take_approver_filter (client, tp_asv_new (
        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
67
          TP_IFACE_CHANNEL_TYPE_CALL,
68 69 70 71
        TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
          G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
        NULL));

72
  tp_base_client_take_handler_filter (client, tp_asv_new (
73
        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
74
          TP_IFACE_CHANNEL_TYPE_CALL,
Sjoerd Simons's avatar
Sjoerd Simons committed
75 76
        TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
          G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
77 78
        NULL));

79
  tp_base_client_take_handler_filter (client, tp_asv_new (
80
        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
81
          TP_IFACE_CHANNEL_TYPE_CALL,
Sjoerd Simons's avatar
Sjoerd Simons committed
82 83
        TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
          G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
84
        TP_PROP_CHANNEL_TYPE_CALL_INITIAL_AUDIO, G_TYPE_BOOLEAN, TRUE,
85 86
        NULL));

87
  tp_base_client_take_handler_filter (client, tp_asv_new (
88
        TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
89
          TP_IFACE_CHANNEL_TYPE_CALL,
Sjoerd Simons's avatar
Sjoerd Simons committed
90 91
        TP_PROP_CHANNEL_TARGET_HANDLE_TYPE,
          G_TYPE_UINT, TP_HANDLE_TYPE_CONTACT,
92
        TP_PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO, G_TYPE_BOOLEAN, TRUE,
93 94
        NULL));

95
  tp_base_client_add_handler_capabilities_varargs (client,
96 97
      "org.freedesktop.Telepathy.Channel.Type.Call1/audio",
      "org.freedesktop.Telepathy.Channel.Type.Call1/video",
98
      "org.freedesktop.Telepathy.Channel.Type.Call1/ice",
99 100 101
      "org.freedesktop.Telepathy.Channel.Type.Call1/gtalk-p2p",
      "org.freedesktop.Telepathy.Channel.Type.Call1/video/h264",
      NULL);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
}

static GObject *
empathy_call_factory_constructor (GType type, guint n_construct_params,
  GObjectConstructParam *construct_params)
{
  g_return_val_if_fail (call_factory == NULL, NULL);

  call_factory = G_OBJECT_CLASS (empathy_call_factory_parent_class)->constructor
          (type, n_construct_params, construct_params);
  g_object_add_weak_pointer (call_factory, (gpointer)&call_factory);

  return call_factory;
}

static void
118
empathy_call_factory_class_init (EmpathyCallFactoryClass *klass)
119
{
120 121
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  TpBaseClientClass *base_clt_cls = TP_BASE_CLIENT_CLASS (klass);
122 123

  object_class->constructor = empathy_call_factory_constructor;
124 125

  base_clt_cls->handle_channels = handle_channels;
126
  base_clt_cls->add_dispatch_operation = approve_channels;
127 128 129

  signals[NEW_CALL_HANDLER] =
    g_signal_new ("new-call-handler",
130
      G_TYPE_FROM_CLASS (klass),
131 132
      G_SIGNAL_RUN_LAST, 0,
      NULL, NULL,
133
      g_cclosure_marshal_generic,
134 135
      G_TYPE_NONE,
      2, EMPATHY_TYPE_CALL_HANDLER, G_TYPE_BOOLEAN);
136 137 138 139 140 141

  signals[INCOMING_CALL] =
    g_signal_new ("incoming-call",
      G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, 0,
      NULL, NULL,
142
      g_cclosure_marshal_generic,
143
      G_TYPE_BOOLEAN,
144
      4, G_TYPE_UINT, TP_TYPE_CALL_CHANNEL,
145 146
      TP_TYPE_CHANNEL_DISPATCH_OPERATION,
      TP_TYPE_ADD_DISPATCH_OPERATION_CONTEXT);
147 148 149 150 151
}

EmpathyCallFactory *
empathy_call_factory_initialise (void)
{
152 153 154 155
  EmpathyCallFactory *self;
  EmpathyClientFactory *factory;
  TpAccountManager *am;

156 157
  g_return_val_if_fail (call_factory == NULL, NULL);

158 159 160 161 162 163 164 165 166 167 168 169 170
  am = tp_account_manager_dup ();
  factory = empathy_client_factory_dup ();

  self = EMPATHY_CALL_FACTORY (g_object_new (EMPATHY_TYPE_CALL_FACTORY,
      "account-manager", am,
      "factory", factory,
      "name", EMPATHY_CALL_BUS_NAME_SUFFIX,
      NULL));

  g_object_unref (am);
  g_object_unref (factory);

  return self;
171 172 173 174 175 176 177 178 179 180 181
}

EmpathyCallFactory *
empathy_call_factory_get (void)
{
  g_return_val_if_fail (call_factory != NULL, NULL);

  return EMPATHY_CALL_FACTORY (call_factory);
}

static void
182
handle_channels (TpBaseClient *client,
183 184 185 186 187
    TpAccount *account,
    TpConnection *connection,
    GList *channels,
    GList *requests_satisfied,
    gint64 user_action_time,
188
    TpHandleChannelsContext *context)
189
{
190
  EmpathyCallFactory *self = EMPATHY_CALL_FACTORY (client);
191 192 193 194 195
  GList *l;

  for (l = channels; l != NULL; l = g_list_next (l))
    {
      TpChannel *channel = l->data;
196 197 198 199
      TpCallChannel *call;
      TpContact *tp_contact;
      EmpathyContact *contact;
      EmpathyCallHandler *handler;
200 201 202 203 204

      if (tp_proxy_get_invalidated (channel) != NULL)
        continue;

      if (tp_channel_get_channel_type_id (channel) !=
205
          TP_IFACE_QUARK_CHANNEL_TYPE_CALL)
206 207
        continue;

208
      if (!TP_IS_CALL_CHANNEL (channel))
209 210
        continue;

211 212 213 214 215
      call = TP_CALL_CHANNEL (channel);

      tp_contact = tp_channel_get_target_contact (channel);
      contact = empathy_contact_dup_from_tp_contact (tp_contact);
      handler = empathy_call_handler_new_for_channel (call, contact);
216

217 218
      g_signal_emit (self, signals[NEW_CALL_HANDLER], 0,
          handler, FALSE);
219

220 221
      g_object_unref (handler);
      g_object_unref (contact);
222 223 224 225 226
    }

  tp_handle_channels_context_accept (context);
}

227
static TpCallChannel *
228 229 230 231 232 233 234 235 236 237 238 239 240 241
find_call_channel (GList *channels)
{
  GList *l;

  for (l = channels; l != NULL; l = g_list_next (l))
    {
      TpChannel *channel = l->data;
      GQuark channel_type;

      if (tp_proxy_get_invalidated (channel) != NULL)
        continue;

      channel_type = tp_channel_get_channel_type_id (channel);

242 243
      if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_CALL)
        return TP_CALL_CHANNEL (channel);
244 245 246 247 248 249 250 251 252 253 254 255 256 257
    }

  return NULL;
}

static void
approve_channels (TpBaseClient *client,
    TpAccount *account,
    TpConnection *connection,
    GList *channels,
    TpChannelDispatchOperation *dispatch_operation,
    TpAddDispatchOperationContext *context)
{
  EmpathyCallFactory *self = EMPATHY_CALL_FACTORY (client);
258
  TpCallChannel *channel;
259
  guint handle;
260
  GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT, "" };
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
  gboolean handled = FALSE;

  channel = find_call_channel (channels);

  if (channel == NULL)
    {
      DEBUG ("Failed to find the main channel; ignoring");
      error.message = "Unknown channel";
      goto out;
    }

  handle = tp_channel_get_handle (TP_CHANNEL (channel), NULL);

  if (handle == 0)
    {
      DEBUG ("Unknown handle, ignoring");
      error.code = TP_ERROR_INVALID_HANDLE;
      error.message = "Unknown handle";
      goto out;
    }

  g_signal_emit (self, signals[INCOMING_CALL], 0,
      handle, channel, dispatch_operation, context,
      &handled);

  if (handled)
    return;

  /* There was no call window so the context wasn't handled. */
  DEBUG ("Call with a contact for which there's no existing "
    "call window, ignoring");
  error.message = "No call window with this contact";

 out:
  tp_add_dispatch_operation_context_fail (context, &error);
}

298 299 300 301
gboolean
empathy_call_factory_register (EmpathyCallFactory *self,
    GError **error)
{
302
  return tp_base_client_register (TP_BASE_CLIENT (self), error);
303
}