4 * Copyright (C) 1998-1999, Mark Spencer <markster@marko.net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #endif /* USE_GNOME */
32 #endif /* USE_APPLET */
35 #endif /* GAIM_PLUGINS */
40 #include <sys/types.h>
41 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
55 #include "pixmaps/logo.xpm"
60 #include "gtkticker.h"
66 static gchar
*ispell_cmd
[] = { "ispell", "-a", NULL
};
68 static GtkWidget
*name
;
69 static GtkWidget
*pass
;
71 GList
*log_conversations
= NULL
;
72 GList
*buddy_pounces
= NULL
;
73 GSList
*away_messages
= NULL
;
74 GList
*conversations
= NULL
;
75 GSList
*message_queue
= NULL
;
76 GSList
*away_time_queue
= NULL
;
78 GtkWidget
*mainwindow
= NULL
;
81 char *opt_away_arg
= NULL
;
82 char *opt_rcfile_arg
= NULL
;
85 void BuddyTickerCreateWindow(void);
87 void cancel_logon(void)
90 applet_buddy_show
= FALSE
;
92 gtk_widget_hide(mainwindow
);
95 /* first we tell those who have requested it we're quitting */
96 plugin_event(event_quit
, 0, 0, 0, 0);
98 /* then we remove everyone in a mass suicide */
100 #endif /* GAIM_PLUGINS */
106 #endif /* USE_APPLET */
109 static int snd_tmout
;
110 int logins_not_muted
= 1;
111 static void sound_timeout()
113 logins_not_muted
= 1;
114 gtk_timeout_remove(snd_tmout
);
117 /* we need to do this for Oscar because serv_login only starts the login
118 * process, it doesn't end there. gaim_setup will be called later from
119 * oscar.c, after the buddy list is made and serv_finish_login is called */
120 void gaim_setup(struct gaim_connection
*gc
)
122 if ((sound_options
& OPT_SOUND_LOGIN
) && (sound_options
& OPT_SOUND_SILENT_SIGNON
)) {
123 logins_not_muted
= 0;
124 snd_tmout
= gtk_timeout_add(10000, (GtkFunction
)sound_timeout
, NULL
);
127 set_user_state(online
);
128 applet_widget_register_callback(APPLET_WIDGET(applet
),
129 "signoff", _("Signoff"), (AppletCallbackFunc
)signoff_all
, NULL
);
130 #endif /* USE_APPLET */
134 static void dologin(GtkWidget
*widget
, GtkWidget
*w
)
137 const char *username
= gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(name
)->entry
));
138 const char *password
= gtk_entry_get_text(GTK_ENTRY(pass
));
140 if (!strlen(username
)) {
141 do_error_dialog(_("Please enter your logon"), _("Signon Error"));
145 /* if there is more than one user of the same name, then fuck
146 * them, they just have to use the account editor to sign in
149 u
= find_user(username
, -1);
151 u
= new_user(username
, DEFAULT_PROTO
, OPT_USR_REM_PASS
);
152 g_snprintf(u
->password
, sizeof u
->password
, "%s", password
);
158 static void doenter(GtkWidget
*widget
, GtkWidget
*w
)
160 if (widget
== name
) {
161 gtk_entry_set_text(GTK_ENTRY(pass
), "");
162 gtk_entry_select_region(GTK_ENTRY(GTK_COMBO(name
)->entry
), 0, 0);
163 gtk_widget_grab_focus(pass
);
164 } else if (widget
== pass
) {
170 static void combo_changed(GtkWidget
*w
, GtkWidget
*combo
)
172 const char *txt
= gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(combo
)->entry
));
175 u
= find_user(txt
, -1);
177 if (u
&& u
->options
& OPT_USR_REM_PASS
) {
178 gtk_entry_set_text(GTK_ENTRY(pass
), u
->password
);
180 gtk_entry_set_text(GTK_ENTRY(pass
), "");
185 static GList
*combo_user_names()
187 GSList
*usr
= aim_users
;
192 return g_list_append(NULL
, "<New User>");
195 u
= (struct aim_user
*)usr
->data
;
196 tmp
= g_list_append(tmp
, u
->username
);
230 gtk_widget_show(mainwindow
);
234 mainwindow
= gtk_window_new(GTK_WINDOW_TOPLEVEL
);
235 gtk_window_set_wmclass(GTK_WINDOW(mainwindow
), "login", "Gaim");
236 gtk_window_set_policy(GTK_WINDOW(mainwindow
), FALSE
, FALSE
, TRUE
);
237 gtk_signal_connect(GTK_OBJECT(mainwindow
), "delete_event",
238 GTK_SIGNAL_FUNC(cancel_logon
), mainwindow
);
239 gtk_window_set_title(GTK_WINDOW(mainwindow
), _("Gaim - Login"));
240 gtk_widget_realize(mainwindow
);
241 aol_icon(mainwindow
->window
);
242 gdk_window_set_group(mainwindow
->window
, mainwindow
->window
);
244 table
= gtk_table_new(8, 2, FALSE
);
245 gtk_container_add(GTK_CONTAINER(mainwindow
), table
);
246 gtk_widget_show(table
);
248 style
= gtk_widget_get_style(mainwindow
);
249 pm
= gdk_pixmap_create_from_xpm_d(mainwindow
->window
, &mask
,
250 &style
->bg
[GTK_STATE_NORMAL
], (gchar
**)gaim_logo_xpm
);
251 pmw
= gtk_pixmap_new(pm
, mask
);
252 gtk_table_attach(GTK_TABLE(table
), pmw
, 0, 2, 0, 1, 0, 0, 5, 5);
253 gtk_widget_show(pmw
);
254 gdk_pixmap_unref(pm
);
255 gdk_bitmap_unref(mask
);
257 label
= gtk_label_new(_("Screen Name: "));
258 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 2, 3, 0, 0, 5, 5);
259 gtk_widget_show(label
);
261 name
= gtk_combo_new();
262 tmp
= combo_user_names();
263 gtk_combo_set_popdown_strings(GTK_COMBO(name
), tmp
);
265 gtk_signal_connect(GTK_OBJECT(GTK_COMBO(name
)->entry
), "activate",
266 GTK_SIGNAL_FUNC(doenter
), mainwindow
);
267 gtk_signal_connect(GTK_OBJECT(GTK_COMBO(name
)->entry
), "changed",
268 GTK_SIGNAL_FUNC(combo_changed
), name
);
269 gtk_widget_set_usize(name
, 100, 0);
270 gtk_table_attach(GTK_TABLE(table
), name
, 1, 2, 2, 3, 0, 0, 5, 5);
271 gtk_widget_show(name
);
273 label
= gtk_label_new(_("Password: "));
274 gtk_table_attach(GTK_TABLE(table
), label
, 0, 1, 3, 4, 0, 0, 5, 5);
275 gtk_widget_show(label
);
277 pass
= gtk_entry_new();
278 gtk_widget_set_usize(pass
, 100, 0);
279 gtk_entry_set_visibility(GTK_ENTRY(pass
), FALSE
);
280 gtk_signal_connect(GTK_OBJECT(pass
), "activate", GTK_SIGNAL_FUNC(doenter
), mainwindow
);
281 gtk_table_attach(GTK_TABLE(table
), pass
, 1, 2, 3, 4, 0, 0, 5, 5);
282 gtk_widget_show(pass
);
284 sbox
= gtk_vbox_new(TRUE
, 5);
285 gtk_container_border_width(GTK_CONTAINER(sbox
), 10);
286 gtk_table_attach(GTK_TABLE(table
), sbox
, 0, 2, 7, 8, 0, 0, 5, 5);
287 gtk_widget_show(sbox
);
289 bbox
= gtk_hbox_new(TRUE
, 10);
290 gtk_box_pack_start(GTK_BOX(sbox
), bbox
, TRUE
, TRUE
, 0);
291 gtk_widget_show(bbox
);
294 cancel
= gtk_button_new_with_label(_("Quit"));
296 cancel
= gtk_button_new_with_label(_("Close"));
299 accts
= gtk_button_new_with_label(_("Accounts"));
301 signon
= gtk_button_new_with_label(_("Signon"));
303 if (misc_options
& OPT_MISC_COOL_LOOK
) {
304 gtk_button_set_relief(GTK_BUTTON(cancel
), GTK_RELIEF_NONE
);
306 gtk_button_set_relief(GTK_BUTTON(accts
), GTK_RELIEF_NONE
);
308 gtk_button_set_relief(GTK_BUTTON(signon
), GTK_RELIEF_NONE
);
311 gtk_signal_connect(GTK_OBJECT(cancel
), "clicked", GTK_SIGNAL_FUNC(cancel_logon
), mainwindow
);
313 gtk_signal_connect(GTK_OBJECT(accts
), "clicked", GTK_SIGNAL_FUNC(account_editor
), mainwindow
);
315 gtk_signal_connect(GTK_OBJECT(signon
), "clicked", GTK_SIGNAL_FUNC(dologin
), mainwindow
);
317 gtk_box_pack_start(GTK_BOX(bbox
), cancel
, TRUE
, TRUE
, 0);
319 gtk_box_pack_start(GTK_BOX(bbox
), accts
, TRUE
, TRUE
, 0);
321 gtk_box_pack_start(GTK_BOX(bbox
), signon
, TRUE
, TRUE
, 0);
323 gtk_widget_show(cancel
);
325 gtk_widget_show(accts
);
327 gtk_widget_show(signon
);
329 hbox
= gtk_hbox_new(TRUE
, 10);
330 gtk_box_pack_start(GTK_BOX(sbox
), hbox
, TRUE
, TRUE
, 0);
331 gtk_widget_show(hbox
);
333 reg
= gtk_button_new_with_label(_("About"));
334 options
= gtk_button_new_with_label(_("Options"));
336 plugs
= gtk_button_new_with_label(_("Plugins"));
338 if (misc_options
& OPT_MISC_COOL_LOOK
) {
339 gtk_button_set_relief(GTK_BUTTON(reg
), GTK_RELIEF_NONE
);
340 gtk_button_set_relief(GTK_BUTTON(options
), GTK_RELIEF_NONE
);
342 gtk_button_set_relief(GTK_BUTTON(plugs
), GTK_RELIEF_NONE
);
346 gtk_signal_connect(GTK_OBJECT(reg
), "clicked", GTK_SIGNAL_FUNC(show_about
), NULL
);
347 gtk_signal_connect(GTK_OBJECT(options
), "clicked", GTK_SIGNAL_FUNC(show_prefs
), NULL
);
349 gtk_signal_connect(GTK_OBJECT(plugs
), "clicked", GTK_SIGNAL_FUNC(show_plugins
), NULL
);
352 gtk_box_pack_start(GTK_BOX(hbox
), reg
, TRUE
, TRUE
, 0);
353 gtk_box_pack_start(GTK_BOX(hbox
), options
, TRUE
, TRUE
, 0);
355 gtk_box_pack_start(GTK_BOX(hbox
), plugs
, TRUE
, TRUE
, 0);
358 gtk_widget_show(reg
);
359 gtk_widget_show(options
);
361 gtk_widget_show(plugs
);
365 struct aim_user
*c
= (struct aim_user
*)aim_users
->data
;
366 if (c
->options
& OPT_USR_REM_PASS
) {
367 combo_changed(NULL
, name
);
368 gtk_widget_grab_focus(signon
);
370 gtk_widget_grab_focus(pass
);
373 gtk_widget_grab_focus(name
);
376 gtk_widget_show(mainwindow
);
380 void sighandler(int sig
)
384 debug_printf("caught signal %d\n", sig
);
385 signoff_all(NULL
, NULL
);
390 fprintf(stderr
, "Gaim has segfaulted and attempted to dump a core file.\n"
391 "This is a bug in the software and has happened through\n"
392 "no fault of your own.\n\n"
393 "It is possible that this bug is already fixed in CVS.\n"
394 "You can get a tarball of CVS from the Gaim website, at\n"
395 WEBSITE
"gaim-CVS.tar.gz.\n\n"
396 "If you are already using CVS, or can reproduce the crash\n"
397 "using the CVS version, please notify the gaim maintainers\n"
398 "by reporting a bug at\n"
399 WEBSITE
"bug.php3\n\n"
400 "Please make sure to specify what you were doing at the time,\n"
401 "and post the backtrace from the core file. If you do not know\n"
402 "how to get the backtrace, please get instructions at\n"
403 WEBSITE
"gdb.php. If you need further\n"
404 "assistance, please IM either RobFlynn or SeanEgn and\n"
405 "they can help you.\n");
410 debug_printf("caught signal %d\n", sig
);
412 signoff_all(NULL
, NULL
);
414 remove_all_plugins();
416 if (gtk_main_level())
424 static gboolean
socket_readable(GIOChannel
*source
, GIOCondition cond
, gpointer ud
)
432 debug_printf("Core says: ");
433 g_io_channel_read(source
, &type
, sizeof(type
), &x
);
435 debug_printf("CORE IS GONE!\n");
436 g_io_channel_close(source
);
439 debug_printf("%d ", type
);
440 g_io_channel_read(source
, &subtype
, sizeof(subtype
), &x
);
442 debug_printf("CORE IS GONE!\n");
443 g_io_channel_close(source
);
446 debug_printf("%d ", subtype
);
447 g_io_channel_read(source
, (guchar
*)&len
, sizeof(len
), &x
);
449 debug_printf("CORE IS GONE!\n");
450 g_io_channel_close(source
);
453 debug_printf("(%d bytes)\n", len
);
455 data
= g_malloc(len
);
456 g_io_channel_read(source
, data
, len
, &x
);
458 debug_printf("CORE IS GONE! (read %d/%d bytes)\n", x
, len
);
460 g_io_channel_close(source
);
468 static int open_socket(char *name
)
470 struct sockaddr_un saddr
;
473 if ((fd
= socket(AF_UNIX
, SOCK_STREAM
, 0)) != -1) {
474 saddr
.sun_family
= AF_UNIX
;
475 g_snprintf(saddr
.sun_path
, 108, "%s", name
);
476 if (connect(fd
, (struct sockaddr
*)&saddr
, sizeof(saddr
)) != -1)
479 debug_printf("Failed to assign %s to a socket (Error: %s)",
480 saddr
.sun_path
, strerror(errno
));
482 debug_printf("Unable to open socket: %s", strerror(errno
));
493 g_snprintf(name
, sizeof(name
), "%s/gaim_%s.%d", g_get_tmp_dir(), g_get_user_name(), getpid());
495 UI_fd
= open_socket(name
);
499 channel
= g_io_channel_unix_new(UI_fd
);
500 g_io_add_watch(channel
, G_IO_IN
| G_IO_HUP
| G_IO_ERR
, socket_readable
, NULL
);
504 static void set_first_user(char *name
)
508 u
= find_user(name
, -1);
510 if (!u
) { /* new user */
511 u
= g_new0(struct aim_user
, 1);
512 g_snprintf(u
->username
, sizeof(u
->username
), "%s", name
);
513 u
->protocol
= DEFAULT_PROTO
;
514 aim_users
= g_slist_prepend(aim_users
, u
);
515 } else { /* user already exists */
516 aim_users
= g_slist_remove(aim_users
, u
);
517 aim_users
= g_slist_prepend(aim_users
, u
);
522 /* FUCKING GET ME A TOWEL! */
523 int main(int argc
, char *argv
[])
525 int opt_acct
= 0, opt_help
= 0, opt_version
= 0, opt_login
= 0, do_login_ret
= -1;
526 char *opt_user_arg
= NULL
, *opt_login_arg
= NULL
;
528 int opt
, opt_user
= 0;
532 struct poptOption popt_options
[] = {
533 {"acct", 'a', POPT_ARG_NONE
, &opt_acct
, 'a',
534 "Display account editor window", NULL
},
535 {"away", 'w', POPT_ARG_STRING
, NULL
, 'w',
536 "Make away on signon (optional argument MESG specifies name of away message to use)",
538 {"login", 'l', POPT_ARG_STRING
, NULL
, 'l',
539 "Automatically login (optional argument NAME specifies account(s) to use)", "[NAME]"},
540 {"user", 'u', POPT_ARG_STRING
, &opt_user_arg
, 'u',
541 "Use account NAME", "NAME"},
542 {"file", 'f', POPT_ARG_STRING
, &opt_rcfile_arg
, 'f',
543 "Use FILE as config", "FILE"},
544 {"debug", 'd', POPT_ARG_NONE
, &opt_debug
, 'd',
545 "Print debugging messages to stdout", NULL
},
546 {0, 0, 0, 0, 0, 0, 0}
548 #endif /* USE_GNOME */
549 struct option long_options
[] = {
550 {"acct", no_argument
, NULL
, 'a'},
551 /*{"away", optional_argument, NULL, 'w'}, */
552 {"help", no_argument
, NULL
, 'h'},
553 /*{"login", optional_argument, NULL, 'l'}, */
554 {"user", required_argument
, NULL
, 'u'},
555 {"file", required_argument
, NULL
, 'f'},
556 {"debug", no_argument
, NULL
, 'd'},
557 {"version", no_argument
, NULL
, 'v'},
567 bindtextdomain(PACKAGE
, LOCALEDIR
);
572 /* Let's not violate any PLA's!!!! */
573 signal(SIGSEGV
, sighandler
);
574 signal(SIGHUP
, sighandler
);
575 signal(SIGINT
, sighandler
);
576 signal(SIGTERM
, sighandler
);
577 signal(SIGQUIT
, sighandler
);
578 signal(SIGPIPE
, SIG_IGN
);
583 init_applet_mgr(argc
, argv
);
585 for (i
= 0; i
< argc
; i
++) {
587 if (strstr(argv
[i
], "--l") == argv
[i
]) {
590 if ((equals
= strchr(argv
[i
], '=')) != NULL
) {
592 opt_login_arg
= g_strdup(equals
+ 1);
593 if (strlen(opt_login_arg
) == 0) {
594 g_free(opt_login_arg
);
595 opt_login_arg
= NULL
;
597 } else if (i
+ 1 < argc
&& argv
[i
+ 1][0] != '-') {
599 opt_login_arg
= g_strdup(argv
[i
+ 1]);
600 strcpy(argv
[i
+ 1], " ");
602 strcpy(argv
[i
], " ");
605 else if (strstr(argv
[i
], "-l") == argv
[i
]) {
607 if (strlen(argv
[i
]) > 2) {
609 opt_login_arg
= g_strdup(argv
[i
] + 2);
610 } else if (i
+ 1 < argc
&& argv
[i
+ 1][0] != '-') {
612 opt_login_arg
= g_strdup(argv
[i
+ 1]);
613 strcpy(argv
[i
+ 1], " ");
615 strcpy(argv
[i
], " ");
618 else if (strstr(argv
[i
], "--aw") == argv
[i
]) {
621 if ((equals
= strchr(argv
[i
], '=')) != NULL
) {
623 opt_away_arg
= g_strdup(equals
+ 1);
624 if (strlen(opt_away_arg
) == 0) {
625 g_free(opt_away_arg
);
628 } else if (i
+ 1 < argc
&& argv
[i
+ 1][0] != '-') {
630 opt_away_arg
= g_strdup(argv
[i
+ 1]);
631 strcpy(argv
[i
+ 1], " ");
633 strcpy(argv
[i
], " ");
636 else if (strstr(argv
[i
], "-w") == argv
[i
]) {
638 if (strlen(argv
[i
]) > 2) {
640 opt_away_arg
= g_strdup(argv
[i
] + 2);
641 } else if (i
+ 1 < argc
&& argv
[i
+ 1][0] != '-') {
643 opt_away_arg
= g_strdup(argv
[i
+ 1]);
644 strcpy(argv
[i
+ 1], " ");
646 strcpy(argv
[i
], " ");
651 printf ("--login given with arg %s\n",
652 opt_login_arg ? opt_login_arg : "NULL");
659 gnome_init_with_popt_table(PACKAGE
, VERSION
, argc
, argv
, popt_options
, 0, NULL
);
661 gtk_init(&argc
, &argv
);
664 /* scan command-line options */
670 while ((opt
= getopt_long(argc
, argv
, "adhu:f:v", long_options
, NULL
)) != -1) {
672 case 'u': /* set user */
674 opt_user_arg
= g_strdup(optarg
);
676 case 'a': /* account editor */
679 case 'd': /* debug */
683 opt_rcfile_arg
= g_strdup(optarg
);
685 case 'v': /* version */
694 show_usage(1, argv
[0]);
701 #endif /* USE_APPLET */
703 /* show help message */
705 show_usage(0, argv
[0]);
708 /* show version window */
710 gtk_init(&argc
, &argv
);
712 show_about(0, (void *)2);
723 /* set the default username */
724 if (opt_user_arg
!= NULL
) {
725 set_first_user(opt_user_arg
);
727 g_free(opt_user_arg
);
729 #endif /* USE_GNOME */
732 if (misc_options
& OPT_MISC_DEBUG
)
735 if (convo_options
& OPT_CONVO_CHECK_SPELLING
)
736 gtkspell_start(NULL
, ispell_cmd
);
742 /* deal with --login */
744 do_login_ret
= do_auto_login(opt_login_arg
);
745 if (opt_login_arg
!= NULL
) {
746 g_free(opt_login_arg
);
747 opt_login_arg
= NULL
;
751 applet_widget_register_callback(APPLET_WIDGET(applet
),
752 "prefs", _("Preferences"), show_prefs
, NULL
);
753 applet_widget_register_callback(APPLET_WIDGET(applet
),
755 _("Accounts"), (AppletCallbackFunc
)account_editor
, (void *)1);
757 applet_widget_register_callback(APPLET_WIDGET(applet
),
758 "plugins", _("Plugins"), GTK_SIGNAL_FUNC(show_plugins
), NULL
);
759 #endif /* GAIM_PLUGINS */
764 applet_widget_gtk_main();
771 account_editor(NULL
, NULL
);
772 } else if ((do_login_ret
== -1) && !connections
)
777 #endif /* USE_APPLET */
779 if (convo_options
& OPT_CONVO_CHECK_SPELLING
)
782 /* don't need ui_quit here because ui doesn't create anything */