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