eds: Clarify mapping between properties and vCard fields in EDS
[platform/upstream/folks.git] / tools / import.vala
1 /*
2  * Copyright (C) 2010 Collabora Ltd.
3  *
4  * This library is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published by
6  * the Free Software Foundation, either version 2.1 of the License, or
7  * (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
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors:
18  *       Philip Withnall <philip.withnall@collabora.co.uk>
19  */
20
21 using GLib;
22 using Gee;
23 using Xml;
24 using Folks;
25
26 /*
27  * Command line application to import meta-contact information from various
28  * places into libfolks' key file backend.
29  *
30  * Used as follows:
31  *   folks-import [--source=pidgin] [--source-filename=~/.purple/blist.xml]
32  */
33
34 public class Folks.ImportTool : Object
35 {
36   private static string source;
37   private static string source_filename;
38
39   private static const string DEFAULT_SOURCE = "pidgin";
40
41   private static const OptionEntry[] options =
42     {
43       { "source", 's', 0, OptionArg.STRING, ref ImportTool.source,
44           N_("Source backend name (default: 'pidgin')"), "name" },
45       { "source-filename", 0, 0, OptionArg.FILENAME,
46           ref ImportTool.source_filename,
47           N_("Source filename (default: specific to source backend)"), null },
48       { null }
49     };
50
51   public static int main (string[] args)
52     {
53       Intl.setlocale (LocaleCategory.ALL, "");
54       Intl.bindtextdomain (BuildConf.GETTEXT_PACKAGE, BuildConf.LOCALE_DIR);
55       Intl.textdomain (BuildConf.GETTEXT_PACKAGE);
56
57       OptionContext context = new OptionContext (
58           _("— import meta-contact information to libfolks"));
59       context.add_main_entries (ImportTool.options, "folks");
60
61       try
62         {
63           context.parse (ref args);
64         }
65       catch (OptionError e)
66         {
67           /* Translators: the parameter is an error message. */
68           stderr.printf (_("Couldn't parse command line options: %s") + "\n",
69               e.message);
70           return 1;
71         }
72
73       /* We only support importing from Pidgin at the moment */
74       if (source == null || source.strip () == "")
75         source = ImportTool.DEFAULT_SOURCE;
76
77       /* FIXME: We need to create this, even though we don't use it, to prevent
78        * debug message spew, as its constructor initialises the log handling.
79        * bgo#629096 */
80       IndividualAggregator aggregator = new IndividualAggregator ();
81       aggregator = null;
82
83       /* Create a main loop and start importing */
84       MainLoop main_loop = new MainLoop ();
85
86       bool success = false;
87       ImportTool.import.begin ((o, r) =>
88         {
89           success = ImportTool.import.end (r);
90           main_loop.quit ();
91         });
92
93       main_loop.run ();
94
95       return success ? 0 : 1;
96     }
97
98   private static async bool import ()
99     {
100       BackendStore backend_store = BackendStore.dup ();
101
102       try
103         {
104           yield backend_store.load_backends ();
105         }
106       catch (GLib.Error e1)
107         {
108           /* Translators: the parameter is an error message. */
109           stderr.printf (_("Couldn't load the backends: %s") + "\n",
110               e1.message);
111           return false;
112         }
113
114       /* Get the key-file backend */
115       Backend kf_backend = backend_store.dup_backend_by_name ("key-file");
116
117       if (kf_backend == null)
118         {
119           /* Translators: the parameter is a backend identifier. */
120           stderr.printf (_("Couldn't load the ‘%s’ backend.") + "\n",
121               "key-file");
122           return false;
123         }
124
125       try
126         {
127           yield kf_backend.prepare ();
128         }
129       catch (GLib.Error e2)
130         {
131           /* Translators: the first parameter is a backend identifier and the
132            * second parameter is an error message. */
133           stderr.printf (_("Couldn't prepare the ‘%s’ backend: %s") + "\n",
134               "key-file", e2.message);
135           return false;
136         }
137
138       /* Get its only PersonaStore */
139       PersonaStore destination_store = null;
140       var stores = kf_backend.persona_stores.values;
141
142       if (stores.size == 0)
143         {
144           stderr.printf (
145               /* Translators: the parameter is a backend identifier. */
146               _("Couldn't load the ‘%s’ backend's persona store.") + "\n",
147               "key-file");
148           return false;
149         }
150
151       try
152         {
153           /* Get the first persona store */
154           foreach (var persona_store in stores)
155             {
156               destination_store = persona_store;
157               break;
158             }
159
160           yield destination_store.prepare ();
161         }
162       catch (GLib.Error e3)
163         {
164           /* Translators: the first parameter is a backend identifier and the
165            * second parameter is an error message. */
166           stderr.printf (
167               _("Couldn't prepare the ‘%s’ backend's persona store: %s") + "\n",
168               e3.message);
169           return false;
170         }
171
172       if (source == "pidgin")
173         {
174           Importer importer = new Importers.Pidgin ();
175
176           try
177             {
178               /* Import! */
179               yield importer.import (destination_store,
180                   ImportTool.source_filename);
181             }
182           catch (ImportError e)
183             {
184               /* Translators: the parameter is an error message. */
185               stderr.printf (_("Error importing contacts: %s") + "\n",
186                   e.message);
187               return false;
188             }
189
190           /* Wait for the PersonaStore to finish writing its changes to disk */
191           yield destination_store.flush ();
192
193           return true;
194         }
195       else
196         {
197           stderr.printf (
198               /* Translators: both parameters are identifiers for backends. */
199               _("Unrecognized source backend name ‘%s’. ‘%s’ is currently the only supported source backend.") + "\n",
200               source, "pidgin");
201           return false;
202         }
203     }
204 }
205
206 public errordomain Folks.ImportError
207 {
208   MALFORMED_INPUT,
209 }
210
211 public abstract class Folks.Importer : Object
212 {
213   public abstract async uint import (PersonaStore destination_store,
214       string? source_filename) throws ImportError;
215 }