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
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.
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.
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
28 #include "conversation.h"
30 #include "dbus-maybe.h"
32 #include "eventloop.h"
43 #include "whiteboard.h"
45 #include "gtkaccount.h"
50 #include "gtkdialogs.h"
51 #include "gtkdocklet.h"
52 #include "gtkeventloop.h"
57 #include "gtknotify.h"
58 #include "gtkplugin.h"
59 #include "gtkpounce.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"
68 #include "gtkthemes.h"
70 #include "pidginstock.h"
71 #include "gtkwhiteboard.h"
83 * Lists of signals we wish to catch and those we wish to ignore.
84 * Each list terminated with -1
86 static const int catch_sig_list
[] = {
92 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING)
98 static const int ignore_sig_list
[] = {
105 dologin_named(const char *name
)
107 PurpleAccount
*account
;
111 if (name
!= NULL
) { /* list of names given */
112 names
= g_strsplit(name
, ",", 64);
113 for (i
= 0; names
[i
] != NULL
; i
++) {
114 account
= purple_accounts_find(names
[i
], NULL
);
115 if (account
!= NULL
) { /* found a user */
116 purple_account_set_enabled(account
, PIDGIN_UI
, TRUE
);
120 } else { /* no name given, use the first account */
123 accounts
= purple_accounts_get_all();
124 if (accounts
!= NULL
)
126 account
= (PurpleAccount
*)accounts
->data
;
127 purple_account_set_enabled(account
, PIDGIN_UI
, TRUE
);
133 static char *segfault_message
;
135 static int signal_sockets
[2];
137 static void sighandler(int sig
);
140 * This child process reaping stuff is currently only used for processes that
141 * were forked to play sounds. It's not needed for forked DNS child, which
142 * have their own waitpid() call. It might be wise to move this code into
152 pid
= waitpid(-1, &status
, WNOHANG
);
153 } while (pid
!= 0 && pid
!= (pid_t
)-1);
155 if ((pid
== (pid_t
) - 1) && (errno
!= ECHILD
)) {
157 snprintf(errmsg
, sizeof(errmsg
), "Warning: waitpid() returned %d", pid
);
162 static void sighandler(int sig
)
167 * We won't do any of the heavy lifting for the signal handling here
168 * because we have no idea what was interrupted. Previously this signal
169 * handler could result in some calls to malloc/free, which can cause
170 * deadlock in libc when the signal handler was interrupting a previous
171 * malloc or free. So instead we'll do an ugly hack where we write the
172 * signal number to one end of a socket pair. The other half of the
173 * socket pair is watched by our main loop. When the main loop sees new
174 * data on the socket it reads in the signal and performs the appropriate
175 * action without fear of interrupting stuff.
177 if (sig
== SIGSEGV
) {
178 fprintf(stderr
, "%s", segfault_message
);
183 written
= write(signal_sockets
[0], &sig
, sizeof(int));
184 if (written
< 0 || written
!= sizeof(int)) {
185 /* This should never happen */
186 purple_debug_error("sighandler", "Received signal %d but only "
187 "wrote %" G_GSSIZE_FORMAT
" bytes out of %"
188 G_GSIZE_FORMAT
": %s\n",
189 sig
, written
, sizeof(int), g_strerror(errno
));
195 mainloop_sighandler(GIOChannel
*source
, GIOCondition cond
, gpointer data
)
200 GError
*error
= NULL
;
202 /* read the signal number off of the io channel */
203 stat
= g_io_channel_read_chars(source
, (gchar
*)&sig
, sizeof(int),
204 &bytes_read
, &error
);
205 if (stat
!= G_IO_STATUS_NORMAL
) {
206 purple_debug_error("sighandler", "Signal callback failed to read "
207 "from signal socket: %s", error
->message
);
213 #if defined(USE_GSTREAMER) && !defined(GST_CAN_DISABLE_FORKING)
214 /* By default, gstreamer forks when you initialize it, and waitpids for the
215 * child. But if libpurple reaps the child rather than leaving it to
216 * gstreamer, gstreamer's initialization fails. So, we wait a second before
217 * reaping child processes, to give gst a chance to reap it if it wants to.
219 * This is not needed in later gstreamers, which let us disable the forking.
220 * And, it breaks the world on some Real Unices.
223 /* Restore signal catching */
224 signal(SIGCHLD
, sighandler
);
232 /* Restore signal catching */
233 signal(SIGCHLD
, sighandler
);
236 purple_debug_warning("sighandler", "Caught signal %d\n", sig
);
249 GdkPixbuf
*icon
= NULL
;
254 const char *filename
;
256 {"16x16", "pidgin.png"},
257 {"24x24", "pidgin.png"},
258 {"32x32", "pidgin.png"},
259 {"48x48", "pidgin.png"},
260 {"scalable", "pidgin.svg"}
265 pidgin_themes_init();
267 pidgin_blist_setup_sort_methods();
270 /* use the nice PNG icon for all the windows */
271 for(i
=0; i
<G_N_ELEMENTS(icon_sizes
); i
++) {
272 icon_path
= g_build_filename(DATADIR
, "icons", "hicolor", icon_sizes
[i
].dir
, "apps", icon_sizes
[i
].filename
, NULL
);
273 icon
= pidgin_pixbuf_new_from_file(icon_path
);
276 icons
= g_list_append(icons
,icon
);
278 purple_debug_error("ui_main",
279 "Failed to load the default window icon (%spx version)!\n", icon_sizes
[i
].dir
);
283 purple_debug_error("ui_main", "Unable to load any size of default window icon!\n");
285 gtk_window_set_default_icon_list(icons
);
287 g_list_foreach(icons
, (GFunc
)g_object_unref
, NULL
);
298 purple_debug_set_ui_ops(pidgin_debug_get_ui_ops());
307 /* Set the UI operation structures. */
308 purple_accounts_set_ui_ops(pidgin_accounts_get_ui_ops());
309 purple_xfers_set_ui_ops(pidgin_xfers_get_ui_ops());
310 purple_blist_set_ui_ops(pidgin_blist_get_ui_ops());
311 purple_notify_set_ui_ops(pidgin_notify_get_ui_ops());
312 purple_privacy_set_ui_ops(pidgin_privacy_get_ui_ops());
313 purple_request_set_ui_ops(pidgin_request_get_ui_ops());
314 purple_sound_set_ui_ops(pidgin_sound_get_ui_ops());
315 purple_connections_set_ui_ops(pidgin_connections_get_ui_ops());
316 purple_whiteboard_set_ui_ops(pidgin_whiteboard_get_ui_ops());
317 #if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
318 purple_idle_set_ui_ops(pidgin_idle_get_ui_ops());
321 pidgin_account_init();
322 pidgin_connection_init();
324 pidgin_status_init();
325 pidgin_conversations_init();
326 pidgin_pounces_init();
327 pidgin_privacy_init();
329 pidgin_roomlist_init();
331 pidgin_docklet_init();
332 pidgin_smileys_init();
334 pidgin_medias_init();
335 pidgin_notify_init();
338 static GHashTable
*ui_info
= NULL
;
345 pidgin_session_end();
349 pidgin_utils_uninit();
350 pidgin_notify_uninit();
351 pidgin_smileys_uninit();
352 pidgin_conversations_uninit();
353 pidgin_status_uninit();
354 pidgin_docklet_uninit();
355 pidgin_blist_uninit();
356 pidgin_connection_uninit();
357 pidgin_account_uninit();
358 pidgin_xfers_uninit();
359 pidgin_debug_uninit();
362 g_hash_table_destroy(ui_info
);
364 /* and end it all... */
368 static GHashTable
*pidgin_ui_get_info(void)
370 if(NULL
== ui_info
) {
371 ui_info
= g_hash_table_new(g_str_hash
, g_str_equal
);
373 g_hash_table_insert(ui_info
, "name", (char*)PIDGIN_NAME
);
374 g_hash_table_insert(ui_info
, "version", VERSION
);
375 g_hash_table_insert(ui_info
, "website", "http://pidgin.im");
376 g_hash_table_insert(ui_info
, "dev_website", "http://developer.pidgin.im");
377 g_hash_table_insert(ui_info
, "client_type", "pc");
380 * prpl-aim-clientkey is a DevID (or "client key") for Pidgin, given to
381 * us by AOL in September 2016. prpl-icq-clientkey is also a client key
382 * for Pidgin, owned by the AIM account "markdoliner." Please don't use
383 * either for other applications. Instead, you can either not specify a
384 * client key, in which case the default "libpurple" key will be used,
385 * or you can try to register your own at the AIM or ICQ web sites
386 * (although this functionality was removed at some point, it's possible
387 * it has been re-added).
389 g_hash_table_insert(ui_info
, "prpl-aim-clientkey", "do1UCeb5gNqxB1S1");
390 g_hash_table_insert(ui_info
, "prpl-icq-clientkey", "ma1cSASNCKFtrdv9");
393 * prpl-aim-distid is a distID for Pidgin, given to us by AOL in
394 * September 2016. prpl-icq-distid is also a distID for Pidgin, given
395 * to us by AOL. Please don't use either for other applications.
396 * Instead, you can just not specify a distID and libpurple will use a
399 g_hash_table_insert(ui_info
, "prpl-aim-distid", GINT_TO_POINTER(1715));
400 g_hash_table_insert(ui_info
, "prpl-icq-distid", GINT_TO_POINTER(1550));
406 static PurpleCoreUiOps core_ops
=
418 static PurpleCoreUiOps
*
419 pidgin_core_get_ui_ops(void)
425 show_usage(const char *name
, gboolean terse
)
430 text
= g_strdup_printf(_("%s %s. Try `%s -h' for more information.\n"), PIDGIN_NAME
, DISPLAY_VERSION
, name
);
432 GString
*str
= g_string_new(NULL
);
433 g_string_append_printf(str
, "%s %s\n", PIDGIN_NAME
, DISPLAY_VERSION
);
434 g_string_append_printf(str
, _("Usage: %s [OPTION]...\n\n"), name
);
435 g_string_append_printf(str
, " -c, --config=%s %s\n",
436 _("DIR"), _("use DIR for config files"));
437 g_string_append_printf(str
, " -d, --debug %s\n",
438 _("print debugging messages to stdout"));
439 g_string_append_printf(str
, " -f, --force-online %s\n",
440 _("force online, regardless of network status"));
441 g_string_append_printf(str
, " -h, --help %s\n",
442 _("display this help and exit"));
443 g_string_append_printf(str
, " -m, --multiple %s\n",
444 _("allow multiple instances"));
445 g_string_append_printf(str
, " -n, --nologin %s\n",
446 _("don't automatically login"));
447 g_string_append_printf(str
, " -l, --login[=%s] %s\n",
449 _("enable specified account(s) (optional argument NAME\n"
451 "specifies account(s) to use, separated by commas.\n"
453 "Without this only the first account will be enabled)."));
455 g_string_append_printf(str
, " --display=DISPLAY %s\n",
456 _("X display to use"));
458 g_string_append_printf(str
, " -v, --version %s\n",
459 _("display the current version and exit"));
460 text
= g_string_free(str
, FALSE
);
463 purple_print_utf8_to_console(stdout
, text
);
467 /* FUCKING GET ME A TOWEL! */
469 /* suppress gcc "no previous prototype" warning */
470 int __cdecl
pidgin_main(HINSTANCE hint
, int argc
, char *argv
[]);
471 int __cdecl
pidgin_main(HINSTANCE hint
, int argc
, char *argv
[])
473 int main(int argc
, char *argv
[])
476 gboolean opt_force_online
= FALSE
;
477 gboolean opt_help
= FALSE
;
478 gboolean opt_login
= FALSE
;
479 gboolean opt_nologin
= FALSE
;
480 gboolean opt_version
= FALSE
;
481 gboolean opt_si
= TRUE
; /* Check for single instance? */
482 char *opt_config_dir_arg
= NULL
;
483 char *opt_login_arg
= NULL
;
484 char *opt_session_arg
= NULL
;
488 int sig_indx
; /* for setting up signal catching */
491 GIOChannel
*signal_channel
;
492 GIOStatus signal_status
;
493 guint signal_channel_watcher
;
495 char *segfault_message_tmp
;
501 gboolean debug_enabled
;
502 gboolean migration_failed
= FALSE
;
503 GList
*active_accounts
;
505 struct option long_options
[] = {
506 {"config", required_argument
, NULL
, 'c'},
507 {"debug", no_argument
, NULL
, 'd'},
508 {"force-online", no_argument
, NULL
, 'f'},
509 {"help", no_argument
, NULL
, 'h'},
510 {"login", optional_argument
, NULL
, 'l'},
511 {"multiple", no_argument
, NULL
, 'm'},
512 {"nologin", no_argument
, NULL
, 'n'},
513 {"session", required_argument
, NULL
, 's'},
514 {"version", no_argument
, NULL
, 'v'},
515 {"display", required_argument
, NULL
, 'D'},
516 {"sync", no_argument
, NULL
, 'S'},
521 debug_enabled
= TRUE
;
523 debug_enabled
= FALSE
;
526 #if !GLIB_CHECK_VERSION(2, 32, 0)
527 /* GLib threading system is automaticaly initialized since 2.32.
528 * For earlier versions, it have to be initialized before calling any
529 * Glib or GTK+ functions.
534 g_set_prgname("Pidgin");
537 bindtextdomain(PACKAGE
, LOCALEDIR
);
538 bind_textdomain_codeset(PACKAGE
, "UTF-8");
542 #ifdef HAVE_SETLOCALE
543 /* Locale initialization is not complete here. See gtk_init_check() */
544 setlocale(LC_ALL
, "");
550 /* We translate this here in case the crash breaks gettext. */
551 segfault_message_tmp
= g_strdup_printf(_(
552 "%s %s has segfaulted and attempted to dump a core file.\n"
553 "This is a bug in the software and has happened through\n"
554 "no fault of your own.\n\n"
555 "If you can reproduce the crash, please notify the developers\n"
556 "by reporting a bug at:\n"
557 "%ssimpleticket/\n\n"
558 "Please make sure to specify what you were doing at the time\n"
559 "and post the backtrace from the core file. If you do not know\n"
560 "how to get the backtrace, please read the instructions at\n"
561 "%swiki/GetABacktrace\n"),
562 PIDGIN_NAME
, DISPLAY_VERSION
, PURPLE_DEVEL_WEBSITE
, PURPLE_DEVEL_WEBSITE
565 /* we have to convert the message (UTF-8 to console
566 charset) early because after a segmentation fault
567 it's not a good practice to allocate memory */
569 segfault_message
= g_locale_from_utf8(segfault_message_tmp
,
570 -1, NULL
, NULL
, &error
);
571 if (segfault_message
!= NULL
) {
572 g_free(segfault_message_tmp
);
575 /* use 'segfault_message_tmp' (UTF-8) as a fallback */
576 g_warning("%s\n", error
->message
);
578 segfault_message
= segfault_message_tmp
;
581 /* Don't mark this for translation. */
582 segfault_message
= g_strdup(
583 "Hi, user. We need to talk.\n"
584 "I think something's gone wrong here. It's probably my fault.\n"
585 "No, really, it's not you... it's me... no no no, I think we get along well\n"
586 "it's just that.... well, I want to see other people. I... what?!? NO! I \n"
587 "haven't been cheating on you!! How many times do you want me to tell you?! And\n"
588 "for the last time, it's just a rash!\n"
593 * Create a socket pair for receiving unix signals from a signal
596 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, signal_sockets
) < 0) {
597 perror("Failed to create sockets for GLib signal handling");
600 signal_channel
= g_io_channel_unix_new(signal_sockets
[1]);
603 * Set the channel encoding to raw binary instead of the default of
604 * UTF-8, because we'll be sending integers across instead of strings.
607 signal_status
= g_io_channel_set_encoding(signal_channel
, NULL
, &error
);
608 if (signal_status
!= G_IO_STATUS_NORMAL
) {
609 fprintf(stderr
, "Failed to set the signal channel to raw "
610 "binary: %s", error
->message
);
613 signal_channel_watcher
= g_io_add_watch(signal_channel
, G_IO_IN
, mainloop_sighandler
, NULL
);
614 g_io_channel_unref(signal_channel
);
616 /* Let's not violate any PLA's!!!! */
617 /* jseymour: whatever the fsck that means */
618 /* Robot101: for some reason things like gdm like to block *
619 * useful signals like SIGCHLD, so we unblock all the ones we *
620 * declare a handler for. thanks JSeymour and Vann. */
621 if (sigemptyset(&sigset
)) {
622 snprintf(errmsg
, sizeof(errmsg
), "Warning: couldn't initialise empty signal set");
625 for(sig_indx
= 0; catch_sig_list
[sig_indx
] != -1; ++sig_indx
) {
626 if(signal(catch_sig_list
[sig_indx
], sighandler
) == SIG_ERR
) {
627 snprintf(errmsg
, sizeof(errmsg
), "Warning: couldn't set signal %d for catching",
628 catch_sig_list
[sig_indx
]);
631 if(sigaddset(&sigset
, catch_sig_list
[sig_indx
])) {
632 snprintf(errmsg
, sizeof(errmsg
), "Warning: couldn't include signal %d for unblocking",
633 catch_sig_list
[sig_indx
]);
637 for(sig_indx
= 0; ignore_sig_list
[sig_indx
] != -1; ++sig_indx
) {
638 if(signal(ignore_sig_list
[sig_indx
], SIG_IGN
) == SIG_ERR
) {
639 snprintf(errmsg
, sizeof(errmsg
), "Warning: couldn't set signal %d to ignore",
640 ignore_sig_list
[sig_indx
]);
645 if (sigprocmask(SIG_UNBLOCK
, &sigset
, NULL
)) {
646 snprintf(errmsg
, sizeof(errmsg
), "Warning: couldn't unblock signals");
651 /* scan command-line options */
653 while ((opt
= getopt_long(argc
, argv
,
659 long_options
, NULL
)) != -1) {
661 case 'c': /* config dir */
662 g_free(opt_config_dir_arg
);
663 opt_config_dir_arg
= g_strdup(optarg
);
665 case 'd': /* debug */
666 debug_enabled
= TRUE
;
668 case 'f': /* force-online */
669 opt_force_online
= TRUE
;
674 case 'n': /* no autologin */
677 case 'l': /* login, option username */
679 g_free(opt_login_arg
);
681 opt_login_arg
= g_strdup(optarg
);
683 case 's': /* use existing session ID */
684 g_free(opt_session_arg
);
685 opt_session_arg
= g_strdup(optarg
);
687 case 'v': /* version */
690 case 'm': /* do not ensure single instance. */
693 case 'D': /* --display */
694 case 'S': /* --sync */
695 /* handled by gtk_init_check below */
697 case '?': /* show terse help */
699 show_usage(argv
[0], TRUE
);
701 g_free(segfault_message
);
708 /* show help message */
710 show_usage(argv
[0], FALSE
);
712 g_free(segfault_message
);
716 /* show version message */
718 printf("%s %s (libpurple %s)\n", PIDGIN_NAME
, DISPLAY_VERSION
,
719 purple_core_get_version());
721 g_free(segfault_message
);
726 /* set a user-specified config directory */
727 if (opt_config_dir_arg
!= NULL
) {
728 purple_util_set_user_dir(opt_config_dir_arg
);
732 * We're done piddling around with command line arguments.
736 purple_debug_set_enabled(debug_enabled
);
738 /* If we're using a custom configuration directory, we
739 * do NOT want to migrate, or weird things will happen. */
740 if (opt_config_dir_arg
== NULL
)
742 if (!purple_core_migrate())
744 migration_failed
= TRUE
;
748 search_path
= g_build_filename(purple_user_dir(), "gtkrc-2.0", NULL
);
749 gtk_rc_add_default_file(search_path
);
752 gui_check
= gtk_init_check(&argc
, &argv
);
754 char *display
= gdk_get_display();
756 printf("%s %s\n", PIDGIN_NAME
, DISPLAY_VERSION
);
758 g_warning("cannot open display: %s", display
? display
: "unset");
761 g_free(segfault_message
);
767 g_set_application_name(PIDGIN_NAME
);
770 winpidgin_init(hint
);
773 if (migration_failed
)
775 char *old
= g_strconcat(purple_home_dir(),
776 G_DIR_SEPARATOR_S
".gaim", NULL
);
777 const char *text
= _(
778 "%s encountered errors migrating your settings "
779 "from %s to %s. Please investigate and complete the "
780 "migration by hand. Please report this error at http://developer.pidgin.im");
783 dialog
= gtk_message_dialog_new(NULL
,
788 old
, purple_user_dir());
791 g_signal_connect_swapped(dialog
, "response",
792 G_CALLBACK(gtk_main_quit
), NULL
);
794 gtk_widget_show_all(dialog
);
799 g_free(segfault_message
);
804 purple_core_set_ui_ops(pidgin_core_get_ui_ops());
805 purple_eventloop_set_ui_ops(pidgin_eventloop_get_ui_ops());
808 * Set plugin search directories. Give priority to the plugins
809 * in user's home directory.
811 search_path
= g_build_filename(purple_user_dir(), "plugins", NULL
);
812 if (g_mkdir(search_path
, S_IRUSR
| S_IWUSR
| S_IXUSR
) != 0 && errno
!= EEXIST
)
813 fprintf(stderr
, "Couldn't create plugins dir\n");
814 purple_plugins_add_search_path(search_path
);
816 purple_plugins_add_search_path(LIBDIR
);
818 if (!purple_core_init(PIDGIN_UI
)) {
820 "Initialization of the libpurple core failed. Dumping core.\n"
821 "Please report this!\n");
823 g_free(segfault_message
);
828 if (opt_si
&& !purple_core_ensure_single_instance()) {
830 DBusConnection
*conn
= purple_dbus_get_connection();
831 DBusMessage
*message
= dbus_message_new_method_call(DBUS_SERVICE_PURPLE
, DBUS_PATH_PURPLE
,
832 DBUS_INTERFACE_PURPLE
, "PurpleBlistSetVisible");
834 dbus_message_append_args(message
, DBUS_TYPE_INT32
, &tr
, DBUS_TYPE_INVALID
);
835 dbus_connection_send_with_reply_and_block(conn
, message
, -1, NULL
);
836 dbus_message_unref(message
);
838 gdk_notify_startup_complete();
840 g_printerr(_("Exiting because another libpurple client is already running.\n"));
842 g_free(segfault_message
);
847 /* TODO: Move blist loading into purple_blist_init() */
848 purple_set_blist(purple_blist_new());
851 /* load plugins we had when we quit */
852 purple_plugins_load_saved(PIDGIN_PREFS_ROOT
"/plugins/loaded");
854 /* TODO: Move pounces loading into purple_pounces_init() */
855 purple_pounces_load();
860 pidgin_session_init(argv
[0], opt_session_arg
, opt_config_dir_arg
);
862 if (opt_session_arg
!= NULL
) {
863 g_free(opt_session_arg
);
864 opt_session_arg
= NULL
;
866 if (opt_config_dir_arg
!= NULL
) {
867 g_free(opt_config_dir_arg
);
868 opt_config_dir_arg
= NULL
;
871 /* This needs to be before purple_blist_show() so the
872 * statusbox gets the forced online status. */
873 if (opt_force_online
)
874 purple_network_force_online();
877 * We want to show the blist early in the init process so the
878 * user feels warm and fuzzy (not cold and prickley).
882 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/debug/enabled"))
883 pidgin_debug_window_show();
886 /* disable all accounts */
887 for (accounts
= purple_accounts_get_all(); accounts
!= NULL
; accounts
= accounts
->next
) {
888 PurpleAccount
*account
= accounts
->data
;
889 purple_account_set_enabled(account
, PIDGIN_UI
, FALSE
);
891 /* honor the startup status preference */
892 if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status"))
893 purple_savedstatus_activate(purple_savedstatus_get_startup());
894 /* now enable the requested ones */
895 dologin_named(opt_login_arg
);
896 if (opt_login_arg
!= NULL
) {
897 g_free(opt_login_arg
);
898 opt_login_arg
= NULL
;
900 } else if (opt_nologin
) {
901 /* Set all accounts to "offline" */
902 PurpleSavedStatus
*saved_status
;
904 /* If we've used this type+message before, lookup the transient status */
905 saved_status
= purple_savedstatus_find_transient_by_type_and_message(
906 PURPLE_STATUS_OFFLINE
, NULL
);
908 /* If this type+message is unique then create a new transient saved status */
909 if (saved_status
== NULL
)
910 saved_status
= purple_savedstatus_new(NULL
, PURPLE_STATUS_OFFLINE
);
912 /* Set the status for each account */
913 purple_savedstatus_activate(saved_status
);
915 /* Everything is good to go--sign on already */
916 if (!purple_prefs_get_bool("/purple/savedstatus/startup_current_status"))
917 purple_savedstatus_activate(purple_savedstatus_get_startup());
918 purple_accounts_restore_current_statuses();
921 if ((active_accounts
= purple_accounts_get_all_active()) == NULL
)
923 pidgin_accounts_window_show();
927 g_list_free(active_accounts
);
930 /* GTK clears the notification for us when opening the first window,
931 * but we may have launched with only a status icon, so clear the it
933 gdk_notify_startup_complete();
936 winpidgin_post_init();
942 g_free(segfault_message
);
943 g_source_remove(signal_channel_watcher
);
944 close(signal_sockets
[0]);
945 close(signal_sockets
[1]);