Ejemplo n.º 1
0
static void
query_unread_mails_cb (GObject *source_object,
    GAsyncResult *res,
    gpointer user_data)
{
  GError *error = NULL;
  WockyPorter *porter = WOCKY_PORTER (source_object);
  WockyStanza *reply = wocky_porter_send_iq_finish (porter, res, &error);
  GabbleConnection *conn = GABBLE_CONNECTION (user_data);

  if (reply == NULL ||
      wocky_stanza_extract_errors (reply, NULL, &error, NULL, NULL))
    {
      DEBUG ("Failed retreive unread emails information: %s", error->message);
      g_error_free (error);
    }
  else if (conn->mail_priv->interested)
    {
      WockyNode *node = wocky_node_get_child (
          wocky_stanza_get_top_node (reply), "mailbox");

      DEBUG ("Got unread mail details");

      if (node != NULL)
        store_unread_mails (conn, node);
    }
  /* else we no longer care about unread mail, so ignore it */

  tp_clear_object (&reply);

  return_from_request_inbox_url (conn);
}
Ejemplo n.º 2
0
/* Signals incoming delivery receipts. http://xmpp.org/extensions/xep-0184.html
 */
static gboolean
im_factory_receipt_cb (
    WockyPorter *porter,
    WockyStanza *message,
    gpointer user_data)
{
  GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
  WockyNode *received;
  const gchar *from, *received_id;
  GabbleIMChannel *channel;

  received = wocky_node_get_child_ns (wocky_stanza_get_top_node (message),
      "received", NS_RECEIPTS);
  g_return_val_if_fail (received != NULL, FALSE);

  received_id = wocky_node_get_attribute (received, "id");
  if (received_id == NULL)
    {
      STANZA_DEBUG (message, "but *what* did you receive?!");
      return TRUE;
    }

  from = wocky_stanza_get_from (message);
  channel = get_channel_for_incoming_message (self, from, FALSE);
  if (channel == NULL)
    {
      DEBUG ("no existing channel with '%s'; ignoring receipt", from);
      return TRUE;
    }

  gabble_im_channel_receive_receipt (channel, received_id);
  return TRUE;
}
/* initial XMPP stream setup, up to sending features stanza */
static WockyStanza *
feature_stanza (TestConnectorServer *self)
{
  TestConnectorServerPrivate *priv = self->priv;
  XmppProblem problem = priv->problem.connector->xmpp;
  const gchar *name = NULL;
  WockyStanza *feat = NULL;
  WockyNode *node = NULL;

  DEBUG ("");
  if (problem & XMPP_PROBLEM_OTHER_HOST)
    return error_stanza ("host-unknown", "some sort of DNS error", TRUE);

  name = (problem & XMPP_PROBLEM_FEATURES) ? "badger" : "features";
  feat = wocky_stanza_new (name, WOCKY_XMPP_NS_STREAM);
  node = wocky_stanza_get_top_node (feat);

  DEBUG ("constructing <%s...>... stanza", name);

  if (priv->problem.sasl != SERVER_PROBLEM_NO_SASL)
    {
      if (priv->sasl == NULL)
        priv->sasl = test_sasl_auth_server_new (NULL, priv->mech,
            priv->user, priv->pass, NULL, priv->problem.sasl, FALSE);
      test_sasl_auth_server_set_mechs (G_OBJECT (priv->sasl), feat);
    }

  if (problem & XMPP_PROBLEM_OLD_AUTH_FEATURE)
    wocky_node_add_child_ns (node, "auth", WOCKY_JABBER_NS_AUTH_FEATURE);

  if (!(problem & XMPP_PROBLEM_NO_TLS) && !priv->tls_started)
    wocky_node_add_child_ns (node, "starttls", WOCKY_XMPP_NS_TLS);

  return feat;
}
/* resume control after the sasl auth server is done:                        */
static void
after_auth (GObject *source,
    GAsyncResult *res,
    gpointer data)
{
  GError *error = NULL;
  WockyStanza *feat = NULL;
  WockyNode *node = NULL;
  TestSaslAuthServer *tsas = TEST_SASL_AUTH_SERVER (source);
  TestConnectorServer *tcs = TEST_CONNECTOR_SERVER (data);
  TestConnectorServerPrivate *priv = tcs->priv;
  WockyXmppConnection *conn = priv->conn;

  DEBUG ("Auth finished: %d", priv->outstanding);
  if (!test_sasl_auth_server_auth_finish (tsas, res, &error))
    {
      g_object_unref (priv->sasl);
      priv->sasl = NULL;

      if (server_dec_outstanding (tcs))
        return;

      server_enc_outstanding (tcs);
      wocky_xmpp_connection_send_close_async (conn, priv->cancellable,
          xmpp_close, data);
      return;
    }

  priv->used_mech = g_strdup (test_sasl_auth_server_get_selected_mech
    (priv->sasl));

  g_object_unref (priv->sasl);
  priv->sasl = NULL;

  if (server_dec_outstanding (tcs))
    return;

  feat = wocky_stanza_build (WOCKY_STANZA_TYPE_STREAM_FEATURES,
      WOCKY_STANZA_SUB_TYPE_NONE, NULL, NULL, NULL);

  node = wocky_stanza_get_top_node (feat);

  if (!(priv->problem.connector->xmpp & XMPP_PROBLEM_NO_SESSION))
    wocky_node_add_child_ns (node, "session", WOCKY_XMPP_NS_SESSION);

  if (!(priv->problem.connector->xmpp & XMPP_PROBLEM_CANNOT_BIND))
    wocky_node_add_child_ns (node, "bind", WOCKY_XMPP_NS_BIND);

  priv->state = SERVER_STATE_FEATURES_SENT;

  server_enc_outstanding (tcs);
  wocky_xmpp_connection_send_stanza_async (conn, feat, priv->cancellable,
    xmpp_init, data);

  g_object_unref (feat);
}
/*
 * gabble_bytestream_multiple_accept
 *
 * Implements gabble_bytestream_iface_accept on GabbleBytestreamIface
 */
