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