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"
36 #include "accountopt.h"
43 #include "mdns_common.h"
46 #include "bonjour_ft.h"
48 static PurpleProtocol
*my_protocol
= NULL
;
50 static char *default_firstname
;
51 static char *default_lastname
;
54 bonjour_get_jid(PurpleAccount
*account
)
56 PurpleConnection
*conn
= purple_account_get_connection(account
);
57 BonjourData
*bd
= purple_connection_get_protocol_data(conn
);
62 bonjour_removeallfromlocal(PurpleConnection
*conn
, PurpleGroup
*bonjour_group
)
64 PurpleAccount
*account
= purple_connection_get_account(conn
);
65 PurpleBlistNode
*cnode
, *cnodenext
, *bnode
, *bnodenext
;
68 if (bonjour_group
== NULL
)
71 /* Go through and remove all buddies that belong to this account */
72 for (cnode
= purple_blist_node_get_first_child((PurpleBlistNode
*) bonjour_group
); cnode
; cnode
= cnodenext
) {
73 cnodenext
= purple_blist_node_get_sibling_next(cnode
);
74 if (!PURPLE_IS_CONTACT(cnode
))
76 for (bnode
= purple_blist_node_get_first_child(cnode
); bnode
; bnode
= bnodenext
) {
77 bnodenext
= purple_blist_node_get_sibling_next(bnode
);
78 if (!PURPLE_IS_BUDDY(bnode
))
80 buddy
= (PurpleBuddy
*) bnode
;
81 if (purple_buddy_get_account(buddy
) != account
)
83 purple_account_remove_buddy(account
, buddy
, NULL
);
84 purple_blist_remove_buddy(buddy
);
91 bonjour_login(PurpleAccount
*account
)
93 PurpleConnection
*gc
= purple_account_get_connection(account
);
96 PurplePresence
*presence
;
99 if (!dns_sd_available()) {
100 purple_connection_error(gc
,
101 PURPLE_CONNECTION_ERROR_OTHER_ERROR
,
102 _("Unable to find Apple's \"Bonjour for Windows\" toolkit, see "
103 "https://developer.pidgin.im/BonjourWindows for more information."));
108 purple_connection_set_flags(gc
, PURPLE_CONNECTION_FLAG_HTML
|
109 PURPLE_CONNECTION_FLAG_NO_IMAGES
);
110 bd
= g_new0(BonjourData
, 1);
111 purple_connection_set_protocol_data(gc
, bd
);
113 /* Start waiting for jabber connections (iChat style) */
114 bd
->jabber_data
= g_new0(BonjourJabber
, 1);
115 bd
->jabber_data
->port
= purple_account_get_int(account
, "port", BONJOUR_DEFAULT_PORT
);
116 bd
->jabber_data
->account
= account
;
118 if (bonjour_jabber_start(bd
->jabber_data
) == -1) {
119 /* Send a message about the connection error */
120 purple_connection_error (gc
,
121 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
122 _("Unable to listen for incoming IM connections"));
126 /* Connect to the mDNS daemon looking for buddies in the LAN */
127 bd
->dns_sd_data
= bonjour_dns_sd_new();
128 bd
->dns_sd_data
->first
= g_strdup(purple_account_get_string(account
, "first", default_firstname
));
129 bd
->dns_sd_data
->last
= g_strdup(purple_account_get_string(account
, "last", default_lastname
));
130 bd
->dns_sd_data
->port_p2pj
= bd
->jabber_data
->port
;
131 /* Not engaged in AV conference */
132 bd
->dns_sd_data
->vc
= g_strdup("!");
134 status
= purple_account_get_active_status(account
);
135 presence
= purple_account_get_presence(account
);
136 if (purple_presence_is_available(presence
))
137 bd
->dns_sd_data
->status
= g_strdup("avail");
138 else if (purple_presence_is_idle(presence
))
139 bd
->dns_sd_data
->status
= g_strdup("away");
141 bd
->dns_sd_data
->status
= g_strdup("dnd");
142 bd
->dns_sd_data
->msg
= g_strdup(purple_status_get_attr_string(status
, "message"));
144 bd
->dns_sd_data
->account
= account
;
145 if (!bonjour_dns_sd_start(bd
->dns_sd_data
))
147 purple_connection_error (gc
,
148 PURPLE_CONNECTION_ERROR_NETWORK_ERROR
,
149 _("Unable to establish connection with the local mDNS server. Is it running?"));
153 bonjour_dns_sd_update_buddy_icon(bd
->dns_sd_data
);
155 /* Show the buddy list by telling Purple we have already connected */
156 purple_connection_set_state(gc
, PURPLE_CONNECTION_CONNECTED
);
160 bonjour_close(PurpleConnection
*connection
)
162 PurpleGroup
*bonjour_group
;
163 BonjourData
*bd
= purple_connection_get_protocol_data(connection
);
165 bonjour_group
= purple_blist_find_group(BONJOUR_GROUP_NAME
);
167 /* Remove all the bonjour buddies */
168 bonjour_removeallfromlocal(connection
, bonjour_group
);
170 /* Stop looking for buddies in the LAN */
171 if (bd
!= NULL
&& bd
->dns_sd_data
!= NULL
)
173 bonjour_dns_sd_stop(bd
->dns_sd_data
);
174 bonjour_dns_sd_free(bd
->dns_sd_data
);
177 if (bd
!= NULL
&& bd
->jabber_data
!= NULL
)
179 /* Stop waiting for conversations */
180 bonjour_jabber_stop(bd
->jabber_data
);
181 g_free(bd
->jabber_data
);
184 /* Delete the bonjour group
185 * (purple_blist_remove_group will bail out if the group isn't empty)
187 if (bonjour_group
!= NULL
)
188 purple_blist_remove_group(bonjour_group
);
190 /* Cancel any file transfers */
191 while (bd
!= NULL
&& bd
->xfer_lists
) {
192 purple_xfer_cancel_local(bd
->xfer_lists
->data
);
198 purple_connection_set_protocol_data(connection
, NULL
);
202 bonjour_list_icon(PurpleAccount
*account
, PurpleBuddy
*buddy
)
204 return BONJOUR_ICON_NAME
;
208 bonjour_send_im(PurpleConnection
*connection
, PurpleMessage
*msg
)
210 BonjourData
*bd
= purple_connection_get_protocol_data(connection
);
212 if (purple_message_is_empty(msg
) || !purple_message_get_recipient(msg
))
215 return bonjour_jabber_send_message(bd
->jabber_data
,
216 purple_message_get_recipient(msg
),
217 purple_message_get_contents(msg
));
221 bonjour_set_status(PurpleAccount
*account
, PurpleStatus
*status
)
223 PurpleConnection
*gc
;
225 PurplePresence
*presence
;
226 const char *message
, *bonjour_status
;
229 gc
= purple_account_get_connection(account
);
230 bd
= purple_connection_get_protocol_data(gc
);
231 presence
= purple_account_get_presence(account
);
233 message
= purple_status_get_attr_string(status
, "message");
236 stripped
= purple_markup_strip_html(message
);
239 * The three possible status for Bonjour are
240 * -available ("avail")
243 * Each of them can have an optional message.
245 if (purple_presence_is_available(presence
))
246 bonjour_status
= "avail";
247 else if (purple_presence_is_idle(presence
))
248 bonjour_status
= "away";
250 bonjour_status
= "dnd";
252 bonjour_dns_sd_send_status(bd
->dns_sd_data
, bonjour_status
, stripped
);
257 * The add_buddy callback removes the buddy from the local list.
258 * Bonjour manages buddies for you, and adding someone locally by
259 * hand is stupid. Perhaps we should change libpurple not to allow adding
260 * if there is no add_buddy callback.
263 bonjour_fake_add_buddy(PurpleConnection
*pc
, PurpleBuddy
*buddy
, PurpleGroup
*group
, const char *message
) {
264 purple_debug_error("bonjour", "Buddy '%s' manually added; removing. "
265 "Bonjour buddies must be discovered and not manually added.\n",
266 purple_buddy_get_name(buddy
));
268 /* I suppose we could alert the user here, but it seems unnecessary. */
270 /* If this causes problems, it can be moved to an idle callback */
271 purple_blist_remove_buddy(buddy
);
275 static void bonjour_remove_buddy(PurpleConnection
*pc
, PurpleBuddy
*buddy
, PurpleGroup
*group
) {
276 BonjourBuddy
*bb
= purple_buddy_get_protocol_data(buddy
);
278 bonjour_buddy_delete(bb
);
279 purple_buddy_set_protocol_data(buddy
, NULL
);
284 bonjour_status_types(PurpleAccount
*account
)
286 GList
*status_types
= NULL
;
287 PurpleStatusType
*type
;
289 g_return_val_if_fail(account
!= NULL
, NULL
);
291 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AVAILABLE
,
292 BONJOUR_STATUS_ID_AVAILABLE
,
293 NULL
, TRUE
, TRUE
, FALSE
,
294 "message", _("Message"),
295 purple_value_new(G_TYPE_STRING
), NULL
);
296 status_types
= g_list_append(status_types
, type
);
298 type
= purple_status_type_new_with_attrs(PURPLE_STATUS_AWAY
,
299 BONJOUR_STATUS_ID_AWAY
,
300 NULL
, TRUE
, TRUE
, FALSE
,
301 "message", _("Message"),
302 purple_value_new(G_TYPE_STRING
), NULL
);
303 status_types
= g_list_append(status_types
, type
);
305 type
= purple_status_type_new_full(PURPLE_STATUS_OFFLINE
,
306 BONJOUR_STATUS_ID_OFFLINE
,
307 NULL
, TRUE
, TRUE
, FALSE
);
308 status_types
= g_list_append(status_types
, type
);
314 bonjour_convo_closed(PurpleConnection
*connection
, const char *who
)
316 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
319 if (buddy
== NULL
|| (bb
= purple_buddy_get_protocol_data(buddy
)) == NULL
)
322 * This buddy is not in our buddy list, and therefore does not really
323 * exist, so we won't have any data about them.
328 bonjour_jabber_close_conversation(bb
->conversation
);
329 bb
->conversation
= NULL
;
333 bonjour_set_buddy_icon(PurpleConnection
*conn
, PurpleImage
*img
)
335 BonjourData
*bd
= purple_connection_get_protocol_data(conn
);
336 bonjour_dns_sd_update_buddy_icon(bd
->dns_sd_data
);
341 bonjour_status_text(PurpleBuddy
*buddy
)
343 PurplePresence
*presence
;
344 PurpleStatus
*status
;
348 presence
= purple_buddy_get_presence(buddy
);
349 status
= purple_presence_get_active_status(presence
);
351 message
= purple_status_get_attr_string(status
, "message");
353 if (message
!= NULL
) {
354 ret
= g_markup_escape_text(message
, -1);
355 purple_util_chrreplace(ret
, '\n', ' ');
362 bonjour_tooltip_text(PurpleBuddy
*buddy
, PurpleNotifyUserInfo
*user_info
, gboolean full
)
364 PurplePresence
*presence
;
365 PurpleStatus
*status
;
366 BonjourBuddy
*bb
= purple_buddy_get_protocol_data(buddy
);
367 const char *status_description
;
370 presence
= purple_buddy_get_presence(buddy
);
371 status
= purple_presence_get_active_status(presence
);
372 message
= purple_status_get_attr_string(status
, "message");
374 if (purple_presence_is_available(presence
))
375 status_description
= purple_status_get_name(status
);
376 else if (purple_presence_is_idle(presence
))
377 status_description
= _("Idle");
379 status_description
= purple_status_get_name(status
);
381 purple_notify_user_info_add_pair_plaintext(user_info
, _("Status"), status_description
);
382 if (message
!= NULL
) {
383 /* TODO: Check whether it's correct to call add_pair_html,
384 or if we should be using add_pair_plaintext */
385 purple_notify_user_info_add_pair_html(user_info
, _("Message"), message
);
389 purple_debug_error("bonjour", "Got tooltip request for a buddy without protocol data.\n");
393 /* Only show first/last name if there is a nickname set (to avoid duplication) */
394 if (bb
->nick
!= NULL
&& *bb
->nick
!= '\0') {
395 if (bb
->first
!= NULL
&& *bb
->first
!= '\0') {
396 /* TODO: Check whether it's correct to call add_pair_html,
397 or if we should be using add_pair_plaintext */
398 purple_notify_user_info_add_pair_html(user_info
, _("First name"), bb
->first
);
400 if (bb
->last
!= NULL
&& *bb
->last
!= '\0') {
401 /* TODO: Check whether it's correct to call add_pair_html,
402 or if we should be using add_pair_plaintext */
403 purple_notify_user_info_add_pair_html(user_info
, _("Last name"), bb
->last
);
407 if (bb
->email
!= NULL
&& *bb
->email
!= '\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
, _("Email"), bb
->email
);
413 if (bb
->AIM
!= NULL
&& *bb
->AIM
!= '\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
, _("AIM Account"), bb
->AIM
);
419 if (bb
->jid
!= NULL
&& *bb
->jid
!= '\0') {
420 /* TODO: Check whether it's correct to call add_pair_html,
421 or if we should be using add_pair_plaintext */
422 purple_notify_user_info_add_pair_html(user_info
, _("XMPP Account"), bb
->jid
);
427 bonjour_do_group_change(PurpleBuddy
*buddy
, const char *new_group
)
432 /* If we're moving them out of the bonjour group, make them persistent */
433 if (purple_strequal(new_group
, BONJOUR_GROUP_NAME
))
434 purple_blist_node_set_transient(PURPLE_BLIST_NODE(buddy
), TRUE
);
436 purple_blist_node_set_transient(PURPLE_BLIST_NODE(buddy
),
437 !purple_blist_node_is_transient(PURPLE_BLIST_NODE(buddy
)));
442 bonjour_group_buddy(PurpleConnection
*connection
, const char *who
, const char *old_group
, const char *new_group
)
444 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
446 bonjour_do_group_change(buddy
, new_group
);
451 bonjour_rename_group(PurpleConnection
*connection
, const char *old_name
, PurpleGroup
*group
, GList
*moved_buddies
)
454 const char *new_group
;
457 new_group
= purple_group_get_name(group
);
459 for (cur
= moved_buddies
; cur
; cur
= cur
->next
) {
461 bonjour_do_group_change(buddy
, new_group
);
467 bonjour_can_receive_file(PurpleProtocolXfer
*prplxfer
, PurpleConnection
*connection
, const char *who
)
469 PurpleBuddy
*buddy
= purple_blist_find_buddy(purple_connection_get_account(connection
), who
);
471 return (buddy
!= NULL
&& purple_buddy_get_protocol_data(buddy
) != NULL
);
475 bonjour_get_max_message_size(PurpleConversation
*conv
)
477 return -1; /* 5MB successfully tested. */
482 _set_default_name_cb(gpointer data
) {
483 gchar
*fullname
= data
;
484 const char *splitpoint
;
485 GList
*tmp
= my_protocol
->account_options
;
486 PurpleAccountOption
*option
;
489 purple_debug_info("bonjour", "Unable to look up First and Last name or Username from system; using defaults.\n");
493 g_free(default_firstname
);
494 g_free(default_lastname
);
496 /* Split the real name into a first and last name */
497 splitpoint
= strchr(fullname
, ' ');
498 if (splitpoint
!= NULL
) {
499 default_firstname
= g_strndup(fullname
, splitpoint
- fullname
);
500 default_lastname
= g_strdup(&splitpoint
[1]);
502 default_firstname
= g_strdup(fullname
);
503 default_lastname
= g_strdup("");
508 for(; tmp
!= NULL
; tmp
= tmp
->next
) {
510 if (purple_strequal("first", purple_account_option_get_setting(option
)))
511 purple_account_option_set_default_string(option
, default_firstname
);
512 else if (purple_strequal("last", purple_account_option_get_setting(option
)))
513 purple_account_option_set_default_string(option
, default_lastname
);
520 _win32_name_lookup_thread(gpointer data
) {
521 gchar
*fullname
= NULL
;
522 wchar_t username
[UNLEN
+ 1];
523 DWORD dwLenUsername
= UNLEN
+ 1;
525 GetUserNameW((LPWSTR
) &username
, &dwLenUsername
);
527 if (username
!= NULL
&& *username
!= '\0') {
528 LPBYTE servername
= NULL
;
531 NetGetDCName(NULL
, NULL
, &servername
);
533 /* purple_debug_info("bonjour", "Looking up the full name from the %s.\n", (servername ? "domain controller" : "local machine")); */
535 if (NetUserGetInfo((LPCWSTR
) servername
, username
, 10, &info
) == NERR_Success
536 && info
!= NULL
&& ((LPUSER_INFO_10
) info
)->usri10_full_name
!= NULL
537 && *(((LPUSER_INFO_10
) info
)->usri10_full_name
) != '\0') {
538 fullname
= g_utf16_to_utf8(
539 ((LPUSER_INFO_10
) info
)->usri10_full_name
,
540 -1, NULL
, NULL
, NULL
);
542 /* Fall back to the local machine if we didn't get the full name from the domain controller */
543 else if (servername
!= NULL
) {
544 /* purple_debug_info("bonjour", "Looking up the full name from the local machine"); */
546 if (info
!= NULL
) NetApiBufferFree(info
);
549 if (NetUserGetInfo(NULL
, username
, 10, &info
) == NERR_Success
550 && info
!= NULL
&& ((LPUSER_INFO_10
) info
)->usri10_full_name
!= NULL
551 && *(((LPUSER_INFO_10
) info
)->usri10_full_name
) != '\0') {
552 fullname
= g_utf16_to_utf8(
553 ((LPUSER_INFO_10
) info
)->usri10_full_name
,
554 -1, NULL
, NULL
, NULL
);
558 if (info
!= NULL
) NetApiBufferFree(info
);
559 if (servername
!= NULL
) NetApiBufferFree(servername
);
562 fullname
= g_utf16_to_utf8(username
, -1, NULL
, NULL
, NULL
);
565 g_timeout_add(0, _set_default_name_cb
, fullname
);
572 initialize_default_account_values(void)
577 GThread
*lookup_thread
;
579 const char *fullname
= NULL
, *splitpoint
, *tmp
;
583 /* Try to figure out the user's real name */
584 info
= getpwuid(getuid());
585 if ((info
!= NULL
) && (info
->pw_gecos
!= NULL
) && (info
->pw_gecos
[0] != '\0'))
586 fullname
= info
->pw_gecos
;
587 else if ((info
!= NULL
) && (info
->pw_name
!= NULL
) && (info
->pw_name
[0] != '\0'))
588 fullname
= info
->pw_name
;
589 else if (((fullname
= getlogin()) != NULL
) && (fullname
[0] == '\0'))
592 /* The Win32 username lookup functions are synchronous so we do it in a thread */
593 lookup_thread
= g_thread_try_new("bonjour dns thread", _win32_name_lookup_thread
, NULL
, NULL
);
595 g_thread_unref(lookup_thread
);
597 purple_debug_fatal("bonjour", "failed to create lookup thread\n");
600 /* Make sure fullname is valid UTF-8. If not, try to convert it. */
601 if (fullname
!= NULL
&& !g_utf8_validate(fullname
, -1, NULL
)) {
602 fullname
= conv
= g_locale_to_utf8(fullname
, -1, NULL
, NULL
, NULL
);
603 if (conv
== NULL
|| *conv
== '\0')
607 if (fullname
== NULL
)
608 fullname
= _("Purple Person");
610 /* Split the real name into a first and last name */
611 splitpoint
= strchr(fullname
, ' ');
612 if (splitpoint
!= NULL
) {
613 default_firstname
= g_strndup(fullname
, splitpoint
- fullname
);
614 tmp
= &splitpoint
[1];
616 /* The last name may be followed by a comma and additional data.
617 * Only use the last name itself.
619 splitpoint
= strchr(tmp
, ',');
620 if (splitpoint
!= NULL
)
621 default_lastname
= g_strndup(tmp
, splitpoint
- tmp
);
623 default_lastname
= g_strdup(tmp
);
625 default_firstname
= g_strdup(fullname
);
626 default_lastname
= g_strdup("");
633 bonjour_protocol_init(PurpleProtocol
*protocol
)
635 PurpleAccountOption
*option
;
637 protocol
->id
= "prpl-bonjour";
638 protocol
->name
= "Bonjour";
639 protocol
->options
= OPT_PROTO_NO_PASSWORD
;
640 protocol
->icon_spec
= purple_buddy_icon_spec_new("png,gif,jpeg",
642 PURPLE_ICON_SCALE_DISPLAY
);
644 /* Creating the options for the protocol */
645 option
= purple_account_option_int_new(_("Local Port"), "port", BONJOUR_DEFAULT_PORT
);
646 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
648 option
= purple_account_option_string_new(_("First name"), "first", default_firstname
);
649 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
651 option
= purple_account_option_string_new(_("Last name"), "last", default_lastname
);
652 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
654 option
= purple_account_option_string_new(_("Email"), "email", "");
655 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
657 option
= purple_account_option_string_new(_("AIM Account"), "AIM", "");
658 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
660 option
= purple_account_option_string_new(_("XMPP Account"), "jid", "");
661 protocol
->account_options
= g_list_append(protocol
->account_options
, option
);
665 bonjour_protocol_class_init(PurpleProtocolClass
*klass
)
667 klass
->login
= bonjour_login
;
668 klass
->close
= bonjour_close
;
669 klass
->status_types
= bonjour_status_types
;
670 klass
->list_icon
= bonjour_list_icon
;
674 bonjour_protocol_client_iface_init(PurpleProtocolClientInterface
*client_iface
)
676 client_iface
->status_text
= bonjour_status_text
;
677 client_iface
->tooltip_text
= bonjour_tooltip_text
;
678 client_iface
->convo_closed
= bonjour_convo_closed
;
679 client_iface
->get_max_message_size
= bonjour_get_max_message_size
;
683 bonjour_protocol_server_iface_init(PurpleProtocolServerInterface
*server_iface
)
685 server_iface
->add_buddy
= bonjour_fake_add_buddy
;
686 server_iface
->remove_buddy
= bonjour_remove_buddy
;
687 server_iface
->group_buddy
= bonjour_group_buddy
;
688 server_iface
->rename_group
= bonjour_rename_group
;
689 server_iface
->set_buddy_icon
= bonjour_set_buddy_icon
;
690 server_iface
->set_status
= bonjour_set_status
;
694 bonjour_protocol_im_iface_init(PurpleProtocolIMInterface
*im_iface
)
696 im_iface
->send
= bonjour_send_im
;
700 bonjour_protocol_xfer_iface_init(PurpleProtocolXferInterface
*xfer_iface
)
702 xfer_iface
->can_receive
= bonjour_can_receive_file
;
703 xfer_iface
->send_file
= bonjour_send_file
;
704 xfer_iface
->new_xfer
= bonjour_new_xfer
;
707 PURPLE_DEFINE_TYPE_EXTENDED(
708 BonjourProtocol
, bonjour_protocol
, PURPLE_TYPE_PROTOCOL
, 0,
710 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_CLIENT
,
711 bonjour_protocol_client_iface_init
)
713 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_SERVER
,
714 bonjour_protocol_server_iface_init
)
716 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_IM
,
717 bonjour_protocol_im_iface_init
)
719 PURPLE_IMPLEMENT_INTERFACE_STATIC(PURPLE_TYPE_PROTOCOL_XFER
,
720 bonjour_protocol_xfer_iface_init
)
723 static PurplePluginInfo
*
724 plugin_query(GError
**error
)
726 return purple_plugin_info_new(
727 "id", "prpl-bonjour",
728 "name", "Bonjour Protocol",
729 "version", DISPLAY_VERSION
,
730 "category", N_("Protocol"),
731 "summary", N_("Bonjour Protocol Plugin"),
732 "description", N_("Bonjour Protocol Plugin"),
733 "website", PURPLE_WEBSITE
,
734 "abi-version", PURPLE_ABI_VERSION
,
735 "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL
|
736 PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD
,
742 plugin_load(PurplePlugin
*plugin
, GError
**error
)
744 bonjour_protocol_register_type(plugin
);
746 xep_xfer_register(G_TYPE_MODULE(plugin
));
748 my_protocol
= purple_protocols_add(BONJOUR_TYPE_PROTOCOL
, error
);
752 initialize_default_account_values();
758 plugin_unload(PurplePlugin
*plugin
, GError
**error
)
760 if (!purple_protocols_remove(my_protocol
, error
))
763 g_free(default_firstname
);
764 g_free(default_lastname
);
769 PURPLE_PLUGIN_INIT(bonjour
, plugin_query
, plugin_load
, plugin_unload
);