1 /**
2  * @file gntpounce.c GNT Buddy Pounce API
3  * @ingroup finch
4  */
5 
6 /* finch
7  *
8  * Finch 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 
29 #include <gnt.h>
30 #include <gntbox.h>
31 #include <gntbutton.h>
32 #include <gntcheckbox.h>
33 #include <gntcombobox.h>
34 #include <gntentry.h>
35 #include <gntlabel.h>
36 #include <gntline.h>
37 #include <gnttree.h>
38 #include <gntutils.h>
39 
40 #include "finch.h"
41 
42 #include "account.h"
43 #include "conversation.h"
44 #include "debug.h"
45 #include "notify.h"
46 #include "prpl.h"
47 #include "request.h"
48 #include "server.h"
49 #include "util.h"
50 
51 #include "gntpounce.h"
52 
53 
54 typedef struct
55 {
56 	/* Pounce data */
57 	PurplePounce  *pounce;
58 	PurpleAccount *account;
59 
60 	/* The window */
61 	GntWidget *window;
62 
63 	/* Pounce on Whom */
64 	GntWidget *account_menu;
65 	GntWidget *buddy_entry;
66 
67 	/* Pounce options */
68 	GntWidget *on_away;
69 
70 	/* Pounce When Buddy... */
71 	GntWidget *signon;
72 	GntWidget *signoff;
73 	GntWidget *away;
74 	GntWidget *away_return;
75 	GntWidget *idle;
76 	GntWidget *idle_return;
77 	GntWidget *typing;
78 	GntWidget *typed;
79 	GntWidget *stop_typing;
80 	GntWidget *message_recv;
81 
82 	/* Action */
83 	GntWidget *open_win;
84 	GntWidget *popup;
85 	GntWidget *popup_entry;
86 	GntWidget *send_msg;
87 	GntWidget *send_msg_entry;
88 	GntWidget *exec_cmd;
89 	GntWidget *exec_cmd_entry;
90 	GntWidget *play_sound;
91 
92 	GntWidget *save_pounce;
93 
94 	/* Buttons */
95 	GntWidget *save_button;
96 
97 } PurpleGntPounceDialog;
98 
99 typedef struct
100 {
101 	GntWidget *window;
102 	GntWidget *tree;
103 	GntWidget *modify_button;
104 	GntWidget *delete_button;
105 } PouncesManager;
106 
107 static PouncesManager *pounces_manager = NULL;
108 
109 /**************************************************************************
110  * Callbacks
111  **************************************************************************/
112 static gint
delete_win_cb(GntWidget * w,PurpleGntPounceDialog * dialog)113 delete_win_cb(GntWidget *w, PurpleGntPounceDialog *dialog)
114 {
115 	gnt_widget_destroy(dialog->window);
116 	g_free(dialog);
117 
118 	return TRUE;
119 }
120 
121 static void
cancel_cb(GntWidget * w,PurpleGntPounceDialog * dialog)122 cancel_cb(GntWidget *w, PurpleGntPounceDialog *dialog)
123 {
124 	gnt_widget_destroy(dialog->window);
125 }
126 
127 static void
add_pounce_to_treeview(GntTree * tree,PurplePounce * pounce)128 add_pounce_to_treeview(GntTree *tree, PurplePounce *pounce)
129 {
130 	PurpleAccount *account;
131 	const char *pouncer;
132 	const char *pouncee;
133 
134 	account = purple_pounce_get_pouncer(pounce);
135 	pouncer = purple_account_get_username(account);
136 	pouncee = purple_pounce_get_pouncee(pounce);
137 	gnt_tree_add_row_last(tree, pounce,
138 		gnt_tree_create_row(tree, pouncer, pouncee), NULL);
139 }
140 
141 static void
populate_pounces_list(PouncesManager * dialog)142 populate_pounces_list(PouncesManager *dialog)
143 {
144 	GList *pounces;
145 
146 	gnt_tree_remove_all(GNT_TREE(dialog->tree));
147 
148 	for (pounces = purple_pounces_get_all_for_ui(FINCH_UI); pounces != NULL;
149 			pounces = g_list_delete_link(pounces, pounces))
150 	{
151 		add_pounce_to_treeview(GNT_TREE(dialog->tree), pounces->data);
152 	}
153 }
154 
155 static void
update_pounces(void)156 update_pounces(void)
157 {
158 	/* Rebuild the pounces list if the pounces manager is open */
159 	if (pounces_manager != NULL)
160 	{
161 		populate_pounces_list(pounces_manager);
162 	}
163 }
164 
165 static void
signed_on_off_cb(PurpleConnection * gc,gpointer user_data)166 signed_on_off_cb(PurpleConnection *gc, gpointer user_data)
167 {
168 	update_pounces();
169 }
170 
171 static void
setup_buddy_list_suggestion(GntEntry * entry,gboolean offline)172 setup_buddy_list_suggestion(GntEntry *entry, gboolean offline)
173 {
174 	PurpleBlistNode *node = purple_blist_get_root();
175 	for (; node; node = purple_blist_node_next(node, offline)) {
176 		if (!PURPLE_BLIST_NODE_IS_BUDDY(node))
177 			continue;
178 		gnt_entry_add_suggest(entry, purple_buddy_get_name((PurpleBuddy*)node));
179 	}
180 }
181 
182 static void
save_pounce_cb(GntWidget * w,PurpleGntPounceDialog * dialog)183 save_pounce_cb(GntWidget *w, PurpleGntPounceDialog *dialog)
184 {
185 	const char *name;
186 	const char *message, *command, *reason;
187 	PurplePounceEvent events   = PURPLE_POUNCE_NONE;
188 	PurplePounceOption options = PURPLE_POUNCE_OPTION_NONE;
189 
190 	name = gnt_entry_get_text(GNT_ENTRY(dialog->buddy_entry));
191 
192 	if (*name == '\0')
193 	{
194 		purple_notify_error(NULL, NULL,
195 						  _("Please enter a buddy to pounce."), NULL);
196 		return;
197 	}
198 
199 	/* Options */
200 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->on_away)))
201 		options |= PURPLE_POUNCE_OPTION_AWAY;
202 
203 	/* Events */
204 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signon)))
205 		events |= PURPLE_POUNCE_SIGNON;
206 
207 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->signoff)))
208 		events |= PURPLE_POUNCE_SIGNOFF;
209 
210 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away)))
211 		events |= PURPLE_POUNCE_AWAY;
212 
213 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->away_return)))
214 		events |= PURPLE_POUNCE_AWAY_RETURN;
215 
216 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle)))
217 		events |= PURPLE_POUNCE_IDLE;
218 
219 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->idle_return)))
220 		events |= PURPLE_POUNCE_IDLE_RETURN;
221 
222 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typing)))
223 		events |= PURPLE_POUNCE_TYPING;
224 
225 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->typed)))
226 		events |= PURPLE_POUNCE_TYPED;
227 
228 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->stop_typing)))
229 		events |= PURPLE_POUNCE_TYPING_STOPPED;
230 
231 	if (gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->message_recv)))
232 		events |= PURPLE_POUNCE_MESSAGE_RECEIVED;
233 
234 	/* Data fields */
235 	message = gnt_entry_get_text(GNT_ENTRY(dialog->send_msg_entry));
236 	command = gnt_entry_get_text(GNT_ENTRY(dialog->exec_cmd_entry));
237 	reason  = gnt_entry_get_text(GNT_ENTRY(dialog->popup_entry));
238 
239 	if (*reason == '\0') reason = NULL;
240 	if (*message == '\0') message = NULL;
241 	if (*command == '\0') command = NULL;
242 
243 	if (dialog->pounce == NULL) {
244 		dialog->pounce = purple_pounce_new(FINCH_UI, dialog->account,
245 										 name, events, options);
246 	} else {
247 		purple_pounce_set_events(dialog->pounce, events);
248 		purple_pounce_set_options(dialog->pounce, options);
249 		purple_pounce_set_pouncer(dialog->pounce, dialog->account);
250 		purple_pounce_set_pouncee(dialog->pounce, name);
251 	}
252 
253 	/* Actions */
254 	purple_pounce_action_set_enabled(dialog->pounce, "open-window",
255 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win)));
256 	purple_pounce_action_set_enabled(dialog->pounce, "popup-notify",
257 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup)));
258 	purple_pounce_action_set_enabled(dialog->pounce, "send-message",
259 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg)));
260 	purple_pounce_action_set_enabled(dialog->pounce, "execute-command",
261 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd)));
262 	purple_pounce_action_set_enabled(dialog->pounce, "play-beep",
263 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound)));
264 
265 	purple_pounce_action_set_attribute(dialog->pounce, "send-message",
266 									 "message", message);
267 	purple_pounce_action_set_attribute(dialog->pounce, "execute-command",
268 									 "command", command);
269 	purple_pounce_action_set_attribute(dialog->pounce, "popup-notify",
270 									 "reason", reason);
271 
272 	/* Set the defaults for next time. */
273 	purple_prefs_set_bool("/finch/pounces/default_actions/open-window",
274 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->open_win)));
275 	purple_prefs_set_bool("/finch/pounces/default_actions/popup-notify",
276 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->popup)));
277 	purple_prefs_set_bool("/finch/pounces/default_actions/send-message",
278 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->send_msg)));
279 	purple_prefs_set_bool("/finch/pounces/default_actions/execute-command",
280 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->exec_cmd)));
281 	purple_prefs_set_bool("/finch/pounces/default_actions/play-beep",
282 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->play_sound)));
283 
284 	purple_pounce_set_save(dialog->pounce,
285 		gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->save_pounce)));
286 
287 	purple_pounce_set_pouncer(dialog->pounce,
288 		(PurpleAccount *)gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->account_menu)));
289 
290 	update_pounces();
291 
292 	gnt_widget_destroy(dialog->window);
293 }
294 
295 
296 void
finch_pounce_editor_show(PurpleAccount * account,const char * name,PurplePounce * cur_pounce)297 finch_pounce_editor_show(PurpleAccount *account, const char *name,
298 							PurplePounce *cur_pounce)
299 {
300 	PurpleGntPounceDialog *dialog;
301 	GntWidget *window;
302 	GntWidget *bbox;
303 	GntWidget *hbox, *vbox;
304 	GntWidget *button;
305 	GntWidget *combo;
306 	GList *list;
307 
308 	g_return_if_fail((cur_pounce != NULL) ||
309 	                 (account != NULL) ||
310 	                 (purple_accounts_get_all() != NULL));
311 
312 	dialog = g_new0(PurpleGntPounceDialog, 1);
313 
314 	if (cur_pounce != NULL) {
315 		dialog->pounce  = cur_pounce;
316 		dialog->account = purple_pounce_get_pouncer(cur_pounce);
317 	} else if (account != NULL) {
318 		dialog->pounce  = NULL;
319 		dialog->account = account;
320 	} else {
321 		GList *connections = purple_connections_get_all();
322 		PurpleConnection *gc;
323 
324 		if (connections != NULL) {
325 			gc = (PurpleConnection *)connections->data;
326 			dialog->account = purple_connection_get_account(gc);
327 		} else
328 			dialog->account = purple_accounts_get_all()->data;
329 
330 		dialog->pounce  = NULL;
331 	}
332 
333 	/* Create the window. */
334 	dialog->window = window = gnt_vbox_new(FALSE);
335 	gnt_box_set_pad(GNT_BOX(window), 0);
336 	gnt_box_set_toplevel(GNT_BOX(window), TRUE);
337 	gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_LEFT);
338 	gnt_box_set_title(GNT_BOX(window),
339 						 (cur_pounce == NULL
340 						  ? _("New Buddy Pounce") : _("Edit Buddy Pounce")));
341 
342 	g_signal_connect(G_OBJECT(window), "destroy",
343 					 G_CALLBACK(delete_win_cb), dialog);
344 
345 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce on Whom"), GNT_TEXT_FLAG_BOLD));
346 
347 	/* Account: */
348 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Account:")));
349 	dialog->account_menu = combo = gnt_combo_box_new();
350 	list = purple_accounts_get_all();
351 	for (; list; list = list->next)
352 	{
353 		PurpleAccount *account;
354 		char *text;
355 
356 		account = list->data;
357 		text = g_strdup_printf("%s (%s)",
358 				purple_account_get_username(account),
359 				purple_account_get_protocol_name(account));
360 		gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text);
361 		g_free(text);
362 	}
363 	if (dialog->account)
364 		gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), dialog->account);
365 
366 	gnt_box_add_widget(GNT_BOX(window), combo);
367 
368 	/* Buddy: */
369 	hbox = gnt_hbox_new(FALSE);
370 	gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Buddy name:")));
371 
372 	dialog->buddy_entry = gnt_entry_new(NULL);
373 	gnt_box_add_widget(GNT_BOX(hbox), dialog->buddy_entry);
374 
375 	setup_buddy_list_suggestion(GNT_ENTRY(dialog->buddy_entry), TRUE);
376 
377 	gnt_box_add_widget(GNT_BOX(window), hbox);
378 
379 	if (cur_pounce != NULL) {
380 		gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry),
381 						   purple_pounce_get_pouncee(cur_pounce));
382 	} else if (name != NULL) {
383 		gnt_entry_set_text(GNT_ENTRY(dialog->buddy_entry), name);
384 	}
385 
386 	/* Create the event frame */
387 	gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
388 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Pounce When Buddy..."), GNT_TEXT_FLAG_BOLD));
389 
390 	dialog->signon = gnt_check_box_new(_("Signs on"));
391 	dialog->signoff = gnt_check_box_new(_("Signs off"));
392 	dialog->away = gnt_check_box_new(_("Goes away"));
393 	dialog->away_return = gnt_check_box_new(_("Returns from away"));
394 	dialog->idle = gnt_check_box_new(_("Becomes idle"));
395 	dialog->idle_return = gnt_check_box_new(_("Is no longer idle"));
396 	dialog->typing = gnt_check_box_new(_("Starts typing"));
397 	dialog->typed = gnt_check_box_new(_("Pauses while typing"));
398 	dialog->stop_typing = gnt_check_box_new(_("Stops typing"));
399 	dialog->message_recv = gnt_check_box_new(_("Sends a message"));
400 
401 	hbox = gnt_hbox_new(TRUE);
402 	gnt_box_set_pad(GNT_BOX(hbox), 2);
403 
404 	vbox = gnt_vbox_new(FALSE);
405 	gnt_box_set_pad(GNT_BOX(vbox), 0);
406 	gnt_box_add_widget(GNT_BOX(hbox), vbox);
407 
408 	gnt_box_add_widget(GNT_BOX(vbox), dialog->signon);
409 	gnt_box_add_widget(GNT_BOX(vbox), dialog->away);
410 	gnt_box_add_widget(GNT_BOX(vbox), dialog->idle);
411 	gnt_box_add_widget(GNT_BOX(vbox), dialog->typing);
412 	gnt_box_add_widget(GNT_BOX(vbox), dialog->stop_typing);
413 
414 	vbox = gnt_vbox_new(FALSE);
415 	gnt_box_set_pad(GNT_BOX(vbox), 0);
416 	gnt_box_add_widget(GNT_BOX(hbox), vbox);
417 
418 	gnt_box_add_widget(GNT_BOX(vbox), dialog->signoff);
419 	gnt_box_add_widget(GNT_BOX(vbox), dialog->away_return);
420 	gnt_box_add_widget(GNT_BOX(vbox), dialog->idle_return);
421 	gnt_box_add_widget(GNT_BOX(vbox), dialog->typed);
422 	gnt_box_add_widget(GNT_BOX(vbox), dialog->message_recv);
423 
424 	gnt_box_add_widget(GNT_BOX(window), hbox);
425 
426 	/* Create the "Action" frame. */
427 	gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
428 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Action"), GNT_TEXT_FLAG_BOLD));
429 
430 	dialog->open_win = gnt_check_box_new(_("Open an IM window"));
431 	dialog->popup = gnt_check_box_new(_("Pop up a notification"));
432 	dialog->send_msg = gnt_check_box_new(_("Send a message"));
433 	dialog->exec_cmd = gnt_check_box_new(_("Execute a command"));
434 	dialog->play_sound = gnt_check_box_new(_("Play a sound"));
435 
436 	dialog->send_msg_entry    = gnt_entry_new(NULL);
437 	dialog->exec_cmd_entry    = gnt_entry_new(NULL);
438 	dialog->popup_entry       = gnt_entry_new(NULL);
439 	dialog->exec_cmd_entry   = gnt_entry_new(NULL);
440 
441 	hbox = gnt_hbox_new(FALSE);
442 	gnt_box_add_widget(GNT_BOX(hbox), dialog->open_win);
443 	gnt_box_add_widget(GNT_BOX(window), hbox);
444 	hbox = gnt_hbox_new(FALSE);
445 	gnt_box_add_widget(GNT_BOX(hbox), dialog->popup);
446 	gnt_box_add_widget(GNT_BOX(hbox), dialog->popup_entry);
447 	gnt_box_add_widget(GNT_BOX(window), hbox);
448 	hbox = gnt_hbox_new(FALSE);
449 	gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg);
450 	gnt_box_add_widget(GNT_BOX(hbox), dialog->send_msg_entry);
451 	gnt_box_add_widget(GNT_BOX(window), hbox);
452 	hbox = gnt_hbox_new(FALSE);
453 	gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd);
454 	gnt_box_add_widget(GNT_BOX(hbox), dialog->exec_cmd_entry);
455 	gnt_box_add_widget(GNT_BOX(window), hbox);
456 	hbox = gnt_hbox_new(FALSE);
457 	gnt_box_add_widget(GNT_BOX(hbox), dialog->play_sound);
458 	gnt_box_add_widget(GNT_BOX(window), hbox);
459 
460 	gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
461 	gnt_box_add_widget(GNT_BOX(window), gnt_label_new_with_format(_("Options"), GNT_TEXT_FLAG_BOLD));
462 	dialog->on_away = gnt_check_box_new(_("Pounce only when my status is not Available"));
463 	gnt_box_add_widget(GNT_BOX(window), dialog->on_away);
464 	dialog->save_pounce = gnt_check_box_new(_("Recurring"));
465 	gnt_box_add_widget(GNT_BOX(window), dialog->save_pounce);
466 
467 
468 	gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
469 	/* Now the button box! */
470 	bbox = gnt_hbox_new(FALSE);
471 
472 	/* Cancel button */
473 	button = gnt_button_new(_("Cancel"));
474 	gnt_box_add_widget(GNT_BOX(bbox), button);
475 	g_signal_connect(G_OBJECT(button), "activate",
476 					 G_CALLBACK(cancel_cb), dialog);
477 
478 	/* Save button */
479 	dialog->save_button = button = gnt_button_new(_("Save"));
480 	gnt_box_add_widget(GNT_BOX(bbox), button);
481 	g_signal_connect(G_OBJECT(button), "activate",
482 					 G_CALLBACK(save_pounce_cb), dialog);
483 
484 	gnt_box_add_widget(GNT_BOX(window), bbox);
485 
486 
487 	/* Set the values of stuff. */
488 	if (cur_pounce != NULL)
489 	{
490 		PurplePounceEvent events   = purple_pounce_get_events(cur_pounce);
491 		PurplePounceOption options = purple_pounce_get_options(cur_pounce);
492 		const char *value;
493 
494 		/* Options */
495 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->on_away),
496 									(options & PURPLE_POUNCE_OPTION_AWAY));
497 
498 		/* Events */
499 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signon),
500 									(events & PURPLE_POUNCE_SIGNON));
501 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->signoff),
502 									(events & PURPLE_POUNCE_SIGNOFF));
503 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away),
504 									(events & PURPLE_POUNCE_AWAY));
505 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->away_return),
506 									(events & PURPLE_POUNCE_AWAY_RETURN));
507 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle),
508 									(events & PURPLE_POUNCE_IDLE));
509 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->idle_return),
510 									(events & PURPLE_POUNCE_IDLE_RETURN));
511 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typing),
512 									(events & PURPLE_POUNCE_TYPING));
513 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->typed),
514 									(events & PURPLE_POUNCE_TYPED));
515 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->stop_typing),
516 									(events & PURPLE_POUNCE_TYPING_STOPPED));
517 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->message_recv),
518 									(events & PURPLE_POUNCE_MESSAGE_RECEIVED));
519 
520 		/* Actions */
521 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win),
522 			purple_pounce_action_is_enabled(cur_pounce, "open-window"));
523 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup),
524 			purple_pounce_action_is_enabled(cur_pounce, "popup-notify"));
525 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg),
526 			purple_pounce_action_is_enabled(cur_pounce, "send-message"));
527 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd),
528 			purple_pounce_action_is_enabled(cur_pounce, "execute-command"));
529 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound),
530 			purple_pounce_action_is_enabled(cur_pounce, "play-beep"));
531 
532 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->save_pounce),
533 			purple_pounce_get_save(cur_pounce));
534 
535 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
536 		                                              "send-message",
537 		                                              "message")) != NULL)
538 		{
539 			gnt_entry_set_text(GNT_ENTRY(dialog->send_msg_entry), value);
540 		}
541 
542 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
543 		                                              "popup-notify",
544 		                                              "reason")) != NULL)
545 		{
546 			gnt_entry_set_text(GNT_ENTRY(dialog->popup_entry), value);
547 		}
548 
549 		if ((value = purple_pounce_action_get_attribute(cur_pounce,
550 		                                              "execute-command",
551 		                                              "command")) != NULL)
552 		{
553 			gnt_entry_set_text(GNT_ENTRY(dialog->exec_cmd_entry), value);
554 		}
555 	}
556 	else
557 	{
558 		PurpleBuddy *buddy = NULL;
559 
560 		if (name != NULL)
561 			buddy = purple_find_buddy(account, name);
562 
563 		/* Set some defaults */
564 		if (buddy == NULL) {
565 			gnt_check_box_set_checked(
566 				GNT_CHECK_BOX(dialog->signon), TRUE);
567 		} else {
568 			if (!PURPLE_BUDDY_IS_ONLINE(buddy)) {
569 				gnt_check_box_set_checked(
570 					GNT_CHECK_BOX(dialog->signon), TRUE);
571 			} else {
572 				gboolean default_set = FALSE;
573 				PurplePresence *presence = purple_buddy_get_presence(buddy);
574 
575 				if (purple_presence_is_idle(presence))
576 				{
577 					gnt_check_box_set_checked(
578 						GNT_CHECK_BOX(dialog->idle_return), TRUE);
579 
580 					default_set = TRUE;
581 				}
582 
583 				if (!purple_presence_is_available(presence))
584 				{
585 					gnt_check_box_set_checked(
586 						GNT_CHECK_BOX(dialog->away_return), TRUE);
587 
588 					default_set = TRUE;
589 				}
590 
591 				if (!default_set)
592 				{
593 					gnt_check_box_set_checked(
594 						GNT_CHECK_BOX(dialog->signon), TRUE);
595 				}
596 			}
597 		}
598 
599 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->open_win),
600 			purple_prefs_get_bool("/finch/pounces/default_actions/open-window"));
601 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->popup),
602 			purple_prefs_get_bool("/finch/pounces/default_actions/popup-notify"));
603 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->send_msg),
604 			purple_prefs_get_bool("/finch/pounces/default_actions/send-message"));
605 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->exec_cmd),
606 			purple_prefs_get_bool("/finch/pounces/default_actions/execute-command"));
607 		gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->play_sound),
608 			purple_prefs_get_bool("/finch/pounces/default_actions/play-beep"));
609 	}
610 
611 	gnt_widget_show(window);
612 }
613 
614 
615 
616 static gboolean
pounces_manager_destroy_cb(GntWidget * widget,gpointer user_data)617 pounces_manager_destroy_cb(GntWidget *widget, gpointer user_data)
618 {
619 	PouncesManager *dialog = user_data;
620 
621 	dialog->window = NULL;
622 	finch_pounces_manager_hide();
623 
624 	return FALSE;
625 }
626 
627 
628 static void
pounces_manager_add_cb(GntButton * button,gpointer user_data)629 pounces_manager_add_cb(GntButton *button, gpointer user_data)
630 {
631 	if (purple_accounts_get_all() == NULL) {
632 		purple_notify_error(NULL, _("Cannot create pounce"),
633 				_("You do not have any accounts."),
634 				_("You must create an account first before you can create a pounce."));
635 		return;
636 	}
637 	finch_pounce_editor_show(NULL, NULL, NULL);
638 }
639 
640 
641 static void
pounces_manager_modify_cb(GntButton * button,gpointer user_data)642 pounces_manager_modify_cb(GntButton *button, gpointer user_data)
643 {
644 	PouncesManager *dialog = user_data;
645 	PurplePounce *pounce = gnt_tree_get_selection_data(GNT_TREE(dialog->tree));
646 	if (pounce)
647 		finch_pounce_editor_show(NULL, NULL, pounce);
648 }
649 
650 static void
pounces_manager_delete_confirm_cb(PurplePounce * pounce)651 pounces_manager_delete_confirm_cb(PurplePounce *pounce)
652 {
653 	gnt_tree_remove(GNT_TREE(pounces_manager->tree), pounce);
654 
655 	purple_request_close_with_handle(pounce);
656 	purple_pounce_destroy(pounce);
657 }
658 
659 
660 static void
pounces_manager_delete_cb(GntButton * button,gpointer user_data)661 pounces_manager_delete_cb(GntButton *button, gpointer user_data)
662 {
663 	PouncesManager *dialog = user_data;
664 	PurplePounce *pounce;
665 	PurpleAccount *account;
666 	const char *pouncer, *pouncee;
667 	char *buf;
668 
669 	pounce = (PurplePounce *)gnt_tree_get_selection_data(GNT_TREE(dialog->tree));
670 	if (pounce == NULL)
671 		return;
672 
673 	account = purple_pounce_get_pouncer(pounce);
674 	pouncer = purple_account_get_username(account);
675 	pouncee = purple_pounce_get_pouncee(pounce);
676 	buf = g_strdup_printf(_("Are you sure you want to delete the pounce on %s for %s?"), pouncee, pouncer);
677 	purple_request_action(pounce, NULL, buf, NULL, 0,
678 						account, pouncee, NULL,
679 						pounce, 2,
680 						_("Delete"), pounces_manager_delete_confirm_cb,
681 						_("Cancel"), NULL);
682 	g_free(buf);
683 }
684 
685 static void
pounces_manager_close_cb(GntButton * button,gpointer user_data)686 pounces_manager_close_cb(GntButton *button, gpointer user_data)
687 {
688 	finch_pounces_manager_hide();
689 }
690 
691 
692 void
finch_pounces_manager_show(void)693 finch_pounces_manager_show(void)
694 {
695 	PouncesManager *dialog;
696 	GntWidget *bbox;
697 	GntWidget *button;
698 	GntWidget *tree;
699 	GntWidget *win;
700 
701 	if (pounces_manager != NULL) {
702 		gnt_window_present(pounces_manager->window);
703 		return;
704 	}
705 
706 	pounces_manager = dialog = g_new0(PouncesManager, 1);
707 
708 	dialog->window = win = gnt_vbox_new(FALSE);
709 	gnt_box_set_toplevel(GNT_BOX(win), TRUE);
710 	gnt_box_set_title(GNT_BOX(win), _("Buddy Pounces"));
711 	gnt_box_set_pad(GNT_BOX(win), 0);
712 
713 	g_signal_connect(G_OBJECT(win), "destroy",
714 					 G_CALLBACK(pounces_manager_destroy_cb), dialog);
715 
716 	/* List of saved buddy pounces */
717 	dialog->tree = tree = GNT_WIDGET(gnt_tree_new_with_columns(2));
718 	gnt_tree_set_column_titles(GNT_TREE(tree), "Account", "Pouncee", NULL);
719 	gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
720 
721 	gnt_box_add_widget(GNT_BOX(win), tree);
722 
723 	/* Button box. */
724 	bbox = gnt_hbox_new(FALSE);
725 
726 	/* Add button */
727 	button = gnt_button_new(_("Add"));
728 	gnt_box_add_widget(GNT_BOX(bbox), button);
729 	gnt_util_set_trigger_widget(tree, GNT_KEY_INS, button);
730 
731 	g_signal_connect(G_OBJECT(button), "activate",
732 					 G_CALLBACK(pounces_manager_add_cb), dialog);
733 
734 	/* Modify button */
735 	button = gnt_button_new(_("Modify"));
736 	dialog->modify_button = button;
737 	gnt_box_add_widget(GNT_BOX(bbox), button);
738 
739 	g_signal_connect(G_OBJECT(button), "activate",
740 					 G_CALLBACK(pounces_manager_modify_cb), dialog);
741 
742 	/* Delete button */
743 	button = gnt_button_new(_("Delete"));
744 	dialog->delete_button = button;
745 	gnt_box_add_widget(GNT_BOX(bbox), button);
746 	gnt_util_set_trigger_widget(tree, GNT_KEY_DEL, button);
747 
748 	g_signal_connect(G_OBJECT(button), "activate",
749 					 G_CALLBACK(pounces_manager_delete_cb), dialog);
750 
751 	/* Close button */
752 	button = gnt_button_new(_("Close"));
753 	gnt_box_add_widget(GNT_BOX(bbox), button);
754 	gnt_widget_show(button);
755 
756 	g_signal_connect(G_OBJECT(button), "activate",
757 					 G_CALLBACK(pounces_manager_close_cb), dialog);
758 
759 	gnt_box_add_widget(GNT_BOX(win), bbox);
760 
761 	gnt_widget_show(win);
762 	populate_pounces_list(pounces_manager);
763 }
764 
765 void
finch_pounces_manager_hide(void)766 finch_pounces_manager_hide(void)
767 {
768 	if (pounces_manager == NULL)
769 		return;
770 
771 	if (pounces_manager->window != NULL)
772 		gnt_widget_destroy(pounces_manager->window);
773 
774 	purple_signals_disconnect_by_handle(pounces_manager);
775 
776 	g_free(pounces_manager);
777 	pounces_manager = NULL;
778 }
779 
780 static void
pounce_cb(PurplePounce * pounce,PurplePounceEvent events,void * data)781 pounce_cb(PurplePounce *pounce, PurplePounceEvent events, void *data)
782 {
783 	PurpleConversation *conv;
784 	PurpleAccount *account;
785 	PurpleBuddy *buddy;
786 	const char *pouncee;
787 	const char *alias;
788 
789 	pouncee = purple_pounce_get_pouncee(pounce);
790 	account = purple_pounce_get_pouncer(pounce);
791 
792 	buddy = purple_find_buddy(account, pouncee);
793 	if (buddy != NULL)
794 	{
795 		alias = purple_buddy_get_alias(buddy);
796 		if (alias == NULL)
797 			alias = pouncee;
798 	}
799 	else
800 		alias = pouncee;
801 
802 	if (purple_pounce_action_is_enabled(pounce, "open-window"))
803 	{
804 		if (!purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pouncee, account))
805 			purple_conversation_new(PURPLE_CONV_TYPE_IM, account, pouncee);
806 	}
807 
808 	if (purple_pounce_action_is_enabled(pounce, "popup-notify"))
809 	{
810 		char *tmp = NULL;
811 		const char *name_shown;
812 		const char *reason;
813 		struct {
814 			PurplePounceEvent event;
815 			const char *format;
816 		} messages[] = {
817 			{PURPLE_POUNCE_TYPING, _("%s has started typing to you (%s)")},
818 			{PURPLE_POUNCE_TYPED, _("%s has paused while typing to you (%s)")},
819 			{PURPLE_POUNCE_SIGNON, _("%s has signed on (%s)")},
820 			{PURPLE_POUNCE_IDLE_RETURN, _("%s has returned from being idle (%s)")},
821 			{PURPLE_POUNCE_AWAY_RETURN, _("%s has returned from being away (%s)")},
822 			{PURPLE_POUNCE_TYPING_STOPPED, _("%s has stopped typing to you (%s)")},
823 			{PURPLE_POUNCE_SIGNOFF, _("%s has signed off (%s)")},
824 			{PURPLE_POUNCE_IDLE, _("%s has become idle (%s)")},
825 			{PURPLE_POUNCE_AWAY, _("%s has gone away. (%s)")},
826 			{PURPLE_POUNCE_MESSAGE_RECEIVED, _("%s has sent you a message. (%s)")},
827 			{0, NULL}
828 		};
829 		int i;
830 		reason = purple_pounce_action_get_attribute(pounce, "popup-notify",
831 				"reason");
832 
833 		/*
834 		 * Here we place the protocol name in the pounce dialog to lessen
835 		 * confusion about what protocol a pounce is for.
836 		 */
837 		for (i = 0; messages[i].format != NULL; i++) {
838 			if (messages[i].event & events) {
839 				tmp = g_strdup_printf(messages[i].format, alias,
840 						purple_account_get_protocol_name(account));
841 				break;
842 			}
843 		}
844 		if (tmp == NULL)
845 			tmp = g_strdup(_("Unknown pounce event. Please report this!"));
846 
847 		/*
848 		 * Ok here is where I change the second argument, title, from
849 		 * NULL to the account alias if we have it or the account
850 		 * name if that's all we have
851 		 */
852 		if ((name_shown = purple_account_get_alias(account)) == NULL)
853 			name_shown = purple_account_get_username(account);
854 
855 		if (reason == NULL)
856 		{
857 			purple_notify_info(NULL, name_shown, tmp, purple_date_format_full(NULL));
858 		}
859 		else
860 		{
861 			char *tmp2 = g_strdup_printf("%s\n\n%s", reason, purple_date_format_full(NULL));
862 			purple_notify_info(NULL, name_shown, tmp, tmp2);
863 			g_free(tmp2);
864 		}
865 		g_free(tmp);
866 	}
867 
868 	if (purple_pounce_action_is_enabled(pounce, "send-message"))
869 	{
870 		const char *message;
871 
872 		message = purple_pounce_action_get_attribute(pounce, "send-message",
873 												   "message");
874 
875 		if (message != NULL)
876 		{
877 			conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, pouncee, account);
878 
879 			if (conv == NULL)
880 				conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, account, pouncee);
881 
882 			purple_conversation_write(conv, NULL, message,
883 									PURPLE_MESSAGE_SEND, time(NULL));
884 
885 			serv_send_im(purple_account_get_connection(account), (char *)pouncee, (char *)message, 0);
886 		}
887 	}
888 
889 	if (purple_pounce_action_is_enabled(pounce, "execute-command"))
890 	{
891 		const char *command;
892 
893 		command = purple_pounce_action_get_attribute(pounce,
894 				"execute-command", "command");
895 
896 		if (command != NULL)
897 		{
898 			char *localecmd = g_locale_from_utf8(command, -1, NULL,
899 					NULL, NULL);
900 
901 			if (localecmd != NULL)
902 			{
903 				int pid = fork();
904 
905 				if (pid == 0) {
906 					char *args[4];
907 
908 					args[0] = "sh";
909 					args[1] = "-c";
910 					args[2] = (char *)localecmd;
911 					args[3] = NULL;
912 
913 					execvp(args[0], args);
914 
915 					_exit(0);
916 				}
917 				g_free(localecmd);
918 			}
919 		}
920 	}
921 
922 	if (purple_pounce_action_is_enabled(pounce, "play-beep"))
923 	{
924 		beep();
925 	}
926 }
927 
928 static void
free_pounce(PurplePounce * pounce)929 free_pounce(PurplePounce *pounce)
930 {
931 	update_pounces();
932 }
933 
934 static void
new_pounce(PurplePounce * pounce)935 new_pounce(PurplePounce *pounce)
936 {
937 	purple_pounce_action_register(pounce, "open-window");
938 	purple_pounce_action_register(pounce, "popup-notify");
939 	purple_pounce_action_register(pounce, "send-message");
940 	purple_pounce_action_register(pounce, "execute-command");
941 	purple_pounce_action_register(pounce, "play-beep");
942 
943 	update_pounces();
944 }
945 
946 void *
finch_pounces_get_handle()947 finch_pounces_get_handle()
948 {
949 	static int handle;
950 
951 	return &handle;
952 }
953 
954 void
finch_pounces_init(void)955 finch_pounces_init(void)
956 {
957 	purple_pounces_register_handler(FINCH_UI, pounce_cb, new_pounce,
958 								  free_pounce);
959 
960 	purple_prefs_add_none("/finch/pounces");
961 	purple_prefs_add_none("/finch/pounces/default_actions");
962 	purple_prefs_add_bool("/finch/pounces/default_actions/open-window",
963 						FALSE);
964 	purple_prefs_add_bool("/finch/pounces/default_actions/popup-notify",
965 						TRUE);
966 	purple_prefs_add_bool("/finch/pounces/default_actions/send-message",
967 						FALSE);
968 	purple_prefs_add_bool("/finch/pounces/default_actions/execute-command",
969 						FALSE);
970 	purple_prefs_add_bool("/finch/pounces/default_actions/play-beep",
971 						FALSE);
972 	purple_prefs_add_none("/finch/pounces/dialog");
973 
974 	purple_signal_connect(purple_connections_get_handle(), "signed-on",
975 						finch_pounces_get_handle(),
976 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
977 	purple_signal_connect(purple_connections_get_handle(), "signed-off",
978 						finch_pounces_get_handle(),
979 						PURPLE_CALLBACK(signed_on_off_cb), NULL);
980 }
981 
982 /* XXX: There's no such thing in pidgin. Perhaps there should be? */
finch_pounces_uninit()983 void finch_pounces_uninit()
984 {
985 	purple_pounces_unregister_handler(FINCH_UI);
986 
987 	purple_signals_disconnect_by_handle(finch_pounces_get_handle());
988 }
989 
990