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