1 /*
2  * protocol.c - SalutProtocol
3  * Copyright © 2007-2010 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "protocol.h"
21 
22 #include <config.h>
23 
24 #include <dbus/dbus-glib.h>
25 #include <dbus/dbus-protocol.h>
26 #include <telepathy-glib/base-connection-manager.h>
27 #include <telepathy-glib/telepathy-glib.h>
28 
29 #include "connection.h"
30 #include "contact-manager.h"
31 #include "ft-manager.h"
32 #include "im-manager.h"
33 #include "muc-manager.h"
34 #include "roomlist-manager.h"
35 #include "tubes-manager.h"
36 
37 #ifdef USE_BACKEND_AVAHI
38 #include "avahi-discovery-client.h"
39 #elif defined (USE_BACKEND_DUMMY)
40 #include "dummy-discovery-client.h"
41 #elif defined (USE_BACKEND_BONJOUR)
42 #include "bonjour-discovery-client.h"
43 #endif
44 
45 /* there is no appropriate vCard field for this protocol */
46 #define VCARD_FIELD_NAME ""
47 
48 G_DEFINE_TYPE (SalutProtocol,
49     salut_protocol,
50     TP_TYPE_BASE_PROTOCOL)
51 
52 enum {
53     PROP_BACKEND = 1,
54     PROP_DNSSD_NAME,
55     PROP_ENGLISH_NAME,
56     PROP_ICON_NAME
57 };
58 
59 struct _SalutProtocolPrivate
60 {
61   GType backend_type;
62   gchar *english_name;
63   gchar *icon_name;
64   gchar *dnssd_name;
65 };
66 
67 static const TpCMParamSpec salut_params[] = {
68   { "nickname", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, 0,
69      tp_cm_param_filter_string_nonempty, NULL },
70   { "first-name", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
71      TP_CONN_MGR_PARAM_FLAG_REQUIRED, NULL, 0 },
72   { "last-name", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING,
73      TP_CONN_MGR_PARAM_FLAG_REQUIRED, NULL, 0 },
74   { "jid", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, 0 },
75   { "email", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, 0 },
76   { "published-name", DBUS_TYPE_STRING_AS_STRING, G_TYPE_STRING, 0, NULL, 0,
77      tp_cm_param_filter_string_nonempty, NULL },
78   { NULL, NULL, 0, 0, NULL, 0 }
79 };
80 
81 static void
salut_protocol_init(SalutProtocol * self)82 salut_protocol_init (SalutProtocol *self)
83 {
84   self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SALUT_TYPE_PROTOCOL,
85       SalutProtocolPrivate);
86 }
87 
88 static const TpCMParamSpec *
get_parameters(TpBaseProtocol * self G_GNUC_UNUSED)89 get_parameters (TpBaseProtocol *self G_GNUC_UNUSED)
90 {
91   return salut_params;
92 }
93 
94 static TpBaseConnection *
new_connection(TpBaseProtocol * protocol,GHashTable * params,GError ** error)95 new_connection (TpBaseProtocol *protocol,
96                 GHashTable *params,
97                 GError **error)
98 {
99   SalutProtocol *self = SALUT_PROTOCOL (protocol);
100   GObject *obj;
101   guint i;
102 
103   obj = g_object_new (SALUT_TYPE_CONNECTION,
104       "protocol", tp_base_protocol_get_name (protocol),
105       /* deliberately set :dnssd-name before backend-type */
106       "dnssd-name", self->priv->dnssd_name,
107       "backend-type", self->priv->backend_type,
108       NULL);
109 
110   for (i = 0; salut_params[i].name != NULL; i++)
111     {
112       GValue *val = g_hash_table_lookup (params, salut_params[i].name);
113 
114       if (val != NULL)
115         {
116           g_object_set_property (obj, salut_params[i].name, val);
117         }
118     }
119 
120   return TP_BASE_CONNECTION (obj);
121 }
122 
123 static gchar *
normalize_contact(TpBaseProtocol * self G_GNUC_UNUSED,const gchar * contact,GError ** error)124 normalize_contact (TpBaseProtocol *self G_GNUC_UNUSED,
125                    const gchar *contact,
126                    GError **error)
127 {
128   return salut_normalize_non_empty (contact, error);
129 }
130 
131 static gchar *
identify_account(TpBaseProtocol * self G_GNUC_UNUSED,GHashTable * asv,GError ** error)132 identify_account (TpBaseProtocol *self G_GNUC_UNUSED,
133     GHashTable *asv,
134     GError **error)
135 {
136   /* Nothing uniquely identifies a particular Salut account. The published
137    * name is part of our identifier, but can be changed at any time;
138    * the best an account manager can do is to number accounts. */
139   return g_strdup ("");
140 }
141 
142 static GStrv
get_interfaces(TpBaseProtocol * self)143 get_interfaces (TpBaseProtocol *self)
144 {
145   return g_new0 (gchar *, 1);
146 }
147 
148 static void
get_connection_details(TpBaseProtocol * self,GStrv * connection_interfaces,GType ** channel_managers,gchar ** icon_name,gchar ** english_name,gchar ** vcard_field)149 get_connection_details (TpBaseProtocol *self,
150     GStrv *connection_interfaces,
151     GType **channel_managers,
152     gchar **icon_name,
153     gchar **english_name,
154     gchar **vcard_field)
155 {
156   SalutProtocolPrivate *priv = SALUT_PROTOCOL (self)->priv;
157 
158   if (connection_interfaces != NULL)
159     {
160       *connection_interfaces = g_strdupv (
161           (GStrv) salut_connection_get_implemented_interfaces ());
162     }
163 
164   if (channel_managers != NULL)
165     {
166       GType types[] = {
167           SALUT_TYPE_CONTACT_MANAGER,
168           SALUT_TYPE_FT_MANAGER,
169           SALUT_TYPE_IM_MANAGER,
170           SALUT_TYPE_MUC_MANAGER,
171           SALUT_TYPE_ROOMLIST_MANAGER,
172           SALUT_TYPE_TUBES_MANAGER,
173           G_TYPE_INVALID };
174 
175       *channel_managers = g_memdup (types, sizeof(types));
176     }
177 
178   if (icon_name != NULL)
179     {
180       *icon_name = g_strdup (priv->icon_name);
181     }
182 
183   if (vcard_field != NULL)
184     {
185       *vcard_field = g_strdup (VCARD_FIELD_NAME);
186     }
187 
188   if (english_name != NULL)
189     {
190       *english_name = g_strdup (priv->english_name);
191     }
192 }
193 
194 static void
salut_protocol_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)195 salut_protocol_get_property (GObject *object,
196     guint property_id,
197     GValue *value,
198     GParamSpec *pspec)
199 {
200   SalutProtocol *self = SALUT_PROTOCOL (object);
201 
202   switch (property_id)
203     {
204       case PROP_BACKEND:
205         g_value_set_gtype (value, self->priv->backend_type);
206         break;
207 
208       case PROP_DNSSD_NAME:
209         g_value_set_string (value, self->priv->dnssd_name);
210         break;
211 
212       case PROP_ENGLISH_NAME:
213         g_value_set_string (value, self->priv->english_name);
214         break;
215 
216       case PROP_ICON_NAME:
217         g_value_set_string (value, self->priv->icon_name);
218         break;
219 
220       default:
221         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
222         break;
223     }
224 }
225 
226 static void
salut_protocol_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)227 salut_protocol_set_property (GObject *object,
228     guint property_id,
229     const GValue *value,
230     GParamSpec *pspec)
231 {
232   SalutProtocol *self = SALUT_PROTOCOL (object);
233 
234   switch (property_id)
235     {
236       case PROP_BACKEND:
237         {
238           GType type = g_value_get_gtype (value);
239 
240           if (type == G_TYPE_NONE)
241 #ifdef USE_BACKEND_AVAHI
242             type = SALUT_TYPE_AVAHI_DISCOVERY_CLIENT;
243 #elif defined (USE_BACKEND_DUMMY)
244             type = SALUT_TYPE_DUMMY_DISCOVERY_CLIENT;
245 #elif defined (USE_BACKEND_BONJOUR)
246             type = SALUT_TYPE_BONJOUR_DISCOVERY_CLIENT;
247 #endif
248 
249           self->priv->backend_type = type;
250         }
251         break;
252 
253       case PROP_DNSSD_NAME:
254         self->priv->dnssd_name = g_value_dup_string (value);
255         break;
256 
257       case PROP_ENGLISH_NAME:
258         self->priv->english_name = g_value_dup_string (value);
259         break;
260 
261       case PROP_ICON_NAME:
262         self->priv->icon_name = g_value_dup_string (value);
263         break;
264 
265       default:
266         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
267         break;
268     }
269 }
270 
271 static void
salut_protocol_finalize(GObject * object)272 salut_protocol_finalize (GObject *object)
273 {
274   SalutProtocol *self = SALUT_PROTOCOL (object);
275 
276   tp_clear_pointer (&self->priv->english_name, g_free);
277   tp_clear_pointer (&self->priv->icon_name, g_free);
278   tp_clear_pointer (&self->priv->dnssd_name, g_free);
279 
280   if (G_OBJECT_CLASS (salut_protocol_parent_class)->finalize)
281     G_OBJECT_CLASS (salut_protocol_parent_class)->finalize (object);
282 }
283 
284 
285 static void
salut_protocol_class_init(SalutProtocolClass * klass)286 salut_protocol_class_init (SalutProtocolClass *klass)
287 {
288   TpBaseProtocolClass *base_class = (TpBaseProtocolClass *) klass;
289   GObjectClass *object_class = (GObjectClass *) klass;
290   GParamSpec *param_spec;
291 
292   g_type_class_add_private (klass, sizeof (SalutProtocolPrivate));
293 
294   base_class->get_parameters = get_parameters;
295   base_class->new_connection = new_connection;
296   base_class->normalize_contact = normalize_contact;
297   base_class->identify_account = identify_account;
298   base_class->get_interfaces = get_interfaces;
299   base_class->get_connection_details = get_connection_details;
300 
301   object_class->get_property = salut_protocol_get_property;
302   object_class->set_property = salut_protocol_set_property;
303   object_class->finalize = salut_protocol_finalize;
304 
305   param_spec = g_param_spec_gtype ("backend-type", "backend type",
306       "a G_TYPE_GTYPE of the backend to use", G_TYPE_NONE,
307       G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
308   g_object_class_install_property (object_class, PROP_BACKEND,
309       param_spec);
310 
311   param_spec = g_param_spec_string ("dnssd-name", "DNS-SD name",
312       "The DNS-SD name of the protocol", "",
313       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
314   g_object_class_install_property (object_class, PROP_DNSSD_NAME,
315       param_spec);
316 
317   param_spec = g_param_spec_string ("english-name", "English name",
318       "The English name of the protocol", "",
319       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
320   g_object_class_install_property (object_class, PROP_ENGLISH_NAME,
321       param_spec);
322 
323   param_spec = g_param_spec_string ("icon-name", "Icon name",
324       "The icon name of the protocol", "",
325       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
326   g_object_class_install_property (object_class, PROP_ICON_NAME,
327       param_spec);
328 }
329 
330 TpBaseProtocol *
salut_protocol_new(GType backend_type,const gchar * dnssd_name,const gchar * protocol_name,const gchar * english_name,const gchar * icon_name)331 salut_protocol_new (GType backend_type,
332     const gchar *dnssd_name,
333     const gchar *protocol_name,
334     const gchar *english_name,
335     const gchar *icon_name)
336 {
337   return g_object_new (SALUT_TYPE_PROTOCOL,
338       "name", protocol_name,
339       "dnssd-name", dnssd_name,
340       "english-name", english_name,
341       "backend-type", backend_type,
342       "icon-name", icon_name,
343       NULL);
344 }
345