telepathygabble/src/gabble-register.c
branchRCL_3
changeset 11 3404599e4dda
parent 9 46cc8e302e43
equal deleted inserted replaced
9:46cc8e302e43 11:3404599e4dda
     1 /*
       
     2  * gabble-register.c - Source for Gabble account registration
       
     3  *
       
     4  * Copyright (C) 2006 Collabora Ltd.
       
     5  * 
       
     6  *   @author Ole Andre Vadla Ravnaas <ole.andre.ravnaas@collabora.co.uk>
       
     7  *
       
     8  * This library is free software; you can redistribute it and/or
       
     9  * modify it under the terms of the GNU Lesser General Public
       
    10  * License as published by the Free Software Foundation; either
       
    11  * version 2.1 of the License, or (at your option) any later version.
       
    12  *
       
    13  * This library is distributed in the hope that it will be useful,
       
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    16  * Lesser General Public License for more details.
       
    17  *
       
    18  * You should have received a copy of the GNU Lesser General Public
       
    19  * License along with this library; if not, write to the Free Software
       
    20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    21  */
       
    22 
       
    23 #define DBUS_API_SUBJECT_TO_CHANGE
       
    24 
       
    25 #include <dbus/dbus-glib.h>
       
    26 #include <dbus/dbus-glib-lowlevel.h>
       
    27 #include <stdlib.h>
       
    28 #include <string.h>
       
    29 
       
    30 #include "telepathy-helpers.h"
       
    31 #include "telepathy-errors.h"
       
    32 
       
    33 #include "gabble-connection.h"
       
    34 #include "gabble-error.h"
       
    35 #include "gabble-register.h"
       
    36 #include "gabble-register-signals-marshal.h"
       
    37 #include "namespaces.h"
       
    38 #include "util.h"
       
    39 
       
    40 
       
    41 #include "gabble_enums.h"
       
    42 
       
    43 #ifndef EMULATOR
       
    44 G_DEFINE_TYPE(GabbleRegister, gabble_register, G_TYPE_OBJECT);
       
    45 #endif
       
    46 
       
    47 /* signal enum */
       
    48 enum
       
    49 {
       
    50   FINISHED,
       
    51   LAST_SIGNAL 
       
    52 #ifdef EMULATOR  
       
    53   = LAST_SIGNAL_REGISTER
       
    54 #endif
       
    55   
       
    56 };
       
    57 
       
    58 #ifdef EMULATOR
       
    59 #include "libgabble_wsd_solution.h"
       
    60 
       
    61 	GET_STATIC_ARRAY_FROM_TLS(signals,gabble_register,guint)
       
    62 	#define signals (GET_WSD_VAR_NAME(signals,gabble_register, s)())
       
    63 	
       
    64 	GET_STATIC_VAR_FROM_TLS(gabble_register_parent_class,gabble_register,gpointer)
       
    65 	#define gabble_register_parent_class (*GET_WSD_VAR_NAME(gabble_register_parent_class,gabble_register,s)())
       
    66 	
       
    67 	GET_STATIC_VAR_FROM_TLS(g_define_type_id,gabble_register,GType)
       
    68 	#define g_define_type_id (*GET_WSD_VAR_NAME(g_define_type_id,gabble_register,s)())
       
    69 	
       
    70 	
       
    71 static void gabble_register_init (GabbleRegister *self); 
       
    72 static void gabble_register_class_init (GabbleRegisterClass *klass); 
       
    73 static void gabble_register_class_intern_init (gpointer klass) 
       
    74 {
       
    75  gabble_register_parent_class = g_type_class_peek_parent (klass); 
       
    76  gabble_register_class_init ((GabbleRegisterClass*) klass); 
       
    77  } 
       
    78  EXPORT_C GType gabble_register_get_type (void) 
       
    79  { 
       
    80  if ((g_define_type_id == 0)) 
       
    81  	{ static const GTypeInfo g_define_type_info = { sizeof (GabbleRegisterClass), (GBaseInitFunc) ((void *)0), (GBaseFinalizeFunc) ((void *)0), (GClassInitFunc) gabble_register_class_intern_init, (GClassFinalizeFunc) ((void *)0), ((void *)0), sizeof (GabbleRegister), 0, (GInstanceInitFunc) gabble_register_init, ((void *)0) }; g_define_type_id = g_type_register_static ( ((GType) ((20) << (2))), g_intern_static_string ("GabbleRegister"), &g_define_type_info, (GTypeFlags) 0); { {} ; } } return g_define_type_id; 
       
    82  } ;
       
    83 
       
    84 		
       
    85 #else
       
    86 
       
    87 	static guint signals[LAST_SIGNAL] = {0};
       
    88 
       
    89 #endif
       
    90 
       
    91 
       
    92 /* properties */
       
    93 enum
       
    94 {
       
    95   PROP_CONNECTION = 1,
       
    96   LAST_PROPERTY
       
    97 };
       
    98 
       
    99 
       
   100 /* private structure */
       
   101 typedef struct _GabbleRegisterPrivate GabbleRegisterPrivate;
       
   102 struct _GabbleRegisterPrivate
       
   103 {
       
   104   GabbleConnection *conn;
       
   105 
       
   106   gboolean dispose_has_run;
       
   107 };
       
   108 
       
   109 #define GABBLE_REGISTER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), GABBLE_TYPE_REGISTER, GabbleRegisterPrivate))
       
   110 
       
   111 static void
       
   112 gabble_register_init (GabbleRegister *obj)
       
   113 {
       
   114 }
       
   115 
       
   116 static void gabble_register_set_property (GObject *object, guint property_id,
       
   117     const GValue *value, GParamSpec *pspec);
       
   118 static void gabble_register_get_property (GObject *object, guint property_id,
       
   119     GValue *value, GParamSpec *pspec);
       
   120 static void gabble_register_dispose (GObject *object);
       
   121 static void gabble_register_finalize (GObject *object);
       
   122 
       
   123 static void
       
   124 gabble_register_class_init (GabbleRegisterClass *gabble_register_class)
       
   125 {
       
   126   GObjectClass *object_class = G_OBJECT_CLASS (gabble_register_class);
       
   127   GParamSpec *param_spec;
       
   128 
       
   129   g_type_class_add_private (gabble_register_class, sizeof (GabbleRegisterPrivate));
       
   130 
       
   131   object_class->get_property = gabble_register_get_property;
       
   132   object_class->set_property = gabble_register_set_property;
       
   133 
       
   134   object_class->dispose = gabble_register_dispose;
       
   135   object_class->finalize = gabble_register_finalize;
       
   136 
       
   137   param_spec = g_param_spec_object ("connection", "GabbleConnection object",
       
   138                                     "Gabble connection object that owns this "
       
   139                                     "GabbleRegister object.",
       
   140                                     GABBLE_TYPE_CONNECTION,
       
   141                                     G_PARAM_CONSTRUCT_ONLY |
       
   142                                     G_PARAM_READWRITE |
       
   143                                     G_PARAM_STATIC_NICK |
       
   144                                     G_PARAM_STATIC_BLURB);
       
   145   g_object_class_install_property (object_class, PROP_CONNECTION, param_spec);
       
   146 
       
   147   signals[FINISHED] =
       
   148     g_signal_new ("finished",
       
   149                   G_OBJECT_CLASS_TYPE (gabble_register_class),
       
   150                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
       
   151                   0,
       
   152                   NULL, NULL,
       
   153                   gabble_register_marshal_VOID__BOOLEAN_INT_STRING,
       
   154                   G_TYPE_NONE, 3, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING);
       
   155 }
       
   156 
       
   157 static void
       
   158 gabble_register_get_property (GObject    *object,
       
   159                               guint       property_id,
       
   160                               GValue     *value,
       
   161                               GParamSpec *pspec)
       
   162 {
       
   163   GabbleRegister *chan = GABBLE_REGISTER (object);
       
   164   GabbleRegisterPrivate *priv = GABBLE_REGISTER_GET_PRIVATE (chan);
       
   165 
       
   166   switch (property_id) {
       
   167     case PROP_CONNECTION:
       
   168       g_value_set_object (value, priv->conn);
       
   169       break;
       
   170     default:
       
   171       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   172       break;
       
   173   }
       
   174 }
       
   175 
       
   176 static void
       
   177 gabble_register_set_property (GObject     *object,
       
   178                               guint        property_id,
       
   179                               const GValue *value,
       
   180                               GParamSpec   *pspec)
       
   181 {
       
   182   GabbleRegister *chan = GABBLE_REGISTER (object);
       
   183   GabbleRegisterPrivate *priv = GABBLE_REGISTER_GET_PRIVATE (chan);
       
   184 
       
   185   switch (property_id) {
       
   186     case PROP_CONNECTION:
       
   187       priv->conn = g_value_get_object (value);
       
   188       break;
       
   189     default:
       
   190       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       
   191       break;
       
   192   }
       
   193 }
       
   194 
       
   195 void
       
   196 gabble_register_dispose (GObject *object)
       
   197 {
       
   198   GabbleRegister *self = GABBLE_REGISTER (object);
       
   199   GabbleRegisterPrivate *priv = GABBLE_REGISTER_GET_PRIVATE (self);
       
   200 
       
   201   if (priv->dispose_has_run)
       
   202     return;
       
   203 
       
   204   priv->dispose_has_run = TRUE;
       
   205 
       
   206   g_debug ("%s: dispose called", G_STRFUNC);
       
   207 
       
   208   if (G_OBJECT_CLASS (gabble_register_parent_class)->dispose)
       
   209     G_OBJECT_CLASS (gabble_register_parent_class)->dispose (object);
       
   210 }
       
   211 
       
   212 void
       
   213 gabble_register_finalize (GObject *object)
       
   214 {
       
   215   g_debug ("%s called with %p", G_STRFUNC, object);
       
   216 
       
   217   G_OBJECT_CLASS (gabble_register_parent_class)->finalize (object);
       
   218 }
       
   219 
       
   220 /**
       
   221  * gabble_register_new:
       
   222  *
       
   223  * Creates an object to use for account registration.
       
   224  *
       
   225  * @conn: The #GabbleConnection to register an account on
       
   226  */
       
   227 GabbleRegister *
       
   228 gabble_register_new (GabbleConnection *conn)
       
   229 {
       
   230   g_return_val_if_fail (GABBLE_IS_CONNECTION (conn), NULL);
       
   231   return GABBLE_REGISTER (g_object_new (GABBLE_TYPE_REGISTER,
       
   232         "connection", conn, NULL));
       
   233 }
       
   234 
       
   235 static LmHandlerResult
       
   236 set_reply_cb (GabbleConnection *conn,
       
   237               LmMessage *sent_msg,
       
   238               LmMessage *reply_msg,
       
   239               GObject *object,
       
   240               gpointer user_data)
       
   241 {
       
   242   if (lm_message_get_sub_type (reply_msg) != LM_MESSAGE_SUB_TYPE_RESULT)
       
   243     {
       
   244       LmMessageNode *node;
       
   245       gint code = NotAvailable;
       
   246       GString *msg;
       
   247 
       
   248       msg = g_string_sized_new (30);
       
   249       g_string_append (msg, "Request failed");
       
   250 
       
   251       node = lm_message_node_get_child (reply_msg->node, "error");
       
   252       if (node)
       
   253         {
       
   254           GabbleXmppError error;
       
   255 
       
   256           error = gabble_xmpp_error_from_node (node);
       
   257           if (error == XMPP_ERROR_CONFLICT)
       
   258             {
       
   259               code = InvalidArgument;
       
   260             }
       
   261 
       
   262           if (error != INVALID_XMPP_ERROR)
       
   263             {
       
   264               g_string_append_printf (msg, ": %s",
       
   265                   gabble_xmpp_error_string (error));
       
   266             }
       
   267         }
       
   268 
       
   269       g_signal_emit (object, signals[FINISHED], 0, FALSE, code, msg->str);
       
   270       g_string_free (msg, TRUE);
       
   271     }
       
   272   else
       
   273     {
       
   274       g_signal_emit (object, signals[FINISHED], 0, TRUE, -1, NULL);
       
   275     }
       
   276 
       
   277   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   278 }
       
   279 
       
   280 static LmHandlerResult
       
   281 get_reply_cb (GabbleConnection *conn,
       
   282               LmMessage *sent_msg,
       
   283               LmMessage *reply_msg,
       
   284               GObject *object,
       
   285               gpointer user_data)
       
   286 {
       
   287   GabbleRegister *reg = GABBLE_REGISTER (object);
       
   288   GabbleRegisterPrivate *priv = GABBLE_REGISTER_GET_PRIVATE (reg);
       
   289   GError *error = NULL;
       
   290   gint err_code = -1;
       
   291   const gchar *err_msg = NULL;
       
   292   LmMessage *msg = NULL;
       
   293   LmMessageNode *query_node;
       
   294   gchar *username, *password;
       
   295 
       
   296   if (lm_message_get_sub_type (reply_msg) != LM_MESSAGE_SUB_TYPE_RESULT)
       
   297     {
       
   298       err_code = NotAvailable;
       
   299       err_msg = "Server doesn't support " NS_REGISTER;
       
   300 
       
   301       goto OUT;
       
   302     }
       
   303 
       
   304   /* sanity check the reply to some degree ... */
       
   305   query_node = lm_message_node_get_child_with_namespace (reply_msg->node,
       
   306       "query", NS_REGISTER);
       
   307 
       
   308   if (query_node == NULL)
       
   309     goto ERROR_MALFORMED_REPLY;
       
   310 
       
   311   if (!lm_message_node_get_child (query_node, "username"))
       
   312     goto ERROR_MALFORMED_REPLY;
       
   313 
       
   314   if (!lm_message_node_get_child (query_node, "password"))
       
   315     goto ERROR_MALFORMED_REPLY;
       
   316 
       
   317   /* craft a reply */
       
   318   msg = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
       
   319                                       LM_MESSAGE_SUB_TYPE_SET);
       
   320 
       
   321   query_node = lm_message_node_add_child (msg->node, "query", NULL);
       
   322   lm_message_node_set_attribute (query_node, "xmlns", NS_REGISTER);
       
   323 
       
   324   g_object_get (priv->conn,
       
   325       "username", &username,
       
   326       "password", &password,
       
   327       NULL);
       
   328 
       
   329   lm_message_node_add_child (query_node, "username", username);
       
   330   lm_message_node_add_child (query_node, "password", password);
       
   331 
       
   332   g_free (username);
       
   333   g_free (password);
       
   334 
       
   335   if (!_gabble_connection_send_with_reply (priv->conn, msg, set_reply_cb,
       
   336                                            G_OBJECT (reg), NULL, &error))
       
   337     {
       
   338       err_code = error->code;
       
   339       err_msg = error->message;
       
   340     }
       
   341 
       
   342   goto OUT;
       
   343 
       
   344 ERROR_MALFORMED_REPLY:
       
   345   err_code = NotAvailable;
       
   346   err_msg = "Malformed reply";
       
   347 
       
   348 OUT:
       
   349   if (err_code != -1)
       
   350     {
       
   351       g_signal_emit (reg, signals[FINISHED], 0, FALSE, err_code, err_msg);
       
   352     }
       
   353 
       
   354   if (msg)
       
   355     lm_message_unref (msg);
       
   356 
       
   357   if (error)
       
   358     g_error_free (error);
       
   359 
       
   360   return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   361 }
       
   362 
       
   363 /**
       
   364  * gabble_register_start:
       
   365  *
       
   366  * Start account registration.
       
   367  *
       
   368  * @reg: The #GabbleRegister object performing the registration
       
   369  */
       
   370 void gabble_register_start (GabbleRegister *reg)
       
   371 {
       
   372   GabbleRegisterPrivate *priv = GABBLE_REGISTER_GET_PRIVATE (reg);
       
   373   LmMessage *msg;
       
   374   LmMessageNode *node;
       
   375   GError *error = NULL;
       
   376 
       
   377   msg = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
       
   378                                       LM_MESSAGE_SUB_TYPE_GET);
       
   379 
       
   380   node = lm_message_node_add_child (msg->node, "query", NULL);
       
   381   lm_message_node_set_attribute (node, "xmlns", NS_REGISTER);
       
   382 
       
   383   if (!_gabble_connection_send_with_reply (priv->conn, msg, get_reply_cb,
       
   384                                            G_OBJECT (reg), NULL, &error))
       
   385     {
       
   386       g_signal_emit (reg, signals[FINISHED], 0, FALSE, error->code,
       
   387                      error->message);
       
   388       g_error_free (error);
       
   389     }
       
   390 
       
   391   lm_message_unref (msg);
       
   392 }
       
   393