pidgin/gtkpidgin.c

branch
soc.2013.gobjectification.plugins
changeset 36875
e77b9f184125
parent 36825
2f4439558507
child 36877
b2b1ef1c9b7f
equal deleted inserted replaced
36874:3560f0bc6eaf 36875:e77b9f184125
1 /*
2 * pidgin
3 *
4 * Pidgin is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
21 *
22 */
23
24 #include "internal.h"
25 #include "pidgin.h"
26
27 #include "account.h"
28 #include "conversation.h"
29 #include "core.h"
30 #include "dbus-maybe.h"
31 #include "debug.h"
32 #include "eventloop.h"
33 #include "xfer.h"
34 #include "log.h"
35 #include "network.h"
36 #include "notify.h"
37 #include "prefs.h"
38 #include "protocol.h"
39 #include "pounce.h"
40 #include "sound.h"
41 #include "status.h"
42 #include "util.h"
43 #include "whiteboard.h"
44
45 #include "gtkaccount.h"
46 #include "gtkblist.h"
47 #include "gtkconn.h"
48 #include "gtkconv.h"
49 #include "gtkdebug.h"
50 #include "gtkdialogs.h"
51 #include "gtkdocklet.h"
52 #include "gtkeventloop.h"
53 #include "gtkxfer.h"
54 #include "gtkidle.h"
55 #include "gtklog.h"
56 #include "gtkmedia.h"
57 #include "gtknotify.h"
58 #include "gtkplugin.h"
59 #include "gtkpounce.h"
60 #include "gtkprefs.h"
61 #include "gtkprivacy.h"
62 #include "gtkrequest.h"
63 #include "gtkroomlist.h"
64 #include "gtksavedstatuses.h"
65 #include "gtksession.h"
66 #include "gtksmiley.h"
67 #include "gtksound.h"
68 #include "gtkthemes.h"
69 #include "gtkutils.h"
70 #include "pidginstock.h"
71 #include "gtkwhiteboard.h"
72
73 #ifdef HAVE_SIGNAL_H
74 # include <signal.h>
75 #endif
76
77 #ifdef ENABLE_INTROSPECTION
78 # include <girepository.h>
79 #endif
80
81 #include <getopt.h>
82
83
84 #ifdef HAVE_SIGNAL_H
85
86 /*
87 * Lists of signals we wish to catch and those we wish to ignore.
88 * Each list terminated with -1
89 */
90 static const int catch_sig_list[] = {
91 SIGSEGV,
92 SIGINT,
93 SIGTERM,
94 SIGQUIT,
95 SIGCHLD,
96 -1
97 };
98
99 static const int ignore_sig_list[] = {
100 SIGPIPE,
101 -1
102 };
103 #endif
104
105 static void
106 dologin_named(const char *name)
107 {
108 PurpleAccount *account;
109 char **names;
110 int i;
111
112 if (name != NULL) { /* list of names given */
113 names = g_strsplit(name, ",", 64);
114 for (i = 0; names[i] != NULL; i++) {
115 account = purple_accounts_find(names[i], NULL);
116 if (account != NULL) { /* found a user */
117 purple_account_set_enabled(account, PIDGIN_UI, TRUE);
118 }
119 }
120 g_strfreev(names);
121 } else { /* no name given, use the first account */
122 GList *accounts;
123
124 accounts = purple_accounts_get_all();
125 if (accounts != NULL)
126 {
127 account = (PurpleAccount *)accounts->data;
128 purple_account_set_enabled(account, PIDGIN_UI, TRUE);
129 }
130 }
131 }
132
133 #ifdef HAVE_SIGNAL_H
134 static char *segfault_message;
135
136 static int signal_sockets[2];
137
138 static void sighandler(int sig);
139
140 static void sighandler(int sig)
141 {
142 ssize_t written;
143
144 /*
145 * We won't do any of the heavy lifting for the signal handling here
146 * because we have no idea what was interrupted. Previously this signal
147 * handler could result in some calls to malloc/free, which can cause
148 * deadlock in libc when the signal handler was interrupting a previous
149 * malloc or free. So instead we'll do an ugly hack where we write the
150 * signal number to one end of a socket pair. The other half of the
151 * socket pair is watched by our main loop. When the main loop sees new
152 * data on the socket it reads in the signal and performs the appropriate
153 * action without fear of interrupting stuff.
154 */
155 if (sig == SIGSEGV) {
156 fprintf(stderr, "%s", segfault_message);
157 abort();
158 return;
159 }
160
161 written = write(signal_sockets[0], &sig, sizeof(int));
162 if (written < 0 || written != sizeof(int)) {
163 /* This should never happen */
164 purple_debug_error("sighandler", "Received signal %d but only "
165 "wrote %" G_GSSIZE_FORMAT " bytes out of %"
166 G_GSIZE_FORMAT ": %s\n",
167 sig, written, sizeof(int), g_strerror(errno));
168 exit(1);
169 }
170 }
171
172 static gboolean
173 mainloop_sighandler(GIOChannel *source, GIOCondition cond, gpointer data)
174 {
175 GIOStatus stat;
176 int sig;
177 gsize bytes_read;
178 GError *error = NULL;
179
180 /* read the signal number off of the io channel */
181 stat = g_io_channel_read_chars(source, (gchar *)&sig, sizeof(int),
182 &bytes_read, &error);
183 if (stat != G_IO_STATUS_NORMAL) {
184 purple_debug_error("sighandler", "Signal callback failed to read "
185 "from signal socket: %s", error->message);
186 purple_core_quit();
187 return FALSE;
188 }
189
190 switch (sig) {
191 case SIGCHLD:
192 /* Restore signal catching */
193 signal(SIGCHLD, sighandler);
194 break;
195 default:
196 purple_debug_warning("sighandler", "Caught signal %d\n", sig);
197 purple_core_quit();
198 }
199
200 return TRUE;
201 }
202 #endif
203
204 static int
205 ui_main(void)
206 {
207 #ifndef _WIN32
208 GList *icons = NULL;
209 GdkPixbuf *icon = NULL;
210 char *icon_path;
211 gsize i;
212 struct {
213 const char *dir;
214 const char *filename;
215 } icon_sizes[] = {
216 {"16x16", "pidgin.png"},
217 {"24x24", "pidgin.png"},
218 {"32x32", "pidgin.png"},
219 {"48x48", "pidgin.png"},
220 {"scalable", "pidgin.svg"}
221 };
222
223 #endif
224
225 pidgin_themes_init();
226
227 pidgin_blist_setup_sort_methods();
228
229 #ifndef _WIN32
230 /* use the nice PNG icon for all the windows */
231 for(i=0; i<G_N_ELEMENTS(icon_sizes); i++) {
232 icon_path = g_build_filename(DATADIR, "icons", "hicolor", icon_sizes[i].dir, "apps", icon_sizes[i].filename, NULL);
233 icon = pidgin_pixbuf_new_from_file(icon_path);
234 g_free(icon_path);
235 if (icon) {
236 icons = g_list_append(icons,icon);
237 } else {
238 purple_debug_error("ui_main",
239 "Failed to load the default window icon (%spx version)!\n", icon_sizes[i].dir);
240 }
241 }
242 if(NULL == icons) {
243 purple_debug_error("ui_main", "Unable to load any size of default window icon!\n");
244 } else {
245 gtk_window_set_default_icon_list(icons);
246
247 g_list_foreach(icons, (GFunc)g_object_unref, NULL);
248 g_list_free(icons);
249 }
250 #endif
251
252 return 0;
253 }
254
255 static void
256 debug_init(void)
257 {
258 purple_debug_set_ui_ops(pidgin_debug_get_ui_ops());
259 pidgin_debug_init();
260 }
261
262 static void
263 pidgin_ui_init(void)
264 {
265 pidgin_stock_init();
266
267 /* Set the UI operation structures. */
268 purple_accounts_set_ui_ops(pidgin_accounts_get_ui_ops());
269 purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops());
270 purple_blist_set_ui_ops(pidgin_blist_get_ui_ops());
271 purple_notify_set_ui_ops(pidgin_notify_get_ui_ops());
272 purple_request_set_ui_ops(pidgin_request_get_ui_ops());
273 purple_sound_set_ui_ops(pidgin_sound_get_ui_ops());
274 purple_connections_set_ui_ops(pidgin_connections_get_ui_ops());
275 purple_whiteboard_set_ui_ops(pidgin_whiteboard_get_ui_ops());
276 #if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
277 purple_idle_set_ui_ops(pidgin_idle_get_ui_ops());
278 #endif
279
280 pidgin_accounts_init();
281 pidgin_connection_init();
282 pidgin_blist_init();
283 pidgin_status_init();
284 pidgin_conversations_init();
285 pidgin_pounces_init();
286 pidgin_privacy_init();
287 pidgin_xfers_init();
288 pidgin_roomlist_init();
289 pidgin_log_init();
290 pidgin_docklet_init();
291 pidgin_smileys_init();
292 pidgin_utils_init();
293 pidgin_medias_init();
294 pidgin_notify_init();
295 }
296
297 static GHashTable *ui_info = NULL;
298
299 static void
300 pidgin_quit(void)
301 {
302 #ifdef USE_SM
303 /* unplug */
304 pidgin_session_end();
305 #endif
306
307 /* Uninit */
308 pidgin_utils_uninit();
309 pidgin_notify_uninit();
310 pidgin_smileys_uninit();
311 pidgin_conversations_uninit();
312 pidgin_status_uninit();
313 pidgin_docklet_uninit();
314 pidgin_blist_uninit();
315 pidgin_connection_uninit();
316 pidgin_accounts_uninit();
317 pidgin_xfers_uninit();
318 pidgin_debug_uninit();
319
320 if(NULL != ui_info)
321 g_hash_table_destroy(ui_info);
322
323 /* and end it all... */
324 gtk_main_quit();
325 }
326
327 static GHashTable *pidgin_ui_get_info(void)
328 {
329 if(NULL == ui_info) {
330 ui_info = g_hash_table_new(g_str_hash, g_str_equal);
331
332 g_hash_table_insert(ui_info, "name", (char*)PIDGIN_NAME);
333 g_hash_table_insert(ui_info, "version", VERSION);
334 g_hash_table_insert(ui_info, "website", "https://pidgin.im");
335 g_hash_table_insert(ui_info, "dev_website", "https://developer.pidgin.im");
336 g_hash_table_insert(ui_info, "client_type", "pc");
337
338 /*
339 * This is the client key for "Pidgin." It is owned by the AIM
340 * account "markdoliner." Please don't use this key for other
341 * applications. You can either not specify a client key, in
342 * which case the default "libpurple" key will be used, or you
343 * can try to register your own at the AIM or ICQ web sites
344 * (although this functionality was removed at some point, it's
345 * possible it has been re-added). AOL's old key management
346 * page is http://developer.aim.com/manageKeys.jsp
347 */
348 g_hash_table_insert(ui_info, "protocol-aim-clientkey", "ma1cSASNCKFtrdv9");
349 g_hash_table_insert(ui_info, "protocol-icq-clientkey", "ma1cSASNCKFtrdv9");
350
351 /*
352 * This is the distid for Pidgin, given to us by AOL. Please
353 * don't use this for other applications. You can just not
354 * specify a distid and libpurple will use a default.
355 */
356 g_hash_table_insert(ui_info, "protocol-aim-distid", GINT_TO_POINTER(1550));
357 g_hash_table_insert(ui_info, "protocol-icq-distid", GINT_TO_POINTER(1550));
358 }
359
360 return ui_info;
361 }
362
363 static PurpleCoreUiOps core_ops =
364 {
365 pidgin_prefs_init,
366 debug_init,
367 pidgin_ui_init,
368 pidgin_quit,
369 pidgin_ui_get_info,
370 NULL,
371 NULL,
372 NULL
373 };
374
375 static PurpleCoreUiOps *
376 pidgin_core_get_ui_ops(void)
377 {
378 return &core_ops;
379 }
380
381 static void
382 show_usage(const char *name, gboolean terse)
383 {
384 char *text;
385
386 if (terse) {
387 text = g_strdup_printf(_("%s %s. Try `%s -h' for more information.\n"), PIDGIN_NAME, DISPLAY_VERSION, name);
388 } else {
389 GString *str = g_string_new(NULL);
390 g_string_append_printf(str, "%s %s\n", PIDGIN_NAME, DISPLAY_VERSION);
391 g_string_append_printf(str, _("Usage: %s [OPTION]...\n\n"), name);
392 g_string_append_printf(str, " -c, --config=%s %s\n",
393 _("DIR"), _("use DIR for config files"));
394 g_string_append_printf(str, " -d, --debug[=colored] %s\n",
395 _("print debugging messages to stdout"));
396 g_string_append_printf(str, " -f, --force-online %s\n",
397 _("force online, regardless of network status"));
398 g_string_append_printf(str, " -h, --help %s\n",
399 _("display this help and exit"));
400 g_string_append_printf(str, " -m, --multiple %s\n",
401 _("allow multiple instances"));
402 g_string_append_printf(str, " -n, --nologin %s\n",
403 _("don't automatically login"));
404 g_string_append_printf(str, " -l, --login[=%s] %s\n",
405 _("NAME"),
406 _("enable specified account(s) (optional argument NAME\n"
407 " "
408 "specifies account(s) to use, separated by commas.\n"
409 " "
410 "Without this only the first account will be enabled)."));
411 #ifndef WIN32
412 g_string_append_printf(str, " --display=DISPLAY %s\n",
413 _("X display to use"));
414 #endif /* !WIN32 */
415 g_string_append_printf(str, " -v, --version %s\n",
416 _("display the current version and exit"));
417 text = g_string_free(str, FALSE);
418 }
419
420 purple_print_utf8_to_console(stdout, text);
421 g_free(text);
422 }
423
424 int pidgin_start(int argc, char *argv[])
425 {
426 gboolean opt_force_online = FALSE;
427 gboolean opt_help = FALSE;
428 gboolean opt_login = FALSE;
429 gboolean opt_nologin = FALSE;
430 gboolean opt_version = FALSE;
431 gboolean opt_si = TRUE; /* Check for single instance? */
432 char *opt_config_dir_arg = NULL;
433 char *opt_login_arg = NULL;
434 char *opt_session_arg = NULL;
435 char *search_path;
436 #if GTK_CHECK_VERSION(3,0,0)
437 GtkCssProvider *provider;
438 GdkScreen *screen;
439 #endif
440 GList *accounts;
441 #ifdef HAVE_SIGNAL_H
442 int sig_indx; /* for setting up signal catching */
443 sigset_t sigset;
444 char errmsg[BUFSIZ];
445 GIOChannel *signal_channel;
446 GIOStatus signal_status;
447 guint signal_channel_watcher;
448 #ifndef DEBUG
449 char *segfault_message_tmp;
450 #endif
451 #endif
452 #if defined(HAVE_SIGNAL_H) || GTK_CHECK_VERSION(3,0,0)
453 GError *error;
454 #endif
455 int opt;
456 gboolean gui_check;
457 gboolean debug_enabled, debug_colored;
458 GList *active_accounts;
459 GStatBuf st;
460
461 struct option long_options[] = {
462 {"config", required_argument, NULL, 'c'},
463 {"debug", optional_argument, NULL, 'd'},
464 {"force-online", no_argument, NULL, 'f'},
465 {"help", no_argument, NULL, 'h'},
466 {"login", optional_argument, NULL, 'l'},
467 {"multiple", no_argument, NULL, 'm'},
468 {"nologin", no_argument, NULL, 'n'},
469 {"session", required_argument, NULL, 's'},
470 {"version", no_argument, NULL, 'v'},
471 {"display", required_argument, NULL, 'D'},
472 {"sync", no_argument, NULL, 'S'},
473 #ifdef ENABLE_INTROSPECTION
474 {"introspect-dump", required_argument, NULL, 'i'},
475 #endif
476 {0, 0, 0, 0}
477 };
478
479 debug_colored = FALSE;
480 #ifdef DEBUG
481 debug_enabled = TRUE;
482 #else
483 debug_enabled = FALSE;
484 #endif
485
486 #ifdef ENABLE_NLS
487 bindtextdomain(PACKAGE, LOCALEDIR);
488 bind_textdomain_codeset(PACKAGE, "UTF-8");
489 textdomain(PACKAGE);
490 #endif
491
492 #ifdef HAVE_SETLOCALE
493 /* Locale initialization is not complete here. See gtk_init_check() */
494 setlocale(LC_ALL, "");
495 #endif
496
497 #ifdef HAVE_SIGNAL_H
498
499 #ifndef DEBUG
500 /* We translate this here in case the crash breaks gettext. */
501 segfault_message_tmp = g_strdup_printf(_(
502 "%s %s has segfaulted and attempted to dump a core file.\n"
503 "This is a bug in the software and has happened through\n"
504 "no fault of your own.\n\n"
505 "If you can reproduce the crash, please notify the developers\n"
506 "by reporting a bug at:\n"
507 "%ssimpleticket/\n\n"
508 "Please make sure to specify what you were doing at the time\n"
509 "and post the backtrace from the core file. If you do not know\n"
510 "how to get the backtrace, please read the instructions at\n"
511 "%swiki/GetABacktrace\n"),
512 PIDGIN_NAME, DISPLAY_VERSION, PURPLE_DEVEL_WEBSITE, PURPLE_DEVEL_WEBSITE
513 );
514
515 /* we have to convert the message (UTF-8 to console
516 charset) early because after a segmentation fault
517 it's not a good practice to allocate memory */
518 error = NULL;
519 segfault_message = g_locale_from_utf8(segfault_message_tmp,
520 -1, NULL, NULL, &error);
521 if (segfault_message != NULL) {
522 g_free(segfault_message_tmp);
523 }
524 else {
525 /* use 'segfault_message_tmp' (UTF-8) as a fallback */
526 g_warning("%s\n", error->message);
527 g_error_free(error);
528 segfault_message = segfault_message_tmp;
529 }
530 #else
531 /* Don't mark this for translation. */
532 segfault_message = g_strdup(
533 "Hi, user. We need to talk.\n"
534 "I think something's gone wrong here. It's probably my fault.\n"
535 "No, really, it's not you... it's me... no no no, I think we get along well\n"
536 "it's just that.... well, I want to see other people. I... what?!? NO! I \n"
537 "haven't been cheating on you!! How many times do you want me to tell you?! And\n"
538 "for the last time, it's just a rash!\n"
539 );
540 #endif
541
542 /*
543 * Create a socket pair for receiving unix signals from a signal
544 * handler.
545 */
546 if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_sockets) < 0) {
547 perror("Failed to create sockets for GLib signal handling");
548 exit(1);
549 }
550 signal_channel = g_io_channel_unix_new(signal_sockets[1]);
551
552 /*
553 * Set the channel encoding to raw binary instead of the default of
554 * UTF-8, because we'll be sending integers across instead of strings.
555 */
556 error = NULL;
557 signal_status = g_io_channel_set_encoding(signal_channel, NULL, &error);
558 if (signal_status != G_IO_STATUS_NORMAL) {
559 fprintf(stderr, "Failed to set the signal channel to raw "
560 "binary: %s", error->message);
561 exit(1);
562 }
563 signal_channel_watcher = g_io_add_watch(signal_channel, G_IO_IN, mainloop_sighandler, NULL);
564 g_io_channel_unref(signal_channel);
565
566 /* Let's not violate any PLA's!!!! */
567 /* jseymour: whatever the fsck that means */
568 /* Robot101: for some reason things like gdm like to block *
569 * useful signals like SIGCHLD, so we unblock all the ones we *
570 * declare a handler for. thanks JSeymour and Vann. */
571 if (sigemptyset(&sigset)) {
572 snprintf(errmsg, sizeof(errmsg), "Warning: couldn't initialise empty signal set");
573 perror(errmsg);
574 }
575 for(sig_indx = 0; catch_sig_list[sig_indx] != -1; ++sig_indx) {
576 if(signal(catch_sig_list[sig_indx], sighandler) == SIG_ERR) {
577 snprintf(errmsg, sizeof(errmsg), "Warning: couldn't set signal %d for catching",
578 catch_sig_list[sig_indx]);
579 perror(errmsg);
580 }
581 if(sigaddset(&sigset, catch_sig_list[sig_indx])) {
582 snprintf(errmsg, sizeof(errmsg), "Warning: couldn't include signal %d for unblocking",
583 catch_sig_list[sig_indx]);
584 perror(errmsg);
585 }
586 }
587 for(sig_indx = 0; ignore_sig_list[sig_indx] != -1; ++sig_indx) {
588 if(signal(ignore_sig_list[sig_indx], SIG_IGN) == SIG_ERR) {
589 snprintf(errmsg, sizeof(errmsg), "Warning: couldn't set signal %d to ignore",
590 ignore_sig_list[sig_indx]);
591 perror(errmsg);
592 }
593 }
594
595 if (sigprocmask(SIG_UNBLOCK, &sigset, NULL)) {
596 snprintf(errmsg, sizeof(errmsg), "Warning: couldn't unblock signals");
597 perror(errmsg);
598 }
599 #endif
600
601 /* scan command-line options */
602 opterr = 1;
603 while ((opt = getopt_long(argc, argv,
604 #ifndef _WIN32
605 "c:dfhmnl::s:vi:",
606 #else
607 "c:dfhmnl::vi:",
608 #endif
609 long_options, NULL)) != -1) {
610 switch (opt) {
611 case 'c': /* config dir */
612 g_free(opt_config_dir_arg);
613 opt_config_dir_arg = g_strdup(optarg);
614 break;
615 case 'd': /* debug */
616 debug_enabled = TRUE;
617 if (g_strcmp0(optarg, "colored") == 0)
618 debug_colored = TRUE;
619 break;
620 case 'f': /* force-online */
621 opt_force_online = TRUE;
622 break;
623 case 'h': /* help */
624 opt_help = TRUE;
625 break;
626 case 'n': /* no autologin */
627 opt_nologin = TRUE;
628 break;
629 case 'l': /* login, option username */
630 opt_login = TRUE;
631 g_free(opt_login_arg);
632 if (optarg != NULL)
633 opt_login_arg = g_strdup(optarg);
634 break;
635 case 's': /* use existing session ID */
636 g_free(opt_session_arg);
637 opt_session_arg = g_strdup(optarg);
638 break;
639 case 'v': /* version */
640 opt_version = TRUE;
641 break;
642 case 'm': /* do not ensure single instance. */
643 opt_si = FALSE;
644 break;
645 case 'D': /* --display */
646 case 'S': /* --sync */
647 /* handled by gtk_init_check below */
648 break;
649 #ifdef ENABLE_INTROSPECTION
650 case 'i': /* introspection */
651 g_irepository_dump(optarg, NULL);
652 return 0;
653 break;
654 #endif
655 case '?': /* show terse help */
656 default:
657 show_usage(argv[0], TRUE);
658 #ifdef HAVE_SIGNAL_H
659 g_free(segfault_message);
660 #endif
661 return 0;
662 break;
663 }
664 }
665
666 /* show help message */
667 if (opt_help) {
668 show_usage(argv[0], FALSE);
669 #ifdef HAVE_SIGNAL_H
670 g_free(segfault_message);
671 #endif
672 return 0;
673 }
674 /* show version message */
675 if (opt_version) {
676 printf("%s %s (libpurple %s)\n", PIDGIN_NAME, DISPLAY_VERSION,
677 purple_core_get_version());
678 #ifdef HAVE_SIGNAL_H
679 g_free(segfault_message);
680 #endif
681 return 0;
682 }
683
684 /* set a user-specified config directory */
685 if (opt_config_dir_arg != NULL) {
686 if (g_path_is_absolute(opt_config_dir_arg)) {
687 purple_util_set_user_dir(opt_config_dir_arg);
688 } else {
689 /* Make an absolute (if not canonical) path */
690 char *cwd = g_get_current_dir();
691 char *path = g_build_path(G_DIR_SEPARATOR_S, cwd, opt_config_dir_arg, NULL);
692 purple_util_set_user_dir(path);
693 g_free(path);
694 g_free(cwd);
695 }
696 }
697
698 /*
699 * We're done piddling around with command line arguments.
700 * Fire up this baby.
701 */
702
703 purple_debug_set_enabled(debug_enabled);
704 purple_debug_set_colored(debug_colored);
705
706 #if !GTK_CHECK_VERSION(3,0,0)
707 search_path = g_build_filename(purple_user_dir(), "gtkrc-2.0", NULL);
708 gtk_rc_add_default_file(search_path);
709 g_free(search_path);
710 #endif
711
712 gui_check = gtk_init_check(&argc, &argv);
713 if (!gui_check) {
714 char *display = gdk_get_display();
715
716 printf("%s %s\n", PIDGIN_NAME, DISPLAY_VERSION);
717
718 g_warning("cannot open display: %s", display ? display : "unset");
719 g_free(display);
720 #ifdef HAVE_SIGNAL_H
721 g_free(segfault_message);
722 #endif
723
724 return 1;
725 }
726
727 #if GTK_CHECK_VERSION(3,0,0)
728 search_path = g_build_filename(purple_user_dir(), "gtk-3.0.css", NULL);
729
730 error = NULL;
731 provider = gtk_css_provider_new();
732 gui_check = gtk_css_provider_load_from_path(provider, search_path, &error);
733
734 if (gui_check && !error) {
735 screen = gdk_screen_get_default();
736 gtk_style_context_add_provider_for_screen(screen,
737 GTK_STYLE_PROVIDER(provider),
738 GTK_STYLE_PROVIDER_PRIORITY_USER);
739 } else {
740 purple_debug_error("gtk", "Unable to load custom gtk-3.0.css: %s\n",
741 error ? error->message : "(unknown error)");
742 }
743
744 g_free(search_path);
745 #endif
746
747 #ifdef _WIN32
748 winpidgin_init(hint);
749 #endif
750
751 purple_core_set_ui_ops(pidgin_core_get_ui_ops());
752 purple_eventloop_set_ui_ops(pidgin_eventloop_get_ui_ops());
753
754 if (!purple_core_init(PIDGIN_UI)) {
755 fprintf(stderr,
756 "Initialization of the libpurple core failed. Dumping core.\n"
757 "Please report this!\n");
758 #ifdef HAVE_SIGNAL_H
759 g_free(segfault_message);
760 #endif
761 abort();
762 }
763
764 search_path = g_build_filename(purple_user_dir(), "plugins", NULL);
765 if (!g_stat(search_path, &st))
766 g_mkdir(search_path, S_IRUSR | S_IWUSR | S_IXUSR);
767 purple_plugins_add_search_path(search_path);
768 g_free(search_path);
769
770 purple_plugins_add_search_path(LIBDIR);
771 purple_plugins_refresh();
772
773 if (opt_si && !purple_core_ensure_single_instance()) {
774 #ifdef HAVE_DBUS
775 DBusConnection *conn = purple_dbus_get_connection();
776 DBusMessage *message = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE,
777 DBUS_INTERFACE_PURPLE, "PurpleBlistSetVisible");
778 gboolean tr = TRUE;
779 dbus_message_append_args(message, DBUS_TYPE_INT32, &tr, DBUS_TYPE_INVALID);
780 dbus_connection_send_with_reply_and_block(conn, message, -1, NULL);
781 dbus_message_unref(message);
782 #endif
783 gdk_notify_startup_complete();
784 purple_core_quit();
785 g_printerr(_("Exiting because another libpurple client is already running.\n"));
786 #ifdef HAVE_SIGNAL_H
787 g_free(segfault_message);
788 #endif
789 return 0;
790 }
791
792 /* load plugins we had when we quit */
793 purple_plugins_load_saved(PIDGIN_PREFS_ROOT "/plugins/loaded");
794
795 ui_main();
796
797 #ifdef USE_SM
798 pidgin_session_init(argv[0], opt_session_arg, opt_config_dir_arg);
799 #endif
800 if (opt_session_arg != NULL) {
801 g_free(opt_session_arg);
802 opt_session_arg = NULL;
803 }
804 if (opt_config_dir_arg != NULL) {
805 g_free(opt_config_dir_arg);
806 opt_config_dir_arg = NULL;
807 }
808
809 /* This needs to be before purple_blist_show() so the
810 * statusbox gets the forced online status. */
811 if (opt_force_online)
812 purple_network_force_online();
813
814 /*
815 * We want to show the blist early in the init process so the
816 * user feels warm and fuzzy (not cold and prickley).
817 */
818 purple_blist_show();
819
820 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/debug/enabled"))
821 pidgin_debug_window_show();
822
823 if (opt_login) {
824 /* disable all accounts */
825 for (accounts = purple_accounts_get_all(); accounts != NULL; accounts = accounts->next) {
826 PurpleAccount *account = accounts->data;
827 purple_account_set_enabled(account, PIDGIN_UI, FALSE);
828 }
829 /* honor the startup status preference */
830 if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status"))
831 purple_savedstatus_activate(purple_savedstatus_get_startup());
832 /* now enable the requested ones */
833 dologin_named(opt_login_arg);
834 if (opt_login_arg != NULL) {
835 g_free(opt_login_arg);
836 opt_login_arg = NULL;
837 }
838 } else if (opt_nologin) {
839 /* Set all accounts to "offline" */
840 PurpleSavedStatus *saved_status;
841
842 /* If we've used this type+message before, lookup the transient status */
843 saved_status = purple_savedstatus_find_transient_by_type_and_message(
844 PURPLE_STATUS_OFFLINE, NULL);
845
846 /* If this type+message is unique then create a new transient saved status */
847 if (saved_status == NULL)
848 saved_status = purple_savedstatus_new(NULL, PURPLE_STATUS_OFFLINE);
849
850 /* Set the status for each account */
851 purple_savedstatus_activate(saved_status);
852 } else {
853 /* Everything is good to go--sign on already */
854 if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status"))
855 purple_savedstatus_activate(purple_savedstatus_get_startup());
856 purple_accounts_restore_current_statuses();
857 }
858
859 if ((active_accounts = purple_accounts_get_all_active()) == NULL)
860 {
861 pidgin_accounts_window_show();
862 }
863 else
864 {
865 g_list_free(active_accounts);
866 }
867
868 /* GTK clears the notification for us when opening the first window,
869 * but we may have launched with only a status icon, so clear the it
870 * just in case. */
871 gdk_notify_startup_complete();
872
873 #ifdef _WIN32
874 winpidgin_post_init();
875 #endif
876
877 gtk_main();
878
879 #ifdef HAVE_SIGNAL_H
880 g_free(segfault_message);
881 g_source_remove(signal_channel_watcher);
882 close(signal_sockets[0]);
883 close(signal_sockets[1]);
884 #endif
885
886 #ifdef _WIN32
887 winpidgin_cleanup();
888 #endif
889
890 return 0;
891 }

mercurial