]> git.0d.be Git - empathy.git/blob - libempathy/empathy-utils.c
Make sure we allocate the right size for certificates
[empathy.git] / libempathy / empathy-utils.c
1 /*
2  * Copyright (C) 2003-2007 Imendio AB
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program 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  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Richard Hult <richard@imendio.com>
21  *          Martyn Russell <martyn@imendio.com>
22  *          Xavier Claessens <xclaesse@gmail.com>
23  *
24  * Some snippets are taken from GnuTLS 2.8.6, which is distributed under the
25  * same GNU Lesser General Public License 2.1 (or later) version. See
26  * empathy_get_x509_certified_hostname ().
27  */
28
29 #include "config.h"
30
31 #include <string.h>
32 #include <time.h>
33 #include <sys/types.h>
34
35 #include <glib/gi18n-lib.h>
36
37 #include <libxml/uri.h>
38
39 #include <folks/folks.h>
40 #include <folks/folks-telepathy.h>
41
42 #include <telepathy-glib/account-manager.h>
43 #include <telepathy-glib/connection.h>
44 #include <telepathy-glib/channel.h>
45 #include <telepathy-glib/dbus.h>
46 #include <telepathy-glib/util.h>
47
48 #include "empathy-utils.h"
49 #include "empathy-contact-manager.h"
50 #include "empathy-individual-manager.h"
51 #include "empathy-dispatcher.h"
52 #include "empathy-idle.h"
53 #include "empathy-tp-call.h"
54 #include "empathy-tp-contact-factory.h"
55
56 #include <extensions/extensions.h>
57
58 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
59 #include "empathy-debug.h"
60
61 /* Translation between presence types and string */
62 static struct {
63         const gchar *name;
64         TpConnectionPresenceType type;
65 } presence_types[] = {
66         { "available", TP_CONNECTION_PRESENCE_TYPE_AVAILABLE },
67         { "busy",      TP_CONNECTION_PRESENCE_TYPE_BUSY },
68         { "away",      TP_CONNECTION_PRESENCE_TYPE_AWAY },
69         { "ext_away",  TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY },
70         { "hidden",    TP_CONNECTION_PRESENCE_TYPE_HIDDEN },
71         { "offline",   TP_CONNECTION_PRESENCE_TYPE_OFFLINE },
72         { "unset",     TP_CONNECTION_PRESENCE_TYPE_UNSET },
73         { "unknown",   TP_CONNECTION_PRESENCE_TYPE_UNKNOWN },
74         { "error",     TP_CONNECTION_PRESENCE_TYPE_ERROR },
75         /* alternative names */
76         { "dnd",      TP_CONNECTION_PRESENCE_TYPE_BUSY },
77         { "brb",      TP_CONNECTION_PRESENCE_TYPE_AWAY },
78         { "xa",       TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY },
79         { NULL, },
80 };
81
82
83
84 void
85 empathy_init (void)
86 {
87         static gboolean initialized = FALSE;
88
89         if (initialized)
90                 return;
91
92         g_type_init ();
93
94         /* Setup gettext */
95         bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
96         bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
97
98         /* Setup debug output for empathy and telepathy-glib */
99         if (g_getenv ("EMPATHY_TIMING") != NULL) {
100                 g_log_set_default_handler (tp_debug_timestamped_log_handler, NULL);
101         }
102         empathy_debug_set_flags (g_getenv ("EMPATHY_DEBUG"));
103         tp_debug_divert_messages (g_getenv ("EMPATHY_LOGFILE"));
104
105         emp_cli_init ();
106
107         initialized = TRUE;
108 }
109
110 gchar *
111 empathy_substring (const gchar *str,
112                   gint         start,
113                   gint         end)
114 {
115         return g_strndup (str + start, end - start);
116 }
117
118 gint
119 empathy_strcasecmp (const gchar *s1,
120                    const gchar *s2)
121 {
122         return empathy_strncasecmp (s1, s2, -1);
123 }
124
125 gint
126 empathy_strncasecmp (const gchar *s1,
127                     const gchar *s2,
128                     gsize        n)
129 {
130         gchar *u1, *u2;
131         gint   ret_val;
132
133         u1 = g_utf8_casefold (s1, n);
134         u2 = g_utf8_casefold (s2, n);
135
136         ret_val = g_utf8_collate (u1, u2);
137         g_free (u1);
138         g_free (u2);
139
140         return ret_val;
141 }
142
143 gboolean
144 empathy_xml_validate (xmlDoc      *doc,
145                      const gchar *dtd_filename)
146 {
147         gchar        *path;
148         xmlChar      *escaped;
149         xmlValidCtxt  cvp;
150         xmlDtd       *dtd;
151         gboolean      ret;
152
153         path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "libempathy",
154                                  dtd_filename, NULL);
155         if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
156                 g_free (path);
157                 path = g_build_filename (DATADIR, "empathy", dtd_filename, NULL);
158         }
159         DEBUG ("Loading dtd file %s", path);
160
161         /* The list of valid chars is taken from libxml. */
162         escaped = xmlURIEscapeStr ((const xmlChar *) path,
163                 (const xmlChar *)":@&=+$,/?;");
164         g_free (path);
165
166         memset (&cvp, 0, sizeof (cvp));
167         dtd = xmlParseDTD (NULL, escaped);
168         ret = xmlValidateDtd (&cvp, doc, dtd);
169
170         xmlFree (escaped);
171         xmlFreeDtd (dtd);
172
173         return ret;
174 }
175
176 xmlNodePtr
177 empathy_xml_node_get_child (xmlNodePtr   node,
178                            const gchar *child_name)
179 {
180         xmlNodePtr l;
181
182         g_return_val_if_fail (node != NULL, NULL);
183         g_return_val_if_fail (child_name != NULL, NULL);
184
185         for (l = node->children; l; l = l->next) {
186                 if (l->name && strcmp ((const gchar *) l->name, child_name) == 0) {
187                         return l;
188                 }
189         }
190
191         return NULL;
192 }
193
194 xmlChar *
195 empathy_xml_node_get_child_content (xmlNodePtr   node,
196                                    const gchar *child_name)
197 {
198         xmlNodePtr l;
199
200         g_return_val_if_fail (node != NULL, NULL);
201         g_return_val_if_fail (child_name != NULL, NULL);
202
203         l = empathy_xml_node_get_child (node, child_name);
204         if (l) {
205                 return xmlNodeGetContent (l);
206         }
207
208         return NULL;
209 }
210
211 xmlNodePtr
212 empathy_xml_node_find_child_prop_value (xmlNodePtr   node,
213                                        const gchar *prop_name,
214                                        const gchar *prop_value)
215 {
216         xmlNodePtr l;
217         xmlNodePtr found = NULL;
218
219         g_return_val_if_fail (node != NULL, NULL);
220         g_return_val_if_fail (prop_name != NULL, NULL);
221         g_return_val_if_fail (prop_value != NULL, NULL);
222
223         for (l = node->children; l && !found; l = l->next) {
224                 xmlChar *prop;
225
226                 if (!xmlHasProp (l, (const xmlChar *) prop_name)) {
227                         continue;
228                 }
229
230                 prop = xmlGetProp (l, (const xmlChar *) prop_name);
231                 if (prop && strcmp ((const gchar *) prop, prop_value) == 0) {
232                         found = l;
233                 }
234
235                 xmlFree (prop);
236         }
237
238         return found;
239 }
240
241 const gchar *
242 empathy_presence_get_default_message (TpConnectionPresenceType presence)
243 {
244         switch (presence) {
245         case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE:
246                 return _("Available");
247         case TP_CONNECTION_PRESENCE_TYPE_BUSY:
248                 return _("Busy");
249         case TP_CONNECTION_PRESENCE_TYPE_AWAY:
250         case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY:
251                 return _("Away");
252         case TP_CONNECTION_PRESENCE_TYPE_HIDDEN:
253                 return _("Invisible");
254         case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
255                 return _("Offline");
256         case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
257                 return _("Unknown");
258         case TP_CONNECTION_PRESENCE_TYPE_UNSET:
259         case TP_CONNECTION_PRESENCE_TYPE_ERROR:
260         default:
261                 return NULL;
262         }
263
264         return NULL;
265 }
266
267 const gchar *
268 empathy_presence_to_str (TpConnectionPresenceType presence)
269 {
270         int i;
271
272         for (i = 0 ; presence_types[i].name != NULL; i++)
273                 if (presence == presence_types[i].type)
274                         return presence_types[i].name;
275
276         return NULL;
277 }
278
279 TpConnectionPresenceType
280 empathy_presence_from_str (const gchar *str)
281 {
282         int i;
283
284         for (i = 0 ; presence_types[i].name != NULL; i++)
285                 if (!tp_strdiff (str, presence_types[i].name))
286                         return presence_types[i].type;
287
288         return TP_CONNECTION_PRESENCE_TYPE_UNSET;
289 }
290
291 static const gchar *
292 empathy_status_reason_get_default_message (TpConnectionStatusReason reason)
293 {
294         switch (reason) {
295         case TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED:
296                 return _("No reason specified");
297         case TP_CONNECTION_STATUS_REASON_REQUESTED:
298                 return _("Status is set to offline");
299         case TP_CONNECTION_STATUS_REASON_NETWORK_ERROR:
300                 return _("Network error");
301         case TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED:
302                 return _("Authentication failed");
303         case TP_CONNECTION_STATUS_REASON_ENCRYPTION_ERROR:
304                 return _("Encryption error");
305         case TP_CONNECTION_STATUS_REASON_NAME_IN_USE:
306                 return _("Name in use");
307         case TP_CONNECTION_STATUS_REASON_CERT_NOT_PROVIDED:
308                 return _("Certificate not provided");
309         case TP_CONNECTION_STATUS_REASON_CERT_UNTRUSTED:
310                 return _("Certificate untrusted");
311         case TP_CONNECTION_STATUS_REASON_CERT_EXPIRED:
312                 return _("Certificate expired");
313         case TP_CONNECTION_STATUS_REASON_CERT_NOT_ACTIVATED:
314                 return _("Certificate not activated");
315         case TP_CONNECTION_STATUS_REASON_CERT_HOSTNAME_MISMATCH:
316                 return _("Certificate hostname mismatch");
317         case TP_CONNECTION_STATUS_REASON_CERT_FINGERPRINT_MISMATCH:
318                 return _("Certificate fingerprint mismatch");
319         case TP_CONNECTION_STATUS_REASON_CERT_SELF_SIGNED:
320                 return _("Certificate self-signed");
321         case TP_CONNECTION_STATUS_REASON_CERT_OTHER_ERROR:
322                 return _("Certificate error");
323         default:
324                 return _("Unknown reason");
325         }
326 }
327
328 static GHashTable *
329 create_errors_to_message_hash (void)
330 {
331         GHashTable *errors;
332
333         errors = g_hash_table_new (g_str_hash, g_str_equal);
334         g_hash_table_insert (errors, TP_ERROR_STR_NETWORK_ERROR, _("Network error"));
335         g_hash_table_insert (errors, TP_ERROR_STR_AUTHENTICATION_FAILED,
336                 _("Authentication failed"));
337         g_hash_table_insert (errors, TP_ERROR_STR_ENCRYPTION_ERROR,
338                 _("Encryption error"));
339         g_hash_table_insert (errors, TP_ERROR_STR_CERT_NOT_PROVIDED,
340                 _("Certificate not provided"));
341         g_hash_table_insert (errors, TP_ERROR_STR_CERT_UNTRUSTED,
342                 _("Certificate untrusted"));
343         g_hash_table_insert (errors, TP_ERROR_STR_CERT_EXPIRED,
344                 _("Certificate expired"));
345         g_hash_table_insert (errors, TP_ERROR_STR_CERT_NOT_ACTIVATED,
346                 _("Certificate not activated"));
347         g_hash_table_insert (errors, TP_ERROR_STR_CERT_HOSTNAME_MISMATCH,
348                 _("Certificate hostname mismatch"));
349         g_hash_table_insert (errors, TP_ERROR_STR_CERT_FINGERPRINT_MISMATCH,
350                 _("Certificate fingerprint mismatch"));
351         g_hash_table_insert (errors, TP_ERROR_STR_CERT_SELF_SIGNED,
352                 _("Certificate self-signed"));
353         g_hash_table_insert (errors, TP_ERROR_STR_CANCELLED,
354                 _("Status is set to offline"));
355         g_hash_table_insert (errors, TP_ERROR_STR_ENCRYPTION_NOT_AVAILABLE,
356                 _("Encryption is not available"));
357         g_hash_table_insert (errors, TP_ERROR_STR_CERT_INVALID,
358                 _("Certificate is invalid"));
359         g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_REFUSED,
360                 _("Connection has been refused"));
361         g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_FAILED,
362                 _("Connection can't be established"));
363         g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_LOST,
364                 _("Connection has been lost"));
365         g_hash_table_insert (errors, TP_ERROR_STR_ALREADY_CONNECTED,
366                 _("This resource is already connected to the server"));
367         g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_REPLACED,
368                 _("Connection has been replaced by a new connection using the "
369                 "same resource"));
370         g_hash_table_insert (errors, TP_ERROR_STR_REGISTRATION_EXISTS,
371                 _("The account already exists on the server"));
372         g_hash_table_insert (errors, TP_ERROR_STR_SERVICE_BUSY,
373                 _("Server is currently too busy to handle the connection"));
374         g_hash_table_insert (errors, TP_ERROR_STR_CERT_REVOKED,
375                 _("Certificate has been revoked"));
376         g_hash_table_insert (errors, TP_ERROR_STR_CERT_INSECURE,
377                 _("Certificate uses an insecure cipher algorithm or is "
378                 "cryptographically weak"));
379         g_hash_table_insert (errors, TP_ERROR_STR_CERT_LIMIT_EXCEEDED,
380                 _("The length of the server certificate, or the depth of the "
381                 "server certificate chain, exceed the limits imposed by the "
382                 "cryptography library"));
383
384         return errors;
385 }
386
387 static const gchar *
388 empathy_dbus_error_name_get_default_message  (const gchar *error)
389 {
390         static GHashTable *errors_to_message = NULL;
391
392         if (error == NULL)
393                 return NULL;
394
395         if (G_UNLIKELY (errors_to_message == NULL)) {
396                 errors_to_message = create_errors_to_message_hash ();
397         }
398
399         return g_hash_table_lookup (errors_to_message, error);
400 }
401
402 const gchar *
403 empathy_account_get_error_message (TpAccount *account,
404     gboolean *user_requested)
405 {
406         const gchar *dbus_error;
407         const gchar *message;
408         const GHashTable *details = NULL;
409         TpConnectionStatusReason reason;
410
411         dbus_error = tp_account_get_detailed_error (account, &details);
412
413         if (user_requested != NULL)
414           {
415             if (tp_asv_get_boolean (details, "user-requested", NULL))
416               *user_requested = TRUE;
417             else
418               *user_requested = FALSE;
419           }
420
421         message = empathy_dbus_error_name_get_default_message (dbus_error);
422         if (message != NULL)
423                 return message;
424
425         DEBUG ("Don't understand error '%s'; fallback to the status reason (%u)",
426                 dbus_error, reason);
427
428         tp_account_get_connection_status (account, &reason);
429
430         return empathy_status_reason_get_default_message (reason);
431 }
432
433 gchar *
434 empathy_file_lookup (const gchar *filename, const gchar *subdir)
435 {
436         gchar *path;
437
438         if (!subdir) {
439                 subdir = ".";
440         }
441
442         path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), subdir, filename, NULL);
443         if (!g_file_test (path, G_FILE_TEST_EXISTS)) {
444                 g_free (path);
445                 path = g_build_filename (DATADIR, "empathy", filename, NULL);
446         }
447
448         return path;
449 }
450
451 guint
452 empathy_proxy_hash (gconstpointer key)
453 {
454         TpProxy      *proxy = TP_PROXY (key);
455         TpProxyClass *proxy_class = TP_PROXY_GET_CLASS (key);
456
457         g_return_val_if_fail (TP_IS_PROXY (proxy), 0);
458         g_return_val_if_fail (proxy_class->must_have_unique_name, 0);
459
460         return g_str_hash (proxy->object_path) ^ g_str_hash (proxy->bus_name);
461 }
462
463 gboolean
464 empathy_proxy_equal (gconstpointer a,
465                      gconstpointer b)
466 {
467         TpProxy *proxy_a = TP_PROXY (a);
468         TpProxy *proxy_b = TP_PROXY (b);
469         TpProxyClass *proxy_a_class = TP_PROXY_GET_CLASS (a);
470         TpProxyClass *proxy_b_class = TP_PROXY_GET_CLASS (b);
471
472         g_return_val_if_fail (TP_IS_PROXY (proxy_a), FALSE);
473         g_return_val_if_fail (TP_IS_PROXY (proxy_b), FALSE);
474         g_return_val_if_fail (proxy_a_class->must_have_unique_name, 0);
475         g_return_val_if_fail (proxy_b_class->must_have_unique_name, 0);
476
477         return g_str_equal (proxy_a->object_path, proxy_b->object_path) &&
478                g_str_equal (proxy_a->bus_name, proxy_b->bus_name);
479 }
480
481 gboolean
482 empathy_check_available_state (void)
483 {
484         TpConnectionPresenceType presence;
485         EmpathyIdle *idle;
486
487         idle = empathy_idle_dup_singleton ();
488         presence = empathy_idle_get_state (idle);
489         g_object_unref (idle);
490
491         if (presence != TP_CONNECTION_PRESENCE_TYPE_AVAILABLE &&
492                 presence != TP_CONNECTION_PRESENCE_TYPE_UNSET) {
493                 return FALSE;
494         }
495
496         return TRUE;
497 }
498
499 gint
500 empathy_uint_compare (gconstpointer a,
501                       gconstpointer b)
502 {
503         return *(guint *) a - *(guint *) b;
504 }
505
506 gchar *
507 empathy_protocol_icon_name (const gchar *protocol)
508 {
509   if (!tp_strdiff (protocol, "yahoojp"))
510     /* Yahoo Japan uses the same icon as Yahoo */
511     protocol = "yahoo";
512   else if (!tp_strdiff (protocol, "simple"))
513     /* SIMPLE uses the same icon as SIP */
514     protocol = "sip";
515   else if (!tp_strdiff (protocol, "sms"))
516     return g_strdup ("phone");
517
518   return g_strdup_printf ("im-%s", protocol);
519 }
520
521 GType
522 empathy_type_dbus_ao (void)
523 {
524   static GType t = 0;
525
526   if (G_UNLIKELY (t == 0))
527      t = dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH);
528
529   return t;
530 }
531
532 const char *
533 empathy_protocol_name_to_display_name (const gchar *proto_name)
534 {
535   int i;
536   static struct {
537     const gchar *proto;
538     const gchar *display;
539     gboolean translated;
540   } names[] = {
541     { "jabber", "Jabber", FALSE },
542     { "gtalk", "Google Talk", FALSE },
543     { "msn", "MSN", FALSE, },
544     { "local-xmpp", N_("People Nearby"), TRUE },
545     { "irc", "IRC", FALSE },
546     { "icq", "ICQ", FALSE },
547     { "aim", "AIM", FALSE },
548     { "yahoo", "Yahoo!", FALSE },
549     { "yahoojp", N_("Yahoo! Japan"), TRUE },
550     { "facebook", N_("Facebook Chat"), TRUE },
551     { "groupwise", "GroupWise", FALSE },
552     { "sip", "SIP", FALSE },
553     { NULL, NULL }
554   };
555
556   for (i = 0; names[i].proto != NULL; i++)
557     {
558       if (!tp_strdiff (proto_name, names[i].proto))
559         {
560           if (names[i].translated)
561             return _(names[i].display);
562           else
563             return names[i].display;
564         }
565     }
566
567   return NULL;
568 }
569
570 /* Note: this function depends on the account manager having its core feature
571  * prepared. */
572 TpAccount *
573 empathy_get_account_for_connection (TpConnection *connection)
574 {
575   TpAccountManager *manager;
576   TpAccount *account = NULL;
577   GList *accounts, *l;
578
579   manager = tp_account_manager_dup ();
580
581   accounts = tp_account_manager_get_valid_accounts (manager);
582
583   for (l = accounts; l != NULL; l = l->next)
584     {
585       TpAccount *a = l->data;
586
587       if (tp_account_get_connection (a) == connection)
588         {
589           account = a;
590           break;
591         }
592     }
593
594   g_list_free (accounts);
595   g_object_unref (manager);
596
597   return account;
598 }
599
600 gboolean
601 empathy_account_manager_get_accounts_connected (gboolean *connecting)
602 {
603   TpAccountManager *manager;
604   GList *accounts, *l;
605   gboolean out_connecting = FALSE;
606   gboolean out_connected = FALSE;
607
608   manager = tp_account_manager_dup ();
609
610   if (G_UNLIKELY (!tp_account_manager_is_prepared (manager,
611           TP_ACCOUNT_MANAGER_FEATURE_CORE)))
612     g_critical (G_STRLOC ": %s called before AccountManager ready", G_STRFUNC);
613
614   accounts = tp_account_manager_get_valid_accounts (manager);
615
616   for (l = accounts; l != NULL; l = l->next)
617     {
618       TpConnectionStatus s = tp_account_get_connection_status (
619           TP_ACCOUNT (l->data), NULL);
620
621       if (s == TP_CONNECTION_STATUS_CONNECTING)
622         out_connecting = TRUE;
623       else if (s == TP_CONNECTION_STATUS_CONNECTED)
624         out_connected = TRUE;
625
626       if (out_connecting && out_connected)
627         break;
628     }
629
630   g_list_free (accounts);
631   g_object_unref (manager);
632
633   if (connecting != NULL)
634     *connecting = out_connecting;
635
636   return out_connected;
637 }
638
639 /* Change the RequestedPresence of a newly created account to ensure that it
640  * is actually connected. */
641 void
642 empathy_connect_new_account (TpAccount *account,
643     TpAccountManager *account_manager)
644 {
645   TpConnectionPresenceType presence;
646   gchar *status, *message;
647
648   /* only force presence if presence was offline, unknown or unset */
649   presence = tp_account_get_requested_presence (account, NULL, NULL);
650   switch (presence)
651     {
652       case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
653       case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
654       case TP_CONNECTION_PRESENCE_TYPE_UNSET:
655         presence = tp_account_manager_get_most_available_presence (
656             account_manager, &status, &message);
657
658         if (presence == TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
659           /* Global presence is offline; we force it so user doesn't have to
660            * manually change the presence to connect his new account. */
661           presence = TP_CONNECTION_PRESENCE_TYPE_AVAILABLE;
662
663         tp_account_request_presence_async (account, presence,
664             status, NULL, NULL, NULL);
665
666         g_free (status);
667         g_free (message);
668         break;
669
670        case TP_CONNECTION_PRESENCE_TYPE_AVAILABLE:
671        case TP_CONNECTION_PRESENCE_TYPE_AWAY:
672        case TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY:
673        case TP_CONNECTION_PRESENCE_TYPE_HIDDEN:
674        case TP_CONNECTION_PRESENCE_TYPE_BUSY:
675        case TP_CONNECTION_PRESENCE_TYPE_ERROR:
676        default:
677         /* do nothing if the presence is not offline */
678         break;
679     }
680 }
681
682 /* Translate Folks' general presence type to the Tp presence type */
683 TpConnectionPresenceType
684 empathy_folks_presence_type_to_tp (FolksPresenceType type)
685 {
686   return (TpConnectionPresenceType) type;
687 }
688
689 /* Returns TRUE if the given Individual contains a TpContact */
690 gboolean
691 empathy_folks_individual_contains_contact (FolksIndividual *individual)
692 {
693   GList *personas, *l;
694
695   g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), FALSE);
696
697   personas = folks_individual_get_personas (individual);
698   for (l = personas; l != NULL; l = l->next)
699     {
700       if (TPF_IS_PERSONA (l->data))
701         return (tpf_persona_get_contact (TPF_PERSONA (l->data)) != NULL);
702     }
703
704   return FALSE;
705 }
706
707 /* TODO: this needs to be eliminated (and replaced in some cases with user
708  * prompts) when we break the assumption that FolksIndividuals are 1:1 with
709  * TpContacts */
710
711 /* Retrieve the EmpathyContact corresponding to the first TpContact contained
712  * within the given Individual. Note that this is a temporary convenience. See
713  * the TODO above. */
714 EmpathyContact *
715 empathy_contact_dup_from_folks_individual (FolksIndividual *individual)
716 {
717   GList *personas, *l;
718   EmpathyContact *contact = NULL;
719
720   g_return_val_if_fail (FOLKS_IS_INDIVIDUAL (individual), NULL);
721
722   personas = folks_individual_get_personas (individual);
723   for (l = personas; (l != NULL) && (contact == NULL); l = l->next)
724     {
725       TpfPersona *persona = l->data;
726
727       if (TPF_IS_PERSONA (persona))
728         {
729           TpContact *tp_contact;
730
731           tp_contact = tpf_persona_get_contact (persona);
732           contact = empathy_contact_dup_from_tp_contact (tp_contact);
733           empathy_contact_set_persona (contact, FOLKS_PERSONA (persona));
734         }
735     }
736
737   return contact;
738 }
739
740 TpChannelGroupChangeReason
741 tp_chanel_group_change_reason_from_folks_groups_change_reason (
742     FolksGroupsChangeReason reason)
743 {
744   return (TpChannelGroupChangeReason) reason;
745 }
746
747 gchar *
748 empathy_get_x509_certificate_hostname (gnutls_x509_crt_t cert)
749 {
750   gchar dns_name[256];
751   gsize dns_name_size;
752   gint idx;
753   gint res = 0;
754
755   /* this snippet is taken from GnuTLS.
756    * see gnutls/lib/x509/rfc2818_hostname.c
757    */
758   for (idx = 0; res >= 0; idx++)
759     {
760       dns_name_size = sizeof (dns_name);
761       res = gnutls_x509_crt_get_subject_alt_name (cert, idx,
762           dns_name, &dns_name_size, NULL);
763
764       if (res == GNUTLS_SAN_DNSNAME || res == GNUTLS_SAN_IPADDRESS)
765         return g_strndup (dns_name, dns_name_size);
766     }
767
768   dns_name_size = sizeof (dns_name);
769   res = gnutls_x509_crt_get_dn_by_oid (cert, GNUTLS_OID_X520_COMMON_NAME,
770       0, 0, dns_name, &dns_name_size);
771
772   if (res >= 0)
773     return g_strndup (dns_name, dns_name_size);
774
775   return NULL;
776 }