pidgin/gtkmain.c

changeset 15435
4b933b06d75e
parent 15434
94dcf9e39d66
child 15498
2ee3112b6f24
equal deleted inserted replaced
15434:94dcf9e39d66 15435:4b933b06d75e
1 /*
2 * gaim
3 *
4 * Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24 #include "internal.h"
25 #include "gtkgaim.h"
26
27 #include "account.h"
28 #include "conversation.h"
29 #include "core.h"
30 #include "debug.h"
31 #include "eventloop.h"
32 #include "ft.h"
33 #include "log.h"
34 #include "notify.h"
35 #include "prefs.h"
36 #include "prpl.h"
37 #include "pounce.h"
38 #include "sound.h"
39 #include "status.h"
40 #include "util.h"
41 #include "whiteboard.h"
42
43 #include "gtkaccount.h"
44 #include "gtkblist.h"
45 #include "gtkconn.h"
46 #include "gtkconv.h"
47 #include "gtkdebug.h"
48 #include "gtkdialogs.h"
49 #include "gtkdocklet.h"
50 #include "gtkeventloop.h"
51 #include "gtkft.h"
52 #include "gtkidle.h"
53 #include "gtklog.h"
54 #include "gtknotify.h"
55 #include "gtkplugin.h"
56 #include "gtkpounce.h"
57 #include "gtkprefs.h"
58 #include "gtkprivacy.h"
59 #include "gtkrequest.h"
60 #include "gtkroomlist.h"
61 #include "gtksavedstatuses.h"
62 #include "gtksession.h"
63 #include "gtksound.h"
64 #include "gtkthemes.h"
65 #include "gtkutils.h"
66 #include "gaimstock.h"
67 #include "gtkwhiteboard.h"
68
69 #ifdef HAVE_SIGNAL_H
70 # include <signal.h>
71 #endif
72
73 #include <getopt.h>
74
75 #ifdef HAVE_STARTUP_NOTIFICATION
76 # define SN_API_NOT_YET_FROZEN
77 # include <libsn/sn-launchee.h>
78 # include <gdk/gdkx.h>
79 #endif
80
81
82
83 #ifdef HAVE_STARTUP_NOTIFICATION
84 static SnLauncheeContext *sn_context = NULL;
85 static SnDisplay *sn_display = NULL;
86 #endif
87
88 #ifdef HAVE_SIGNAL_H
89
90 /*
91 * Lists of signals we wish to catch and those we wish to ignore.
92 * Each list terminated with -1
93 */
94 static int catch_sig_list[] = {
95 SIGSEGV,
96 SIGHUP,
97 SIGINT,
98 SIGTERM,
99 SIGQUIT,
100 SIGCHLD,
101 SIGALRM,
102 -1
103 };
104
105 static int ignore_sig_list[] = {
106 SIGPIPE,
107 -1
108 };
109 #endif
110
111 static int
112 dologin_named(const char *name)
113 {
114 GaimAccount *account;
115 char **names;
116 int i;
117 int ret = -1;
118
119 if (name != NULL) { /* list of names given */
120 names = g_strsplit(name, ",", 64);
121 for (i = 0; names[i] != NULL; i++) {
122 account = gaim_accounts_find(names[i], NULL);
123 if (account != NULL) { /* found a user */
124 ret = 0;
125 gaim_account_connect(account);
126 }
127 }
128 g_strfreev(names);
129 } else { /* no name given, use the first account */
130 GList *accounts;
131
132 accounts = gaim_accounts_get_all();
133 if (accounts != NULL)
134 {
135 account = (GaimAccount *)accounts->data;
136 ret = 0;
137 gaim_account_connect(account);
138 }
139 }
140
141 return ret;
142 }
143
144 #ifdef HAVE_SIGNAL_H
145 static void sighandler(int sig);
146
147 /**
148 * Reap all our dead children. Sometimes Gaim forks off a separate
149 * process to do some stuff. When that process exits we are
150 * informed about it so that we can call waitpid() and let it
151 * stop being a zombie.
152 *
153 * We used to do this immediately when our signal handler was
154 * called, but because of GStreamer we now wait one second before
155 * reaping anything. Why? For some reason GStreamer fork()s
156 * during their initialization process. I don't understand why...
157 * but they do it, and there's nothing we can do about it.
158 *
159 * Anyway, so then GStreamer waits for its child to die and then
160 * it continues with the initialization process. This means that
161 * we have a race condition where GStreamer is waitpid()ing for its
162 * child to die and we're catching the SIGCHLD signal. If GStreamer
163 * is awarded the zombied process then everything is ok. But if Gaim
164 * reaps the zombie process then the GStreamer initialization sequence
165 * fails.
166 *
167 * So the ugly solution is to wait a second to give GStreamer time to
168 * reap that bad boy.
169 *
170 * GStreamer 0.10.10 and newer have a gst_register_fork_set_enabled()
171 * function that can be called by applications to disable forking
172 * during initialization. But it's not in 0.10.0, so we shouldn't
173 * use it.
174 */
175 static void
176 clean_pid()
177 {
178 int status;
179 pid_t pid;
180
181 do {
182 pid = waitpid(-1, &status, WNOHANG);
183 } while (pid != 0 && pid != (pid_t)-1);
184
185 if ((pid == (pid_t) - 1) && (errno != ECHILD)) {
186 char errmsg[BUFSIZ];
187 snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid);
188 perror(errmsg);
189 }
190
191 /* Restore signal catching */
192 signal(SIGALRM, sighandler);
193 }
194
195 char *segfault_message;
196
197 static void
198 sighandler(int sig)
199 {
200 switch (sig) {
201 case SIGHUP:
202 gaim_debug_warning("sighandler", "Caught signal %d\n", sig);
203 gaim_connections_disconnect_all();
204 break;
205 case SIGSEGV:
206 fprintf(stderr, "%s", segfault_message);
207 abort();
208 break;
209 case SIGCHLD:
210 /* Restore signal catching */
211 signal(SIGCHLD, sighandler);
212 alarm(1);
213 break;
214 case SIGALRM:
215 clean_pid();
216 break;
217 default:
218 gaim_debug_warning("sighandler", "Caught signal %d\n", sig);
219 gaim_connections_disconnect_all();
220
221 gaim_plugins_unload_all();
222
223 if (gtk_main_level())
224 gtk_main_quit();
225 exit(0);
226 }
227 }
228 #endif
229
230 static int
231 ui_main()
232 {
233 #ifndef _WIN32
234 GList *icons = NULL;
235 GdkPixbuf *icon = NULL;
236 char *icon_path;
237 #endif
238
239 gaim_gtkthemes_init();
240
241 gaim_gtk_blist_setup_sort_methods();
242
243 #ifndef _WIN32
244 /* use the nice PNG icon for all the windows */
245 icon_path = g_build_filename(DATADIR, "pixmaps", "gaim", "icons", "online.png", NULL);
246 icon = gdk_pixbuf_new_from_file(icon_path, NULL);
247 g_free(icon_path);
248 if (icon) {
249 icons = g_list_append(icons,icon);
250 gtk_window_set_default_icon_list(icons);
251 g_object_unref(G_OBJECT(icon));
252 g_list_free(icons);
253 } else {
254 gaim_debug_error("ui_main",
255 "Failed to load the default window icon!\n");
256 }
257 #endif
258
259 return 0;
260 }
261
262 static void
263 debug_init(void)
264 {
265 gaim_debug_set_ui_ops(gaim_gtk_debug_get_ui_ops());
266 gaim_gtk_debug_init();
267 }
268
269 static void
270 gaim_gtk_ui_init(void)
271 {
272 /* Set the UI operation structures. */
273 gaim_accounts_set_ui_ops(gaim_gtk_accounts_get_ui_ops());
274 gaim_xfers_set_ui_ops(gaim_gtk_xfers_get_ui_ops());
275 gaim_blist_set_ui_ops(gaim_gtk_blist_get_ui_ops());
276 gaim_notify_set_ui_ops(gaim_gtk_notify_get_ui_ops());
277 gaim_privacy_set_ui_ops(gaim_gtk_privacy_get_ui_ops());
278 gaim_request_set_ui_ops(gaim_gtk_request_get_ui_ops());
279 gaim_sound_set_ui_ops(gaim_gtk_sound_get_ui_ops());
280 gaim_connections_set_ui_ops(gaim_gtk_connections_get_ui_ops());
281 gaim_whiteboard_set_ui_ops(gaim_gtk_whiteboard_get_ui_ops());
282 #ifdef USE_SCREENSAVER
283 gaim_idle_set_ui_ops(gaim_gtk_idle_get_ui_ops());
284 #endif
285
286 gaim_gtk_stock_init();
287 gaim_gtk_account_init();
288 gaim_gtk_connection_init();
289 gaim_gtk_blist_init();
290 gaim_gtk_status_init();
291 gaim_gtk_conversations_init();
292 gaim_gtk_pounces_init();
293 gaim_gtk_privacy_init();
294 gaim_gtk_xfers_init();
295 gaim_gtk_roomlist_init();
296 gaim_gtk_log_init();
297 }
298
299 static void
300 gaim_gtk_quit(void)
301 {
302 #ifdef USE_SM
303 /* unplug */
304 gaim_gtk_session_end();
305 #endif
306
307 /* Save the plugins we have loaded for next time. */
308 gaim_gtk_plugins_save();
309
310 /* Uninit */
311 gaim_gtk_conversations_uninit();
312 gaim_gtk_status_uninit();
313 gaim_gtk_docklet_uninit();
314 gaim_gtk_blist_uninit();
315 gaim_gtk_connection_uninit();
316 gaim_gtk_account_uninit();
317 gaim_gtk_xfers_uninit();
318 gaim_gtk_debug_uninit();
319
320 /* and end it all... */
321 gtk_main_quit();
322 }
323
324 static GaimCoreUiOps core_ops =
325 {
326 gaim_gtk_prefs_init,
327 debug_init,
328 gaim_gtk_ui_init,
329 gaim_gtk_quit
330 };
331
332 static GaimCoreUiOps *
333 gaim_gtk_core_get_ui_ops(void)
334 {
335 return &core_ops;
336 }
337
338 static void
339 show_usage(const char *name, gboolean terse)
340 {
341 char *text;
342
343 if (terse) {
344 text = g_strdup_printf(_(PIDGIN_NAME " %s. Try `%s -h' for more information.\n"), VERSION, name);
345 } else {
346 text = g_strdup_printf(_(PIDGIN_NAME " %s\n"
347 "Usage: %s [OPTION]...\n\n"
348 " -c, --config=DIR use DIR for config files\n"
349 " -d, --debug print debugging messages to stdout\n"
350 " -h, --help display this help and exit\n"
351 " -n, --nologin don't automatically login\n"
352 " -l, --login[=NAME] automatically login (optional argument NAME specifies\n"
353 " account(s) to use, separated by commas)\n"
354 " -v, --version display the current version and exit\n"), VERSION, name);
355 }
356
357 gaim_print_utf8_to_console(stdout, text);
358 g_free(text);
359 }
360
361 #ifdef HAVE_STARTUP_NOTIFICATION
362 static void
363 sn_error_trap_push(SnDisplay *display, Display *xdisplay)
364 {
365 gdk_error_trap_push();
366 }
367
368 static void
369 sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
370 {
371 gdk_error_trap_pop();
372 }
373
374 static void
375 startup_notification_complete(void)
376 {
377 Display *xdisplay;
378
379 xdisplay = GDK_DISPLAY();
380 sn_display = sn_display_new(xdisplay,
381 sn_error_trap_push,
382 sn_error_trap_pop);
383 sn_context =
384 sn_launchee_context_new_from_environment(sn_display,
385 DefaultScreen(xdisplay));
386
387 if (sn_context != NULL)
388 {
389 sn_launchee_context_complete(sn_context);
390 sn_launchee_context_unref(sn_context);
391
392 sn_display_unref(sn_display);
393 }
394 }
395 #endif /* HAVE_STARTUP_NOTIFICATION */
396
397 #ifndef _WIN32
398 static char *gaim_find_binary_location(void *symbol, void *data)
399 {
400 static char *fullname = NULL;
401 static gboolean first = TRUE;
402
403 char *argv0 = data;
404 struct stat st;
405 char *basebuf, *linkbuf, *fullbuf;
406
407 if (!first)
408 /* We've already been through this. */
409 return strdup(fullname);
410
411 first = FALSE;
412
413 if (!argv0)
414 return NULL;
415
416
417 basebuf = g_find_program_in_path(argv0);
418
419 /* But we still need to deal with symbolic links */
420 g_lstat(basebuf, &st);
421 while ((st.st_mode & S_IFLNK) == S_IFLNK) {
422 int written;
423 linkbuf = g_malloc(1024);
424 written = readlink(basebuf, linkbuf, 1024 - 1);
425 if (written == -1)
426 {
427 /* This really shouldn't happen, but do we
428 * need something better here? */
429 g_free(linkbuf);
430 continue;
431 }
432 linkbuf[written] = '\0';
433 if (linkbuf[0] == G_DIR_SEPARATOR) {
434 /* an absolute path */
435 fullbuf = g_strdup(linkbuf);
436 } else {
437 char *dirbuf = g_path_get_dirname(basebuf);
438 /* a relative path */
439 fullbuf = g_strdup_printf("%s%s%s",
440 dirbuf, G_DIR_SEPARATOR_S,
441 linkbuf);
442 g_free(dirbuf);
443 }
444 /* There's no memory leak here. Really! */
445 g_free(linkbuf);
446 g_free(basebuf);
447 basebuf = fullbuf;
448 g_lstat(basebuf, &st);
449 }
450
451 fullname = basebuf;
452 return strdup(fullname);
453 }
454 #endif /* #ifndef _WIN32 */
455
456 /* FUCKING GET ME A TOWEL! */
457 #ifdef _WIN32
458 int gaim_main(HINSTANCE hint, int argc, char *argv[])
459 #else
460 int main(int argc, char *argv[])
461 #endif
462 {
463 gboolean opt_help = FALSE;
464 gboolean opt_login = FALSE;
465 gboolean opt_nologin = FALSE;
466 gboolean opt_version = FALSE;
467 char *opt_config_dir_arg = NULL;
468 char *opt_login_arg = NULL;
469 char *opt_session_arg = NULL;
470 int dologin_ret = -1;
471 char *search_path;
472 GList *accounts;
473 #ifdef HAVE_SIGNAL_H
474 int sig_indx; /* for setting up signal catching */
475 sigset_t sigset;
476 RETSIGTYPE (*prev_sig_disp)(int);
477 char errmsg[BUFSIZ];
478 #ifndef DEBUG
479 char *segfault_message_tmp;
480 GError *error = NULL;
481 #endif
482 #endif
483 int opt;
484 gboolean gui_check;
485 gboolean debug_enabled;
486
487 struct option long_options[] = {
488 {"config", required_argument, NULL, 'c'},
489 {"debug", no_argument, NULL, 'd'},
490 {"help", no_argument, NULL, 'h'},
491 {"login", optional_argument, NULL, 'l'},
492 {"nologin", no_argument, NULL, 'n'},
493 {"session", required_argument, NULL, 's'},
494 {"version", no_argument, NULL, 'v'},
495 {0, 0, 0, 0}
496 };
497
498 #ifdef DEBUG
499 debug_enabled = TRUE;
500 #else
501 debug_enabled = FALSE;
502 #endif
503
504 #ifdef GAIM_FATAL_ASSERTS
505 /* Make g_return_... functions fatal. */
506 g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL);
507 #endif
508
509 #ifndef _WIN32
510 br_set_locate_fallback_func(gaim_find_binary_location, argv[0]);
511 #endif
512 #ifdef ENABLE_NLS
513 bindtextdomain(PACKAGE, LOCALEDIR);
514 bind_textdomain_codeset(PACKAGE, "UTF-8");
515 textdomain(PACKAGE);
516 #endif
517
518 #ifdef HAVE_SETLOCALE
519 /* Locale initialization is not complete here. See gtk_init_check() */
520 setlocale(LC_ALL, "");
521 #endif
522
523 #ifdef HAVE_SIGNAL_H
524
525 #ifndef DEBUG
526 /* We translate this here in case the crash breaks gettext. */
527 segfault_message_tmp = g_strdup_printf(_(
528 PIDGIN_NAME " has segfaulted and attempted to dump a core file.\n"
529 "This is a bug in the software and has happened through\n"
530 "no fault of your own.\n\n"
531 "If you can reproduce the crash, please notify the gaim\n"
532 "developers by reporting a bug at\n"
533 "%sbug.php\n\n"
534 "Please make sure to specify what you were doing at the time\n"
535 "and post the backtrace from the core file. If you do not know\n"
536 "how to get the backtrace, please read the instructions at\n"
537 "%sgdb.php\n\n"
538 "If you need further assistance, please IM either SeanEgn or \n"
539 "LSchiere (via AIM). Contact information for Sean and Luke \n"
540 "on other protocols is at\n"
541 "%scontactinfo.php\n"),
542 GAIM_WEBSITE, GAIM_WEBSITE, GAIM_WEBSITE
543 );
544
545 /* we have to convert the message (UTF-8 to console
546 charset) early because after a segmentation fault
547 it's not a good practice to allocate memory */
548 segfault_message = g_locale_from_utf8(segfault_message_tmp,
549 -1, NULL, NULL, &error);
550 if (segfault_message != NULL) {
551 g_free(segfault_message_tmp);
552 }
553 else {
554 /* use 'segfault_message_tmp' (UTF-8) as a fallback */
555 g_warning("%s\n", error->message);
556 g_error_free(error);
557 segfault_message = segfault_message_tmp;
558 }
559 #else
560 /* Don't mark this for translation. */
561 segfault_message = g_strdup(
562 "Hi, user. We need to talk.\n"
563 "I think something's gone wrong here. It's probably my fault.\n"
564 "No, really, it's not you... it's me... no no no, I think we get along well\n"
565 "it's just that.... well, I want to see other people. I... what?!? NO! I \n"
566 "haven't been cheating on you!! How many times do you want me to tell you?! And\n"
567 "for the last time, it's just a rash!\n"
568 );
569 #endif
570
571 /* Let's not violate any PLA's!!!! */
572 /* jseymour: whatever the fsck that means */
573 /* Robot101: for some reason things like gdm like to block *
574 * useful signals like SIGCHLD, so we unblock all the ones we *
575 * declare a handler for. thanks JSeymour and Vann. */
576 if (sigemptyset(&sigset)) {
577 snprintf(errmsg, BUFSIZ, "Warning: couldn't initialise empty signal set");
578 perror(errmsg);
579 }
580 for(sig_indx = 0; catch_sig_list[sig_indx] != -1; ++sig_indx) {
581 if((prev_sig_disp = signal(catch_sig_list[sig_indx], sighandler)) == SIG_ERR) {
582 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d for catching",
583 catch_sig_list[sig_indx]);
584 perror(errmsg);
585 }
586 if(sigaddset(&sigset, catch_sig_list[sig_indx])) {
587 snprintf(errmsg, BUFSIZ, "Warning: couldn't include signal %d for unblocking",
588 catch_sig_list[sig_indx]);
589 perror(errmsg);
590 }
591 }
592 for(sig_indx = 0; ignore_sig_list[sig_indx] != -1; ++sig_indx) {
593 if((prev_sig_disp = signal(ignore_sig_list[sig_indx], SIG_IGN)) == SIG_ERR) {
594 snprintf(errmsg, BUFSIZ, "Warning: couldn't set signal %d to ignore",
595 ignore_sig_list[sig_indx]);
596 perror(errmsg);
597 }
598 }
599
600 if (sigprocmask(SIG_UNBLOCK, &sigset, NULL)) {
601 snprintf(errmsg, BUFSIZ, "Warning: couldn't unblock signals");
602 perror(errmsg);
603 }
604 #endif
605
606 /* scan command-line options */
607 opterr = 1;
608 while ((opt = getopt_long(argc, argv,
609 #ifndef _WIN32
610 "c:dhnl::s:v",
611 #else
612 "c:dhnl::v",
613 #endif
614 long_options, NULL)) != -1) {
615 switch (opt) {
616 case 'c': /* config dir */
617 g_free(opt_config_dir_arg);
618 opt_config_dir_arg = g_strdup(optarg);
619 break;
620 case 'd': /* debug */
621 debug_enabled = 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 '?': /* show terse help */
643 default:
644 show_usage(argv[0], TRUE);
645 return 0;
646 break;
647 }
648 }
649
650 /* show help message */
651 if (opt_help) {
652 show_usage(argv[0], FALSE);
653 return 0;
654 }
655 /* show version message */
656 if (opt_version) {
657 printf(PIDGIN_NAME " %s\n", VERSION);
658 return 0;
659 }
660
661 /* set a user-specified config directory */
662 if (opt_config_dir_arg != NULL) {
663 gaim_util_set_user_dir(opt_config_dir_arg);
664 }
665
666 /*
667 * We're done piddling around with command line arguments.
668 * Fire up this baby.
669 */
670
671 gaim_debug_set_enabled(debug_enabled);
672
673
674 search_path = g_build_filename(gaim_user_dir(), "gtkrc-2.0", NULL);
675 gtk_rc_add_default_file(search_path);
676 g_free(search_path);
677
678 gui_check = gtk_init_check(&argc, &argv);
679 if (!gui_check) {
680 char *display = gdk_get_display();
681
682 printf(PIDGIN_NAME " %s\n", VERSION);
683
684 g_warning("cannot open display: %s", display ? display : "unset");
685 g_free(display);
686
687 return 1;
688 }
689
690 #ifdef _WIN32
691 gtkwgaim_init(hint);
692 #endif
693
694 gaim_core_set_ui_ops(gaim_gtk_core_get_ui_ops());
695 gaim_eventloop_set_ui_ops(gaim_gtk_eventloop_get_ui_ops());
696
697 /*
698 * Set plugin search directories. Give priority to the plugins
699 * in user's home directory.
700 */
701 search_path = g_build_filename(gaim_user_dir(), "plugins", NULL);
702 gaim_plugins_add_search_path(search_path);
703 g_free(search_path);
704 gaim_plugins_add_search_path(LIBDIR);
705
706 if (!gaim_core_init(GAIM_GTK_UI)) {
707 fprintf(stderr,
708 "Initialization of the " PIDGIN_NAME " core failed. Dumping core.\n"
709 "Please report this!\n");
710 abort();
711 }
712
713 /* TODO: Move blist loading into gaim_blist_init() */
714 gaim_set_blist(gaim_blist_new());
715 gaim_blist_load();
716
717 /* TODO: Move prefs loading into gaim_prefs_init() */
718 gaim_prefs_load();
719 gaim_prefs_update_old();
720 gaim_gtk_prefs_update_old();
721
722 /* load plugins we had when we quit */
723 gaim_plugins_load_saved("/gaim/gtk/plugins/loaded");
724 gaim_gtk_docklet_init();
725
726 /* TODO: Move pounces loading into gaim_pounces_init() */
727 gaim_pounces_load();
728
729
730 /* HACK BY SEANEGAN:
731 * We've renamed prpl-oscar to prpl-aim and prpl-icq, accordingly.
732 * Let's do that change right here... after everything's loaded, but
733 * before anything has happened
734 */
735 for (accounts = gaim_accounts_get_all(); accounts != NULL; accounts = accounts->next) {
736 GaimAccount *account = accounts->data;
737 if (!strcmp(gaim_account_get_protocol_id(account), "prpl-oscar")) {
738 if (isdigit(*gaim_account_get_username(account)))
739 gaim_account_set_protocol_id(account, "prpl-icq");
740 else
741 gaim_account_set_protocol_id(account, "prpl-aim");
742 }
743 }
744
745 ui_main();
746
747 #ifdef USE_SM
748 gaim_gtk_session_init(argv[0], opt_session_arg, opt_config_dir_arg);
749 #endif
750 if (opt_session_arg != NULL) {
751 g_free(opt_session_arg);
752 opt_session_arg = NULL;
753 }
754 if (opt_config_dir_arg != NULL) {
755 g_free(opt_config_dir_arg);
756 opt_config_dir_arg = NULL;
757 }
758
759 /*
760 * We want to show the blist early in the init process so the
761 * user feels warm and fuzzy (not cold and prickley).
762 */
763 gaim_blist_show();
764
765 if (gaim_prefs_get_bool("/gaim/gtk/debug/enabled"))
766 gaim_gtk_debug_window_show();
767
768 if (opt_login) {
769 dologin_ret = dologin_named(opt_login_arg);
770 if (opt_login_arg != NULL) {
771 g_free(opt_login_arg);
772 opt_login_arg = NULL;
773 }
774 }
775
776 if (opt_nologin)
777 {
778 /* Set all accounts to "offline" */
779 GaimSavedStatus *saved_status;
780
781 /* If we've used this type+message before, lookup the transient status */
782 saved_status = gaim_savedstatus_find_transient_by_type_and_message(
783 GAIM_STATUS_OFFLINE, NULL);
784
785 /* If this type+message is unique then create a new transient saved status */
786 if (saved_status == NULL)
787 saved_status = gaim_savedstatus_new(NULL, GAIM_STATUS_OFFLINE);
788
789 /* Set the status for each account */
790 gaim_savedstatus_activate(saved_status);
791 }
792 else
793 {
794 /* Everything is good to go--sign on already */
795 if (!gaim_prefs_get_bool("/core/savedstatus/startup_current_status"))
796 gaim_savedstatus_activate(gaim_savedstatus_get_startup());
797 gaim_accounts_restore_current_statuses();
798 }
799
800 if ((accounts = gaim_accounts_get_all_active()) == NULL)
801 {
802 gaim_gtk_accounts_window_show();
803 }
804 else
805 {
806 g_list_free(accounts);
807 }
808
809 #ifdef HAVE_STARTUP_NOTIFICATION
810 startup_notification_complete();
811 #endif
812
813 #ifdef _WIN32
814 gtkwgaim_post_init();
815 #endif
816
817 gtk_main();
818
819 #ifdef HAVE_SIGNAL_H
820 g_free(segfault_message);
821 #endif
822
823 #ifdef _WIN32
824 gtkwgaim_cleanup();
825 #endif
826
827 return 0;
828 }

mercurial