]> git.0d.be Git - empathy.git/blob - libempathy/empathy-irc-network-manager.c
Merge remote-tracking branch 'origin/gnome-3-8'
[empathy.git] / libempathy / empathy-irc-network-manager.c
1 /*
2  * Copyright (C) 2007-2008 Guillaume Desmottes
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors: Guillaume Desmottes <gdesmott@gnome.org>
19  */
20
21 #include "config.h"
22 #include "empathy-irc-network-manager.h"
23
24 #include <sys/stat.h>
25
26 #include "empathy-utils.h"
27
28 #define DEBUG_FLAG EMPATHY_DEBUG_IRC
29 #include "empathy-debug.h"
30
31 #define IRC_NETWORKS_DTD_RESOURCENAME "/org/gnome/Empathy/empathy-irc-networks.dtd"
32 #define IRC_NETWORKS_FILENAME "irc-networks.xml"
33 #define SAVE_TIMER 4
34
35 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyIrcNetworkManager)
36 typedef struct {
37   GHashTable *networks;
38
39   gchar *global_file;
40   gchar *user_file;
41   guint last_id;
42
43   /* Do we have to save modifications to the user file ? */
44   gboolean have_to_save;
45   /* Are we loading networks from XML files ? */
46   gboolean loading;
47   /* source id of the autosave timer */
48   gint save_timer_id;
49 } EmpathyIrcNetworkManagerPriv;
50
51 /* properties */
52 enum
53 {
54   PROP_GLOBAL_FILE = 1,
55   PROP_USER_FILE,
56   LAST_PROPERTY
57 };
58
59 G_DEFINE_TYPE (EmpathyIrcNetworkManager, empathy_irc_network_manager,
60     G_TYPE_OBJECT);
61
62 static void irc_network_manager_load_servers (
63     EmpathyIrcNetworkManager *manager);
64 static gboolean irc_network_manager_file_parse (
65     EmpathyIrcNetworkManager *manager, const gchar *filename,
66     gboolean user_defined);
67 static gboolean irc_network_manager_file_save (
68     EmpathyIrcNetworkManager *manager);
69
70 static void
71 empathy_irc_network_manager_get_property (GObject *object,
72                                           guint property_id,
73                                           GValue *value,
74                                           GParamSpec *pspec)
75 {
76   EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object);
77   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
78
79   switch (property_id)
80     {
81       case PROP_GLOBAL_FILE:
82         g_value_set_string (value, priv->global_file);
83         break;
84       case PROP_USER_FILE:
85         g_value_set_string (value, priv->user_file);
86         break;
87       default:
88         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
89         break;
90     }
91 }
92
93 static void
94 empathy_irc_network_manager_set_property (GObject *object,
95                                           guint property_id,
96                                           const GValue *value,
97                                           GParamSpec *pspec)
98 {
99   EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object);
100   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
101
102   switch (property_id)
103     {
104       case PROP_GLOBAL_FILE:
105         g_free (priv->global_file);
106         priv->global_file = g_value_dup_string (value);
107         break;
108       case PROP_USER_FILE:
109         g_free (priv->user_file);
110         priv->user_file = g_value_dup_string (value);
111         break;
112       default:
113         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
114         break;
115     }
116 }
117
118 static GObject *
119 empathy_irc_network_manager_constructor (GType type,
120                                          guint n_props,
121                                          GObjectConstructParam *props)
122 {
123   GObject *obj;
124   EmpathyIrcNetworkManager *self;
125
126   /* Parent constructor chain */
127   obj = G_OBJECT_CLASS (empathy_irc_network_manager_parent_class)->
128         constructor (type, n_props, props);
129
130   self = EMPATHY_IRC_NETWORK_MANAGER (obj);
131   irc_network_manager_load_servers (self);
132
133   return obj;
134 }
135
136 static void
137 empathy_irc_network_manager_finalize (GObject *object)
138 {
139   EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object);
140   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
141
142   if (priv->save_timer_id > 0)
143     {
144       g_source_remove (priv->save_timer_id);
145     }
146
147   if (priv->have_to_save)
148     {
149       irc_network_manager_file_save (self);
150     }
151
152   g_free (priv->global_file);
153   g_free (priv->user_file);
154
155   g_hash_table_unref (priv->networks);
156
157   G_OBJECT_CLASS (empathy_irc_network_manager_parent_class)->finalize (object);
158 }
159
160 static void
161 empathy_irc_network_manager_init (EmpathyIrcNetworkManager *self)
162 {
163   EmpathyIrcNetworkManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
164       EMPATHY_TYPE_IRC_NETWORK_MANAGER, EmpathyIrcNetworkManagerPriv);
165
166   self->priv = priv;
167
168   priv->networks = g_hash_table_new_full (g_str_hash, g_str_equal,
169       (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref);
170
171   priv->last_id = 0;
172
173   priv->have_to_save = FALSE;
174   priv->loading = FALSE;
175   priv->save_timer_id = 0;
176 }
177
178 static void
179 empathy_irc_network_manager_class_init (EmpathyIrcNetworkManagerClass *klass)
180 {
181   GObjectClass *object_class = G_OBJECT_CLASS (klass);
182   GParamSpec *param_spec;
183
184   object_class->constructor = empathy_irc_network_manager_constructor;
185   object_class->get_property = empathy_irc_network_manager_get_property;
186   object_class->set_property = empathy_irc_network_manager_set_property;
187
188   g_type_class_add_private (object_class, sizeof (EmpathyIrcNetworkManagerPriv));
189
190   object_class->finalize = empathy_irc_network_manager_finalize;
191
192   param_spec = g_param_spec_string (
193       "global-file",
194       "path of the global networks file",
195       "The path of the system-wide filename from which we have to load"
196       " the networks list",
197       NULL,
198       G_PARAM_CONSTRUCT_ONLY |
199       G_PARAM_READWRITE |
200       G_PARAM_STATIC_NAME |
201       G_PARAM_STATIC_NICK |
202       G_PARAM_STATIC_BLURB);
203   g_object_class_install_property (object_class, PROP_GLOBAL_FILE, param_spec);
204
205   param_spec = g_param_spec_string (
206       "user-file",
207       "path of the user networks file",
208       "The path of user's  filename from which we have to load"
209       " the networks list and to which we'll save his modifications",
210       NULL,
211       G_PARAM_CONSTRUCT_ONLY |
212       G_PARAM_READWRITE |
213       G_PARAM_STATIC_NAME |
214       G_PARAM_STATIC_NICK |
215       G_PARAM_STATIC_BLURB);
216   g_object_class_install_property (object_class, PROP_USER_FILE, param_spec);
217 }
218
219 /**
220  * empathy_irc_network_manager_new:
221  * @global_file: the path of the global networks file, or %NULL
222  * @user_file: the path of the user networks file, or %NULL
223  *
224  * Creates a new #EmpathyIrcNetworkManager
225  *
226  * Returns: a new #EmpathyIrcNetworkManager
227  */
228 EmpathyIrcNetworkManager *
229 empathy_irc_network_manager_new (const gchar *global_file,
230                                  const gchar *user_file)
231 {
232   EmpathyIrcNetworkManager *manager;
233
234   manager = g_object_new (EMPATHY_TYPE_IRC_NETWORK_MANAGER,
235       "global-file", global_file,
236       "user-file", user_file,
237       NULL);
238
239   return manager;
240 }
241
242 static gboolean
243 save_timeout (EmpathyIrcNetworkManager *self)
244 {
245   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
246
247   priv->save_timer_id = 0;
248   irc_network_manager_file_save (self);
249
250   return FALSE;
251 }
252
253 static void
254 reset_save_timeout (EmpathyIrcNetworkManager *self)
255 {
256   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
257
258   if (priv->save_timer_id > 0)
259     {
260       g_source_remove (priv->save_timer_id);
261     }
262
263   priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER,
264       (GSourceFunc) save_timeout, self);
265 }
266
267 static void
268 network_modified (EmpathyIrcNetwork *network,
269                   EmpathyIrcNetworkManager *self)
270 {
271   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
272
273   network->user_defined = TRUE;
274
275   if (!priv->loading)
276     {
277       priv->have_to_save = TRUE;
278       reset_save_timeout (self);
279     }
280 }
281
282 static void
283 add_network (EmpathyIrcNetworkManager *self,
284              EmpathyIrcNetwork *network,
285              const gchar *id)
286 {
287   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
288
289   g_hash_table_insert (priv->networks, g_strdup (id), g_object_ref (network));
290
291   g_signal_connect (network, "modified", G_CALLBACK (network_modified), self);
292 }
293
294 /**
295  * empathy_irc_network_manager_add:
296  * @manager: an #EmpathyIrcNetworkManager
297  * @network: the #EmpathyIrcNetwork to add
298  *
299  * Add an #EmpathyIrcNetwork to the given #EmpathyIrcNetworkManager.
300  *
301  */
302 void
303 empathy_irc_network_manager_add (EmpathyIrcNetworkManager *self,
304                                  EmpathyIrcNetwork *network)
305 {
306   EmpathyIrcNetworkManagerPriv *priv;
307   gchar *id = NULL;
308
309   g_return_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self));
310   g_return_if_fail (EMPATHY_IS_IRC_NETWORK (network));
311
312   priv = GET_PRIV (self);
313
314   /* generate an id for this network */
315   do
316     {
317       g_free (id);
318       id = g_strdup_printf ("id%u", ++priv->last_id);
319     } while (g_hash_table_lookup (priv->networks, id) != NULL &&
320         priv->last_id < G_MAXUINT);
321
322   if (priv->last_id == G_MAXUINT)
323     {
324       DEBUG ("Can't add network: too many networks using a similar ID");
325       return;
326     }
327
328   DEBUG ("add server with \"%s\" as ID", id);
329
330   network->user_defined = TRUE;
331   add_network (self, network, id);
332
333   priv->have_to_save = TRUE;
334   reset_save_timeout (self);
335
336   g_free (id);
337 }
338
339 /**
340  * empathy_irc_network_manager_remove:
341  * @manager: an #EmpathyIrcNetworkManager
342  * @network: the #EmpathyIrcNetwork to remove
343  *
344  * Remove an #EmpathyIrcNetwork from the given #EmpathyIrcNetworkManager.
345  *
346  */
347 void
348 empathy_irc_network_manager_remove (EmpathyIrcNetworkManager *self,
349                                     EmpathyIrcNetwork *network)
350 {
351   EmpathyIrcNetworkManagerPriv *priv;
352
353   g_return_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self));
354   g_return_if_fail (EMPATHY_IS_IRC_NETWORK (network));
355
356   priv = GET_PRIV (self);
357
358   network->user_defined = TRUE;
359   network->dropped = TRUE;
360
361   priv->have_to_save = TRUE;
362   reset_save_timeout (self);
363 }
364
365 static void
366 append_active_networks_to_list (const gchar *id,
367                         EmpathyIrcNetwork *network,
368                         GSList **list)
369 {
370   if (network->dropped)
371     return;
372
373   *list = g_slist_prepend (*list, g_object_ref (network));
374 }
375
376 static void
377 append_dropped_networks_to_list (const gchar *id,
378                         EmpathyIrcNetwork *network,
379                         GSList **list)
380 {
381   if (!network->dropped)
382     return;
383
384   *list = g_slist_prepend (*list, g_object_ref (network));
385 }
386
387 static GSList *
388 get_network_list (EmpathyIrcNetworkManager *self,
389     gboolean get_active)
390 {
391   EmpathyIrcNetworkManagerPriv *priv;
392   GSList *irc_networks = NULL;
393
394   g_return_val_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self), NULL);
395
396   priv = GET_PRIV (self);
397
398   if (get_active)
399     {
400       g_hash_table_foreach (priv->networks,
401           (GHFunc) append_active_networks_to_list, &irc_networks);
402     }
403   else
404     {
405       g_hash_table_foreach (priv->networks,
406           (GHFunc) append_dropped_networks_to_list, &irc_networks);
407     }
408
409   return irc_networks;
410 }
411
412 /**
413  * empathy_irc_network_manager_get_networks:
414  * @manager: an #EmpathyIrcNetworkManager
415  *
416  * Get the list of #EmpathyIrcNetwork associated with the given
417  * manager.
418  *
419  * Returns: a new #GSList of refed #EmpathyIrcNetwork
420  */
421 GSList *
422 empathy_irc_network_manager_get_networks (EmpathyIrcNetworkManager *self)
423 {
424   return get_network_list (self, TRUE);
425 }
426
427 /**
428  * empathy_irc_network_manager_get_dropped_networks:
429  * @manager: an #EmpathyIrcNetworkManager
430  *
431  * Get the list of dropped #EmpathyIrcNetworks associated with the given
432  * manager.
433  *
434  * Returns: a new #GSList of refed dropped #EmpathyIrcNetworks
435  */
436 GSList *
437 empathy_irc_network_manager_get_dropped_networks (EmpathyIrcNetworkManager *self)
438 {
439   return get_network_list (self, FALSE);
440 }
441
442 /*
443  * API to save/load and parse the irc_networks file.
444  */
445
446 static void
447 load_global_file (EmpathyIrcNetworkManager *self)
448 {
449   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
450
451   if (priv->global_file == NULL)
452     return;
453
454   if (!g_file_test (priv->global_file, G_FILE_TEST_EXISTS))
455     {
456       DEBUG ("Global networks file %s doesn't exist", priv->global_file);
457       return;
458     }
459
460   irc_network_manager_file_parse (self, priv->global_file, FALSE);
461 }
462
463 static void
464 load_user_file (EmpathyIrcNetworkManager *self)
465 {
466   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
467
468   if (priv->user_file == NULL)
469     return;
470
471   if (!g_file_test (priv->user_file, G_FILE_TEST_EXISTS))
472     {
473       DEBUG ("User networks file %s doesn't exist", priv->global_file);
474       return;
475     }
476
477   irc_network_manager_file_parse (self, priv->user_file, TRUE);
478 }
479
480 static void
481 irc_network_manager_load_servers (EmpathyIrcNetworkManager *self)
482 {
483   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
484
485   priv->loading = TRUE;
486
487   load_global_file (self);
488   load_user_file (self);
489
490   priv->loading = FALSE;
491   priv->have_to_save = FALSE;
492 }
493
494 static void
495 irc_network_manager_parse_irc_server (EmpathyIrcNetwork *network,
496                                       xmlNodePtr node)
497 {
498   xmlNodePtr server_node;
499
500   for (server_node = node->children; server_node;
501       server_node = server_node->next)
502     {
503       gchar *address = NULL, *port = NULL, *ssl = NULL;
504
505       if (strcmp ((const gchar *) server_node->name, "server") != 0)
506         continue;
507
508       address = (gchar *) xmlGetProp (server_node, (const xmlChar *) "address");
509       port = (gchar *) xmlGetProp (server_node, (const xmlChar *) "port");
510       ssl = (gchar *) xmlGetProp (server_node, (const xmlChar *) "ssl");
511
512       if (address != NULL)
513         {
514           gint port_nb = 0;
515           gboolean have_ssl = FALSE;
516           EmpathyIrcServer *server;
517
518           if (port != NULL)
519             port_nb = strtol (port, NULL, 10);
520
521           if (port_nb <= 0 || port_nb > G_MAXUINT16)
522             port_nb = 6667;
523
524           if (ssl == NULL || strcmp (ssl, "TRUE") == 0)
525             have_ssl = TRUE;
526
527           DEBUG ("parsed server %s port %d ssl %d", address, port_nb, have_ssl);
528
529           server = empathy_irc_server_new (address, port_nb, have_ssl);
530           empathy_irc_network_append_server (network, server);
531         }
532
533       if (address)
534         xmlFree (address);
535       if (port)
536         xmlFree (port);
537       if (ssl)
538         xmlFree (ssl);
539     }
540 }
541
542 static void
543 irc_network_manager_parse_irc_network (EmpathyIrcNetworkManager *self,
544                                        xmlNodePtr node,
545                                        gboolean user_defined)
546 {
547   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
548   EmpathyIrcNetwork  *network;
549   xmlNodePtr child;
550   gchar *str;
551   gchar *id, *name;
552
553   id = (gchar *) xmlGetProp (node, (const xmlChar *) "id");
554   if (xmlHasProp (node, (const xmlChar *) "dropped"))
555     {
556       if (!user_defined)
557         {
558           DEBUG ("the 'dropped' attribute shouldn't be used in the global file");
559         }
560
561       network = g_hash_table_lookup (priv->networks, id);
562       if (network != NULL)
563         {
564           network->dropped = TRUE;
565           network->user_defined = TRUE;
566         }
567        xmlFree (id);
568       return;
569     }
570
571   if (!xmlHasProp (node, (const xmlChar *) "name"))
572     return;
573
574   name = (gchar *) xmlGetProp (node, (const xmlChar *) "name");
575   network = empathy_irc_network_new (name);
576
577   if (xmlHasProp (node, (const xmlChar *) "network_charset"))
578     {
579       gchar *charset;
580       charset = (gchar *) xmlGetProp (node, (const xmlChar *) "network_charset");
581       g_object_set (network, "charset", charset, NULL);
582       xmlFree (charset);
583     }
584
585   add_network (self, network, id);
586   DEBUG ("add network %s (id %s)", name, id);
587
588   for (child = node->children; child; child = child->next)
589     {
590       gchar *tag;
591
592       tag = (gchar *) child->name;
593       str = (gchar *) xmlNodeGetContent (child);
594
595       if (!str)
596         continue;
597
598       if (strcmp (tag, "servers") == 0)
599         {
600           irc_network_manager_parse_irc_server (network, child);
601         }
602
603       xmlFree (str);
604     }
605
606   network->user_defined = user_defined;
607   g_object_unref (network);
608   xmlFree (name);
609   xmlFree (id);
610 }
611
612 static gboolean
613 irc_network_manager_file_parse (EmpathyIrcNetworkManager *self,
614                                 const gchar *filename,
615                                 gboolean user_defined)
616 {
617   xmlParserCtxtPtr ctxt;
618   xmlDocPtr doc;
619   xmlNodePtr networks;
620   xmlNodePtr node;
621
622   DEBUG ("Attempting to parse file:'%s'...", filename);
623
624   ctxt = xmlNewParserCtxt ();
625
626   /* Parse and validate the file. */
627   doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
628   if (!doc)
629     {
630       g_warning ("Failed to parse file:'%s'", filename);
631       xmlFreeParserCtxt (ctxt);
632       return FALSE;
633     }
634
635   if (!empathy_xml_validate_from_resource (doc, IRC_NETWORKS_DTD_RESOURCENAME)) {
636     g_warning ("Failed to validate file:'%s'", filename);
637     xmlFreeDoc (doc);
638     xmlFreeParserCtxt (ctxt);
639     return FALSE;
640   }
641
642   /* The root node, networks. */
643   networks = xmlDocGetRootElement (doc);
644
645   for (node = networks->children; node; node = node->next)
646     {
647       irc_network_manager_parse_irc_network (self, node, user_defined);
648     }
649
650   xmlFreeDoc (doc);
651   xmlFreeParserCtxt (ctxt);
652
653   return TRUE;
654 }
655
656 static void
657 write_network_to_xml (const gchar *id,
658                       EmpathyIrcNetwork *network,
659                       xmlNodePtr root)
660 {
661   xmlNodePtr network_node, servers_node;
662   GSList *servers, *l;
663   gchar *name, *charset;
664
665   if (!network->user_defined)
666     /* no need to write this network to the XML */
667     return;
668
669   network_node = xmlNewChild (root, NULL, (const xmlChar *) "network", NULL);
670   xmlNewProp (network_node, (const xmlChar *) "id", (const xmlChar *) id);
671
672   if (network->dropped)
673     {
674       xmlNewProp (network_node, (const xmlChar *) "dropped",
675           (const xmlChar *)  "1");
676       return;
677     }
678
679   g_object_get (network,
680       "name", &name,
681       "charset", &charset,
682       NULL);
683   xmlNewProp (network_node, (const xmlChar *) "name", (const xmlChar *) name);
684   xmlNewProp (network_node, (const xmlChar *) "network_charset",
685       (const xmlChar *) charset);
686   g_free (name);
687   g_free (charset);
688
689   servers = empathy_irc_network_get_servers (network);
690
691   servers_node = xmlNewChild (network_node, NULL, (const xmlChar *) "servers",
692       NULL);
693   for (l = servers; l != NULL; l = g_slist_next (l))
694     {
695       EmpathyIrcServer *server;
696       xmlNodePtr server_node;
697       gchar *address, *tmp;
698       guint port;
699       gboolean ssl;
700
701       server = l->data;
702
703       server_node = xmlNewChild (servers_node, NULL, (const xmlChar *) "server",
704           NULL);
705
706       g_object_get (server,
707           "address", &address,
708           "port", &port,
709           "ssl", &ssl,
710           NULL);
711
712       xmlNewProp (server_node, (const xmlChar *) "address",
713           (const xmlChar *) address);
714
715       tmp = g_strdup_printf ("%u", port);
716       xmlNewProp (server_node, (const xmlChar *) "port",
717           (const xmlChar *) tmp);
718       g_free (tmp);
719
720       xmlNewProp (server_node, (const xmlChar *) "ssl",
721           ssl ? (const xmlChar *) "TRUE": (const xmlChar *) "FALSE");
722
723       g_free (address);
724     }
725
726   /* free the list */
727   g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
728   g_slist_free (servers);
729 }
730
731 static gboolean
732 irc_network_manager_file_save (EmpathyIrcNetworkManager *self)
733 {
734   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
735   xmlDocPtr doc;
736   xmlNodePtr root;
737
738   if (priv->user_file == NULL)
739     {
740       DEBUG ("can't save: no user file defined");
741       return FALSE;
742     }
743
744   DEBUG ("Saving IRC networks");
745
746   doc = xmlNewDoc ((const xmlChar *)  "1.0");
747   root = xmlNewNode (NULL, (const xmlChar *) "networks");
748   xmlDocSetRootElement (doc, root);
749
750   g_hash_table_foreach (priv->networks, (GHFunc) write_network_to_xml, root);
751
752   /* Make sure the XML is indented properly */
753   xmlIndentTreeOutput = 1;
754
755   xmlSaveFormatFileEnc (priv->user_file, doc, "utf-8", 1);
756   xmlFreeDoc (doc);
757
758   xmlMemoryDump ();
759
760   priv->have_to_save = FALSE;
761
762   return TRUE;
763 }
764
765 static gboolean
766 find_network_by_address (const gchar *id,
767                          EmpathyIrcNetwork *network,
768                          const gchar *address)
769 {
770   GSList *servers, *l;
771   gboolean found = FALSE;
772
773   if (network->dropped)
774     return FALSE;
775
776   servers = empathy_irc_network_get_servers (network);
777
778   for (l = servers; l != NULL && !found; l = g_slist_next (l))
779     {
780       EmpathyIrcServer *server = l->data;
781       gchar *_address;
782
783       g_object_get (server, "address", &_address, NULL);
784       found = (_address != NULL && strcmp (address, _address) == 0);
785
786       g_free (_address);
787     }
788
789   g_slist_foreach (servers, (GFunc) g_object_unref, NULL);
790   g_slist_free (servers);
791
792   return found;
793 }
794
795 /**
796  * empathy_irc_network_manager_find_network_by_address:
797  * @manager: an #EmpathyIrcNetworkManager
798  * @address: the server address to look for
799  *
800  * Find the #EmpathyIrcNetwork which owns an #EmpathyIrcServer
801  * that has the given address.
802  *
803  * Returns: the found #EmpathyIrcNetwork, or %NULL if not found.
804  */
805 EmpathyIrcNetwork *
806 empathy_irc_network_manager_find_network_by_address (
807     EmpathyIrcNetworkManager *self,
808     const gchar *address)
809 {
810   EmpathyIrcNetworkManagerPriv *priv = GET_PRIV (self);
811   EmpathyIrcNetwork *network;
812
813   g_return_val_if_fail (address != NULL, NULL);
814
815   network = g_hash_table_find (priv->networks,
816       (GHRFunc) find_network_by_address, (gchar *) address);
817
818   return network;
819 }
820
821 EmpathyIrcNetworkManager *
822 empathy_irc_network_manager_dup_default (void)
823 {
824   static EmpathyIrcNetworkManager *default_mgr = NULL;
825   gchar *dir, *user_file_with_path, *global_file_with_path;
826
827   if (default_mgr != NULL)
828     return g_object_ref (default_mgr);
829
830   dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
831   g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
832   user_file_with_path = g_build_filename (dir, IRC_NETWORKS_FILENAME, NULL);
833   g_free (dir);
834
835   global_file_with_path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"),
836       "libempathy", IRC_NETWORKS_FILENAME, NULL);
837   if (!g_file_test (global_file_with_path, G_FILE_TEST_EXISTS))
838     {
839       g_free (global_file_with_path);
840       global_file_with_path = g_build_filename (DATADIR, "empathy",
841           IRC_NETWORKS_FILENAME, NULL);
842     }
843
844   default_mgr = empathy_irc_network_manager_new (
845       global_file_with_path, user_file_with_path);
846
847   g_object_add_weak_pointer (G_OBJECT (default_mgr), (gpointer *) &default_mgr);
848
849   g_free (global_file_with_path);
850   g_free (user_file_with_path);
851   return default_mgr;
852 }