eion/purple-hangouts
Clone
* Hangouts Plugin for libpurple/Pidgin * Copyright (c) 2015-2016 Eion Robb, Mike Ruprecht * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. #include "mediamanager.h" #include "hangouts_auth.h" #include "hangouts_pblite.h" #include "hangouts_json.h" #include "hangouts_events.h" #include "hangouts_connection.h" #include "hangouts_conversation.h" #include "hangouts_media.h" /*****************************************************************************/ //TODO move to nicer place hangouts_is_valid_id ( const gchar * id ) for ( i = strlen ( id ) - 1 ; i >= 0 ; i -- ) { if ( ! g_ascii_isdigit ( id [ i ])) { hangouts_get_media_caps ( PurpleAccount * account , const char * who ) return PURPLE_MEDIA_CAPS_AUDIO | PURPLE_MEDIA_CAPS_VIDEO | PURPLE_MEDIA_CAPS_AUDIO_VIDEO | PURPLE_MEDIA_CAPS_MODIFY_SESSION ; hangouts_set_idle ( PurpleConnection * pc , int time ) ha = purple_connection_get_protocol_data ( pc ); if ( time < HANGOUTS_ACTIVE_CLIENT_TIMEOUT ) { hangouts_set_active_client ( pc ); hangouts_add_account_options ( GList * account_options ) PurpleAccountOption * option ; option = purple_account_option_bool_new ( N_ ( "Show call links in chat" ), "show-call-links" , ! purple_media_manager_get ()); account_options = g_list_append ( account_options , option ); option = purple_account_option_bool_new ( N_ ( "Un-Googlify URLs" ), "unravel_google_url" , FALSE ); account_options = g_list_append ( account_options , option ); option = purple_account_option_bool_new ( N_ ( "Treat invisible users as offline" ), "treat_invisible_as_offline" , FALSE ); account_options = g_list_append ( account_options , option ); option = purple_account_option_bool_new ( N_ ( "Hide self from buddy list (requires reconnect)" ), "hide_self" , FALSE ); account_options = g_list_append ( account_options , option ); hangouts_blist_node_removed ( PurpleBlistNode * node ) PurpleBuddy * buddy = NULL ; PurpleAccount * account = NULL ; if ( PURPLE_IS_CHAT ( node )) { chat = PURPLE_CHAT ( node ); account = purple_chat_get_account ( chat ); } else if ( PURPLE_IS_BUDDY ( node )) { buddy = PURPLE_BUDDY ( node ); account = purple_buddy_get_account ( buddy ); if ( ! purple_strequal ( purple_account_get_protocol_id ( account ), HANGOUTS_PLUGIN_ID )) { pc = purple_account_get_connection ( account ); components = purple_chat_get_components ( chat ); conv_id = g_hash_table_lookup ( components , "conv_id" ); conv_id = purple_chat_get_name_only ( chat ); hangouts_chat_leave_by_conv_id ( pc , conv_id , NULL ); HangoutsAccount * ha = purple_connection_get_protocol_data ( pc ); const gchar * gaia_id = purple_buddy_get_name ( buddy ); conv_id = g_hash_table_lookup ( ha -> one_to_ones_rev , gaia_id ); hangouts_archive_conversation ( ha , conv_id ); if ( purple_strequal ( gaia_id , ha -> self_gaia_id )) { purple_account_set_bool ( account , "hide_self" , TRUE ); hangouts_blist_node_aliased ( PurpleBlistNode * node , const char * old_alias ) PurpleAccount * account = NULL ; if ( PURPLE_IS_CHAT ( node )) { chat = PURPLE_CHAT ( node ); account = purple_chat_get_account ( chat ); if ( ! purple_strequal ( purple_account_get_protocol_id ( account ), HANGOUTS_PLUGIN_ID )) { pc = purple_account_get_connection ( account ); ha = purple_connection_get_protocol_data ( pc ); if ( g_dataset_get_data ( ha , "ignore_set_alias" )) { new_alias = purple_chat_get_alias ( chat ); // Don't send update to existing update if ( ! purple_strequal ( old_alias , new_alias )) { components = purple_chat_get_components ( chat ); conv_id = g_hash_table_lookup ( components , "conv_id" ); conv_id = purple_chat_get_name_only ( chat ); hangouts_rename_conversation ( ha , conv_id , new_alias ); hangouts_chat_set_topic ( PurpleConnection * pc , int id , const char * topic ) PurpleChatConversation * chatconv ; ha = purple_connection_get_protocol_data ( pc ); chatconv = purple_conversations_find_chat ( pc , id ); conv_id = purple_conversation_get_data ( PURPLE_CONVERSATION ( chatconv ), "conv_id" ); // Fix for a race condition around the chat data and serv_got_joined_chat() conv_id = purple_conversation_get_name ( PURPLE_CONVERSATION ( chatconv )); return hangouts_rename_conversation ( ha , conv_id , topic ); hangouts_cmd_leave ( PurpleConversation * conv , const gchar * cmd , gchar ** args , gchar ** error , void * data ) PurpleConnection * pc = NULL ; pc = purple_conversation_get_connection ( conv ); id = purple_chat_conversation_get_id ( PURPLE_CHAT_CONVERSATION ( conv )); if ( pc == NULL || id == -1 ) return PURPLE_CMD_RET_FAILED ; hangouts_chat_leave ( pc , id ); return PURPLE_CMD_RET_OK ; hangouts_cmd_kick ( PurpleConversation * conv , const gchar * cmd , gchar ** args , gchar ** error , void * data ) PurpleConnection * pc = NULL ; pc = purple_conversation_get_connection ( conv ); id = purple_chat_conversation_get_id ( PURPLE_CHAT_CONVERSATION ( conv )); if ( pc == NULL || id == -1 ) return PURPLE_CMD_RET_FAILED ; hangouts_chat_kick ( pc , id , args [ 0 ]); return PURPLE_CMD_RET_OK ; hangouts_node_menu ( PurpleBlistNode * node ) if ( PURPLE_IS_BUDDY ( node )) act = purple_menu_action_new ( _ ( "Initiate _Chat" ), PURPLE_CALLBACK ( hangouts_initiate_chat_from_node ), m = g_list_append ( m , act ); } else if ( PURPLE_IS_CHAT ( node )) { act = purple_menu_action_new ( _ ( "_Leave Chat" ), PURPLE_CALLBACK ( hangouts_blist_node_removed ), // A strange coinkidink m = g_list_append ( m , act ); hangouts_join_chat_by_url_action ( PurpleProtocolAction * action ) PurpleConnection * pc = purple_protocol_action_get_connection ( action ); HangoutsAccount * ha = purple_connection_get_protocol_data ( pc ); purple_request_input ( pc , _ ( "Join chat..." ), _ ( "Join a Hangouts group chat from the invite URL..." ), NULL , FALSE , FALSE , "https://hangouts.google.com/group/..." , _ ( "_Join" ), G_CALLBACK ( hangouts_join_chat_from_url ), purple_request_cpar_from_connection ( pc ), #if !PURPLE_VERSION_CHECK(3, 0, 0) PurplePlugin * plugin , gpointer context PurpleProtocolAction * act ; act = purple_protocol_action_new ( _ ( "Search for friends..." ), hangouts_search_users ); m = g_list_append ( m , act ); act = purple_protocol_action_new ( _ ( "Join a group chat by URL..." ), hangouts_join_chat_by_url_action ); m = g_list_append ( m , act ); hangouts_authcode_input_cb ( gpointer user_data , const gchar * auth_code ) HangoutsAccount * ha = user_data ; PurpleConnection * pc = ha -> pc ; purple_connection_update_progress ( pc , _ ( "Authenticating" ), 1 , 3 ); hangouts_oauth_with_code ( ha , auth_code ); hangouts_authcode_input_cancel_cb ( gpointer user_data ) HangoutsAccount * ha = user_data ; purple_connection_error ( ha -> pc , PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE , _ ( "User cancelled authorization" )); static gulong chat_conversation_typing_signal = 0 ; #if !PURPLE_VERSION_CHECK(3, 0, 0) static gulong deleting_chat_buddy_signal = 0 ; // See workaround for purple_chat_conversation_find_user() in purplecompat.h hangouts_deleting_chat_buddy ( PurpleConvChatBuddy * cb ) if ( g_dataset_get_data ( cb , "chat" ) != NULL ) { hangouts_login ( PurpleAccount * account ) HangoutsAccount * ha ; //hahaha const gchar * self_gaia_id ; PurpleConnectionFlags pc_flags ; pc = purple_account_get_connection ( account ); password = purple_connection_get_password ( pc ); pc_flags = purple_connection_get_flags ( pc ); pc_flags |= PURPLE_CONNECTION_FLAG_HTML ; pc_flags |= PURPLE_CONNECTION_FLAG_NO_FONTSIZE ; pc_flags |= PURPLE_CONNECTION_FLAG_NO_BGCOLOR ; pc_flags &= ~ PURPLE_CONNECTION_FLAG_NO_IMAGES ; purple_connection_set_flags ( pc , pc_flags ); ha = g_new0 ( HangoutsAccount , 1 ); ha -> cookie_jar = purple_http_cookie_jar_new (); ha -> channel_buffer = g_byte_array_sized_new ( HANGOUTS_BUFFER_DEFAULT_SIZE ); ha -> channel_keepalive_pool = purple_http_keepalive_pool_new (); ha -> client6_keepalive_pool = purple_http_keepalive_pool_new (); ha -> sent_message_ids = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ); ha -> one_to_ones = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_free ); ha -> one_to_ones_rev = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_free ); ha -> group_chats = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ); ha -> google_voice_conversations = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , NULL ); self_gaia_id = purple_account_get_string ( account , "self_gaia_id" , NULL ); if ( self_gaia_id != NULL ) { ha -> self_gaia_id = g_strdup ( self_gaia_id ); purple_connection_set_display_name ( pc , ha -> self_gaia_id ); purple_connection_set_protocol_data ( pc , ha ); if ( password && * password ) { ha -> refresh_token = g_strdup ( password ); purple_connection_update_progress ( pc , _ ( "Authenticating" ), 1 , 3 ); hangouts_oauth_refresh_token ( ha ); //TODO get this code automatically purple_notify_uri ( pc , "https://www.youtube.com/watch?v=hlDhp-eNLMU" ); purple_request_input ( pc , _ ( "Authorization Code" ), "https://www.youtube.com/watch?v=hlDhp-eNLMU" , _ ( "Please follow the YouTube video to get the OAuth code" ), _ ( "and then paste the Google OAuth code here" ), FALSE , FALSE , NULL , _ ( "OK" ), G_CALLBACK ( hangouts_authcode_input_cb ), _ ( "Cancel" ), G_CALLBACK ( hangouts_authcode_input_cancel_cb ), purple_request_cpar_from_connection ( pc ), ha ); purple_signal_connect ( purple_blist_get_handle (), "blist-node-removed" , account , PURPLE_CALLBACK ( hangouts_blist_node_removed ), NULL ); purple_signal_connect ( purple_blist_get_handle (), "blist-node-aliased" , account , PURPLE_CALLBACK ( hangouts_blist_node_aliased ), NULL ); purple_signal_connect ( purple_conversations_get_handle (), "conversation-updated" , account , PURPLE_CALLBACK ( hangouts_mark_conversation_seen ), NULL ); if ( ! chat_conversation_typing_signal ) { chat_conversation_typing_signal = purple_signal_connect ( purple_conversations_get_handle (), "chat-conversation-typing" , purple_connection_get_protocol ( pc ), PURPLE_CALLBACK ( hangouts_conv_send_typing ), NULL ); #if !PURPLE_VERSION_CHECK(3, 0, 0) if ( ! deleting_chat_buddy_signal ) { deleting_chat_buddy_signal = purple_signal_connect ( purple_conversations_get_handle (), "deleting-chat-buddy" , purple_connection_get_protocol ( pc ), PURPLE_CALLBACK ( hangouts_deleting_chat_buddy ), NULL ); ha -> active_client_timeout = g_timeout_add_seconds ( HANGOUTS_ACTIVE_CLIENT_TIMEOUT , (( GSourceFunc ) hangouts_set_active_client ), pc ); hangouts_close ( PurpleConnection * pc ) HangoutsAccount * ha ; //not so funny anymore ha = purple_connection_get_protocol_data ( pc ); purple_signals_disconnect_by_handle ( ha -> account ); g_source_remove ( ha -> active_client_timeout ); g_source_remove ( ha -> channel_watchdog ); g_source_remove ( ha -> poll_buddy_status_timeout ); purple_http_conn_cancel_all ( pc ); purple_http_keepalive_pool_unref ( ha -> channel_keepalive_pool ); purple_http_keepalive_pool_unref ( ha -> client6_keepalive_pool ); g_free ( ha -> self_gaia_id ); g_free ( ha -> refresh_token ); g_free ( ha -> access_token ); g_free ( ha -> gsessionid_param ); purple_http_cookie_jar_unref ( ha -> cookie_jar ); g_byte_array_free ( ha -> channel_buffer , TRUE ); g_hash_table_remove_all ( ha -> sent_message_ids ); g_hash_table_unref ( ha -> sent_message_ids ); g_hash_table_remove_all ( ha -> one_to_ones ); g_hash_table_unref ( ha -> one_to_ones ); g_hash_table_remove_all ( ha -> one_to_ones_rev ); g_hash_table_unref ( ha -> one_to_ones_rev ); g_hash_table_remove_all ( ha -> group_chats ); g_hash_table_unref ( ha -> group_chats ); g_hash_table_remove_all ( ha -> google_voice_conversations ); g_hash_table_unref ( ha -> google_voice_conversations ); hangouts_list_icon ( PurpleAccount * account , PurpleBuddy * buddy ) hangouts_tooltip_text ( PurpleBuddy * buddy , PurpleNotifyUserInfo * user_info , gboolean full ) PurplePresence * presence ; g_return_if_fail ( buddy != NULL ); presence = purple_buddy_get_presence ( buddy ); status = purple_presence_get_active_status ( presence ); purple_notify_user_info_add_pair_html ( user_info , _ ( "Status" ), purple_status_get_name ( status )); message = purple_status_get_attr_string ( status , "message" ); purple_notify_user_info_add_pair_html ( user_info , _ ( "Message" ), message ); hbuddy = purple_buddy_get_protocol_data ( buddy ); if ( hbuddy -> last_seen != 0 ) { gchar * seen = purple_str_seconds_to_string ( time ( NULL ) - hbuddy -> last_seen ); purple_notify_user_info_add_pair_html ( user_info , _ ( "Last seen" ), seen ); purple_notify_user_info_add_pair_html ( user_info , _ ( "In call" ), NULL ); if ( hbuddy -> device_type ) { purple_notify_user_info_add_pair_html ( user_info , _ ( "Device Type" ), hbuddy -> device_type & HANGOUTS_DEVICE_TYPE_DESKTOP ? _ ( "Desktop" ) : hbuddy -> device_type & HANGOUTS_DEVICE_TYPE_TABLET ? _ ( "Tablet" ) : hbuddy -> device_type & HANGOUTS_DEVICE_TYPE_MOBILE ? _ ( "Mobile" ) : hangouts_status_types ( PurpleAccount * account ) PurpleStatusType * status ; status = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , NULL , NULL , TRUE , TRUE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); status = purple_status_type_new_with_attrs ( PURPLE_STATUS_AWAY , NULL , NULL , FALSE , TRUE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); status = purple_status_type_new_with_attrs ( PURPLE_STATUS_EXTENDED_AWAY , NULL , NULL , FALSE , FALSE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); status = purple_status_type_new_with_attrs ( PURPLE_STATUS_UNAVAILABLE , NULL , _ ( "Do Not Disturb" ), FALSE , TRUE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); status = purple_status_type_new_full ( PURPLE_STATUS_MOBILE , "mobile" , _ ( "Phone" ), FALSE , FALSE , FALSE ); types = g_list_append ( types , status ); status = purple_status_type_new_full ( PURPLE_STATUS_OFFLINE , NULL , NULL , TRUE , TRUE , FALSE ); types = g_list_append ( types , status ); status = purple_status_type_new_with_attrs ( PURPLE_STATUS_OFFLINE , "gone" , NULL , FALSE , FALSE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); status = purple_status_type_new_with_attrs ( PURPLE_STATUS_INVISIBLE , NULL , NULL , FALSE , FALSE , FALSE , "message" , _ ( "Mood" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); types = g_list_append ( types , status ); hangouts_status_text ( PurpleBuddy * buddy ) const gchar * message = purple_status_get_attr_string ( purple_presence_get_active_status ( purple_buddy_get_presence ( buddy )), "message" ); return g_markup_printf_escaped ( "%s" , message ); hangouts_buddy_free ( PurpleBuddy * buddy ) HangoutsBuddy * hbuddy = purple_buddy_get_protocol_data ( buddy ); g_return_if_fail ( hbuddy != NULL ); hangouts_offline_message ( const PurpleBuddy * buddy ) /*****************************************************************************/ plugin_load ( PurplePlugin * plugin , GError ** error ) purple_cmd_register ( "leave" , "" , PURPLE_CMD_P_PLUGIN , PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PROTOCOL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS , HANGOUTS_PLUGIN_ID , hangouts_cmd_leave , _ ( "leave: Leave the group chat" ), NULL ); purple_cmd_register ( "kick" , "s" , PURPLE_CMD_P_PLUGIN , PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_PROTOCOL_ONLY | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS , HANGOUTS_PLUGIN_ID , hangouts_cmd_kick , _ ( "kick <user>: Kick a user from the room." ), NULL ); plugin_unload ( PurplePlugin * plugin , GError ** error ) purple_signals_disconnect_by_handle ( plugin ); #if PURPLE_VERSION_CHECK(3, 0, 0) G_MODULE_EXPORT GType hangouts_protocol_get_type ( void ); #define HANGOUTS_TYPE_PROTOCOL (hangouts_protocol_get_type()) #define HANGOUTS_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), HANGOUTS_TYPE_PROTOCOL, HangoutsProtocol)) #define HANGOUTS_PROTOCOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), HANGOUTS_TYPE_PROTOCOL, HangoutsProtocolClass)) #define HANGOUTS_IS_PROTOCOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), HANGOUTS_TYPE_PROTOCOL)) #define HANGOUTS_IS_PROTOCOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), HANGOUTS_TYPE_PROTOCOL)) #define HANGOUTS_PROTOCOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), HANGOUTS_TYPE_PROTOCOL, HangoutsProtocolClass)) typedef struct _HangoutsProtocol typedef struct _HangoutsProtocolClass PurpleProtocolClass parent_class ; hangouts_protocol_init ( PurpleProtocol * prpl_info ) PurpleProtocol * plugin = prpl_info , * info = prpl_info ; info -> id = HANGOUTS_PLUGIN_ID ; prpl_info -> options = OPT_PROTO_NO_PASSWORD | OPT_PROTO_CHAT_TOPIC | OPT_PROTO_MAIL_CHECK ; prpl_info -> account_options = hangouts_add_account_options ( prpl_info -> account_options ); purple_signal_register ( plugin , "hangouts-received-stateupdate" , purple_marshal_VOID__POINTER_POINTER , G_TYPE_NONE , 2 , purple_signal_register ( plugin , "hangouts-gmail-notification" , purple_marshal_VOID__POINTER_POINTER_POINTER , G_TYPE_NONE , 3 , hangouts_register_events ( plugin ); hangouts_protocol_class_init ( PurpleProtocolClass * prpl_info ) prpl_info -> login = hangouts_login ; prpl_info -> close = hangouts_close ; prpl_info -> status_types = hangouts_status_types ; prpl_info -> list_icon = hangouts_list_icon ; hangouts_protocol_client_iface_init ( PurpleProtocolClientIface * prpl_info ) prpl_info -> get_actions = hangouts_actions ; prpl_info -> blist_node_menu = hangouts_node_menu ; prpl_info -> status_text = hangouts_status_text ; prpl_info -> tooltip_text = hangouts_tooltip_text ; prpl_info -> buddy_free = hangouts_buddy_free ; prpl_info -> offline_message = hangouts_offline_message ; hangouts_protocol_server_iface_init ( PurpleProtocolServerIface * prpl_info ) prpl_info -> get_info = hangouts_get_info ; prpl_info -> set_status = hangouts_set_status ; prpl_info -> set_idle = hangouts_set_idle ; hangouts_protocol_privacy_iface_init ( PurpleProtocolPrivacyIface * prpl_info ) prpl_info -> add_deny = hangouts_block_user ; prpl_info -> rem_deny = hangouts_unblock_user ; hangouts_protocol_im_iface_init ( PurpleProtocolIMIface * prpl_info ) prpl_info -> send = hangouts_send_im ; prpl_info -> send_typing = hangouts_send_typing ; hangouts_protocol_chat_iface_init ( PurpleProtocolChatIface * prpl_info ) prpl_info -> send = hangouts_chat_send ; prpl_info -> info = hangouts_chat_info ; prpl_info -> info_defaults = hangouts_chat_info_defaults ; prpl_info -> join = hangouts_join_chat ; prpl_info -> get_name = hangouts_get_chat_name ; prpl_info -> invite = hangouts_chat_invite ; prpl_info -> set_topic = hangouts_chat_set_topic ; hangouts_protocol_media_iface_init ( PurpleProtocolMediaIface * prpl_info ) prpl_info -> get_caps = hangouts_get_media_caps ; prpl_info -> initiate_session = hangouts_initiate_media ; hangouts_protocol_roomlist_iface_init ( PurpleProtocolRoomlistIface * prpl_info ) prpl_info -> get_list = hangouts_roomlist_get_list ; static PurpleProtocol * hangouts_protocol ; PURPLE_DEFINE_TYPE_EXTENDED ( HangoutsProtocol , hangouts_protocol , PURPLE_TYPE_PROTOCOL , 0 , PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_IM_IFACE , hangouts_protocol_im_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_CHAT_IFACE , hangouts_protocol_chat_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_CLIENT_IFACE , hangouts_protocol_client_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_SERVER_IFACE , hangouts_protocol_server_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_PRIVACY_IFACE , hangouts_protocol_privacy_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_MEDIA_IFACE , hangouts_protocol_media_iface_init ) PURPLE_IMPLEMENT_INTERFACE_STATIC ( PURPLE_TYPE_PROTOCOL_ROOMLIST_IFACE , hangouts_protocol_roomlist_iface_init ) libpurple3_plugin_load ( PurplePlugin * plugin , GError ** error ) hangouts_protocol_register_type ( plugin ); hangouts_protocol = purple_protocols_add ( HANGOUTS_TYPE_PROTOCOL , error ); return plugin_load ( plugin , error ); libpurple3_plugin_unload ( PurplePlugin * plugin , GError ** error ) if ( ! plugin_unload ( plugin , error )) if ( ! purple_protocols_remove ( hangouts_protocol , error )) static PurplePluginInfo * plugin_query ( GError ** error ) return purple_plugin_info_new ( "id" , HANGOUTS_PLUGIN_ID , "version" , HANGOUTS_PLUGIN_VERSION , "category" , N_ ( "Protocol" ), "summary" , N_ ( "Hangouts Protocol Plugins." ), "description" , N_ ( "Adds Hangouts protocol support to libpurple." ), "website" , "https://bitbucket.org/EionRobb/purple-hangouts/" , "abi-version" , PURPLE_ABI_VERSION , "flags" , PURPLE_PLUGIN_INFO_FLAGS_INTERNAL | PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD , PURPLE_PLUGIN_INIT ( hangouts , plugin_query , libpurple3_plugin_load , libpurple3_plugin_unload ); // Normally set in core.c in purple3 void _purple_socket_init ( void ); void _purple_socket_uninit ( void ); libpurple2_plugin_load ( PurplePlugin * plugin ) return plugin_load ( plugin , NULL ); libpurple2_plugin_unload ( PurplePlugin * plugin ) return plugin_unload ( plugin , NULL ); static PurplePluginInfo info = PURPLE_PLUGIN_PROTOCOL , /**< type */ NULL , /**< ui_requirement */ NULL , /**< dependencies */ PURPLE_PRIORITY_DEFAULT , /**< priority */ HANGOUTS_PLUGIN_ID , /**< id */ N_ ( "Hangouts" ), /**< name */ HANGOUTS_PLUGIN_VERSION , /**< version */ N_ ( "Hangouts Protocol Plugins." ), /**< summary */ N_ ( "Adds Hangouts protocol support to libpurple." ), /**< description */ "Eion Robb <eionrobb+hangouts@gmail.com>" , /**< author */ "https://bitbucket.org/EionRobb/purple-hangouts/" , /**< homepage */ libpurple2_plugin_load , /**< load */ libpurple2_plugin_unload , /**< unload */ init_plugin ( PurplePlugin * plugin ) PurplePluginProtocolInfo * prpl_info = g_new0 ( PurplePluginProtocolInfo , 1 ); plugin -> info = info = g_new0 ( PurplePluginInfo , 1 ); prpl_info -> options = OPT_PROTO_NO_PASSWORD | OPT_PROTO_IM_IMAGE | OPT_PROTO_CHAT_TOPIC | OPT_PROTO_MAIL_CHECK ; prpl_info -> protocol_options = hangouts_add_account_options ( prpl_info -> protocol_options ); purple_signal_register ( plugin , "hangouts-received-stateupdate" , purple_marshal_VOID__POINTER_POINTER , NULL , 2 , purple_value_new ( PURPLE_TYPE_OBJECT )); purple_signal_register ( plugin , "hangouts-gmail-notification" , purple_marshal_VOID__POINTER_POINTER_POINTER , NULL , 3 , purple_value_new ( PURPLE_TYPE_STRING ), purple_value_new ( PURPLE_TYPE_OBJECT )); hangouts_register_events ( plugin ); prpl_info -> login = hangouts_login ; prpl_info -> close = hangouts_close ; prpl_info -> status_types = hangouts_status_types ; prpl_info -> list_icon = hangouts_list_icon ; prpl_info -> status_text = hangouts_status_text ; prpl_info -> tooltip_text = hangouts_tooltip_text ; prpl_info -> buddy_free = hangouts_buddy_free ; prpl_info -> offline_message = hangouts_offline_message ; prpl_info -> get_info = hangouts_get_info ; prpl_info -> set_status = hangouts_set_status ; prpl_info -> set_idle = hangouts_set_idle ; prpl_info -> blist_node_menu = hangouts_node_menu ; prpl_info -> send_im = hangouts_send_im ; prpl_info -> send_typing = hangouts_send_typing ; prpl_info -> chat_send = hangouts_chat_send ; prpl_info -> chat_info = hangouts_chat_info ; prpl_info -> chat_info_defaults = hangouts_chat_info_defaults ; prpl_info -> join_chat = hangouts_join_chat ; prpl_info -> get_chat_name = hangouts_get_chat_name ; prpl_info -> chat_invite = hangouts_chat_invite ; prpl_info -> set_chat_topic = hangouts_chat_set_topic ; prpl_info -> get_media_caps = hangouts_get_media_caps ; prpl_info -> initiate_media = hangouts_initiate_media ; prpl_info -> add_deny = hangouts_block_user ; prpl_info -> rem_deny = hangouts_unblock_user ; prpl_info -> roomlist_get_list = hangouts_roomlist_get_list ; info -> extra_info = prpl_info ; #if PURPLE_MINOR_VERSION >= 5 prpl_info -> struct_size = sizeof ( PurplePluginProtocolInfo ); #if PURPLE_MINOR_VERSION >= 8 //prpl_info->add_buddy_with_invite = skypeweb_add_buddy_with_invite; info -> actions = hangouts_actions ; PURPLE_INIT_PLUGIN ( hangouts , init_plugin , info );