static void
gabble_bytestream_multiple_accept (GabbleBytestreamIface *iface,
                                   GabbleBytestreamAugmentSiAcceptReply func,
                                   gpointer user_data)
{
  GabbleBytestreamMultiple *self = GABBLE_BYTESTREAM_MULTIPLE (iface);
  GabbleBytestreamMultiplePrivate *priv =
      GABBLE_BYTESTREAM_MULTIPLE_GET_PRIVATE (self);
  WockyStanza *msg;
  WockyNode *si;
  GList *all_methods;
  gchar *current_method;

  /* We cannot just call the accept method of the active bytestream because
   * the result stanza is different if we are using si-multiple */

  if (priv->state != GABBLE_BYTESTREAM_STATE_LOCAL_PENDING)
    {
      /* The stream was previoulsy or automatically accepted */
      return;
    }

  g_return_if_fail (priv->active_bytestream != NULL);

  all_methods = g_list_copy (priv->fallback_stream_methods);
  g_object_get (priv->active_bytestream, "protocol", &current_method, NULL);
  all_methods = g_list_prepend (all_methods, current_method);

  msg = gabble_bytestream_factory_make_multi_accept_iq (priv->peer_jid,
      priv->stream_init_id, all_methods);

  g_free (current_method);
  g_list_free (all_methods);

  si = wocky_node_get_child_ns (
    wocky_stanza_get_top_node (msg), "si", NS_SI);
  g_assert (si != NULL);

  if (func != NULL)
    {
      /* let the caller add his profile specific data */
      func (si, user_data);
    }

  if (_gabble_connection_send (priv->conn, msg, NULL))
    {
      DEBUG ("stream %s with %s is now accepted", priv->stream_id,
          priv->peer_jid);
      g_object_set (priv->active_bytestream, "state",
          GABBLE_BYTESTREAM_STATE_ACCEPTED, NULL);
    }

  g_object_unref (msg);
}
Ejemplo n.º 6
0
static gboolean
im_factory_own_message_cb (
    WockyPorter *porter,
    WockyStanza *stanza,
    gpointer user_data)
{
  GabbleImFactory *self = GABBLE_IM_FACTORY (user_data);
  WockyNode *own_message, *body;
  const gchar *to;
  gboolean sent_locally;
  GabbleIMChannel *chan;

  /* Our stanza filter should guarantee that these are present. */
  own_message = wocky_node_get_child (wocky_stanza_get_top_node (stanza),
      "own-message");
  g_return_val_if_fail (own_message != NULL, FALSE);
  body = wocky_node_get_child (own_message, "body");
  g_return_val_if_fail (body != NULL, FALSE);

  to = wocky_node_get_attribute (own_message, "to");
  if (to == NULL)
    {
      DEBUG ("own-message missing to='' attribute; ignoring");
      return FALSE;
    }

  /* If self='true', the message was sent by the local user on this machine,
   * rather than by the local user on some other machine. We don't really have
   * a good way to show this in Messages. Also we don't get told the id='' of
   * the original message, which is annoying.
   */
  sent_locally = !tp_strdiff ("true",
      wocky_node_get_attribute (own_message, "self"));
  DEBUG ("this report is for a message to '%s', sent %s",
      to, sent_locally ? "locally" : "remotely");

  /* Don't create a channel for the sole purpose of reporting an own-message.
   * This is consistent with not creating a channel to report send errors
   * (given that both are delivery reports).
   */
  chan = get_channel_for_incoming_message (self, to, FALSE);
  if (chan != NULL)
    _gabble_im_channel_report_delivery (chan,
        TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL, 0, NULL, body->content,
        GABBLE_TEXT_CHANNEL_SEND_NO_ERROR, TP_DELIVERY_STATUS_ACCEPTED);
  else
    DEBUG ("no channel for '%s'; not spawning one just for the delivery report",
        to);

  wocky_porter_acknowledge_iq (porter, stanza, NULL);
  return TRUE;
}
GibberFileTransfer *
gibber_file_transfer_new_from_stanza (WockyStanza *stanza,
    WockyPorter *porter,
    WockyContact *contact,
    GError **error)
{
  const gchar *from;

  from = wocky_node_get_attribute (wocky_stanza_get_top_node (stanza), "from");

  return gibber_file_transfer_new_from_stanza_with_from (stanza, porter,
      contact, from, error);
}
static gboolean
received_stanza_cb (WockyPorter *porter,
                    WockyStanza *stanza,
                    gpointer user_data)
{
  GibberFileTransfer *self = user_data;
  const gchar *id;

  id = wocky_node_get_attribute (wocky_stanza_get_top_node (stanza),
      "id");
  if (id != NULL && strcmp (id, self->id) == 0)
    {
      GIBBER_FILE_TRANSFER_GET_CLASS (self)->received_stanza (self, stanza);
      return TRUE;
    }

  return FALSE;
}
/* error stanza                                                              */
static WockyStanza *
error_stanza (const gchar *cond,
    const gchar *msg, gboolean extended)
{
  WockyStanza *error = wocky_stanza_new ("error", WOCKY_XMPP_NS_STREAM);
  WockyNode *node = wocky_stanza_get_top_node (error);

  wocky_node_add_child_ns (node, cond, WOCKY_XMPP_NS_STREAMS);

  if ((msg != NULL) && (*msg != '\0'))
    wocky_node_add_child_with_content_ns (node, "text", msg,
        WOCKY_XMPP_NS_STREAMS);

  if (extended)
    wocky_node_add_child_with_content_ns (node, "something", "blah",
        "urn:ietf:a:namespace:I:made:up");

  return error;
}
static void
iq_set_bind_XMPP_BIND (TestConnectorServer *self,
    WockyStanza *xml)
{
  TestConnectorServerPrivate *priv = self->priv;
  WockyXmppConnection *conn = priv->conn;
  WockyStanza *iq = NULL;
  BindProblem problems = priv->problem.connector->bind;
  BindProblem bp = BIND_PROBLEM_NONE;

  DEBUG("");
  if ((bp = problems & BIND_PROBLEM_INVALID)  ||
      (bp = problems & BIND_PROBLEM_DENIED)   ||
      (bp = problems & BIND_PROBLEM_CONFLICT) ||
      (bp = problems & BIND_PROBLEM_REJECTED))
    {
      const gchar *error = NULL;
      const gchar *etype = NULL;
      switch (bp)
        {
        case BIND_PROBLEM_INVALID:
          error = "bad-request";
          etype = "modify";
          break;
        case BIND_PROBLEM_DENIED:
          error = "not-allowed";
          etype = "cancel";
          break;
        case BIND_PROBLEM_CONFLICT:
          error = "conflict";
          etype = "cancel";
          break;
        default:
          error = "badger-badger-badger-mushroom";
          etype = "moomins";
        }
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '(', "bind", ':', WOCKY_XMPP_NS_BIND,
          ')',
          '(', "error", '@', "type", etype,
          '(', error, ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else if (problems & BIND_PROBLEM_FAILED)
    {
      /* deliberately nonsensical response */
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_SET,
          NULL, NULL,
          '(', "bind", ':', WOCKY_XMPP_NS_BIND,
          ')',
          NULL);
    }
  else if (problems & BIND_PROBLEM_NONSENSE)
    {
      /* deliberately nonsensical response */
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
          WOCKY_STANZA_SUB_TYPE_NONE,
          NULL, NULL,
          '(', "bind", ':', WOCKY_XMPP_NS_BIND,
          ')',
          NULL);
    }
  else if (problems & BIND_PROBLEM_CLASH)
    {
      iq = error_stanza ("conflict", NULL, FALSE);
    }
  else
    {
      WockyNode *ciq = wocky_stanza_get_top_node (xml);
      WockyNode *bind =
        wocky_node_get_child_ns (ciq, "bind", WOCKY_XMPP_NS_BIND);
      WockyNode *res = wocky_node_get_child (bind, "resource");
      const gchar *uniq = NULL;
      gchar *jid = NULL;

      if (res != NULL)
        uniq = res->content;
      if (uniq == NULL)
        uniq = "a-made-up-resource";

      if (problems & BIND_PROBLEM_NO_JID)
        {
          iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
              WOCKY_STANZA_SUB_TYPE_RESULT, NULL, NULL,
              '(', "bind", ':', WOCKY_XMPP_NS_BIND,
              ')', NULL);
        }
      else
        {
          jid = g_strdup_printf ("[email protected]/%s", uniq);
          iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
              WOCKY_STANZA_SUB_TYPE_RESULT,
              NULL, NULL,
              '(', "bind", ':', WOCKY_XMPP_NS_BIND,
              '(', "jid", '$', jid, ')',
              ')',
              NULL);
          g_free (jid);
        }
    }

  server_enc_outstanding (self);
  wocky_xmpp_connection_send_stanza_async (conn, iq, priv->cancellable,
    iq_sent, self);
  g_object_unref (xml);
  g_object_unref (iq);
}
static void
iq_set_query_JABBER_AUTH (TestConnectorServer *self,
    WockyStanza *xml)
{
  TestConnectorServerPrivate *priv = self->priv;
  WockyXmppConnection *conn = priv->conn;
  WockyStanza *iq = NULL;
  WockyNode *env = wocky_stanza_get_top_node (xml);
  WockyNode *qry = wocky_node_get_child (env, "query");
  JabberProblem problems = priv->problem.connector->jabber;
  JabberProblem jp = JABBER_PROBLEM_NONE;
  WockyNode *username = wocky_node_get_child (qry, "username");
  WockyNode *password = wocky_node_get_child (qry, "password");
  WockyNode *resource = wocky_node_get_child (qry, "resource");
  WockyNode *sha1hash = wocky_node_get_child (qry, "digest");
  const gchar *id = wocky_node_get_attribute (env, "id");

  DEBUG ("");
  if (username == NULL || resource == NULL)
    problems |= JABBER_PROBLEM_AUTH_PARTIAL;
  else if (password != NULL)
    {
      if (wocky_strdiff (priv->user, username->content) ||
          wocky_strdiff (priv->pass, password->content))
        problems |= JABBER_PROBLEM_AUTH_REJECT;
    }
  else if (sha1hash != NULL)
    {
      gchar *hsrc = g_strconcat (INITIAL_STREAM_ID, priv->pass, NULL);
      gchar *sha1 = g_compute_checksum_for_string (G_CHECKSUM_SHA1, hsrc, -1);
      DEBUG ("checksum: %s vs %s", sha1, sha1hash->content);
      if (wocky_strdiff (priv->user, username->content) ||
          wocky_strdiff (sha1, sha1hash->content))
        problems |= JABBER_PROBLEM_AUTH_REJECT;

      g_free (hsrc);
      g_free (sha1);
    }
  else
    problems |= JABBER_PROBLEM_AUTH_PARTIAL;

  if ((jp = problems & JABBER_PROBLEM_AUTH_REJECT)  ||
      (jp = problems & JABBER_PROBLEM_AUTH_BIND)    ||
      (jp = problems & JABBER_PROBLEM_AUTH_PARTIAL) ||
      (jp = problems & JABBER_PROBLEM_AUTH_FAILED))
    {
      const gchar *error = NULL;
      const gchar *etype = NULL;
      const gchar *ecode = NULL;

      switch (jp)
        {
          case JABBER_PROBLEM_AUTH_REJECT:
            error = "not-authorized";
            etype = "auth";
            ecode = "401";
            break;
          case JABBER_PROBLEM_AUTH_BIND:
            error = "conflict";
            etype = "cancel";
            ecode = "409";
            break;
          case JABBER_PROBLEM_AUTH_PARTIAL:
            error = "not-acceptable";
            etype = "modify";
            ecode = "406";
            break;
          default:
            error = "bad-request";
            etype = "modify";
            ecode = "500";
            break;
        }

      DEBUG ("error: %s/%s", error, etype);
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error",
          '@', "type", etype,
          '@', "code", ecode,
          '(', error, ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else if (problems & JABBER_PROBLEM_AUTH_STRANGE)
    {
      DEBUG ("auth WEIRD");
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_SET,
          NULL, NULL,
          '@', "id", id,
          '(', "surstromming", ':', WOCKY_XMPP_NS_BIND,
          ')',
          NULL);
    }
  else if (problems & JABBER_PROBLEM_AUTH_NONSENSE)
    {
      DEBUG ("auth NONSENSE");
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
          WOCKY_STANZA_SUB_TYPE_NONE,
          NULL, NULL,
          '@', "id", id,
          '(', "surstromming", ':', WOCKY_XMPP_NS_BIND,
          ')',
          NULL);
    }
  else
    {
      DEBUG ("auth OK");
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          NULL);
    }

  server_enc_outstanding (self);
  wocky_xmpp_connection_send_stanza_async (conn, iq, priv->cancellable,
    iq_sent, self);
  g_object_unref (iq);
  g_object_unref (xml);
}
static void
iq_get_query_JABBER_AUTH (TestConnectorServer *self,
    WockyStanza *xml)
{
  TestConnectorServerPrivate *priv = self->priv;
  WockyXmppConnection *conn = priv->conn;
  WockyStanza *iq = NULL;
  WockyNode *env = wocky_stanza_get_top_node (xml);
  const gchar *id = wocky_node_get_attribute (env, "id");
  WockyNode *query = wocky_node_get_child (env, "query");
  WockyNode *user  = (query != NULL) ?
    wocky_node_get_child (query, "username") : NULL;
  const gchar *name = (user != NULL) ? user->content : NULL;

  DEBUG ("");
  if (priv->problem.connector->jabber & JABBER_PROBLEM_AUTH_NIH)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error", '@', "type", "cancel",
          '(', "service-unavailable",
          ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else if (name == NULL || *name == '\0')
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error", '@', "type", "modify",
            '(', "not-acceptable",
              ':', WOCKY_XMPP_NS_STANZAS,
            ')',
            '(', "text", ':', WOCKY_XMPP_NS_STANZAS,
              '$',
                "You must include the username in the initial IQ get to work "
                "around a bug in jabberd 1.4. See "
                "https://bugs.freedesktop.org/show_bug.cgi?id=24013",
            ')',
          ')',
          NULL);
    }
  else if (priv->mech != NULL)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          '(', "query", ':', WOCKY_JABBER_NS_AUTH,
          '(', "username", ')',
          '(', priv->mech, ')',
          '(', "resource", ')',
          ')',
          NULL);
    }
  else
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          '(', "query", ':', WOCKY_JABBER_NS_AUTH,
          '(', "username", ')',
          '(', "password", ')',
          '(', "resource", ')',
          '(', "digest", ')',
          ')',
          NULL);
    }

  DEBUG ("responding to iq get");
  server_enc_outstanding (self);
  wocky_xmpp_connection_send_stanza_async (conn, iq,
    priv->cancellable, iq_sent, self);
  DEBUG ("sent iq get response");
  g_object_unref (xml);
  g_object_unref (iq);
}
static void
iq_get_query_XEP77_REGISTER (TestConnectorServer *self,
    WockyStanza *xml)
{
  TestConnectorServerPrivate *priv = self->priv;
  WockyXmppConnection *conn = priv->conn;
  WockyStanza *iq = NULL;
  WockyNode *env = wocky_stanza_get_top_node (xml);
  WockyNode *query = NULL;
  const gchar *id = wocky_node_get_attribute (env, "id");

  DEBUG ("");
  if (priv->problem.connector->xep77 & XEP77_PROBLEM_NOT_AVAILABLE)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error", '@', "type", "cancel",
          '(', "service-unavailable",
          ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else if (priv->problem.connector->xep77 & XEP77_PROBLEM_QUERY_NONSENSE)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_MESSAGE,
          WOCKY_STANZA_SUB_TYPE_NONE,
          NULL, NULL,
          '@', "id", id,
          '(', "plankton", ':', WOCKY_XEP77_NS_REGISTER,
          ')',
          NULL);
    }
  else if (priv->problem.connector->xep77 & XEP77_PROBLEM_QUERY_ALREADY)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          '(', "query", ':', WOCKY_XEP77_NS_REGISTER,
          '(', "registered", ')',
          '(', "username", '$', "foo", ')',
          '(', "password", '$', "bar", ')',
          ')',
          NULL);
    }
  else
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          '(', "query", ':', WOCKY_XEP77_NS_REGISTER,
            '*', &query,
          ')',
          NULL);

      if (!(priv->problem.connector->xep77 & XEP77_PROBLEM_NO_ARGS))
        {
          wocky_node_add_child (query, "username");
          wocky_node_add_child (query, "password");

          if (priv->problem.connector->xep77 & XEP77_PROBLEM_EMAIL_ARG)
            wocky_node_add_child (query, "email");
          if (priv->problem.connector->xep77 & XEP77_PROBLEM_STRANGE_ARG)
            wocky_node_add_child (query, "wildebeest");
        }
    }

  server_enc_outstanding (self);
  wocky_xmpp_connection_send_stanza_async (conn, iq, NULL, iq_sent, self);
  g_object_unref (xml);
  g_object_unref (iq);
}
static void
xmpp_init (GObject *source,
    GAsyncResult *result,
    gpointer data)
{
  TestConnectorServer *self;
  TestConnectorServerPrivate *priv;
  WockyStanza *xml;
  WockyXmppConnection *conn;

  self = TEST_CONNECTOR_SERVER (data);
  priv = self->priv;
  conn = priv->conn;

  DEBUG ("test_connector_server:xmpp_init %d", priv->state);
  DEBUG ("connection: %p", conn);

  switch (priv->state)
    {
      /* wait for <stream:stream… from the client */
    case SERVER_STATE_START:
      DEBUG ("SERVER_STATE_START");
      priv->state = SERVER_STATE_CLIENT_OPENED;

      server_enc_outstanding (self);
      if (priv->problem.connector->death & SERVER_DEATH_SERVER_START)
        {
          wocky_xmpp_connection_force_close_async (conn,
            priv->cancellable, force_closed_cb, self);
        }
      else
        {
          wocky_xmpp_connection_recv_open_async (conn, priv->cancellable,
            xmpp_init, self);
        }
      break;

      /* send our own <stream:stream… */
    case SERVER_STATE_CLIENT_OPENED:
      DEBUG ("SERVER_STATE_CLIENT_OPENED");
      priv->state = SERVER_STATE_SERVER_OPENED;
      wocky_xmpp_connection_recv_open_finish (conn, result,
          NULL, NULL, NULL, NULL, NULL, NULL);
      if (server_dec_outstanding (self))
        return;

      server_enc_outstanding (self);
      if (priv->problem.connector->death & SERVER_DEATH_CLIENT_OPEN)
        {
          wocky_xmpp_connection_force_close_async (conn,
            priv->cancellable, force_closed_cb, self);
        }
      else
        {
          wocky_xmpp_connection_send_open_async (conn, NULL,
              "testserver",
             priv->version, NULL, INITIAL_STREAM_ID,
             priv->cancellable, xmpp_init, self);
        }
      break;

      /* send our feature set */
    case SERVER_STATE_SERVER_OPENED:
      DEBUG ("SERVER_STATE_SERVER_OPENED");
      priv->state = SERVER_STATE_FEATURES_SENT;
      wocky_xmpp_connection_send_open_finish (conn, result, NULL);
      if (server_dec_outstanding (self))
        return;

      if (priv->problem.connector->death & SERVER_DEATH_SERVER_OPEN)
        {
          server_enc_outstanding (self);
          wocky_xmpp_connection_force_close_async (conn,
            priv->cancellable, force_closed_cb, self);
        }
      else if (priv->problem.connector->xmpp & XMPP_PROBLEM_OLD_SERVER)
        {
          DEBUG ("diverting to old-jabber-auth");
          server_enc_outstanding (self);
          wocky_xmpp_connection_recv_stanza_async (priv->conn,
              priv->cancellable,
              xmpp_handler, self);
        }
      else if (priv->problem.connector->xmpp & XMPP_PROBLEM_SEE_OTHER_HOST)
        {
          WockyStanza *stanza;
          WockyNode *node;
          gchar *host_and_port;

          host_and_port = g_strdup_printf ("%s:%u", self->priv->other_host,
              self->priv->other_port);

          DEBUG ("Redirect to another host: %s", host_and_port);

          stanza = wocky_stanza_new ("error", WOCKY_XMPP_NS_STREAM);
          node = wocky_stanza_get_top_node (stanza);
          wocky_node_add_child_with_content_ns (node, "see-other-host",
              host_and_port, WOCKY_XMPP_NS_STREAMS);

          server_enc_outstanding (self);
          wocky_xmpp_connection_send_stanza_async (self->priv->conn, stanza,
              self->priv->cancellable, see_other_host_cb, self);

          g_object_unref (stanza);
        }
      else
        {
          xml = feature_stanza (self);
          server_enc_outstanding (self);
          wocky_xmpp_connection_send_stanza_async (conn, xml,
              priv->cancellable, xmpp_init, self);
          g_object_unref (xml);
        }
      break;

      /* ok, we're done with initial stream setup */
    case SERVER_STATE_FEATURES_SENT:
      DEBUG ("SERVER_STATE_FEATURES_SENT");
      wocky_xmpp_connection_send_stanza_finish (conn, result, NULL);
      if (server_dec_outstanding (self))
        return;

      server_enc_outstanding (self);
      if (priv->problem.connector->death & SERVER_DEATH_FEATURES)
        {
          wocky_xmpp_connection_force_close_async (conn,
            priv->cancellable, force_closed_cb, self);
        }
      else
        {
          wocky_xmpp_connection_recv_stanza_async (conn, priv->cancellable,
            xmpp_handler, self);
        }
      break;

    default:
      DEBUG ("Unknown Server state. Broken code flow.");
    }
}
static void
xmpp_handler (GObject *source,
    GAsyncResult *result,
    gpointer user_data)
{
  TestConnectorServer *self;
  TestConnectorServerPrivate *priv;
  WockyStanza *xml = NULL;
  WockyXmppConnection *conn = NULL;
  const gchar *ns = NULL;
  const gchar *name = NULL;
  gboolean handled = FALSE;
  GError *error = NULL;
  WockyStanzaType type = WOCKY_STANZA_TYPE_NONE;
  WockyStanzaSubType subtype = WOCKY_STANZA_SUB_TYPE_NONE;
  int i;

  DEBUG ("");
  self = TEST_CONNECTOR_SERVER (user_data);
  priv = self->priv;
  conn = priv->conn;
  xml  = wocky_xmpp_connection_recv_stanza_finish (conn, result, &error);

  /* A real XMPP server would need to do some error handling here, but if
   * we got this far, we can just exit: The client (ie the test) will
   * report any error that actually needs reporting - we don't need to */
  if (error != NULL)
    {
      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          g_error_free (error);
          server_dec_outstanding (self);
          return;
        }
      g_assert_not_reached ();
    }

  if (server_dec_outstanding (self))
    return;

  ns   = wocky_node_get_ns (wocky_stanza_get_top_node (xml));
  name = wocky_stanza_get_top_node (xml)->name;
  wocky_stanza_get_type_info (xml, &type, &subtype);

  /* if we find a handler, the handler is responsible for listening for the
     next stanza and setting up the next callback in the chain: */
  if (type == WOCKY_STANZA_TYPE_IQ)
    for (i = 0; iq_handlers[i].payload != NULL; i++)
      {
        iq_handler *iq = &iq_handlers[i];
        WockyNode *payload =
          wocky_node_get_child_ns (wocky_stanza_get_top_node (xml),
              iq->payload, iq->ns);
        /* namespace, stanza subtype and payload tag name must match: */
        if ((payload == NULL) || (subtype != iq->subtype))
          continue;
        DEBUG ("test_connector_server:invoking iq handler %s", iq->payload);
        (iq->func) (self, xml);
        handled = TRUE;
        break;
      }
  else
    for (i = 0; handlers[i].ns != NULL; i++)
      {
        if (!strcmp (ns, handlers[i].ns) && !strcmp (name, handlers[i].name))
          {
            DEBUG ("test_connector_server:invoking handler %s.%s", ns, name);
            (handlers[i].func) (self, xml);
            handled = TRUE;
            break;
          }
      }

  /* no handler found: just complain and sit waiting for the next stanza */
  if (!handled)
    {
      DEBUG ("<%s xmlns=\"%s\"… not handled", name, ns);
      server_enc_outstanding (self);
      wocky_xmpp_connection_recv_stanza_async (conn, priv->cancellable,
          xmpp_handler, self);
      g_object_unref (xml);
    }
}
Ejemplo n.º 16
0
static gboolean
update_location_from_msg (GabbleConnection *conn,
                          TpHandle contact,
                          LmMessage *msg)
{
  LmMessageNode *node;
  GHashTable *location = g_hash_table_new_full (g_direct_hash, g_direct_equal,
      g_free, (GDestroyNotify) tp_g_value_slice_free);
  TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (
      (TpBaseConnection *) conn, TP_HANDLE_TYPE_CONTACT);
  const gchar *from = tp_handle_inspect (contact_repo, contact);
  NodeIter i;
  const gchar *lang;

  node = lm_message_node_find_child (wocky_stanza_get_top_node (msg),
      "geoloc");
  if (node == NULL)
    return FALSE;

  DEBUG ("LocationsUpdate for %s:", from);

  lang = lm_message_node_get_attribute (node, "xml:lang");
  if (lang != NULL)
    {
      g_hash_table_insert (location, g_strdup ("language"),
          tp_g_value_slice_new_string (lang));
    }

  build_mapping_tables ();

  for (i = node_iter (node); i; i = node_iter_next (i))
    {
      LmMessageNode *subloc_node = node_iter_data (i);
      GValue *value = NULL;
      gchar *xmpp_name;
      const gchar *str;
      LocationMapping *mapping;

      xmpp_name = subloc_node->name;
      str = lm_message_node_get_value (subloc_node);
      if (str == NULL)
        continue;

      mapping = g_hash_table_lookup (xmpp_to_tp, xmpp_name);
      if (mapping == NULL)
        {
          DEBUG ("Unknown location attribute: %s\n", xmpp_name);
          continue;
        }

      if (mapping->type == G_TYPE_DOUBLE)
        {
          gdouble double_value;
          gchar *end;

          double_value = g_ascii_strtod (str, &end);

          if (end == str)
            continue;

          value = tp_g_value_slice_new_double (double_value);
          DEBUG ("\t - %s: %f", xmpp_name, double_value);
        }
      else if (strcmp (xmpp_name, "timestamp") == 0)
        {
          GTimeVal timeval;
          if (g_time_val_from_iso8601 (str, &timeval))
            {
              value = tp_g_value_slice_new_int64 (timeval.tv_sec);
              DEBUG ("\t - %s: %s", xmpp_name, str);
            }
          else
            {
              DEBUG ("\t - %s: %s: unknown date format", xmpp_name, str);
              continue;
            }
        }
      else if (mapping->type == G_TYPE_STRING)
        {
          value = tp_g_value_slice_new_string (str);
          DEBUG ("\t - %s: %s", xmpp_name, str);
        }
      else
        {
          g_assert_not_reached ();
        }

      g_hash_table_insert (location, g_strdup (mapping->tp_name), value);
    }

  tp_svc_connection_interface_location_emit_location_updated (conn,
      contact, location);
  gabble_presence_cache_update_location (conn->presence_cache, contact,
      location);

  return TRUE;
}
Ejemplo n.º 17
0
static void
got_jingle_info_stanza (
    GabbleJingleInfo *self,
    WockyStanza *stanza)
{
  WockyNode *node, *query_node;

  query_node = wocky_node_get_child_ns (
      wocky_stanza_get_top_node (stanza), "query", NS_GOOGLE_JINGLE_INFO);

  if (query_node == NULL)
    return;

  if (self->priv->get_stun_from_jingle)
    node = wocky_node_get_child (query_node, "stun");
  else
    node = NULL;

  if (node != NULL)
    {
      node = wocky_node_get_child (node, "server");

      if (node != NULL)
        {
          const gchar *server;
          const gchar *port_attr;
          guint port = 0;

          server = wocky_node_get_attribute (node, "host");
          port_attr = wocky_node_get_attribute (node, "udp");

          if (port_attr != NULL)
            port = atoi (port_attr);

          if (server != NULL &&
              port_attr != NULL && port > 0 && port <= G_MAXUINT16)
            {
              DEBUG ("jingle info: got stun server %s, port %u", server,
                  port);
              gabble_jingle_info_take_stun_server (self,
                  g_strdup (server), port, FALSE);
            }
        }
    }

#ifdef ENABLE_GOOGLE_RELAY
  node = wocky_node_get_child (query_node, "relay");

  if (node != NULL)
    {
      WockyNode *subnode = wocky_node_get_child (node, "token");

      if (subnode != NULL)
        {
          const gchar *token = subnode->content;

          if (token != NULL)
            {
              DEBUG ("jingle info: got Google relay token %s", token);
              g_free (self->priv->relay_token);
              self->priv->relay_token = g_strdup (token);
            }
        }

      subnode = wocky_node_get_child (node, "server");

      if (subnode != NULL)
        {
          const gchar *server;
          const gchar *port;

          server = wocky_node_get_attribute (subnode, "host");

          if (server != NULL)
            {
              DEBUG ("jingle info: got relay server %s", server);
              g_free (self->priv->relay_server);
              self->priv->relay_server = g_strdup (server);
            }

          if (test_mode)
            {
              /* this is not part of the real protocol, but we can't listen on
               * port 80 in an unprivileged regression test */
              port = wocky_node_get_attribute (subnode,
                  "gabble-test-http-port");

              if (port != NULL)
                {
                  DEBUG ("jingle info: diverting 'Google' HTTP requests to "
                      "port %s", port);
                  self->priv->relay_http_port = atoi (port);
                }
            }

          /* FIXME: these are not really actually used anywhere at
           * the moment, because we get the same info when creating
           * relay session. */
          port = wocky_node_get_attribute (subnode, "udp");

          if (port != NULL)
            {
              DEBUG ("jingle info: got relay udp port %s", port);
              self->priv->relay_udp = atoi (port);
            }

          port = wocky_node_get_attribute (subnode, "tcp");

          if (port != NULL)
            {
              DEBUG ("jingle info: got relay tcp port %s", port);
              self->priv->relay_tcp = atoi (port);
            }

          port = wocky_node_get_attribute (subnode, "tcpssl");

          if (port != NULL)
            {
              DEBUG ("jingle info: got relay tcpssl port %s", port);
              self->priv->relay_ssltcp = atoi (port);
            }

        }

    }
#endif  /* ENABLE_GOOGLE_RELAY */
}
/* ************************************************************************* */
static void
iq_set_query_XEP77_REGISTER (TestConnectorServer *self,
    WockyStanza *xml)
{
  TestConnectorServerPrivate *priv = self->priv;
  WockyXmppConnection *conn = priv->conn;
  WockyStanza *iq = NULL;
  WockyNode *env = wocky_stanza_get_top_node (xml);
  WockyNode *query = wocky_node_get_child (env, "query");
  const gchar *id = wocky_node_get_attribute (env, "id");
  gpointer cb = iq_sent;

  DEBUG ("");

  if (priv->problem.connector->xep77 & XEP77_PROBLEM_ALREADY)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_RESULT,
          NULL, NULL,
          '@', "id", id,
          '(', "query", ':', WOCKY_XEP77_NS_REGISTER,
          '(', "registered", ')',
          '(', "username", '$', "foo", ')',
          '(', "password", '$', "bar", ')',
          ')',
          NULL);
    }
  else if (priv->problem.connector->xep77 & XEP77_PROBLEM_FAIL_CONFLICT)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error", '@', "type", "cancel",
          '(', "conflict",
          ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else if (priv->problem.connector->xep77 & XEP77_PROBLEM_FAIL_REJECTED)
    {
      iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
          WOCKY_STANZA_SUB_TYPE_ERROR,
          NULL, NULL,
          '@', "id", id,
          '(', "error", '@', "type", "modify",
          '(', "not-acceptable",
          ':', WOCKY_XMPP_NS_STANZAS,
          ')',
          ')',
          NULL);
    }
  else
    {
      if (wocky_node_get_child (query, "remove") == NULL)
        {
          iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
              WOCKY_STANZA_SUB_TYPE_RESULT,
              NULL, NULL,
              '@', "id", id,
              NULL);
        }
      else
        {
          XEP77Problem problem = priv->problem.connector->xep77;
          XEP77Problem p = XEP77_PROBLEM_NONE;

          DEBUG ("handling CANCEL");

          if ((p = problem & XEP77_PROBLEM_CANCEL_REJECTED) ||
              (p = problem & XEP77_PROBLEM_CANCEL_DISABLED) ||
              (p = problem & XEP77_PROBLEM_CANCEL_FAILED))
            {
              const gchar *error = NULL;
              const gchar *etype = NULL;
              const gchar *ecode = NULL;

              switch (p)
                {
                  case XEP77_PROBLEM_CANCEL_REJECTED:
                    error = "bad-request";
                    etype = "modify";
                    ecode = "400";
                    break;
                  case XEP77_PROBLEM_CANCEL_DISABLED:
                    error = "not-allowed";
                    etype = "cancel";
                    ecode = "405";
                    break;
                  default:
                    error = "forbidden";
                    etype = "cancel";
                    ecode = "401";
                }

              DEBUG ("error: %s/%s", error, etype);
              iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
                  WOCKY_STANZA_SUB_TYPE_ERROR,
                  NULL, NULL,
                  '@', "id", id,
                  '(', "error",
                  '@', "type", etype,
                  '@', "code", ecode,
                  '(', error, ':', WOCKY_XMPP_NS_STANZAS,
                  ')',
                  ')',
                  NULL);
            }
          else
            {
              if (priv->problem.connector->xep77 & XEP77_PROBLEM_CANCEL_STREAM)
                {
                  iq = error_stanza ("not-authorized", NULL, FALSE);
                  cb = finished;
                }
              else
                {
                  cb = iq_sent_unregistered;
                  iq = wocky_stanza_build (WOCKY_STANZA_TYPE_IQ,
                      WOCKY_STANZA_SUB_TYPE_RESULT,
                      NULL, NULL,
                      '@', "id", id,
                      NULL);
                }
            }
        }
    }

  server_enc_outstanding (self);
  wocky_xmpp_connection_send_stanza_async (conn, iq,
    priv->cancellable, cb, self);
  g_object_unref (xml);
  g_object_unref (iq);
}