]> git.0d.be Git - empathy.git/blob - src/empathy.c
Update simplified Chinese translation.
[empathy.git] / src / empathy.c
1 /*
2  * Copyright (C) 2007-2009 Collabora Ltd.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program 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  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA  02110-1301  USA
18  *
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <string.h>
27
28 #include <glib.h>
29 #include <glib/gstdio.h>
30 #include <glib/gi18n.h>
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33 #include <unique/unique.h>
34
35 #ifdef HAVE_LIBCHAMPLAIN
36 #include <clutter-gtk/clutter-gtk.h>
37 #endif
38
39 #include <libnotify/notify.h>
40
41 #include <telepathy-glib/account-manager.h>
42 #include <telepathy-glib/dbus.h>
43 #include <telepathy-glib/debug-sender.h>
44 #include <telepathy-glib/util.h>
45 #include <telepathy-glib/connection-manager.h>
46 #include <telepathy-glib/interfaces.h>
47
48 #include <telepathy-logger/log-manager.h>
49
50 #include <libempathy/empathy-idle.h>
51 #include <libempathy/empathy-utils.h>
52 #include <libempathy/empathy-chatroom-manager.h>
53 #include <libempathy/empathy-account-settings.h>
54 #include <libempathy/empathy-connectivity.h>
55 #include <libempathy/empathy-connection-managers.h>
56 #include <libempathy/empathy-dispatcher.h>
57 #include <libempathy/empathy-ft-factory.h>
58 #include <libempathy/empathy-gsettings.h>
59 #include <libempathy/empathy-tp-chat.h>
60
61 #include <libempathy-gtk/empathy-ui-utils.h>
62 #include <libempathy-gtk/empathy-location-manager.h>
63
64 #include "empathy-main-window.h"
65 #include "empathy-accounts-common.h"
66 #include "empathy-accounts-dialog.h"
67 #include "empathy-chat-manager.h"
68 #include "empathy-status-icon.h"
69 #include "empathy-ft-manager.h"
70
71 #include "extensions/extensions.h"
72
73 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
74 #include <libempathy/empathy-debug.h>
75
76 static gboolean start_hidden = FALSE;
77 static gboolean no_connect = FALSE;
78
79 static void account_manager_ready_cb (GObject *source_object,
80     GAsyncResult *result,
81     gpointer user_data);
82
83 static void
84 use_conn_notify_cb (GSettings *gsettings,
85     const gchar *key,
86     gpointer     user_data)
87 {
88   EmpathyConnectivity *connectivity = user_data;
89
90   empathy_connectivity_set_use_conn (connectivity,
91       g_settings_get_boolean (gsettings, key));
92 }
93
94 static void
95 migrate_config_to_xdg_dir (void)
96 {
97   gchar *xdg_dir, *old_dir, *xdg_filename, *old_filename;
98   int i;
99   GFile *xdg_file, *old_file;
100   static const gchar* filenames[] = {
101     "geometry.ini",
102     "irc-networks.xml",
103     "chatrooms.xml",
104     "contact-groups.xml",
105     "status-presets.xml",
106     "accels.txt",
107     NULL
108   };
109
110   xdg_dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
111   if (g_file_test (xdg_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
112     {
113       /* xdg config dir already exists */
114       g_free (xdg_dir);
115       return;
116     }
117
118   old_dir = g_build_filename (g_get_home_dir (), ".gnome2",
119       PACKAGE_NAME, NULL);
120   if (!g_file_test (old_dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
121     {
122       /* old config dir didn't exist */
123       g_free (xdg_dir);
124       g_free (old_dir);
125       return;
126     }
127
128   if (g_mkdir_with_parents (xdg_dir, (S_IRUSR | S_IWUSR | S_IXUSR)) == -1)
129     {
130       DEBUG ("Failed to create configuration directory; aborting migration");
131       g_free (xdg_dir);
132       g_free (old_dir);
133       return;
134     }
135
136   for (i = 0; filenames[i]; i++)
137     {
138       old_filename = g_build_filename (old_dir, filenames[i], NULL);
139       if (!g_file_test (old_filename, G_FILE_TEST_EXISTS))
140         {
141           g_free (old_filename);
142           continue;
143         }
144       xdg_filename = g_build_filename (xdg_dir, filenames[i], NULL);
145       old_file = g_file_new_for_path (old_filename);
146       xdg_file = g_file_new_for_path (xdg_filename);
147
148       if (!g_file_move (old_file, xdg_file, G_FILE_COPY_NONE,
149           NULL, NULL, NULL, NULL))
150         DEBUG ("Failed to migrate %s", filenames[i]);
151
152       g_free (old_filename);
153       g_free (xdg_filename);
154       g_object_unref (old_file);
155       g_object_unref (xdg_file);
156     }
157
158   g_free (xdg_dir);
159   g_free (old_dir);
160 }
161
162 static void
163 show_accounts_ui (GdkScreen *screen,
164     gboolean if_needed)
165 {
166   empathy_accounts_dialog_show_application (screen,
167       NULL, if_needed, start_hidden);
168 }
169
170 static UniqueResponse
171 unique_app_message_cb (UniqueApp *unique_app,
172     gint command,
173     UniqueMessageData *data,
174     guint timestamp,
175     gpointer user_data)
176 {
177   GtkWindow *window = user_data;
178   TpAccountManager *account_manager;
179
180   DEBUG ("Other instance launched, presenting the main window. "
181       "Command=%d, timestamp %u", command, timestamp);
182
183   /* XXX: the standalone app somewhat breaks this case, since
184    * communicating it would be a pain */
185
186   /* We're requested to show stuff again, disable the start hidden global
187    * in case the accounts wizard wants to pop up.
188    */
189   start_hidden = FALSE;
190
191   gtk_window_set_screen (GTK_WINDOW (window),
192       unique_message_data_get_screen (data));
193   gtk_window_set_startup_id (GTK_WINDOW (window),
194       unique_message_data_get_startup_id (data));
195   gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
196   gtk_window_set_skip_taskbar_hint (window, FALSE);
197
198   account_manager = tp_account_manager_dup ();
199   tp_account_manager_prepare_async (account_manager, NULL,
200       account_manager_ready_cb, NULL);
201   g_object_unref (account_manager);
202
203   return UNIQUE_RESPONSE_OK;
204 }
205
206 static gboolean show_version_cb (const char *option_name,
207     const char *value,
208     gpointer data,
209     GError **error) G_GNUC_NORETURN;
210
211 static gboolean
212 show_version_cb (const char *option_name,
213     const char *value,
214     gpointer data,
215     GError **error)
216 {
217   g_print ("%s\n", PACKAGE_STRING);
218
219   exit (EXIT_SUCCESS);
220 }
221
222 static void
223 new_incoming_transfer_cb (EmpathyFTFactory *factory,
224     EmpathyFTHandler *handler,
225     GError *error,
226     gpointer user_data)
227 {
228   if (error)
229     empathy_ft_manager_display_error (handler, error);
230   else
231     empathy_receive_file_with_file_chooser (handler);
232 }
233
234 static void
235 new_ft_handler_cb (EmpathyFTFactory *factory,
236     EmpathyFTHandler *handler,
237     GError *error,
238     gpointer user_data)
239 {
240   if (error)
241     empathy_ft_manager_display_error (handler, error);
242   else
243     empathy_ft_manager_add_handler (handler);
244
245   g_object_unref (handler);
246 }
247
248 static void
249 account_manager_ready_cb (GObject *source_object,
250     GAsyncResult *result,
251     gpointer user_data)
252 {
253   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
254   GError *error = NULL;
255   EmpathyIdle *idle;
256   EmpathyConnectivity *connectivity;
257   TpConnectionPresenceType presence;
258   GSettings *gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
259
260   if (!tp_account_manager_prepare_finish (manager, result, &error))
261     {
262       DEBUG ("Failed to prepare account manager: %s", error->message);
263       g_error_free (error);
264       return;
265     }
266
267   /* Autoconnect */
268   idle = empathy_idle_dup_singleton ();
269   connectivity = empathy_connectivity_dup_singleton ();
270
271   presence = tp_account_manager_get_most_available_presence (manager, NULL,
272       NULL);
273
274   if (g_settings_get_boolean (gsettings, EMPATHY_PREFS_AUTOCONNECT) &&
275       !no_connect &&
276       tp_connection_presence_type_cmp_availability
277           (presence, TP_CONNECTION_PRESENCE_TYPE_OFFLINE)
278             <= 0)
279       /* if current state is Offline, then put it online */
280       empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_AVAILABLE);
281
282   /* Pop up the accounts dialog if we don't have any account */
283   if (!empathy_accounts_has_accounts (manager))
284     show_accounts_ui (gdk_screen_get_default (), TRUE);
285
286   g_object_unref (idle);
287   g_object_unref (connectivity);
288   g_object_unref (gsettings);
289 }
290
291 static void
292 account_status_changed_cb (TpAccount *account,
293     guint old_status,
294     guint new_status,
295     guint reason,
296     gchar *dbus_error_name,
297     GHashTable *details,
298     EmpathyChatroom *room)
299 {
300   if (new_status != TP_CONNECTION_STATUS_CONNECTED)
301     return;
302
303   empathy_dispatcher_join_muc (account,
304       empathy_chatroom_get_room (room), TP_USER_ACTION_TIME_NOT_USER_ACTION);
305 }
306
307 static void
308 account_manager_chatroom_ready_cb (GObject *source_object,
309     GAsyncResult *result,
310     gpointer user_data)
311 {
312   TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
313   EmpathyChatroomManager *chatroom_manager = user_data;
314   GList *accounts, *l;
315   GError *error = NULL;
316
317   if (!tp_account_manager_prepare_finish (account_manager, result, &error))
318     {
319       DEBUG ("Failed to prepare account manager: %s", error->message);
320       g_error_free (error);
321       return;
322     }
323
324   accounts = tp_account_manager_get_valid_accounts (account_manager);
325
326   for (l = accounts; l != NULL; l = g_list_next (l))
327     {
328       TpAccount *account = TP_ACCOUNT (l->data);
329       TpConnection *conn;
330       GList *chatrooms, *p;
331
332       conn = tp_account_get_connection (account);
333
334       chatrooms = empathy_chatroom_manager_get_chatrooms (
335           chatroom_manager, account);
336
337       for (p = chatrooms; p != NULL; p = p->next)
338         {
339           EmpathyChatroom *room = EMPATHY_CHATROOM (p->data);
340
341           if (!empathy_chatroom_get_auto_connect (room))
342             continue;
343
344           if (conn == NULL)
345             {
346               g_signal_connect (G_OBJECT (account), "status-changed",
347                   G_CALLBACK (account_status_changed_cb), room);
348             }
349           else
350             {
351               empathy_dispatcher_join_muc (account,
352                   empathy_chatroom_get_room (room),
353                   TP_USER_ACTION_TIME_NOT_USER_ACTION);
354             }
355         }
356
357       g_list_free (chatrooms);
358     }
359
360   g_list_free (accounts);
361 }
362
363 static void
364 chatroom_manager_ready_cb (EmpathyChatroomManager *chatroom_manager,
365     GParamSpec *pspec,
366     gpointer user_data)
367 {
368   TpAccountManager *account_manager = user_data;
369
370   tp_account_manager_prepare_async (account_manager, NULL,
371       account_manager_chatroom_ready_cb, chatroom_manager);
372 }
373
374 static void
375 empathy_idle_set_auto_away_cb (GSettings *gsettings,
376                                 const gchar *key,
377                                 gpointer user_data)
378 {
379         EmpathyIdle *idle = user_data;
380
381         empathy_idle_set_auto_away (idle,
382       g_settings_get_boolean (gsettings, key));
383 }
384
385 int
386 main (int argc, char *argv[])
387 {
388 #ifdef HAVE_GEOCLUE
389   EmpathyLocationManager *location_manager = NULL;
390 #endif
391   EmpathyStatusIcon *icon;
392   EmpathyDispatcher *dispatcher;
393   TpAccountManager *account_manager;
394   TplLogManager *log_manager;
395   EmpathyChatroomManager *chatroom_manager;
396   EmpathyFTFactory  *ft_factory;
397   GtkWidget *window;
398   EmpathyIdle *idle;
399   EmpathyConnectivity *connectivity;
400   EmpathyChatManager *chat_manager;
401   GError *error = NULL;
402   UniqueApp *unique_app;
403   gboolean chatroom_manager_ready;
404   gboolean autoaway = TRUE;
405 #ifdef ENABLE_DEBUG
406   TpDebugSender *debug_sender;
407 #endif
408   GSettings *gsettings;
409
410   GOptionContext *optcontext;
411   GOptionEntry options[] = {
412       { "no-connect", 'n',
413         0, G_OPTION_ARG_NONE, &no_connect,
414         N_("Don't connect on startup"),
415         NULL },
416       { "start-hidden", 'h',
417         0, G_OPTION_ARG_NONE, &start_hidden,
418         N_("Don't display the contact list or any other dialogs on startup"),
419         NULL },
420       { "version", 'v',
421         G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, show_version_cb,
422         NULL, NULL },
423       { NULL }
424   };
425
426   /* Init */
427   g_thread_init (NULL);
428
429 #ifdef HAVE_LIBCHAMPLAIN
430   gtk_clutter_init (&argc, &argv);
431 #endif
432
433   empathy_init ();
434
435   optcontext = g_option_context_new (N_("- Empathy IM Client"));
436   g_option_context_add_group (optcontext, gtk_get_option_group (TRUE));
437   g_option_context_add_main_entries (optcontext, options, GETTEXT_PACKAGE);
438
439   if (!g_option_context_parse (optcontext, &argc, &argv, &error)) {
440     g_print ("%s\nRun '%s --help' to see a full list of available command line options.\n",
441         error->message, argv[0]);
442     g_warning ("Error in empathy init: %s", error->message);
443     return EXIT_FAILURE;
444   }
445
446   g_option_context_free (optcontext);
447
448   empathy_gtk_init ();
449   g_set_application_name (_(PACKAGE_NAME));
450
451   gtk_window_set_default_icon_name ("empathy");
452   textdomain (GETTEXT_PACKAGE);
453
454 #ifdef ENABLE_DEBUG
455   /* Set up debug sender */
456   debug_sender = tp_debug_sender_dup ();
457   g_log_set_default_handler (tp_debug_sender_log_handler, G_LOG_DOMAIN);
458 #endif
459
460   unique_app = unique_app_new ("org.gnome."PACKAGE_NAME, NULL);
461
462   if (unique_app_is_running (unique_app))
463     {
464       unique_app_send_message (unique_app, UNIQUE_ACTIVATE, NULL);
465
466       g_object_unref (unique_app);
467       return EXIT_SUCCESS;
468     }
469
470   notify_init (_(PACKAGE_NAME));
471
472   /* Setting up Idle */
473   idle = empathy_idle_dup_singleton ();
474
475   gsettings = g_settings_new (EMPATHY_PREFS_SCHEMA);
476   autoaway = g_settings_get_boolean (gsettings, EMPATHY_PREFS_AUTOAWAY);
477
478   g_signal_connect (gsettings,
479       "changed::" EMPATHY_PREFS_AUTOAWAY,
480       G_CALLBACK (empathy_idle_set_auto_away_cb), idle);
481
482   empathy_idle_set_auto_away (idle, autoaway);
483
484   /* Setting up Connectivity */
485   connectivity = empathy_connectivity_dup_singleton ();
486   use_conn_notify_cb (gsettings, EMPATHY_PREFS_USE_CONN,
487       connectivity);
488   g_signal_connect (gsettings,
489       "changed::" EMPATHY_PREFS_USE_CONN,
490       G_CALLBACK (use_conn_notify_cb), connectivity);
491
492   /* account management */
493   account_manager = tp_account_manager_dup ();
494   tp_account_manager_prepare_async (account_manager, NULL,
495       account_manager_ready_cb, NULL);
496
497   /* The EmpathyDispatcher doesn't dispatch anything any more but we have to
498    * keep it around as we still use it to request channels */
499   dispatcher = empathy_dispatcher_dup_singleton ();
500
501   migrate_config_to_xdg_dir ();
502
503   /* Setting up UI */
504   window = empathy_main_window_dup ();
505   gtk_widget_show (window);
506   icon = empathy_status_icon_new (GTK_WINDOW (window), start_hidden);
507
508   /* Chat manager */
509   chat_manager = empathy_chat_manager_dup_singleton ();
510
511   g_signal_connect (unique_app, "message-received",
512       G_CALLBACK (unique_app_message_cb), window);
513
514   /* Logging */
515   log_manager = tpl_log_manager_dup_singleton ();
516
517   chatroom_manager = empathy_chatroom_manager_dup_singleton (NULL);
518
519   g_object_get (chatroom_manager, "ready", &chatroom_manager_ready, NULL);
520   if (!chatroom_manager_ready)
521     {
522       g_signal_connect (G_OBJECT (chatroom_manager), "notify::ready",
523           G_CALLBACK (chatroom_manager_ready_cb), account_manager);
524     }
525   else
526     {
527       chatroom_manager_ready_cb (chatroom_manager, NULL, account_manager);
528     }
529
530   /* Create the FT factory */
531   ft_factory = empathy_ft_factory_dup_singleton ();
532   g_signal_connect (ft_factory, "new-ft-handler",
533       G_CALLBACK (new_ft_handler_cb), NULL);
534   g_signal_connect (ft_factory, "new-incoming-transfer",
535       G_CALLBACK (new_incoming_transfer_cb), NULL);
536
537   if (!empathy_ft_factory_register (ft_factory, &error))
538     {
539       g_warning ("Failed to register FileTransfer handler: %s", error->message);
540       g_error_free (error);
541     }
542
543   /* Location mananger */
544 #ifdef HAVE_GEOCLUE
545   location_manager = empathy_location_manager_dup_singleton ();
546 #endif
547
548   gtk_main ();
549
550   empathy_idle_set_state (idle, TP_CONNECTION_PRESENCE_TYPE_OFFLINE);
551
552 #ifdef ENABLE_DEBUG
553   g_object_unref (debug_sender);
554 #endif
555
556   g_object_unref (chat_manager);
557   g_object_unref (idle);
558   g_object_unref (connectivity);
559   g_object_unref (icon);
560   g_object_unref (account_manager);
561   g_object_unref (log_manager);
562   g_object_unref (dispatcher);
563   g_object_unref (chatroom_manager);
564 #ifdef HAVE_GEOCLUE
565   g_object_unref (location_manager);
566 #endif
567   g_object_unref (ft_factory);
568   g_object_unref (unique_app);
569   g_object_unref (gsettings);
570   gtk_widget_destroy (window);
571
572   notify_uninit ();
573   xmlCleanupParser ();
574
575   return EXIT_SUCCESS;
576 }