1 /**
2  * @file gtkpounce.c GTK+ Buddy Pounce API
3  * @ingroup pidgin
4  */
5 
6 /* pidgin
7  *
8  * Pidgin is the legal property of its developers, whose names are too numerous
9  * to list here.  Please refer to the COPYRIGHT file distributed with this
10  * source distribution.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
25  *
26  */
27 #include "internal.h"
28 #include "pidgin.h"
29 
30 #include "account.h"
31 #include "conversation.h"
32 #include "debug.h"
33 #include "prpl.h"
34 #include "request.h"
35 #include "server.h"
36 #include "sound.h"
37 #include "util.h"
38 
39 #include "gtkblist.h"
40 #include "gtkdialogs.h"
41 #include "gtkimhtml.h"
42 #include "gtkpounce.h"
43 #include "gtknotify.h"
44 #include "pidginstock.h"
45 #include "gtkutils.h"
46 
47 /**
48  * These are used for the GtkTreeView when you're scrolling through
49  * all your saved pounces.
50  */
51 enum
52 {
53 	/* Hidden column containing the PurplePounce */
54 	POUNCES_MANAGER_COLUMN_POUNCE,
55 	POUNCES_MANAGER_COLUMN_ICON,
56 	POUNCES_MANAGER_COLUMN_TARGET,
57 	POUNCES_MANAGER_COLUMN_ACCOUNT,
58 	POUNCES_MANAGER_COLUMN_RECURRING,
59 	POUNCES_MANAGER_NUM_COLUMNS
60 };
61 
62 typedef struct
63 {
64 	/* Pounce data */
65 	PurplePounce  *pounce;
66 	PurpleAccount *account;
67 
68 	/* The window */
69 	GtkWidget *window;
70 
71 	/* Pounce on Whom */
72 	GtkWidget *account_menu;
73 	GtkWidget *buddy_entry;
74 
75 	/* Pounce options */
76 	GtkWidget *on_away;
77 
78 	/* Pounce When Buddy... */
79 	GtkWidget *signon;
80 	GtkWidget *signoff;
81 	GtkWidget *away;
82 	GtkWidget *away_return;
83 	GtkWidget *idle;
84 	GtkWidget *idle_return;
85 	GtkWidget *typing;
86 	GtkWidget *typed;
87 	GtkWidget *stop_typing;
88 	GtkWidget *message_recv;
89 
90 	/* Action */
91 	GtkWidget *open_win;
92 	GtkWidget *popup;
93 	GtkWidget *popup_entry;
94 	GtkWidget *send_msg;
95 	GtkWidget *send_msg_entry;
96 	GtkWidget *exec_cmd;
97 	GtkWidget *exec_cmd_entry;
98 	GtkWidget *exec_cmd_browse;
99 	GtkWidget *play_sound;
100 	GtkWidget *play_sound_entry;
101 	GtkWidget *play_sound_browse;
102 	GtkWidget *play_sound_test;
103 	GtkWidget *play_sound_reset;
104 
105 	GtkWidget *save_pounce;
106 
107 	/* Buttons */
108 	GtkWidget *save_button;
109 
110 } PidginPounceDialog;
111 
112 typedef struct
113 {
114 	GtkWidget *window;
115 	GtkListStore *model;
116 	GtkWidget *treeview;
117 	GtkWidget *modify_button;
118 	GtkWidget *delete_button;
119 } PouncesManager;
120 
121 static PouncesManager *pounces_manager = NULL;
122 
123 /**************************************************************************
124  * Callbacks
125  **************************************************************************/
126 static gint
delete_win_cb(GtkWidget * w,GdkEventAny * e,PidginPounceDialog * dialog)127 delete_win_cb(GtkWidget *w, GdkEventAny *e, PidginPounceDialog *dialog)
128 {
129 	gtk_widget_destroy(dialog->window);
130 	g_free(dialog);
131 
132 	return TRUE;
133 }
134 
135 static void
cancel_cb(GtkWidget * w,PidginPounceDialog * dialog)136 cancel_cb(GtkWidget *w, PidginPounceDialog *dialog)
137 {
138 	delete_win_cb(NULL, NULL, dialog);
139 }
140 
141 static void
pounce_update_entry_fields(void * user_data,const char * filename)142 pounce_update_entry_fields(void *user_data, const char *filename)
143 {
144 	GtkWidget *entry = (GtkWidget *)user_data;
145 
146 	gtk_entry_set_text(GTK_ENTRY(entry), filename);
147 }
148 
149 static void
filesel(GtkWidget * widget,gpointer data)150 filesel(GtkWidget *widget, gpointer data)
151 {
152 	GtkWidget *entry;
153 	const gchar *name;
154 
155 	entry = (GtkWidget *)data;
156 	name = gtk_entry_get_text(GTK_ENTRY(entry));
157 
158 	purple_request_file(entry, _("Select a file"), name, FALSE,
159 					  G_CALLBACK(pounce_update_entry_fields), NULL,
160 					  NULL, NULL, NULL,
161 					  entry);
162 	g_signal_connect_swapped(G_OBJECT(entry), "destroy",
163 			G_CALLBACK(purple_request_close_with_handle), entry);
164 }
165 
166 static void
pounce_test_sound(GtkWidget * w,GtkWidget * entry)167 pounce_test_sound(GtkWidget *w, GtkWidget *entry)
168 {
169 	const char *filename;
170 	gboolean temp_mute;
171 
172 	temp_mute = purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/sound/mute");
173 
174 	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", FALSE);
175 
176 	filename = gtk_entry_get_text(GTK_ENTRY(entry));
177 
178 	if (filename != NULL && *filename != '\0' && !purple_strequal(filename, _("(default)")))
179 		purple_sound_play_file(filename, NULL);
180 	else
181 		purple_sound_play_event(PURPLE_SOUND_POUNCE_DEFAULT, NULL);
182 
183 	if (temp_mute) purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/sound/mute", TRUE);
184 }
185 
186 static void
pounce_reset_sound(GtkWidget * w,GtkWidget * entry)187 pounce_reset_sound(GtkWidget *w, GtkWidget *entry)
188 {
189 	gtk_entry_set_text(GTK_ENTRY(entry), _("(default)"));
190 }
191 
192 static void
add_pounce_to_treeview(GtkListStore * model,PurplePounce * pounce)193 add_pounce_to_treeview(GtkListStore *model, PurplePounce *pounce)
194 {
195 	GtkTreeIter iter;
196 	PurpleAccount *account;
197 	gboolean recurring;
198 	const char *pouncer;
199 	const char *pouncee;
200 	GdkPixbuf *pixbuf;
201 
202 	account = purple_pounce_get_pouncer(pounce);
203 
204 	pixbuf = pidgin_create_prpl_icon(account, PIDGIN_PRPL_ICON_MEDIUM);
205 
206 	pouncer = purple_account_get_username(account);
207 	pouncee = purple_pounce_get_pouncee(pounce);
208 	recurring = purple_pounce_get_save(pounce);
209 
210 	gtk_list_store_append(model, &iter);
211 	gtk_list_store_set(model, &iter,
212 					   POUNCES_MANAGER_COLUMN_POUNCE, pounce,
213 					   POUNCES_MANAGER_COLUMN_ICON, pixbuf,
214 					   POUNCES_MANAGER_COLUMN_TARGET, pouncee,
215 					   POUNCES_MANAGER_COLUMN_ACCOUNT, pouncer,
216 					   POUNCES_MANAGER_COLUMN_RECURRING, recurring,
217 					   -1);
218 
219 	if (pixbuf != NULL)
220 		g_object_unref(pixbuf);
221 }
222 
223 static void
populate_pounces_list(PouncesManager * dialog)224 populate_pounces_list(PouncesManager *dialog)
225 {
226 	GList *pounces;
227 
228 	gtk_list_store_clear(dialog->model);
229 
230 	for (pounces = purple_pounces_get_all_for_ui(PIDGIN_UI); pounces != NULL;
231 			pounces = g_list_delete_link(pounces, pounces))
232 	{
233 		add_pounce_to_treeview(dialog->model, pounces->data);
234 	}
235 }
236 
237 static void
update_pounces(void)238 update_pounces(void)
239 {
240 	/* Rebuild the pounces list if the pounces manager is open */
241 	if (pounces_manager != NULL)
242 	{
243 		populate_pounces_list(pounces_manager);
244 	}
245 }
246 
247 static void
signed_on_off_cb(PurpleConnection * gc,gpointer user_data)248 signed_on_off_cb(PurpleConnection *gc, gpointer user_data)
249 {
250 	update_pounces();
251 }
252 
253 static void
save_pounce_cb(GtkWidget * w,PidginPounceDialog * dialog)254 save_pounce_cb(GtkWidget *w, PidginPounceDialog *dialog)
255 {
256 	const char *name;
257 	const char *command, *sound, *reason;
258 	char *message;
259 	PurplePounceEvent events   = PURPLE_POUNCE_NONE;
260 	PurplePounceOption options = PURPLE_POUNCE_OPTION_NONE;
261 
262 	name = gtk_entry_get_text(GTK_ENTRY(dialog->buddy_entry));
263 
264 	if (*name == '\0')
265 	{
266 		purple_notify_error(NULL, NULL,
267 						  _("Please enter a buddy to pounce."), NULL);
268 		return;
269 	}
270 
271 	/* Options */
272 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->on_away)))
273 		options |= PURPLE_POUNCE_OPTION_AWAY;
274 
275 	/* Events */
276 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->signon)))
277 		events |= PURPLE_POUNCE_SIGNON;
278 
279 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->signoff)))
280 		events |= PURPLE_POUNCE_SIGNOFF;
281 
282 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->away)))
283 		events |= PURPLE_POUNCE_AWAY;
284 
285 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->away_return)))
286 		events |= PURPLE_POUNCE_AWAY_RETURN;
287 
288 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->idle)))
289 		events |= PURPLE_POUNCE_IDLE;
290 
291 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->idle_return)))
292 		events |= PURPLE_POUNCE_IDLE_RETURN;
293 
294 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->typing)))
295 		events |= PURPLE_POUNCE_TYPING;
296 
297 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->typed)))
298 		events |= PURPLE_POUNCE_TYPED;
299 
300 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->stop_typing)))
301 		events |= PURPLE_POUNCE_TYPING_STOPPED;
302 
303 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->message_recv)))
304 		events |= PURPLE_POUNCE_MESSAGE_RECEIVED;
305 
306 	/* Data fields */
307 	message = gtk_imhtml_get_markup(GTK_IMHTML(dialog->send_msg_entry));
308 	command = gtk_entry_get_text(GTK_ENTRY(dialog->exec_cmd_entry));
309 	sound   = gtk_entry_get_text(GTK_ENTRY(dialog->play_sound_entry));
310 	reason  = gtk_entry_get_text(GTK_ENTRY(dialog->popup_entry));
311 
312 	if (*reason == '\0') reason = NULL;
313 	if (*message == '\0') {
314 		g_free(message);
315 		message = NULL;
316 	}
317 	if (*command == '\0') command = NULL;
318 	if (*sound   == '\0' || purple_strequal(sound, _("(default)"))) sound   = NULL;
319 
320 	/* If the pounce has already been triggered, let's pretend it is a new one */
321 	if (dialog->pounce != NULL
322 			&& g_list_find(purple_pounces_get_all(), dialog->pounce) == NULL) {
323 		purple_debug_info("gtkpounce", "Saving pounce that no longer exists; creating new pounce.\n");
324 		dialog->pounce = NULL;
325 	}
326 
327 	if (dialog->pounce == NULL)
328 	{
329 		dialog->pounce = purple_pounce_new(PIDGIN_UI, dialog->account,
330 										 name, events, options);
331 	}
332 	else {
333 		purple_pounce_set_events(dialog->pounce, events);
334 		purple_pounce_set_options(dialog->pounce, options);
335 		purple_pounce_set_pouncer(dialog->pounce, dialog->account);
336 		purple_pounce_set_pouncee(dialog->pounce, name);
337 	}
338 
339 	/* Actions */
340 	purple_pounce_action_set_enabled(dialog->pounce, "open-window",
341 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->open_win)));
342 	purple_pounce_action_set_enabled(dialog->pounce, "popup-notify",
343 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->popup)));
344 	purple_pounce_action_set_enabled(dialog->pounce, "send-message",
345 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->send_msg)));
346 	purple_pounce_action_set_enabled(dialog->pounce, "execute-command",
347 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd)));
348 	purple_pounce_action_set_enabled(dialog->pounce, "play-sound",
349 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->play_sound)));
350 
351 	purple_pounce_action_set_attribute(dialog->pounce, "send-message",
352 									 "message", message);
353 	purple_pounce_action_set_attribute(dialog->pounce, "execute-command",
354 									 "command", command);
355 	purple_pounce_action_set_attribute(dialog->pounce, "play-sound",
356 									 "filename", sound);
357 	purple_pounce_action_set_attribute(dialog->pounce, "popup-notify",
358 									 "reason", reason);
359 
360 	/* Set the defaults for next time. */
361 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/open-window",
362 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->open_win)));
363 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/popup-notify",
364 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->popup)));
365 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/send-message",
366 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->send_msg)));
367 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/execute-command",
368 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd)));
369 	purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/play-sound",
370 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->play_sound)));
371 
372 	purple_pounce_set_save(dialog->pounce,
373 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dialog->save_pounce)));
374 
375 	update_pounces();
376 	g_free(message);
377 
378 	delete_win_cb(NULL, NULL, dialog);
379 }
380 
381 static void
pounce_choose_cb(GtkWidget * item,PurpleAccount * account,PidginPounceDialog * dialog)382 pounce_choose_cb(GtkWidget *item, PurpleAccount *account,
383 				 PidginPounceDialog *dialog)
384 {
385 	dialog->account = account;
386 }
387 
388 static void
buddy_changed_cb(GtkEntry * entry,PidginPounceDialog * dialog)389 buddy_changed_cb(GtkEntry *entry, PidginPounceDialog *dialog)
390 {
391 	if (dialog->save_button == NULL)
392 		return;
393 
394 	gtk_widget_set_sensitive(dialog->save_button,
395 		*gtk_entry_get_text(entry) != '\0');
396 }
397 
398 static void
message_recv_toggle(GtkButton * message_recv,GtkWidget * send_msg)399 message_recv_toggle(GtkButton *message_recv, GtkWidget *send_msg)
400 {
401 	gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(message_recv));
402 
403 	gtk_widget_set_sensitive(send_msg, !active);
404 	if (active)
405 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(send_msg), FALSE);
406 }
407 
408 static void
pounce_dnd_recv(GtkWidget * widget,GdkDragContext * dc,gint x,gint y,GtkSelectionData * sd,guint info,guint t,gpointer data)409 pounce_dnd_recv(GtkWidget *widget, GdkDragContext *dc, gint x, gint y,
410 				GtkSelectionData *sd, guint info, guint t, gpointer data)
411 {
412 	PidginPounceDialog *dialog;
413 
414 	if (sd->target == gdk_atom_intern("PURPLE_BLIST_NODE", FALSE))
415 	{
416 		PurpleBlistNode *node = NULL;
417 		PurpleBuddy *buddy;
418 
419 		memcpy(&node, sd->data, sizeof(node));
420 
421 		if (PURPLE_BLIST_NODE_IS_CONTACT(node))
422 			buddy = purple_contact_get_priority_buddy((PurpleContact *)node);
423 		else if (PURPLE_BLIST_NODE_IS_BUDDY(node))
424 			buddy = (PurpleBuddy *)node;
425 		else
426 			return;
427 
428 		dialog = (PidginPounceDialog *)data;
429 
430 		gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), buddy->name);
431 		dialog->account = buddy->account;
432 		pidgin_account_option_menu_set_selected(dialog->account_menu, buddy->account);
433 
434 		gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
435 	}
436 	else if (sd->target == gdk_atom_intern("application/x-im-contact", FALSE))
437 	{
438 		char *protocol = NULL;
439 		char *username = NULL;
440 		PurpleAccount *account;
441 
442 		if (pidgin_parse_x_im_contact((const char *)sd->data, FALSE, &account,
443 										&protocol, &username, NULL))
444 		{
445 			if (account == NULL)
446 			{
447 				purple_notify_error(NULL, NULL,
448 					_("You are not currently signed on with an account that "
449 					  "can add that buddy."), NULL);
450 			}
451 			else
452 			{
453 				dialog = (PidginPounceDialog *)data;
454 
455 				gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), username);
456 				dialog->account = account;
457 				pidgin_account_option_menu_set_selected(dialog->account_menu, account);
458 			}
459 		}
460 
461 		g_free(username);
462 		g_free(protocol);
463 
464 		gtk_drag_finish(dc, TRUE, (dc->action == GDK_ACTION_MOVE), t);
465 	}
466 }
467 
468 static const GtkTargetEntry dnd_targets[] =
469 {
470 	{"PURPLE_BLIST_NODE", GTK_TARGET_SAME_APP, 0},
471 	{"application/x-im-contact", 0, 1}
472 };
473 
474 static void
reset_send_msg_entry(PidginPounceDialog * dialog,GtkWidget * dontcare)475 reset_send_msg_entry(PidginPounceDialog *dialog, GtkWidget *dontcare)
476 {
477 	PurpleAccount *account = pidgin_account_option_menu_get_selected(dialog->account_menu);
478 	gtk_imhtml_setup_entry(GTK_IMHTML(dialog->send_msg_entry),
479 			(account && account->gc) ? account->gc->flags : PURPLE_CONNECTION_HTML);
480 }
481 
482 void
pidgin_pounce_editor_show(PurpleAccount * account,const char * name,PurplePounce * cur_pounce)483 pidgin_pounce_editor_show(PurpleAccount *account, const char *name,
484                           PurplePounce *cur_pounce)
485 {
486 	PidginPounceDialog *dialog;
487 	GtkWidget *window;
488 	GtkWidget *label;
489 	GtkWidget *vbox1, *vbox2;
490 	GtkWidget *hbox;
491 	GtkWidget *button;
492 	GtkWidget *frame;
493 	GtkWidget *table;
494 	GtkSizeGroup *sg;
495 	GPtrArray *sound_widgets;
496 	GPtrArray *exec_widgets;
497 	GtkWidget *send_msg_imhtml;
498 
499 	g_return_if_fail((cur_pounce != NULL) ||
500 	                 (account != NULL) ||
501 	                 (purple_accounts_get_all() != NULL));
502 
503 	dialog = g_new0(PidginPounceDialog, 1);
504 
505 	if (cur_pounce != NULL)
506 	{
507 		dialog->pounce  = cur_pounce;
508 		dialog->account = purple_pounce_get_pouncer(cur_pounce);
509 	}
510 	else if (account != NULL)
511 	{
512 		dialog->pounce  = NULL;
513 		dialog->account = account;
514 	}
515 	else
516 	{
517 		GList *connections = purple_connections_get_all();
518 		PurpleConnection *gc;
519 
520 		if (connections != NULL)
521 		{
522 			gc = (PurpleConnection *)connections->data;
523 			dialog->account = purple_connection_get_account(gc);
524 		}
525 		else
526 			dialog->account = purple_accounts_get_all()->data;
527 
528 		dialog->pounce  = NULL;
529 	}
530 
531 	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
532 
533 	/* Create the window. */
534 	dialog->window = window = gtk_dialog_new();
535 	gtk_window_set_title(GTK_WINDOW(window), (cur_pounce == NULL ? _("Add Buddy Pounce") : _("Modify Buddy Pounce")));
536 	gtk_window_set_role(GTK_WINDOW(window), "buddy_pounce");
537 	gtk_container_set_border_width(GTK_CONTAINER(dialog->window), PIDGIN_HIG_BORDER);
538 
539 	g_signal_connect(G_OBJECT(window), "delete_event",
540 					 G_CALLBACK(delete_win_cb), dialog);
541 
542 	/* Create the parent vbox for everything. */
543 	vbox1 = GTK_DIALOG(window)->vbox;
544 
545 	/* Create the vbox that will contain all the prefs stuff. */
546 	vbox2 = gtk_vbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
547 	gtk_box_pack_start(GTK_BOX(vbox1), vbox2, TRUE, TRUE, 0);
548 
549 	/* Create the "Pounce on Whom" frame. */
550 	frame = pidgin_make_frame(vbox2, _("Pounce on Whom"));
551 
552 	/* Account: */
553 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
554 	gtk_box_pack_start(GTK_BOX(frame), hbox, FALSE, FALSE, 0);
555 	gtk_widget_show(hbox);
556 
557 	label = gtk_label_new_with_mnemonic(_("_Account:"));
558 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
559 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
560 	gtk_widget_show(label);
561 	gtk_size_group_add_widget(sg, label);
562 
563 	dialog->account_menu =
564 		pidgin_account_option_menu_new(dialog->account, TRUE,
565 										 G_CALLBACK(pounce_choose_cb),
566 										 NULL, dialog);
567 
568 	gtk_box_pack_start(GTK_BOX(hbox), dialog->account_menu, FALSE, FALSE, 0);
569 	gtk_widget_show(dialog->account_menu);
570 	pidgin_set_accessible_label (dialog->account_menu, label);
571 
572 	/* Buddy: */
573 	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
574 	gtk_box_pack_start(GTK_BOX(frame), hbox, FALSE, FALSE, 0);
575 	gtk_widget_show(hbox);
576 
577 	label = gtk_label_new_with_mnemonic(_("_Buddy name:"));
578 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
579 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
580 	gtk_widget_show(label);
581 	gtk_size_group_add_widget(sg, label);
582 
583 	dialog->buddy_entry = gtk_entry_new();
584 
585 	pidgin_setup_screenname_autocomplete_with_filter(dialog->buddy_entry, dialog->account_menu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(FALSE));
586 
587 	gtk_box_pack_start(GTK_BOX(hbox), dialog->buddy_entry, TRUE, TRUE, 0);
588 	gtk_widget_show(dialog->buddy_entry);
589 
590 	g_signal_connect(G_OBJECT(dialog->buddy_entry), "changed",
591 			 G_CALLBACK(buddy_changed_cb), dialog);
592 	pidgin_set_accessible_label (dialog->buddy_entry, label);
593 
594 	if (cur_pounce != NULL) {
595 		gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry),
596 						   purple_pounce_get_pouncee(cur_pounce));
597 	}
598 	else if (name != NULL) {
599 		gtk_entry_set_text(GTK_ENTRY(dialog->buddy_entry), name);
600 	}
601 
602 	/* Create the "Pounce When Buddy..." frame. */
603 	frame = pidgin_make_frame(vbox2, _("Pounce When Buddy..."));
604 
605 	table = gtk_table_new(5, 2, FALSE);
606 	gtk_container_add(GTK_CONTAINER(frame), table);
607 	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BORDER);
608 	gtk_widget_show(table);
609 
610 	dialog->signon =
611 		gtk_check_button_new_with_mnemonic(_("Si_gns on"));
612 	dialog->signoff =
613 		gtk_check_button_new_with_mnemonic(_("Signs o_ff"));
614 	dialog->away =
615 		gtk_check_button_new_with_mnemonic(_("Goes a_way"));
616 	dialog->away_return =
617 		gtk_check_button_new_with_mnemonic(_("Ret_urns from away"));
618 	dialog->idle =
619 		gtk_check_button_new_with_mnemonic(_("Becomes _idle"));
620 	dialog->idle_return =
621 		gtk_check_button_new_with_mnemonic(_("Is no longer i_dle"));
622 	dialog->typing =
623 		gtk_check_button_new_with_mnemonic(_("Starts _typing"));
624 	dialog->typed =
625 		gtk_check_button_new_with_mnemonic(_("P_auses while typing"));
626 	dialog->stop_typing =
627 		gtk_check_button_new_with_mnemonic(_("Stops t_yping"));
628 	dialog->message_recv =
629 		gtk_check_button_new_with_mnemonic(_("Sends a _message"));
630 
631 	gtk_table_attach(GTK_TABLE(table), dialog->message_recv, 0, 1, 0, 1,
632 					 GTK_FILL, 0, 0, 0);
633 	gtk_table_attach(GTK_TABLE(table), dialog->signon,       0, 1, 1, 2,
634 					 GTK_FILL, 0, 0, 0);
635 	gtk_table_attach(GTK_TABLE(table), dialog->signoff,      0, 1, 2, 3,
636 					 GTK_FILL, 0, 0, 0);
637 	gtk_table_attach(GTK_TABLE(table), dialog->away,         1, 2, 0, 1,
638 					 GTK_FILL, 0, 0, 0);
639 	gtk_table_attach(GTK_TABLE(table), dialog->away_return,  1, 2, 1, 2,
640 					 GTK_FILL, 0, 0, 0);
641 	gtk_table_attach(GTK_TABLE(table), dialog->idle,         1, 2, 2, 3,
642 					 GTK_FILL, 0, 0, 0);
643 	gtk_table_attach(GTK_TABLE(table), dialog->idle_return,  2, 3, 0, 1,
644 					 GTK_FILL, 0, 0, 0);
645 	gtk_table_attach(GTK_TABLE(table), dialog->typing,       2, 3, 1, 2,
646 					 GTK_FILL, 0, 0, 0);
647 	gtk_table_attach(GTK_TABLE(table), dialog->typed,        2, 3, 2, 3,
648 					 GTK_FILL, 0, 0, 0);
649 	gtk_table_attach(GTK_TABLE(table), dialog->stop_typing,  3, 4, 0, 1,
650 					 GTK_FILL, 0, 0, 0);
651 
652 	gtk_widget_show(dialog->signon);
653 	gtk_widget_show(dialog->signoff);
654 	gtk_widget_show(dialog->away);
655 	gtk_widget_show(dialog->away_return);
656 	gtk_widget_show(dialog->idle);
657 	gtk_widget_show(dialog->idle_return);
658 	gtk_widget_show(dialog->typing);
659 	gtk_widget_show(dialog->typed);
660 	gtk_widget_show(dialog->stop_typing);
661 	gtk_widget_show(dialog->message_recv);
662 
663 	/* Create the "Action" frame. */
664 	frame = pidgin_make_frame(vbox2, _("Action"));
665 
666 	table = gtk_table_new(3, 6, FALSE);
667 	gtk_container_add(GTK_CONTAINER(frame), table);
668 	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BORDER);
669 	gtk_widget_show(table);
670 
671 	dialog->open_win
672 		= gtk_check_button_new_with_mnemonic(_("Ope_n an IM window"));
673 	dialog->popup
674 		= gtk_check_button_new_with_mnemonic(_("_Pop up a notification"));
675 	dialog->send_msg
676 		= gtk_check_button_new_with_mnemonic(_("Send a _message"));
677 	dialog->exec_cmd
678 		= gtk_check_button_new_with_mnemonic(_("E_xecute a command"));
679 	dialog->play_sound
680 		= gtk_check_button_new_with_mnemonic(_("P_lay a sound"));
681 
682 	send_msg_imhtml = pidgin_create_imhtml(TRUE, &dialog->send_msg_entry, NULL, NULL);
683 	reset_send_msg_entry(dialog, NULL);
684 	dialog->exec_cmd_entry    = gtk_entry_new();
685 	dialog->popup_entry       = gtk_entry_new();
686 	dialog->exec_cmd_browse   = gtk_button_new_with_mnemonic(_("Brows_e..."));
687 	dialog->play_sound_entry  = gtk_entry_new();
688 	gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), _("(default)"));
689 	gtk_editable_set_editable(GTK_EDITABLE(dialog->play_sound_entry), FALSE);
690 	dialog->play_sound_browse = gtk_button_new_with_mnemonic(_("Br_owse..."));
691 	dialog->play_sound_test   = gtk_button_new_with_mnemonic(_("Pre_view"));
692 	dialog->play_sound_reset  = gtk_button_new_with_mnemonic(_("Reset"));
693 
694 	gtk_widget_set_sensitive(send_msg_imhtml,           FALSE);
695 	gtk_widget_set_sensitive(dialog->exec_cmd_entry,    FALSE);
696 	gtk_widget_set_sensitive(dialog->popup_entry,       FALSE);
697 	gtk_widget_set_sensitive(dialog->exec_cmd_browse,   FALSE);
698 	gtk_widget_set_sensitive(dialog->play_sound_entry,  FALSE);
699 	gtk_widget_set_sensitive(dialog->play_sound_browse, FALSE);
700 	gtk_widget_set_sensitive(dialog->play_sound_test,   FALSE);
701 	gtk_widget_set_sensitive(dialog->play_sound_reset,  FALSE);
702 
703 	g_object_unref(sg);
704 
705 	sg = gtk_size_group_new(GTK_SIZE_GROUP_VERTICAL);
706 	gtk_size_group_add_widget(sg, dialog->open_win);
707 	gtk_size_group_add_widget(sg, dialog->popup);
708 	gtk_size_group_add_widget(sg, dialog->popup_entry);
709 	gtk_size_group_add_widget(sg, dialog->exec_cmd);
710 	gtk_size_group_add_widget(sg, dialog->exec_cmd_entry);
711 	gtk_size_group_add_widget(sg, dialog->exec_cmd_browse);
712 	gtk_size_group_add_widget(sg, dialog->play_sound);
713 	gtk_size_group_add_widget(sg, dialog->play_sound_entry);
714 	gtk_size_group_add_widget(sg, dialog->play_sound_browse);
715 	gtk_size_group_add_widget(sg, dialog->play_sound_test);
716 	gtk_size_group_add_widget(sg, dialog->play_sound_reset);
717 
718 	g_object_unref(sg);
719 	sg = NULL;
720 
721 	gtk_table_attach(GTK_TABLE(table), dialog->open_win,         0, 1, 0, 1,
722 					 GTK_FILL, 0, 0, 0);
723 	gtk_table_attach(GTK_TABLE(table), dialog->popup,            0, 1, 1, 2,
724 					 GTK_FILL, 0, 0, 0);
725 	gtk_table_attach(GTK_TABLE(table), dialog->popup_entry,      1, 5, 1, 2,
726 					 GTK_FILL, 0, 0, 0);
727 	gtk_table_attach(GTK_TABLE(table), dialog->send_msg,         0, 5, 2, 3,
728 					 GTK_FILL, 0, 0, 0);
729 	gtk_table_attach(GTK_TABLE(table), send_msg_imhtml,          0, 5, 3, 4,
730 					 GTK_FILL, 0, 0, 0);
731 	gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd,         0, 1, 4, 5,
732 					 GTK_FILL, 0, 0, 0);
733 	gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_entry,   1, 2, 4, 5,
734 					 GTK_FILL, 0, 0, 0);
735 	gtk_table_attach(GTK_TABLE(table), dialog->exec_cmd_browse,  2, 3, 4, 5,
736 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
737 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound,       0, 1, 5, 6,
738 					 GTK_FILL, 0, 0, 0);
739 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_entry, 1, 2, 5, 6,
740 					 GTK_FILL, 0, 0, 0);
741 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_browse,2, 3, 5, 6,
742 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
743 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_test,  3, 4, 5, 6,
744 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
745 	gtk_table_attach(GTK_TABLE(table), dialog->play_sound_reset, 4, 5, 5, 6,
746 					 GTK_FILL | GTK_EXPAND, 0, 0, 0);
747 
748 	gtk_table_set_row_spacings(GTK_TABLE(table), PIDGIN_HIG_BOX_SPACE / 2);
749 
750 	gtk_widget_show(dialog->open_win);
751 	gtk_widget_show(dialog->popup);
752 	gtk_widget_show(dialog->popup_entry);
753 	gtk_widget_show(dialog->send_msg);
754 	gtk_widget_show(send_msg_imhtml);
755 	gtk_widget_show(dialog->exec_cmd);
756 	gtk_widget_show(dialog->exec_cmd_entry);
757 	gtk_widget_show(dialog->exec_cmd_browse);
758 	gtk_widget_show(dialog->play_sound);
759 	gtk_widget_show(dialog->play_sound_entry);
760 	gtk_widget_show(dialog->play_sound_browse);
761 	gtk_widget_show(dialog->play_sound_test);
762 	gtk_widget_show(dialog->play_sound_reset);
763 
764 	g_signal_connect(G_OBJECT(dialog->message_recv), "clicked",
765 					 G_CALLBACK(message_recv_toggle),
766 					 dialog->send_msg);
767 
768 	g_signal_connect(G_OBJECT(dialog->send_msg), "clicked",
769 					 G_CALLBACK(pidgin_toggle_sensitive),
770 					 send_msg_imhtml);
771 
772 	g_signal_connect(G_OBJECT(dialog->popup), "clicked",
773 					 G_CALLBACK(pidgin_toggle_sensitive),
774 					 dialog->popup_entry);
775 
776 	exec_widgets = g_ptr_array_new();
777 	g_ptr_array_add(exec_widgets,dialog->exec_cmd_entry);
778 	g_ptr_array_add(exec_widgets,dialog->exec_cmd_browse);
779 
780 	g_signal_connect(G_OBJECT(dialog->exec_cmd), "clicked",
781 					 G_CALLBACK(pidgin_toggle_sensitive_array),
782 					 exec_widgets);
783 	g_signal_connect(G_OBJECT(dialog->exec_cmd_browse), "clicked",
784 					 G_CALLBACK(filesel),
785 					 dialog->exec_cmd_entry);
786 	g_object_set_data_full(G_OBJECT(dialog->window), "exec-widgets",
787 				exec_widgets, (GDestroyNotify)g_ptr_array_free);
788 
789 	sound_widgets = g_ptr_array_new();
790 	g_ptr_array_add(sound_widgets,dialog->play_sound_entry);
791 	g_ptr_array_add(sound_widgets,dialog->play_sound_browse);
792 	g_ptr_array_add(sound_widgets,dialog->play_sound_test);
793 	g_ptr_array_add(sound_widgets,dialog->play_sound_reset);
794 
795 	g_signal_connect(G_OBJECT(dialog->play_sound), "clicked",
796 					 G_CALLBACK(pidgin_toggle_sensitive_array),
797 					 sound_widgets);
798 	g_signal_connect(G_OBJECT(dialog->play_sound_browse), "clicked",
799 					 G_CALLBACK(filesel),
800 					 dialog->play_sound_entry);
801 	g_signal_connect(G_OBJECT(dialog->play_sound_test), "clicked",
802 					 G_CALLBACK(pounce_test_sound),
803 					 dialog->play_sound_entry);
804 	g_signal_connect(G_OBJECT(dialog->play_sound_reset), "clicked",
805 					 G_CALLBACK(pounce_reset_sound),
806 					 dialog->play_sound_entry);
807 	g_object_set_data_full(G_OBJECT(dialog->window), "sound-widgets",
808 				sound_widgets, (GDestroyNotify)g_ptr_array_free);
809 
810 	g_signal_connect_swapped(G_OBJECT(dialog->send_msg_entry), "format_function_clear",
811 			G_CALLBACK(reset_send_msg_entry), dialog);
812 	g_signal_connect_swapped(G_OBJECT(dialog->account_menu), "changed",
813 			G_CALLBACK(reset_send_msg_entry), dialog);
814 
815 	g_signal_connect(G_OBJECT(dialog->send_msg_entry), "message_send",
816 					 G_CALLBACK(save_pounce_cb), dialog);
817 	g_signal_connect(G_OBJECT(dialog->popup_entry), "activate",
818 					 G_CALLBACK(save_pounce_cb), dialog);
819 	g_signal_connect(G_OBJECT(dialog->exec_cmd_entry), "activate",
820 					 G_CALLBACK(save_pounce_cb), dialog);
821 
822 	/* Create the "Options" frame. */
823 	frame = pidgin_make_frame(vbox2, _("Options"));
824 
825 	table = gtk_table_new(2, 1, FALSE);
826 	gtk_container_add(GTK_CONTAINER(frame), table);
827 	gtk_table_set_col_spacings(GTK_TABLE(table), PIDGIN_HIG_BORDER);
828 	gtk_widget_show(table);
829 
830 	dialog->on_away =
831 		gtk_check_button_new_with_mnemonic(_("P_ounce only when my status is not Available"));
832 	gtk_table_attach(GTK_TABLE(table), dialog->on_away, 0, 1, 0, 1,
833 					 GTK_FILL, 0, 0, 0);
834 
835 	dialog->save_pounce = gtk_check_button_new_with_mnemonic(
836 		_("_Recurring"));
837 	gtk_table_attach(GTK_TABLE(table), dialog->save_pounce, 0, 1, 1, 2,
838 					 GTK_FILL, 0, 0, 0);
839 
840 	gtk_widget_show(dialog->on_away);
841 	gtk_widget_show(dialog->save_pounce);
842 
843 	/* Cancel button */
844 	button = gtk_dialog_add_button(GTK_DIALOG(window), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
845 	g_signal_connect(G_OBJECT(button), "clicked",
846 					 G_CALLBACK(cancel_cb), dialog);
847 
848 	/* Save/Add button */
849 	dialog->save_button = button = gtk_dialog_add_button(GTK_DIALOG(window),
850 	                                                     (cur_pounce == NULL ? GTK_STOCK_ADD : GTK_STOCK_SAVE),
851 	                                                     GTK_RESPONSE_OK);
852 	g_signal_connect(G_OBJECT(button), "clicked",
853 	                 G_CALLBACK(save_pounce_cb), dialog);
854 
855 	if (*gtk_entry_get_text(GTK_ENTRY(dialog->buddy_entry)) == '\0')
856 		gtk_widget_set_sensitive(button, FALSE);
857 
858 	/* Setup drag-and-drop */
859 	gtk_drag_dest_set(window,
860 					  GTK_DEST_DEFAULT_MOTION |
861 					  GTK_DEST_DEFAULT_DROP,
862 					  dnd_targets,
863 					  sizeof(dnd_targets) / sizeof(GtkTargetEntry),
864 					  GDK_ACTION_COPY);
865 	gtk_drag_dest_set(dialog->buddy_entry,
866 					  GTK_DEST_DEFAULT_MOTION |
867 					  GTK_DEST_DEFAULT_DROP,
868 					  dnd_targets,
869 					  sizeof(dnd_targets) / sizeof(GtkTargetEntry),
870 					  GDK_ACTION_COPY);
871 
872 	g_signal_connect(G_OBJECT(window), "drag_data_received",
873 					 G_CALLBACK(pounce_dnd_recv), dialog);
874 	g_signal_connect(G_OBJECT(dialog->buddy_entry), "drag_data_received",
875 					 G_CALLBACK(pounce_dnd_recv), dialog);
876 
877 	/* Set the values of stuff. */
878 	if (cur_pounce != NULL)
879 	{
880 		PurplePounceEvent events   = purple_pounce_get_events(cur_pounce);
881 		PurplePounceOption options = purple_pounce_get_options(cur_pounce);
882 		const char *value;
883 
884 		/* Options */
885 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->on_away),
886 									(options & PURPLE_POUNCE_OPTION_AWAY));
887 
888 		/* Events */
889 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->signon),
890 									(events & PURPLE_POUNCE_SIGNON));
891 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->signoff),
892 									(events & PURPLE_POUNCE_SIGNOFF));
893 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->away),
894 									(events & PURPLE_POUNCE_AWAY));
895 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->away_return),
896 									(events & PURPLE_POUNCE_AWAY_RETURN));
897 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->idle),
898 									(events & PURPLE_POUNCE_IDLE));
899 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->idle_return),
900 									(events & PURPLE_POUNCE_IDLE_RETURN));
901 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->typing),
902 									(events & PURPLE_POUNCE_TYPING));
903 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->typed),
904 									(events & PURPLE_POUNCE_TYPED));
905 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->stop_typing),
906 									(events & PURPLE_POUNCE_TYPING_STOPPED));
907 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->message_recv),
908 									(events & PURPLE_POUNCE_MESSAGE_RECEIVED));
909 
910 		/* Actions */
911 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->open_win),
912 			purple_pounce_action_is_enabled(cur_pounce, "open-window"));
913 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->popup),
914 			purple_pounce_action_is_enabled(cur_pounce, "popup-notify"));
915 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->send_msg),
916 			purple_pounce_action_is_enabled(cur_pounce, "send-message"));
917 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd),
918 			purple_pounce_action_is_enabled(cur_pounce, "execute-command"));
919 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->play_sound),
920 			purple_pounce_action_is_enabled(cur_pounce, "play-sound"));
921 
922 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->save_pounce),
923 			purple_pounce_get_save(cur_pounce));
924 
925 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
926 													  "send-message",
927 													  "message")) != NULL)
928 		{
929 			gtk_imhtml_append_text(GTK_IMHTML(dialog->send_msg_entry), value, 0);
930 		}
931 
932 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
933 													  "popup-notify",
934 													  "reason")) != NULL)
935 		{
936 			gtk_entry_set_text(GTK_ENTRY(dialog->popup_entry), value);
937 		}
938 
939 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
940 													  "execute-command",
941 													  "command")) != NULL)
942 		{
943 			gtk_entry_set_text(GTK_ENTRY(dialog->exec_cmd_entry), value);
944 		}
945 
946 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
947 													  "play-sound",
948 													  "filename")) != NULL)
949 		{
950 			gtk_entry_set_text(GTK_ENTRY(dialog->play_sound_entry), (value && *value != '\0') ? value : _("(default)"));
951 		}
952 	}
953 	else
954 	{
955 		PurpleBuddy *buddy = NULL;
956 
957 		if (name != NULL)
958 			buddy = purple_find_buddy(account, name);
959 
960 		/* Set some defaults */
961 		if (buddy == NULL)
962 		{
963 			gtk_toggle_button_set_active(
964 				GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
965 		}
966 		else
967 		{
968 			if (!PURPLE_BUDDY_IS_ONLINE(buddy))
969 			{
970 				gtk_toggle_button_set_active(
971 					GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
972 			}
973 			else
974 			{
975 				gboolean default_set = FALSE;
976 				PurplePresence *presence = purple_buddy_get_presence(buddy);
977 
978 				if (purple_presence_is_idle(presence))
979 				{
980 					gtk_toggle_button_set_active(
981 						GTK_TOGGLE_BUTTON(dialog->idle_return), TRUE);
982 
983 					default_set = TRUE;
984 				}
985 
986 				if (!purple_presence_is_available(presence))
987 				{
988 					gtk_toggle_button_set_active(
989 						GTK_TOGGLE_BUTTON(dialog->away_return), TRUE);
990 
991 					default_set = TRUE;
992 				}
993 
994 				if (!default_set)
995 				{
996 					gtk_toggle_button_set_active(
997 						GTK_TOGGLE_BUTTON(dialog->signon), TRUE);
998 				}
999 			}
1000 		}
1001 
1002 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->open_win),
1003 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/open-window"));
1004 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->popup),
1005 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/popup-notify"));
1006 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->send_msg),
1007 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/send-message"));
1008 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->exec_cmd),
1009 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/execute-command"));
1010 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dialog->play_sound),
1011 			purple_prefs_get_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/play-sound"));
1012 	}
1013 
1014 	gtk_widget_show(vbox2);
1015 	gtk_widget_show(window);
1016 }
1017 
1018 static gboolean
pounces_manager_configure_cb(GtkWidget * widget,GdkEventConfigure * event,PouncesManager * dialog)1019 pounces_manager_configure_cb(GtkWidget *widget, GdkEventConfigure *event, PouncesManager *dialog)
1020 {
1021 	if (GTK_WIDGET_VISIBLE(widget)) {
1022 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width",  event->width);
1023 		purple_prefs_set_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height", event->height);
1024 	}
1025 
1026 	return FALSE;
1027 }
1028 
1029 static gboolean
pounces_manager_find_pounce(GtkTreeIter * iter,PurplePounce * pounce)1030 pounces_manager_find_pounce(GtkTreeIter *iter, PurplePounce *pounce)
1031 {
1032 	GtkTreeModel *model = GTK_TREE_MODEL(pounces_manager->model);
1033 	PurplePounce *p;
1034 
1035 	if (!gtk_tree_model_get_iter_first(model, iter))
1036 		return FALSE;
1037 
1038 	gtk_tree_model_get(model, iter, POUNCES_MANAGER_COLUMN_POUNCE, &p, -1);
1039 	if (pounce == p)
1040 		return TRUE;
1041 
1042 	while (gtk_tree_model_iter_next(model, iter))
1043 	{
1044 		gtk_tree_model_get(model, iter, POUNCES_MANAGER_COLUMN_POUNCE, &p, -1);
1045 		if (pounce == p)
1046 			return TRUE;
1047 	}
1048 
1049 	return FALSE;
1050 }
1051 
1052 static gboolean
pounces_manager_destroy_cb(GtkWidget * widget,GdkEvent * event,gpointer user_data)1053 pounces_manager_destroy_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1054 {
1055 	PouncesManager *dialog = user_data;
1056 
1057 	dialog->window = NULL;
1058 	pidgin_pounces_manager_hide();
1059 
1060 	return FALSE;
1061 }
1062 
1063 static void
pounces_manager_connection_cb(PurpleConnection * gc,GtkWidget * add_button)1064 pounces_manager_connection_cb(PurpleConnection *gc, GtkWidget *add_button)
1065 {
1066 	gtk_widget_set_sensitive(add_button, (purple_connections_get_all() != NULL));
1067 }
1068 
1069 static void
pounces_manager_add_cb(GtkButton * button,gpointer user_data)1070 pounces_manager_add_cb(GtkButton *button, gpointer user_data)
1071 {
1072 	pidgin_pounce_editor_show(NULL, NULL, NULL);
1073 }
1074 
1075 static void
pounces_manager_modify_foreach(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)1076 pounces_manager_modify_foreach(GtkTreeModel *model, GtkTreePath *path,
1077 							 GtkTreeIter *iter, gpointer user_data)
1078 {
1079 	PurplePounce *pounce;
1080 
1081 	gtk_tree_model_get(model, iter, POUNCES_MANAGER_COLUMN_POUNCE, &pounce, -1);
1082 	pidgin_pounce_editor_show(NULL, NULL, pounce);
1083 }
1084 
1085 static void
pounces_manager_modify_cb(GtkButton * button,gpointer user_data)1086 pounces_manager_modify_cb(GtkButton *button, gpointer user_data)
1087 {
1088 	PouncesManager *dialog = user_data;
1089 	GtkTreeSelection *selection;
1090 
1091 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
1092 
1093 	gtk_tree_selection_selected_foreach(selection, pounces_manager_modify_foreach, user_data);
1094 }
1095 
1096 static void
pounces_manager_delete_confirm_cb(PurplePounce * pounce)1097 pounces_manager_delete_confirm_cb(PurplePounce *pounce)
1098 {
1099 	GtkTreeIter iter;
1100 
1101 	if (pounces_manager && pounces_manager_find_pounce(&iter, pounce))
1102 		gtk_list_store_remove(pounces_manager->model, &iter);
1103 
1104 	purple_request_close_with_handle(pounce);
1105 	purple_pounce_destroy(pounce);
1106 }
1107 
1108 static void
pounces_manager_delete_foreach(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer user_data)1109 pounces_manager_delete_foreach(GtkTreeModel *model, GtkTreePath *path,
1110 							   GtkTreeIter *iter, gpointer user_data)
1111 {
1112 	PurplePounce *pounce;
1113 	PurpleAccount *account;
1114 	const char *pouncer, *pouncee;
1115 	char *buf;
1116 
1117 	gtk_tree_model_get(model, iter, POUNCES_MANAGER_COLUMN_POUNCE, &pounce, -1);
1118 	account = purple_pounce_get_pouncer(pounce);
1119 	pouncer = purple_account_get_username(account);
1120 	pouncee = purple_pounce_get_pouncee(pounce);
1121 
1122 	buf = g_strdup_printf(_("Are you sure you want to delete the pounce on %s for %s?"), pouncee, pouncer);
1123 	purple_request_action(pounce, NULL, buf, NULL, 0,
1124 						account, pouncee, NULL,
1125 						pounce, 2,
1126 						_("Delete"), pounces_manager_delete_confirm_cb,
1127 						_("Cancel"), NULL);
1128 	g_free(buf);
1129 }
1130 
1131 static void
pounces_manager_delete_cb(GtkButton * button,gpointer user_data)1132 pounces_manager_delete_cb(GtkButton *button, gpointer user_data)
1133 {
1134 	PouncesManager *dialog = user_data;
1135 	GtkTreeSelection *selection;
1136 
1137 	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->treeview));
1138 
1139 	gtk_tree_selection_selected_foreach(selection, pounces_manager_delete_foreach, user_data);
1140 }
1141 
1142 static void
pounces_manager_close_cb(GtkButton * button,gpointer user_data)1143 pounces_manager_close_cb(GtkButton *button, gpointer user_data)
1144 {
1145 	pidgin_pounces_manager_hide();
1146 }
1147 
1148 static void
pounce_selected_cb(GtkTreeSelection * sel,gpointer user_data)1149 pounce_selected_cb(GtkTreeSelection *sel, gpointer user_data)
1150 {
1151 	PouncesManager *dialog = user_data;
1152 	int num_selected = 0;
1153 
1154 	num_selected = gtk_tree_selection_count_selected_rows(sel);
1155 
1156 	gtk_widget_set_sensitive(dialog->modify_button, (num_selected > 0));
1157 	gtk_widget_set_sensitive(dialog->delete_button, (num_selected > 0));
1158 }
1159 
1160 static gboolean
pounce_double_click_cb(GtkTreeView * treeview,GdkEventButton * event,gpointer user_data)1161 pounce_double_click_cb(GtkTreeView *treeview, GdkEventButton *event, gpointer user_data)
1162 {
1163 	PouncesManager *dialog = user_data;
1164 	GtkTreePath *path;
1165 	GtkTreeIter iter;
1166 	PurplePounce *pounce;
1167 
1168 	/* Figure out which node was clicked */
1169 	if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(dialog->treeview), event->x, event->y, &path, NULL, NULL, NULL))
1170 		return FALSE;
1171 	gtk_tree_model_get_iter(GTK_TREE_MODEL(dialog->model), &iter, path);
1172 	gtk_tree_path_free(path);
1173 	gtk_tree_model_get(GTK_TREE_MODEL(dialog->model), &iter, POUNCES_MANAGER_COLUMN_POUNCE, &pounce, -1);
1174 
1175 	if ((pounce != NULL) && (event->button == 1) &&
1176 		(event->type == GDK_2BUTTON_PRESS))
1177 	{
1178 		pidgin_pounce_editor_show(NULL, NULL, pounce);
1179 		return TRUE;
1180 	}
1181 
1182 	return FALSE;
1183 }
1184 
1185 static void
pounces_manager_recurring_cb(GtkCellRendererToggle * renderer,gchar * path_str,gpointer user_data)1186 pounces_manager_recurring_cb(GtkCellRendererToggle *renderer, gchar *path_str,
1187 							gpointer user_data)
1188 {
1189 	PouncesManager *dialog = user_data;
1190 	PurplePounce *pounce;
1191 	gboolean recurring;
1192 	GtkTreeModel *model = GTK_TREE_MODEL(dialog->model);
1193 	GtkTreeIter iter;
1194 
1195 	gtk_tree_model_get_iter_from_string(model, &iter, path_str);
1196 	gtk_tree_model_get(model, &iter,
1197 					   POUNCES_MANAGER_COLUMN_POUNCE, &pounce,
1198 					   POUNCES_MANAGER_COLUMN_RECURRING, &recurring,
1199 					   -1);
1200 
1201 	purple_pounce_set_save(pounce, !recurring);
1202 
1203 	update_pounces();
1204 }
1205 
1206 static gboolean
search_func(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)1207 search_func(GtkTreeModel *model, gint column, const gchar *key, GtkTreeIter *iter, gpointer search_data)
1208 {
1209 	gboolean result;
1210 	char *haystack;
1211 
1212 	gtk_tree_model_get(model, iter, column, &haystack, -1);
1213 
1214 	result = (purple_strcasestr(haystack, key) == NULL);
1215 
1216 	g_free(haystack);
1217 
1218 	return result;
1219 }
1220 
1221 static GtkWidget *
create_pounces_list(PouncesManager * dialog)1222 create_pounces_list(PouncesManager *dialog)
1223 {
1224 	GtkWidget *treeview;
1225 	GtkTreeSelection *sel;
1226 	GtkTreeViewColumn *column;
1227 	GtkCellRenderer *renderer;
1228 
1229 	/* Create the list model */
1230 	dialog->model = gtk_list_store_new(POUNCES_MANAGER_NUM_COLUMNS,
1231 									   G_TYPE_POINTER,
1232 									   GDK_TYPE_PIXBUF,
1233 									   G_TYPE_STRING,
1234 									   G_TYPE_STRING,
1235 									   G_TYPE_BOOLEAN
1236 									   );
1237 
1238 	/* Create the treeview */
1239 	treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dialog->model));
1240 	g_object_unref(G_OBJECT(dialog->model));
1241 	dialog->treeview = treeview;
1242 	gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE);
1243 
1244 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
1245 	gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
1246 	g_signal_connect(G_OBJECT(sel), "changed",
1247 					 G_CALLBACK(pounce_selected_cb), dialog);
1248 
1249 	/* Handle double-clicking */
1250 	g_signal_connect(G_OBJECT(treeview), "button_press_event",
1251 					 G_CALLBACK(pounce_double_click_cb), dialog);
1252 	gtk_widget_show(treeview);
1253 
1254 	/* Pouncee Column */
1255 	column = gtk_tree_view_column_new();
1256 	gtk_tree_view_column_set_title(column, _("Pounce Target"));
1257 	gtk_tree_view_column_set_resizable(column, TRUE);
1258 	gtk_tree_view_column_set_min_width(column, 200);
1259 	gtk_tree_view_column_set_sort_column_id(column,
1260 											POUNCES_MANAGER_COLUMN_TARGET);
1261 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
1262 
1263 	/* Icon */
1264 	renderer = gtk_cell_renderer_pixbuf_new();
1265 	gtk_tree_view_column_pack_start(column, renderer, FALSE);
1266 	gtk_tree_view_column_add_attribute(column, renderer, "pixbuf",
1267 									   POUNCES_MANAGER_COLUMN_ICON);
1268 
1269 	/* Pouncee */
1270 	renderer = gtk_cell_renderer_text_new();
1271 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
1272 	gtk_tree_view_column_add_attribute(column, renderer, "text",
1273 									   POUNCES_MANAGER_COLUMN_TARGET);
1274 
1275 
1276 	/* Account Column */
1277 	column = gtk_tree_view_column_new();
1278 	gtk_tree_view_column_set_title(column, _("Account"));
1279 	gtk_tree_view_column_set_resizable(column, TRUE);
1280 	gtk_tree_view_column_set_min_width(column, 200);
1281 	gtk_tree_view_column_set_sort_column_id(column,
1282 											POUNCES_MANAGER_COLUMN_ACCOUNT);
1283 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
1284 	renderer = gtk_cell_renderer_text_new();
1285 	gtk_tree_view_column_pack_start(column, renderer, TRUE);
1286 	gtk_tree_view_column_add_attribute(column, renderer, "text",
1287 									   POUNCES_MANAGER_COLUMN_ACCOUNT);
1288 
1289 	/* Recurring Column */
1290 	renderer = gtk_cell_renderer_toggle_new();
1291 	column = gtk_tree_view_column_new_with_attributes(_("Recurring"), renderer,
1292 						"active", POUNCES_MANAGER_COLUMN_RECURRING, NULL);
1293 	gtk_tree_view_column_set_sort_column_id(column,
1294 											POUNCES_MANAGER_COLUMN_RECURRING);
1295 	gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
1296 	g_signal_connect(G_OBJECT(renderer), "toggled",
1297 			 G_CALLBACK(pounces_manager_recurring_cb), dialog);
1298 
1299 	/* Enable CTRL+F searching */
1300 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(treeview), POUNCES_MANAGER_COLUMN_TARGET);
1301 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(treeview), search_func, NULL, NULL);
1302 
1303 	/* Sort the pouncee column by default */
1304 	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dialog->model),
1305 										 POUNCES_MANAGER_COLUMN_TARGET,
1306 										 GTK_SORT_ASCENDING);
1307 
1308 	/* Populate list */
1309 	populate_pounces_list(dialog);
1310 
1311 	return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
1312 }
1313 
1314 void
pidgin_pounces_manager_show(void)1315 pidgin_pounces_manager_show(void)
1316 {
1317 	PouncesManager *dialog;
1318 	GtkWidget *button;
1319 	GtkWidget *list;
1320 	GtkWidget *vbox;
1321 	GtkWidget *win;
1322 	int width, height;
1323 
1324 	if (pounces_manager != NULL) {
1325 		gtk_window_present(GTK_WINDOW(pounces_manager->window));
1326 		return;
1327 	}
1328 
1329 	pounces_manager = dialog = g_new0(PouncesManager, 1);
1330 
1331 	width  = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width");
1332 	height = purple_prefs_get_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height");
1333 
1334 	dialog->window = win = pidgin_create_dialog(_("Buddy Pounces"), PIDGIN_HIG_BORDER, "pounces", TRUE);
1335 	gtk_window_set_default_size(GTK_WINDOW(win), width, height);
1336 
1337 	g_signal_connect(G_OBJECT(win), "delete_event",
1338 					 G_CALLBACK(pounces_manager_destroy_cb), dialog);
1339 	g_signal_connect(G_OBJECT(win), "configure_event",
1340 					 G_CALLBACK(pounces_manager_configure_cb), dialog);
1341 
1342 	/* Setup the vbox */
1343 	vbox = pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(win), FALSE, PIDGIN_HIG_BORDER);
1344 
1345 	/* List of saved buddy pounces */
1346 	list = create_pounces_list(dialog);
1347 	gtk_box_pack_start(GTK_BOX(vbox), list, TRUE, TRUE, 0);
1348 
1349 	/* Add button */
1350 	button = pidgin_dialog_add_button(GTK_DIALOG(win), PIDGIN_STOCK_ADD, G_CALLBACK(pounces_manager_add_cb), dialog);
1351 	gtk_widget_set_sensitive(button, (purple_accounts_get_all() != NULL));
1352 
1353 	purple_signal_connect(purple_connections_get_handle(), "signed-on",
1354 						pounces_manager, PURPLE_CALLBACK(pounces_manager_connection_cb), button);
1355 	purple_signal_connect(purple_connections_get_handle(), "signed-off",
1356 						pounces_manager, PURPLE_CALLBACK(pounces_manager_connection_cb), button);
1357 
1358 	/* Modify button */
1359 	button = pidgin_dialog_add_button(GTK_DIALOG(win), PIDGIN_STOCK_MODIFY, G_CALLBACK(pounces_manager_modify_cb), dialog);
1360 	gtk_widget_set_sensitive(button, FALSE);
1361 	dialog->modify_button = button;
1362 
1363 	/* Delete button */
1364 	button = pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_DELETE, G_CALLBACK(pounces_manager_delete_cb), dialog);
1365 	gtk_widget_set_sensitive(button, FALSE);
1366 	dialog->delete_button = button;
1367 
1368 	/* Close button */
1369 	pidgin_dialog_add_button(GTK_DIALOG(win), GTK_STOCK_CLOSE, G_CALLBACK(pounces_manager_close_cb), dialog);
1370 
1371 	gtk_widget_show(win);
1372 }
1373 
1374 void
pidgin_pounces_manager_hide(void)1375 pidgin_pounces_manager_hide(void)
1376 {
1377 	if (pounces_manager == NULL)
1378 		return;
1379 
1380 	if (pounces_manager->window != NULL)
1381 		gtk_widget_destroy(pounces_manager->window);
1382 
1383 	purple_signals_disconnect_by_handle(pounces_manager);
1384 
1385 	g_free(pounces_manager);
1386 	pounces_manager = NULL;
1387 }
1388 
1389 static void
pounce_cb(PurplePounce * pounce,PurplePounceEvent events,void * data)1390 pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data)
1391 {
1392 	PurpleConversation *conv;
1393 	PurpleAccount *account;
1394 	PurpleBuddy *buddy;
1395 	const char *pouncee;
1396 	const char *alias;
1397 
1398 	pouncee = purple_pounce_get_pouncee(pounce);
1399 	account = purple_pounce_get_pouncer(pounce);
1400 
1401 	buddy = purple_find_buddy(account, pouncee);
1402 	if (buddy != NULL)
1403 	{
1404 		alias = purple_buddy_get_alias(buddy);
1405 		if (alias == NULL)
1406 			alias = pouncee;
1407 	}
1408 	else
1409 		alias = pouncee;
1410 
1411 	if (purple_pounce_action_is_enabled(pounce, "open-window"))
1412 	{
1413 		if (!purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pouncee, account))
1414 			purple_conversation_new(PURPLE_CONV_TYPE_IM, account, pouncee);
1415 	}
1416 
1417 	if (purple_pounce_action_is_enabled(pounce, "popup-notify"))
1418 	{
1419 		char *tmp;
1420 		const char *reason;
1421 		reason = purple_pounce_action_get_attribute(pounce, "popup-notify",
1422 														  "reason");
1423 
1424 		/*
1425 		 * Here we place the protocol name in the pounce dialog to lessen
1426 		 * confusion about what protocol a pounce is for.
1427 		 */
1428 		tmp = g_strdup(
1429 				   (events & PURPLE_POUNCE_TYPING) ?
1430 				   _("Started typing") :
1431 				   (events & PURPLE_POUNCE_TYPED) ?
1432 				   _("Paused while typing") :
1433 				   (events & PURPLE_POUNCE_SIGNON) ?
1434 				   _("Signed on") :
1435 				   (events & PURPLE_POUNCE_IDLE_RETURN) ?
1436 				   _("Returned from being idle") :
1437 				   (events & PURPLE_POUNCE_AWAY_RETURN) ?
1438 				   _("Returned from being away") :
1439 				   (events & PURPLE_POUNCE_TYPING_STOPPED) ?
1440 				   _("Stopped typing") :
1441 				   (events & PURPLE_POUNCE_SIGNOFF) ?
1442 				   _("Signed off") :
1443 				   (events & PURPLE_POUNCE_IDLE) ?
1444 				   _("Became idle") :
1445 				   (events & PURPLE_POUNCE_AWAY) ?
1446 				   _("Went away") :
1447 				   (events & PURPLE_POUNCE_MESSAGE_RECEIVED) ?
1448 				   _("Sent a message") :
1449 				   _("Unknown.... Please report this!")
1450 				   );
1451 
1452 		pidgin_notify_pounce_add(account, pounce, alias, tmp, reason,
1453 				purple_date_format_full(NULL));
1454 
1455 		g_free(tmp);
1456 	}
1457 
1458 	if (purple_pounce_action_is_enabled(pounce, "send-message"))
1459 	{
1460 		const char *message;
1461 
1462 		message = purple_pounce_action_get_attribute(pounce, "send-message",
1463 												   "message");
1464 
1465 		if (message != NULL)
1466 		{
1467 			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pouncee, account);
1468 
1469 			if (conv == NULL)
1470 				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, pouncee);
1471 
1472 			purple_conversation_write(conv, NULL, message,
1473 									PURPLE_MESSAGE_SEND, time(NULL));
1474 
1475 			serv_send_im(account->gc, (char *)pouncee, (char *)message, 0);
1476 		}
1477 	}
1478 
1479 	if (purple_pounce_action_is_enabled(pounce, "execute-command"))
1480 	{
1481 		const char *command;
1482 
1483 		command = purple_pounce_action_get_attribute(pounce,
1484 				"execute-command", "command");
1485 
1486 		if (command != NULL)
1487 		{
1488 #ifndef _WIN32
1489 			char *localecmd = g_locale_from_utf8(command, -1, NULL,
1490 					NULL, NULL);
1491 
1492 			if (localecmd != NULL)
1493 			{
1494 				int pid = fork();
1495 
1496 				if (pid == 0) {
1497 					char *args[4];
1498 
1499 					args[0] = "sh";
1500 					args[1] = "-c";
1501 					args[2] = (char *)localecmd;
1502 					args[3] = NULL;
1503 
1504 					execvp(args[0], args);
1505 
1506 					_exit(0);
1507 				}
1508 				g_free(localecmd);
1509 			}
1510 #else /* !_WIN32 */
1511 			winpidgin_shell_execute(command, "open", NULL);
1512 #endif /* !_WIN32 */
1513 		}
1514 	}
1515 
1516 	if (purple_pounce_action_is_enabled(pounce, "play-sound"))
1517 	{
1518 		const char *sound;
1519 
1520 		sound = purple_pounce_action_get_attribute(pounce,
1521 												 "play-sound", "filename");
1522 
1523 		if (sound != NULL)
1524 			purple_sound_play_file(sound, account);
1525 		else
1526 			purple_sound_play_event(PURPLE_SOUND_POUNCE_DEFAULT, account);
1527 	}
1528 }
1529 
1530 static void
free_pounce(PurplePounce * pounce)1531 free_pounce(PurplePounce *pounce)
1532 {
1533 	update_pounces();
1534 }
1535 
1536 static void
new_pounce(PurplePounce * pounce)1537 new_pounce(PurplePounce *pounce)
1538 {
1539 	purple_pounce_action_register(pounce, "open-window");
1540 	purple_pounce_action_register(pounce, "popup-notify");
1541 	purple_pounce_action_register(pounce, "send-message");
1542 	purple_pounce_action_register(pounce, "execute-command");
1543 	purple_pounce_action_register(pounce, "play-sound");
1544 
1545 	update_pounces();
1546 }
1547 
1548 void *
pidgin_pounces_get_handle()1549 pidgin_pounces_get_handle() {
1550 	static int handle;
1551 
1552 	return &handle;
1553 }
1554 
1555 void
pidgin_pounces_init(void)1556 pidgin_pounces_init(void)
1557 {
1558 	purple_pounces_register_handler(PIDGIN_UI, pounce_cb, new_pounce,
1559 								  free_pounce);
1560 
1561 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/pounces");
1562 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/pounces/default_actions");
1563 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/open-window",
1564 						FALSE);
1565 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/popup-notify",
1566 						TRUE);
1567 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/send-message",
1568 						FALSE);
1569 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/execute-command",
1570 						FALSE);
1571 	purple_prefs_add_bool(PIDGIN_PREFS_ROOT "/pounces/default_actions/play-sound",
1572 						FALSE);
1573 	purple_prefs_add_none(PIDGIN_PREFS_ROOT "/pounces/dialog");
1574 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/pounces/dialog/width",  520);
1575 	purple_prefs_add_int(PIDGIN_PREFS_ROOT "/pounces/dialog/height", 321);
1576 
1577 	purple_signal_connect(purple_connections_get_handle(), "signed-on",
1578 						pidgin_pounces_get_handle(),
1579 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
1580 	purple_signal_connect(purple_connections_get_handle(), "signed-off",
1581 						pidgin_pounces_get_handle(),
1582 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
1583 }
1584