2 * @file notify.c Notification API
8 * Purple 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.
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.
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.
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
26 #define _PURPLE_NOTIFY_C_
29 #include "dbus-maybe.h"
32 static PurpleNotifyUiOps
*notify_ui_ops
= NULL
;
33 static GList
*handles
= NULL
;
37 PurpleNotifyType type
;
40 PurpleNotifyCloseCallback cb
;
41 gpointer cb_user_data
;
45 * Definition of a user info entry
47 struct _PurpleNotifyUserInfoEntry
51 PurpleNotifyUserInfoEntryType type
;
54 struct _PurpleNotifyUserInfo
56 GList
*user_info_entries
;
60 purple_notify_message(void *handle
, PurpleNotifyMsgType type
,
61 const char *title
, const char *primary
,
62 const char *secondary
, PurpleNotifyCloseCallback cb
, gpointer user_data
)
64 PurpleNotifyUiOps
*ops
;
66 g_return_val_if_fail(primary
!= NULL
, NULL
);
68 ops
= purple_notify_get_ui_ops();
70 if (ops
!= NULL
&& ops
->notify_message
!= NULL
) {
71 void *ui_handle
= ops
->notify_message(type
, title
, primary
,
73 if (ui_handle
!= NULL
) {
75 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
76 info
->type
= PURPLE_NOTIFY_MESSAGE
;
77 info
->handle
= handle
;
78 info
->ui_handle
= ui_handle
;
80 info
->cb_user_data
= user_data
;
82 handles
= g_list_append(handles
, info
);
84 return info
->ui_handle
;
96 purple_notify_email(void *handle
, const char *subject
, const char *from
,
97 const char *to
, const char *url
, PurpleNotifyCloseCallback cb
,
100 PurpleNotifyUiOps
*ops
;
102 ops
= purple_notify_get_ui_ops();
104 if (ops
!= NULL
&& ops
->notify_email
!= NULL
) {
107 purple_signal_emit(purple_notify_get_handle(), "displaying-email-notification",
108 subject
, from
, to
, url
);
110 ui_handle
= ops
->notify_email(handle
, subject
, from
, to
, url
);
112 if (ui_handle
!= NULL
) {
114 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
115 info
->type
= PURPLE_NOTIFY_EMAIL
;
116 info
->handle
= handle
;
117 info
->ui_handle
= ui_handle
;
119 info
->cb_user_data
= user_data
;
121 handles
= g_list_append(handles
, info
);
123 return info
->ui_handle
;
134 purple_notify_emails(void *handle
, size_t count
, gboolean detailed
,
135 const char **subjects
, const char **froms
,
136 const char **tos
, const char **urls
,
137 PurpleNotifyCloseCallback cb
, gpointer user_data
)
139 PurpleNotifyUiOps
*ops
;
142 return purple_notify_email(handle
,
143 (subjects
== NULL
? NULL
: *subjects
),
144 (froms
== NULL
? NULL
: *froms
),
145 (tos
== NULL
? NULL
: *tos
),
146 (urls
== NULL
? NULL
: *urls
),
150 ops
= purple_notify_get_ui_ops();
152 if (ops
!= NULL
&& ops
->notify_emails
!= NULL
) {
155 purple_signal_emit(purple_notify_get_handle(), "displaying-emails-notification",
156 subjects
, froms
, tos
, urls
, count
);
158 ui_handle
= ops
->notify_emails(handle
, count
, detailed
, subjects
,
161 if (ui_handle
!= NULL
) {
162 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
163 info
->type
= PURPLE_NOTIFY_EMAILS
;
164 info
->handle
= handle
;
165 info
->ui_handle
= ui_handle
;
167 info
->cb_user_data
= user_data
;
169 handles
= g_list_append(handles
, info
);
171 return info
->ui_handle
;
183 purple_notify_formatted(void *handle
, const char *title
, const char *primary
,
184 const char *secondary
, const char *text
,
185 PurpleNotifyCloseCallback cb
, gpointer user_data
)
187 PurpleNotifyUiOps
*ops
;
189 g_return_val_if_fail(primary
!= NULL
, NULL
);
191 ops
= purple_notify_get_ui_ops();
193 if (ops
!= NULL
&& ops
->notify_formatted
!= NULL
) {
194 void *ui_handle
= ops
->notify_formatted(title
, primary
, secondary
, text
);
196 if (ui_handle
!= NULL
) {
198 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
199 info
->type
= PURPLE_NOTIFY_FORMATTED
;
200 info
->handle
= handle
;
201 info
->ui_handle
= ui_handle
;
203 info
->cb_user_data
= user_data
;
205 handles
= g_list_append(handles
, info
);
207 return info
->ui_handle
;
217 purple_notify_searchresults(PurpleConnection
*gc
, const char *title
,
218 const char *primary
, const char *secondary
,
219 PurpleNotifySearchResults
*results
, PurpleNotifyCloseCallback cb
,
222 PurpleNotifyUiOps
*ops
;
224 ops
= purple_notify_get_ui_ops();
226 if (ops
!= NULL
&& ops
->notify_searchresults
!= NULL
) {
227 void *ui_handle
= ops
->notify_searchresults(gc
, title
, primary
,
228 secondary
, results
, user_data
);
229 if (ui_handle
!= NULL
) {
231 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
232 info
->type
= PURPLE_NOTIFY_SEARCHRESULTS
;
234 info
->ui_handle
= ui_handle
;
236 info
->cb_user_data
= user_data
;
238 handles
= g_list_append(handles
, info
);
240 return info
->ui_handle
;
251 purple_notify_searchresults_free(PurpleNotifySearchResults
*results
)
255 g_return_if_fail(results
!= NULL
);
257 for (l
= results
->buttons
; l
; l
= g_list_delete_link(l
, l
)) {
258 PurpleNotifySearchButton
*button
= l
->data
;
259 g_free(button
->label
);
263 for (l
= results
->rows
; l
; l
= g_list_delete_link(l
, l
)) {
264 GList
*row
= l
->data
;
265 g_list_foreach(row
, (GFunc
)g_free
, NULL
);
269 for (l
= results
->columns
; l
; l
= g_list_delete_link(l
, l
)) {
270 PurpleNotifySearchColumn
*column
= l
->data
;
271 g_free(column
->title
);
279 purple_notify_searchresults_new_rows(PurpleConnection
*gc
,
280 PurpleNotifySearchResults
*results
,
283 PurpleNotifyUiOps
*ops
;
285 ops
= purple_notify_get_ui_ops();
287 if (ops
!= NULL
&& ops
->notify_searchresults
!= NULL
) {
288 ops
->notify_searchresults_new_rows(gc
, results
, data
);
293 purple_notify_searchresults_button_add(PurpleNotifySearchResults
*results
,
294 PurpleNotifySearchButtonType type
,
295 PurpleNotifySearchResultsCallback cb
)
297 PurpleNotifySearchButton
*button
;
299 g_return_if_fail(results
!= NULL
);
300 g_return_if_fail(cb
!= NULL
);
302 button
= g_new0(PurpleNotifySearchButton
, 1);
303 button
->callback
= cb
;
306 results
->buttons
= g_list_append(results
->buttons
, button
);
311 purple_notify_searchresults_button_add_labeled(PurpleNotifySearchResults
*results
,
313 PurpleNotifySearchResultsCallback cb
) {
314 PurpleNotifySearchButton
*button
;
316 g_return_if_fail(results
!= NULL
);
317 g_return_if_fail(cb
!= NULL
);
318 g_return_if_fail(label
!= NULL
);
319 g_return_if_fail(*label
!= '\0');
321 button
= g_new0(PurpleNotifySearchButton
, 1);
322 button
->callback
= cb
;
323 button
->type
= PURPLE_NOTIFY_BUTTON_LABELED
;
324 button
->label
= g_strdup(label
);
326 results
->buttons
= g_list_append(results
->buttons
, button
);
330 PurpleNotifySearchResults
*
331 purple_notify_searchresults_new()
333 PurpleNotifySearchResults
*rs
= g_new0(PurpleNotifySearchResults
, 1);
339 purple_notify_searchresults_column_add(PurpleNotifySearchResults
*results
,
340 PurpleNotifySearchColumn
*column
)
342 g_return_if_fail(results
!= NULL
);
343 g_return_if_fail(column
!= NULL
);
345 results
->columns
= g_list_append(results
->columns
, column
);
348 void purple_notify_searchresults_row_add(PurpleNotifySearchResults
*results
,
351 g_return_if_fail(results
!= NULL
);
352 g_return_if_fail(row
!= NULL
);
354 results
->rows
= g_list_append(results
->rows
, row
);
357 PurpleNotifySearchColumn
*
358 purple_notify_searchresults_column_new(const char *title
)
360 PurpleNotifySearchColumn
*sc
;
362 g_return_val_if_fail(title
!= NULL
, NULL
);
364 sc
= g_new0(PurpleNotifySearchColumn
, 1);
365 sc
->title
= g_strdup(title
);
371 purple_notify_searchresults_get_columns_count(PurpleNotifySearchResults
*results
)
373 g_return_val_if_fail(results
!= NULL
, 0);
375 return g_list_length(results
->columns
);
379 purple_notify_searchresults_get_rows_count(PurpleNotifySearchResults
*results
)
381 g_return_val_if_fail(results
!= NULL
, 0);
383 return g_list_length(results
->rows
);
387 purple_notify_searchresults_column_get_title(PurpleNotifySearchResults
*results
,
388 unsigned int column_id
)
390 g_return_val_if_fail(results
!= NULL
, NULL
);
392 return ((PurpleNotifySearchColumn
*)g_list_nth_data(results
->columns
, column_id
))->title
;
396 purple_notify_searchresults_row_get(PurpleNotifySearchResults
*results
,
399 g_return_val_if_fail(results
!= NULL
, NULL
);
401 return g_list_nth_data(results
->rows
, row_id
);
405 purple_notify_userinfo(PurpleConnection
*gc
, const char *who
,
406 PurpleNotifyUserInfo
*user_info
, PurpleNotifyCloseCallback cb
, gpointer user_data
)
408 PurpleNotifyUiOps
*ops
;
410 g_return_val_if_fail(who
!= NULL
, NULL
);
412 ops
= purple_notify_get_ui_ops();
414 if (ops
!= NULL
&& ops
->notify_userinfo
!= NULL
) {
417 purple_signal_emit(purple_notify_get_handle(), "displaying-userinfo",
418 purple_connection_get_account(gc
), who
, user_info
);
420 ui_handle
= ops
->notify_userinfo(gc
, who
, user_info
);
422 if (ui_handle
!= NULL
) {
424 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
425 info
->type
= PURPLE_NOTIFY_USERINFO
;
427 info
->ui_handle
= ui_handle
;
429 info
->cb_user_data
= user_data
;
431 handles
= g_list_append(handles
, info
);
433 return info
->ui_handle
;
443 PurpleNotifyUserInfoEntry
*
444 purple_notify_user_info_entry_new(const char *label
, const char *value
)
446 PurpleNotifyUserInfoEntry
*user_info_entry
;
448 user_info_entry
= g_new0(PurpleNotifyUserInfoEntry
, 1);
449 PURPLE_DBUS_REGISTER_POINTER(user_info_entry
, PurpleNotifyUserInfoEntry
);
450 user_info_entry
->label
= g_strdup(label
);
451 user_info_entry
->value
= g_strdup(value
);
452 user_info_entry
->type
= PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR
;
454 return user_info_entry
;
458 purple_notify_user_info_entry_destroy(PurpleNotifyUserInfoEntry
*user_info_entry
)
460 g_return_if_fail(user_info_entry
!= NULL
);
462 g_free(user_info_entry
->label
);
463 g_free(user_info_entry
->value
);
464 PURPLE_DBUS_UNREGISTER_POINTER(user_info_entry
);
465 g_free(user_info_entry
);
468 PurpleNotifyUserInfo
*
469 purple_notify_user_info_new()
471 PurpleNotifyUserInfo
*user_info
;
473 user_info
= g_new0(PurpleNotifyUserInfo
, 1);
474 PURPLE_DBUS_REGISTER_POINTER(user_info
, PurpleNotifyUserInfo
);
475 user_info
->user_info_entries
= NULL
;
481 purple_notify_user_info_destroy(PurpleNotifyUserInfo
*user_info
)
485 for (l
= user_info
->user_info_entries
; l
!= NULL
; l
= l
->next
) {
486 PurpleNotifyUserInfoEntry
*user_info_entry
= l
->data
;
488 purple_notify_user_info_entry_destroy(user_info_entry
);
491 g_list_free(user_info
->user_info_entries
);
492 PURPLE_DBUS_UNREGISTER_POINTER(user_info
);
497 purple_notify_user_info_get_entries(PurpleNotifyUserInfo
*user_info
)
499 g_return_val_if_fail(user_info
!= NULL
, NULL
);
501 return user_info
->user_info_entries
;
505 purple_notify_user_info_get_text_with_newline(PurpleNotifyUserInfo
*user_info
, const char *newline
)
510 text
= g_string_new("");
512 for (l
= user_info
->user_info_entries
; l
!= NULL
; l
= l
->next
) {
513 PurpleNotifyUserInfoEntry
*user_info_entry
= l
->data
;
514 /* Add a newline before a section header */
515 if (user_info_entry
->type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
516 g_string_append(text
, newline
);
518 /* Handle the label/value pair itself */
519 /* XXX Todo: Use a larger size for a section header? */
520 if (user_info_entry
->label
)
521 g_string_append_printf(text
, "<b>%s</b>", user_info_entry
->label
);
522 if (user_info_entry
->label
&& user_info_entry
->value
)
523 g_string_append(text
, ": ");
524 if (user_info_entry
->value
)
525 g_string_append(text
, user_info_entry
->value
);
527 /* Display a section break as a horizontal line */
528 if (user_info_entry
->type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
)
529 g_string_append(text
, "<HR>");
531 /* Don't insert a new line before or after a section break; <HR> does that for us */
532 if ((user_info_entry
->type
!= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
) &&
533 (l
->next
&& ((((PurpleNotifyUserInfoEntry
*)(l
->next
->data
))->type
!= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
))))
534 g_string_append(text
, newline
);
536 /* Add an extra newline after a section header */
537 if (user_info_entry
->type
== PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
)
538 g_string_append(text
, newline
);
541 return g_string_free(text
, FALSE
);
546 purple_notify_user_info_entry_get_label(PurpleNotifyUserInfoEntry
*user_info_entry
)
548 g_return_val_if_fail(user_info_entry
!= NULL
, NULL
);
550 return user_info_entry
->label
;
554 purple_notify_user_info_entry_set_label(PurpleNotifyUserInfoEntry
*user_info_entry
, const char *label
)
556 g_return_if_fail(user_info_entry
!= NULL
);
558 g_free(user_info_entry
->label
);
559 user_info_entry
->label
= g_strdup(label
);
563 purple_notify_user_info_entry_get_value(PurpleNotifyUserInfoEntry
*user_info_entry
)
565 g_return_val_if_fail(user_info_entry
!= NULL
, NULL
);
567 return user_info_entry
->value
;
571 purple_notify_user_info_entry_set_value(PurpleNotifyUserInfoEntry
*user_info_entry
, const char *value
)
573 g_return_if_fail(user_info_entry
!= NULL
);
575 g_free(user_info_entry
->value
);
576 user_info_entry
->value
= g_strdup(value
);
579 PurpleNotifyUserInfoEntryType
580 purple_notify_user_info_entry_get_type(PurpleNotifyUserInfoEntry
*user_info_entry
)
582 g_return_val_if_fail(user_info_entry
!= NULL
, PURPLE_NOTIFY_USER_INFO_ENTRY_PAIR
);
584 return user_info_entry
->type
;
588 purple_notify_user_info_entry_set_type(PurpleNotifyUserInfoEntry
*user_info_entry
, PurpleNotifyUserInfoEntryType type
)
590 g_return_if_fail(user_info_entry
!= NULL
);
592 user_info_entry
->type
= type
;
596 purple_notify_user_info_add_pair(PurpleNotifyUserInfo
*user_info
, const char *label
, const char *value
)
598 PurpleNotifyUserInfoEntry
*entry
;
600 entry
= purple_notify_user_info_entry_new(label
, value
);
601 user_info
->user_info_entries
= g_list_append(user_info
->user_info_entries
, entry
);
605 purple_notify_user_info_prepend_pair(PurpleNotifyUserInfo
*user_info
, const char *label
, const char *value
)
607 PurpleNotifyUserInfoEntry
*entry
;
609 entry
= purple_notify_user_info_entry_new(label
, value
);
610 user_info
->user_info_entries
= g_list_prepend(user_info
->user_info_entries
, entry
);
614 purple_notify_user_info_remove_entry(PurpleNotifyUserInfo
*user_info
, PurpleNotifyUserInfoEntry
*entry
)
616 g_return_if_fail(user_info
!= NULL
);
617 g_return_if_fail(entry
!= NULL
);
619 user_info
->user_info_entries
= g_list_remove(user_info
->user_info_entries
, entry
);
623 purple_notify_user_info_add_section_header(PurpleNotifyUserInfo
*user_info
, const char *label
)
625 PurpleNotifyUserInfoEntry
*entry
;
627 entry
= purple_notify_user_info_entry_new(label
, NULL
);
628 entry
->type
= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
;
630 user_info
->user_info_entries
= g_list_append(user_info
->user_info_entries
, entry
);
634 purple_notify_user_info_prepend_section_header(PurpleNotifyUserInfo
*user_info
, const char *label
)
636 PurpleNotifyUserInfoEntry
*entry
;
638 entry
= purple_notify_user_info_entry_new(label
, NULL
);
639 entry
->type
= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER
;
641 user_info
->user_info_entries
= g_list_prepend(user_info
->user_info_entries
, entry
);
645 purple_notify_user_info_add_section_break(PurpleNotifyUserInfo
*user_info
)
647 PurpleNotifyUserInfoEntry
*entry
;
649 entry
= purple_notify_user_info_entry_new(NULL
, NULL
);
650 entry
->type
= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
;
652 user_info
->user_info_entries
= g_list_append(user_info
->user_info_entries
, entry
);
656 purple_notify_user_info_prepend_section_break(PurpleNotifyUserInfo
*user_info
)
658 PurpleNotifyUserInfoEntry
*entry
;
660 entry
= purple_notify_user_info_entry_new(NULL
, NULL
);
661 entry
->type
= PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK
;
663 user_info
->user_info_entries
= g_list_prepend(user_info
->user_info_entries
, entry
);
667 purple_notify_user_info_remove_last_item(PurpleNotifyUserInfo
*user_info
)
669 GList
*last
= g_list_last(user_info
->user_info_entries
);
671 purple_notify_user_info_entry_destroy(last
->data
);
672 user_info
->user_info_entries
= g_list_delete_link(user_info
->user_info_entries
, last
);
677 purple_notify_uri(void *handle
, const char *uri
)
679 PurpleNotifyUiOps
*ops
;
681 g_return_val_if_fail(uri
!= NULL
, NULL
);
683 ops
= purple_notify_get_ui_ops();
685 if (ops
!= NULL
&& ops
->notify_uri
!= NULL
) {
687 void *ui_handle
= ops
->notify_uri(uri
);
689 if (ui_handle
!= NULL
) {
691 PurpleNotifyInfo
*info
= g_new0(PurpleNotifyInfo
, 1);
692 info
->type
= PURPLE_NOTIFY_URI
;
693 info
->handle
= handle
;
694 info
->ui_handle
= ui_handle
;
696 handles
= g_list_append(handles
, info
);
698 return info
->ui_handle
;
706 purple_notify_close(PurpleNotifyType type
, void *ui_handle
)
709 PurpleNotifyUiOps
*ops
;
711 g_return_if_fail(ui_handle
!= NULL
);
713 ops
= purple_notify_get_ui_ops();
715 for (l
= handles
; l
!= NULL
; l
= l
->next
) {
716 PurpleNotifyInfo
*info
= l
->data
;
718 if (info
->ui_handle
== ui_handle
) {
719 handles
= g_list_remove(handles
, info
);
721 if (ops
!= NULL
&& ops
->close_notify
!= NULL
)
722 ops
->close_notify(info
->type
, ui_handle
);
724 if (info
->cb
!= NULL
)
725 info
->cb(info
->cb_user_data
);
735 purple_notify_close_with_handle(void *handle
)
737 GList
*l
, *prev
= NULL
;
738 PurpleNotifyUiOps
*ops
;
740 g_return_if_fail(handle
!= NULL
);
742 ops
= purple_notify_get_ui_ops();
744 for (l
= handles
; l
!= NULL
; l
= prev
? prev
->next
: handles
) {
745 PurpleNotifyInfo
*info
= l
->data
;
747 if (info
->handle
== handle
) {
748 handles
= g_list_remove(handles
, info
);
750 if (ops
!= NULL
&& ops
->close_notify
!= NULL
)
751 ops
->close_notify(info
->type
, info
->ui_handle
);
753 if (info
->cb
!= NULL
)
754 info
->cb(info
->cb_user_data
);
763 purple_notify_set_ui_ops(PurpleNotifyUiOps
*ops
)
769 purple_notify_get_ui_ops(void)
771 return notify_ui_ops
;
775 purple_notify_get_handle(void)
783 purple_notify_init(void)
785 gpointer handle
= purple_notify_get_handle();
787 purple_signal_register(handle
, "displaying-email-notification",
788 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER
, NULL
, 4,
789 purple_value_new(PURPLE_TYPE_STRING
),
790 purple_value_new(PURPLE_TYPE_STRING
),
791 purple_value_new(PURPLE_TYPE_STRING
),
792 purple_value_new(PURPLE_TYPE_STRING
));
794 purple_signal_register(handle
, "displaying-emails-notification",
795 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
, NULL
, 5,
796 purple_value_new(PURPLE_TYPE_POINTER
),
797 purple_value_new(PURPLE_TYPE_POINTER
),
798 purple_value_new(PURPLE_TYPE_POINTER
),
799 purple_value_new(PURPLE_TYPE_POINTER
),
800 purple_value_new(PURPLE_TYPE_UINT
));
802 purple_signal_register(handle
, "displaying-userinfo",
803 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
804 purple_value_new(PURPLE_TYPE_SUBTYPE
,
805 PURPLE_SUBTYPE_ACCOUNT
),
806 purple_value_new(PURPLE_TYPE_STRING
),
807 purple_value_new(PURPLE_TYPE_SUBTYPE
,
808 PURPLE_SUBTYPE_USERINFO
));
812 purple_notify_uninit(void)
814 purple_signals_unregister_by_instance(purple_notify_get_handle());