2 * purple - Bonjour Protocol Plugin
4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
30 #include "dns_sd_proxy.h"
37 #include "mdns_common.h"
40 #include "bonjour_ft.h"
42 static PurpleProtocol
*my_protocol
= NULL
;
44 static char *default_firstname
;
45 static char *default_lastname
;
48 bonjour_get_jid(PurpleAccount
*account
)
50 PurpleConnection
*conn
= purple_account_get_connection(account
);
51 BonjourData
*bd
= purple_connection_get_protocol_data(conn
);
56 bonjour_removeallfromlocal(PurpleConnection
*conn
, PurpleGroup
*bonjour_group
)
58 PurpleAccount
*account
= purple_connection_get_account(conn
);
59 PurpleBlistNode
*cnode
, *cnodenext
, *bnode
, *bnodenext
;
62 if (bonjour_group
== NULL
)
65 /* Go through and remove all buddies that belong to this account */
66 for (cnode
= purple_blist_node_get_first_child((PurpleBlistNode
*) bonjour_group
); cnode
; cnode
= cnodenext
) {
67 cnodenext
= purple_blist_node_get_sibling_next(cnode
);
68 if (!PURPLE_IS_CONTACT(cnode
))
70 for (bnode
= purple_blist_node_get_first_child(cnode
); bnode
; bnode
= bnodenext
) {
71 bnodenext
= purple_blist_node_get_sibling_next(bnode
);
72 if (!PURPLE_IS_BUDDY(bnode
))
74 buddy
= (PurpleBuddy
*) bnode
;
75 if (purple_buddy_get_account(buddy
) != account
)
77 purple_account_remove_buddy(account
, buddy
, NULL
);
78 purple_blist_remove_buddy(buddy
);
85 bonjour_login(PurpleAccount
*account
)
87 PurpleConnection
*gc
= purple_account_get_connection(account
);
90 PurplePresence
*presence
;
93 if (!dns_sd_available()) {
94 purple_connection_error(gc
,
95 PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
96 _("Unable to find Apple's \"Bonjour for Windows\" toolkit, see "
97 "https://developer.pidgin.im/BonjourWindows for more information."));
102 purple_connection_set_flags(gc
, PURPLE_CONNECTION_FLAG_HTML
|
103 PURPLE_CONNECTION_FLAG_NO_IMAGES
);
104 bd
= g_new0(BonjourData
, 1);
105 purple_connection_set_protocol_data(gc
, bd
);
107 /* Start waiting for jabber connections (iChat style) */
108 bd
->jabber_data
= g_new0(BonjourJabber
, 1);
109 bd
->jabber_data
->port
= purple_account_get_int(account
, "port", BONJOUR_DEFAULT_PORT
);
110 bd
->jabber_data
->account
= account
;
112 if (bonjour_jabber_start(bd
->jabber_data
) == -1) {
113 /* Send a message about the connection error */
114 purple_connection_error (gc
,
115 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
116 _("Unable to listen for incoming IM connections"));
120 /* Connect to the mDNS daemon looking for buddies in the LAN */
121 bd
->dns_sd_data
= bonjour_dns_sd_new();
122 bd
->dns_sd_data
->first
= g_strdup(purple_account_get_string(account
, "first", default_firstname
));
123 bd
->dns_sd_data
->last
= g_strdup(purple_account_get_string(account
, "last", default_lastname
));
124 bd
->dns_sd_data
->port_p2pj
= bd
->jabber_data
->port
;
125 /* Not engaged in AV conference */
126 bd
->dns_sd_data
->vc
= g_strdup("!");
128 status
= purple_account_get_active_status(account
);
129 presence
= purple_account_get_presence(account
);
130 if (purple_presence_is_available(presence
))
131 bd
->dns_sd_data
->status
= g_strdup("avail");
132 else if (purple_presence_is_idle(presence
))
133 bd
->dns_sd_data
->status
= g_strdup("away");
135 bd
->dns_sd_data
->status
= g_strdup("dnd");
136 bd
->dns_sd_data
->msg
= g_strdup(purple_status_get_attr_string(status
, "message"));
138 bd
->dns_sd_data
->account
= account
;
139 if (!bonjour_dns_sd_start(bd
->dns_sd_data
))
141 purple_connection_error (gc
,
142 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
143 _("Unable to establish connection with the local mDNS server. Is it running?"));
147 bonjour_dns_sd_update_buddy_icon(bd
->dns_sd_data
);
149 /* Show the buddy list by telling Purple we have already connected */
150 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTED
);
154 bonjour_close(PurpleConnection
*connection
)
156 PurpleGroup
*bonjour_group
;
157 BonjourData
*bd
= purple_connection_get_protocol_data(connection
);
159 bonjour_group
= purple_blist_find_group(BONJOUR_GROUP_NAME
);
161 /* Remove all the bonjour buddies */
162 bonjour_removeallfromlocal(connection
, bonjour_group
);
164 /* Stop looking for buddies in the LAN */
165 if (bd
!= NULL
&& bd
->dns_sd_data
!= NULL
)
167 bonjour_dns_sd_stop(bd
->dns_sd_data
);
168 bonjour_dns_sd_free(bd
->dns_sd_data
);
171 if (bd
!= NULL
&& bd
->jabber_data
!= NULL
)
173 /* Stop waiting for conversations */
174 bonjour_jabber_stop(bd
->jabber_data
);
175 g_free(bd
->jabber_data
);
178 /* Delete the bonjour group
179 * (purple_blist_remove_group will bail out if the group isn't empty)
181 if (bonjour_group
!= NULL
)
182 purple_blist_remove_group(bonjour_group
);
184 /* Cancel any file transfers */
185 while (bd
!= NULL
&& bd
->xfer_lists
) {
186 purple_xfer_cancel_local(bd
->xfer_lists
->data
);
192 purple_connection_set_protocol_data(connection
, NULL
);
196 bonjour_list_icon(PurpleAccount
*account
, PurpleBuddy
*buddy
)
198 return BONJOUR_ICON_NAME
;
202 bonjour_send_im(PurpleConnection
*connection
, PurpleMessage
*msg
)
204 BonjourData
*bd
= purple_connection_get_protocol_data(connection
);
206 if (purple_message_is_empty(msg
) || !purple_message_get_recipient(msg
))
209 return bonjour_jabber_send_message(bd
->jabber_data
,
210 purple_message_get_recipient(msg
),
211 purple_message_get_contents(msg
));
215 bonjour_set_status(PurpleAccount
*account
, PurpleStatus
*status
)
217 PurpleConnection
*gc
;
219 PurplePresence
*presence
;
220 const char *message
, *bonjour_status
;
223 gc
= purple_account_get_connection(account
);
224 bd
= purple_connection_get_protocol_data(gc
);
225 presence
= purple_account_get_presence(account
);
227 message
= purple_status_get_attr_string(status
, "message");
230 stripped
= purple_markup_strip_html(message
);
233 * The three possible status for Bonjour are
234 * -available ("avail")
237 * Each of them can have an optional message.
239 if (purple_presence_is_available(presence
))
240 bonjour_status
= "avail";
241 else if (purple_presence_is_idle(presence
))
242 bonjour_status
= "away";
244 bonjour_status
= "dnd";
246 bonjour_dns_sd_send_status(bd
->dns_sd_data
, bonjour_status
, stripped
);
251 * The add_buddy callback removes the buddy from the local list.
252 * Bonjour manages buddies for you, and adding someone locally by
253 * hand is stupid. Perhaps we should change libpurple not to allow adding
254 * if there is no add_buddy callback.
257 bonjour_fake_add_buddy(PurpleConnection
*pc
, PurpleBuddy
*buddy
, PurpleGroup
*group
, const char *message
) {
258 purple_debug_error("bonjour", "Buddy '%s' manually added; removing. "
259 "Bonjour buddies must be discovered and not manually added.\n",
260 purple_buddy_get_name(buddy
));
262 /* I suppose we could alert the user here, but it seems unnecessary. */
264 /* If this causes problems, it can be moved to an idle callback */
265 purple_blist_remove_buddy(buddy
);
269 static void bonjour_remove_buddy(PurpleConnection
*pc
, PurpleBuddy
*buddy
, PurpleGroup
*group
) {
270 BonjourBuddy
*bb
= purple_buddy_get_protocol_data(buddy
);
272 bonjour_buddy_delete(bb
);
273 purple_buddy_set_protocol_data(buddy
, NULL
);
278 bonjour_status_types(PurpleAccount
*account
)
280 GList
*status_types
= NULL
;
281 PurpleStatusType
*type
;
283 g_return_val_if_fail(account
!= NULL
, NULL
);
285 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE
,
286 BONJOUR_STATUS_ID_AVAILABLE
,
287 NULL
, TRUE
, TRUE
, FALSE
,
288 "message", _("Message"),
289 purple_value_new(G_TYPE_STRING
), NULL
);
290 status_types
= g_list_append(status_types
, type
);
292 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY
,
293 BONJOUR_STATUS_ID_AWAY
,
294 NULL
, TRUE
, TRUE
, FALSE
,
295 "message", _("Message"),
296 purple_value_new(G_TYPE_STRING
), NULL
);
297 status_types
= g_list_append(status_types
, type
);
299 type
= purple_status_type_new_full(PURPLE_STATUS_OFFLINE
,
300 BONJOUR_STATUS_ID_OFFLINE
,
301 NULL
, TRUE
, TRUE
, FALSE
);
302 status_types
= g_list_append(status_types
, type
);
308 bonjour_convo_closed(PurpleConnection
*connection
, const char *who
)
310 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
313 if (buddy
== NULL
|| (bb
= purple_buddy_get_protocol_data(buddy
)) == NULL
)
316 * This buddy is not in our buddy list, and therefore does not really
317 * exist, so we won't have any data about them.
322 bonjour_jabber_close_conversation(bb
->conversation
);
323 bb
->conversation
= NULL
;
327 bonjour_set_buddy_icon(PurpleConnection
*conn
, PurpleImage
*img
)
329 BonjourData
*bd
= purple_connection_get_protocol_data(conn
);
330 bonjour_dns_sd_update_buddy_icon(bd
->dns_sd_data
);
335 bonjour_status_text(PurpleBuddy
*buddy
)
337 PurplePresence
*presence
;
338 PurpleStatus
*status
;
342 presence
= purple_buddy_get_presence(buddy
);
343 status
= purple_presence_get_active_status(presence
);
345 message
= purple_status_get_attr_string(status
, "message");
347 if (message
!= NULL
) {
348 ret
= g_markup_escape_text(message
, -1);
349 purple_util_chrreplace(ret
, '\n', ' ');
356 bonjour_tooltip_text(PurpleBuddy
*buddy
, PurpleNotifyUserInfo
*user_info
, gboolean full
)
358 PurplePresence
*presence
;
359 PurpleStatus
*status
;
360 BonjourBuddy
*bb
= purple_buddy_get_protocol_data(buddy
);
361 const char *status_description
;
364 presence
= purple_buddy_get_presence(buddy
);
365 status
= purple_presence_get_active_status(presence
);
366 message
= purple_status_get_attr_string(status
, "message");
368 if (purple_presence_is_available(presence
))
369 status_description
= purple_status_get_name(status
);
370 else if (purple_presence_is_idle(presence
))
371 status_description
= _("Idle");
373 status_description
= purple_status_get_name(status
);
375 purple_notify_user_info_add_pair_plaintext(user_info
, _("Status"), status_description
);
376 if (message
!= NULL
) {
377 /* TODO: Check whether it's correct to call add_pair_html,
378 or if we should be using add_pair_plaintext */
379 purple_notify_user_info_add_pair_html(user_info
, _("Message"), message
);
383 purple_debug_error("bonjour", "Got tooltip request for a buddy without protocol data.\n");
387 /* Only show first/last name if there is a nickname set (to avoid duplication) */
388 if (bb
->nick
!= NULL
&& *bb
->nick
!= '\0') {
389 if (bb
->first
!= NULL
&& *bb
->first
!= '\0') {
390 /* TODO: Check whether it's correct to call add_pair_html,
391 or if we should be using add_pair_plaintext */
392 purple_notify_user_info_add_pair_html(user_info
, _("First name"), bb
->first
);
394 if (bb
->last
!= NULL
&& *bb
->last
!= '\0') {
395 /* TODO: Check whether it's correct to call add_pair_html,
396 or if we should be using add_pair_plaintext */
397 purple_notify_user_info_add_pair_html(user_info
, _("Last name"), bb
->last
);
401 if (bb
->email
!= NULL
&& *bb
->email
!= '\0') {
402 /* TODO: Check whether it's correct to call add_pair_html,
403 or if we should be using add_pair_plaintext */
404 purple_notify_user_info_add_pair_html(user_info
, _("Email"), bb
->email
);
407 if (bb
->AIM
!= NULL
&& *bb
->AIM
!= '\0') {
408 /* TODO: Check whether it's correct to call add_pair_html,
409 or if we should be using add_pair_plaintext */
410 purple_notify_user_info_add_pair_html(user_info
, _("AIM Account"), bb
->AIM
);
413 if (bb
->jid
!= NULL
&& *bb
->jid
!= '\0') {
414 /* TODO: Check whether it's correct to call add_pair_html,
415 or if we should be using add_pair_plaintext */
416 purple_notify_user_info_add_pair_html(user_info
, _("XMPP Account"), bb
->jid
);
421 bonjour_do_group_change(PurpleBuddy
*buddy
, const char *new_group
)
426 /* If we're moving them out of the bonjour group, make them persistent */
427 if (purple_strequal(new_group
, BONJOUR_GROUP_NAME
))
428 purple_blist_node_set_transient(PURPLE_BLIST_NODE(buddy
), TRUE
);
430 purple_blist_node_set_transient(PURPLE_BLIST_NODE(buddy
),
431 !purple_blist_node_is_transient(PURPLE_BLIST_NODE(buddy
)));
436 bonjour_group_buddy(PurpleConnection
*connection
, const char *who
, const char *old_group
, const char *new_group
)
438 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
440 bonjour_do_group_change(buddy
, new_group
);
445 bonjour_rename_group(PurpleConnection
*connection
, const char *old_name
, PurpleGroup
*group
, GList
*moved_buddies
)
447 const char *new_group
;
449 new_group
= purple_group_get_name(group
);
451 g_list_foreach(moved_buddies
, (GFunc
)bonjour_do_group_change
, new_group
);
455 bonjour_can_receive_file(PurpleProtocolXfer
*prplxfer
, PurpleConnection
*connection
, const char *who
)
457 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
459 return (buddy
!= NULL
&& purple_buddy_get_protocol_data(buddy
) != NULL
);
463 bonjour_get_max_message_size(PurpleConversation
*conv
)
465 return -1; /* 5MB successfully tested. */
470 _set_default_name_cb(gpointer data
) {
471 gchar
*fullname
= data
;
472 const char *splitpoint
;
473 GList
*tmp
= my_protocol
->account_options
;
474 PurpleAccountOption
*option
;
477 purple_debug_info("bonjour", "Unable to look up First and Last name or Username from system; using defaults.\n");
481 g_free(default_firstname
);
482 g_free(default_lastname
);
484 /* Split the real name into a first and last name */
485 splitpoint
= strchr(fullname
, ' ');
486 if (splitpoint
!= NULL
) {
487 default_firstname
= g_strndup(fullname
, splitpoint
- fullname
);
488 default_lastname
= g_strdup(&splitpoint
[1]);
490 default_firstname
= g_strdup(fullname
);
491 default_lastname
= g_strdup("");
496 for(; tmp
!= NULL
; tmp
= tmp
->next
) {
498 if (purple_strequal("first", purple_account_option_get_setting(option
)))
499 purple_account_option_set_default_string(option
, default_firstname
);
500 else if (purple_strequal("last", purple_account_option_get_setting(option
)))
501 purple_account_option_set_default_string(option
, default_lastname
);
508 _win32_name_lookup_thread(gpointer data
) {
509 gchar
*fullname
= NULL
;
510 wchar_t username
[UNLEN
+ 1];
511 DWORD dwLenUsername
= UNLEN
+ 1;
513 GetUserNameW((LPWSTR
) &username
, &dwLenUsername
);
515 if (username
!= NULL
&& *username
!= '\0') {
516 LPBYTE servername
= NULL
;
519 NetGetDCName(NULL
, NULL
, &servername
);
521 /* purple_debug_info("bonjour", "Looking up the full name from the %s.\n", (servername ? "domain controller" : "local machine")); */
523 if (NetUserGetInfo((LPCWSTR
) servername
, username
, 10, &info
) == NERR_Success
524 && info
!= NULL
&& ((LPUSER_INFO_10
) info
)->usri10_full_name
!= NULL
525 && *(((LPUSER_INFO_10
) info
)->usri10_full_name
) != '\0') {
526 fullname
= g_utf16_to_utf8(
527 ((LPUSER_INFO_10
) info
)->usri10_full_name
,
528 -1, NULL
, NULL
, NULL
);
530 /* Fall back to the local machine if we didn't get the full name from the domain controller */
531 else if (servername
!= NULL
) {
532 /* purple_debug_info("bonjour", "Looking up the full name from the local machine"); */
534 if (info
!= NULL
) NetApiBufferFree(info
);
537 if (NetUserGetInfo(NULL
, username
, 10, &info
) == NERR_Success
538 && info
!= NULL
&& ((LPUSER_INFO_10
) info
)->usri10_full_name
!= NULL
539 && *(((LPUSER_INFO_10
) info
)->usri10_full_name
) != '\0') {
540 fullname
= g_utf16_to_utf8(
541 ((LPUSER_INFO_10
) info
)->usri10_full_name
,
542 -1, NULL
, NULL
, NULL
);
546 if (info
!= NULL
) NetApiBufferFree(info
);
547 if (servername
!= NULL
) NetApiBufferFree(servername
);
550 fullname
= g_utf16_to_utf8(username
, -1, NULL
, NULL
, NULL
);
553 g_timeout_add(0, _set_default_name_cb
, fullname
);
560 initialize_default_account_values(void)
565 GThread
*lookup_thread
;
567 const char *fullname
= NULL
, *splitpoint
, *tmp
;
571 /* Try to figure out the user's real name */
572 info
= getpwuid(getuid());
573 if ((info
!= NULL
) && (info
->pw_gecos
!= NULL
) && (info
->pw_gecos
[0] != '\0'))
574 fullname
= info
->pw_gecos
;
575 else if ((info
!= NULL
) && (info
->pw_name
!= NULL
) && (info
->pw_name
[0] != '\0'))
576 fullname
= info
->pw_name
;
577 else if (((fullname
= getlogin()) != NULL
) && (fullname
[0] == '\0'))
580 /* The Win32 username lookup functions are synchronous so we do it in a thread */
581 lookup_thread
= g_thread_try_new("bonjour dns thread", _win32_name_lookup_thread
, NULL
, NULL
);
583 g_thread_unref(lookup_thread
);
585 purple_debug_fatal("bonjour", "failed to create lookup thread\n");
588 /* Make sure fullname is valid UTF-8. If not, try to convert it. */
589 if (fullname
!= NULL
&& !g_utf8_validate(fullname
, -1, NULL
)) {
590 fullname
= conv
= g_locale_to_utf8(fullname
, -1, NULL
, NULL
, NULL
);
591 if (conv
== NULL
|| *conv
== '\0')
595 if (fullname
== NULL
)
596 fullname
= _("Purple Person");
598 /* Split the real name into a first and last name */
599 splitpoint
= strchr(fullname
, ' ');
600 if (splitpoint
!= NULL
) {
601 default_firstname
= g_strndup(fullname
, splitpoint
- fullname
);
602 tmp
= &splitpoint
[1];
604 /* The last name may be followed by a comma and additional data.
605 * Only use the last name itself.
607 splitpoint
= strchr(tmp
, ',');
608 if (splitpoint
!= NULL
)
609 default_lastname
= g_strndup(tmp
, splitpoint
- tmp
);
611 default_lastname
= g_strdup(tmp
);
613 default_firstname
= g_strdup(fullname
);
614 default_lastname
= g_strdup("");
621 bonjour_protocol_init(BonjourProtocol
*self
)
623 PurpleProtocol
*protocol
= PURPLE_PROTOCOL(self
);
624 PurpleAccountOption
*option
;
626 protocol
->id
= "prpl-bonjour";
627 protocol
->name
= "Bonjour";
628 protocol
->options
= OPT_PROTO_NO_PASSWORD
;
629 protocol
->icon_spec
= purple_buddy_icon_spec_new("png,gif,jpeg",
631 PURPLE_ICON_SCALE_DISPLAY
);
633 /* Creating the options for the protocol */
634 option
= purple_account_option_int_new(_("Local Port"), "port", BONJOUR_DEFAULT_PORT
);
635 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
637 option
= purple_account_option_string_new(_("First name"), "first", default_firstname
);
638 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
640 option
= purple_account_option_string_new(_("Last name"), "last", default_lastname
);
641 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
643 option
= purple_account_option_string_new(_("Email"), "email", "");
644 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
646 option
= purple_account_option_string_new(_("AIM Account"), "AIM", "");
647 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
649 option
= purple_account_option_string_new(_("XMPP Account"), "jid", "");
650 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
654 bonjour_protocol_class_init(BonjourProtocolClass
*klass
)
656 PurpleProtocolClass
*protocol_class
= PURPLE_PROTOCOL_CLASS(klass
);
658 protocol_class
->login
= bonjour_login
;
659 protocol_class
->close
= bonjour_close
;
660 protocol_class
->status_types
= bonjour_status_types
;
661 protocol_class
->list_icon
= bonjour_list_icon
;
665 bonjour_protocol_class_finalize(G_GNUC_UNUSED BonjourProtocolClass
*klass
)
670 bonjour_protocol_client_iface_init(PurpleProtocolClientInterface
*client_iface
)
672 client_iface
->status_text
= bonjour_status_text
;
673 client_iface
->tooltip_text
= bonjour_tooltip_text
;
674 client_iface
->convo_closed
= bonjour_convo_closed
;
675 client_iface
->get_max_message_size
= bonjour_get_max_message_size
;
679 bonjour_protocol_server_iface_init(PurpleProtocolServerInterface
*server_iface
)
681 server_iface
->add_buddy
= bonjour_fake_add_buddy
;
682 server_iface
->remove_buddy
= bonjour_remove_buddy
;
683 server_iface
->group_buddy
= bonjour_group_buddy
;
684 server_iface
->rename_group
= bonjour_rename_group
;
685 server_iface
->set_buddy_icon
= bonjour_set_buddy_icon
;
686 server_iface
->set_status
= bonjour_set_status
;
690 bonjour_protocol_im_iface_init(PurpleProtocolIMInterface
*im_iface
)
692 im_iface
->send
= bonjour_send_im
;
696 bonjour_protocol_xfer_iface_init(PurpleProtocolXferInterface
*xfer_iface
)
698 xfer_iface
->can_receive
= bonjour_can_receive_file
;
699 xfer_iface
->send_file
= bonjour_send_file
;
700 xfer_iface
->new_xfer
= bonjour_new_xfer
;
703 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
704 BonjourProtocol
, bonjour_protocol
, PURPLE_TYPE_PROTOCOL
, 0,
706 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_CLIENT
,
707 bonjour_protocol_client_iface_init
)
709 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_SERVER
,
710 bonjour_protocol_server_iface_init
)
712 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_IM
,
713 bonjour_protocol_im_iface_init
)
715 G_IMPLEMENT_INTERFACE_DYNAMIC(PURPLE_TYPE_PROTOCOL_XFER
,
716 bonjour_protocol_xfer_iface_init
));
718 static PurplePluginInfo
*
719 plugin_query(GError
**error
)
721 return purple_plugin_info_new(
722 "id", "prpl-bonjour",
723 "name", "Bonjour Protocol",
724 "version", DISPLAY_VERSION
,
725 "category", N_("Protocol"),
726 "summary", N_("Bonjour Protocol Plugin"),
727 "description", N_("Bonjour Protocol Plugin"),
728 "website", PURPLE_WEBSITE
,
729 "abi-version", PURPLE_ABI_VERSION
,
730 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
731 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
737 plugin_load(PurplePlugin
*plugin
, GError
**error
)
739 bonjour_protocol_register_type(G_TYPE_MODULE(plugin
));
741 xep_xfer_register(G_TYPE_MODULE(plugin
));
743 my_protocol
= purple_protocols_add(BONJOUR_TYPE_PROTOCOL
, error
);
747 initialize_default_account_values();
753 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
755 if (!purple_protocols_remove(my_protocol
, error
))
758 g_free(default_firstname
);
759 g_free(default_lastname
);
764 PURPLE_PLUGIN_INIT(bonjour
, plugin_query
, plugin_load
, plugin_unload
);