* Some code copyright (C) 1998-1999, Mark Spencer <markster@marko.net> * Some code copyright (C) 1999-2001, Eric Warmenhoven * Some code copyright (C) 2001-2003, Sean Egan * Some code copyright (C) 2001-2007, Mark Doliner <thekingant@users.sourceforge.net> * Some code copyright (C) 2005, Jonathan Clark <ardentlygnarly@users.sourceforge.net> * Some code copyright (C) 2007, ComBOTS Product GmbH (htfv) <foss@combots.com> * Some code copyright (C) 2008, Aman Gupta * Most libfaim code copyright (C) 1998-2001 Adam Fritzler <afritz@auk.cx> * Some libfaim code copyright (C) 2001-2004 Mark Doliner <thekingant@users.sourceforge.net> * 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 2 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA #include "conversation.h" #define AIMHASHDATA "http: //pidgin.im/aim_data.php3" #define OSCAR_CONNECT_STEPS 6 static guint64 purple_caps = | OSCAR_CAPABILITY_BUDDYICON | OSCAR_CAPABILITY_DIRECTIM | OSCAR_CAPABILITY_SENDFILE | OSCAR_CAPABILITY_UNICODE | OSCAR_CAPABILITY_INTEROPERATE | OSCAR_CAPABILITY_SHORTCAPS | OSCAR_CAPABILITY_TYPING | OSCAR_CAPABILITY_ICQSERVERRELAY | OSCAR_CAPABILITY_NEWCAPS | OSCAR_CAPABILITY_HTML_MSGS ; static guint8 features_aim [] = { 0x01 , 0x01 , 0x01 , 0x02 }; static guint8 features_icq [] = { 0x01 }; struct oscar_ask_directim_data /* All the libfaim->purple callback functions */ /* Only used when connecting with the old-style BUCP login */ static int purple_parse_auth_resp ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_login ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_auth_securid_request ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_handle_redirect ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_info_change ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_account_confirm ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_oncoming ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_offgoing ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_incoming_im ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_misses ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_clientauto ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_motd ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_chatnav_info ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_conv_chat_join ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_conv_chat_leave ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_conv_chat_info_update ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_conv_chat_incoming_msg ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_email_parseupdate ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_icon_parseicon ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_searcherror ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_searchreply ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_bosrights ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_connerr ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_mtn ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_locaterights ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_buddyrights ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_parse_genericerr ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_memrequest ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_selfinfo ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_popup ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_parseerr ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_parserights ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_parselist ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_parseack ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_parseaddmod ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_authgiven ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_authrequest ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_authreply ( OscarData * , FlapConnection * , FlapFrame * , ...); static int purple_ssi_gotadded ( OscarData * , FlapConnection * , FlapFrame * , ...); static void purple_icons_fetch ( PurpleConnection * gc ); void oscar_set_info ( PurpleConnection * gc , const char * info ); static void oscar_set_info_and_status ( PurpleAccount * account , gboolean setinfo , const char * rawinfo , gboolean setstatus , PurpleStatus * status ); static void oscar_set_extended_status ( PurpleConnection * gc ); static gboolean purple_ssi_rerequestdata ( gpointer data ); void oscar_free_name_data ( struct name_data * data ) { const char * oscar_get_locale_charset ( void ) { static const char * charset = NULL ; static char * oscar_icqstatus ( int state ) { /* Make a cute little string that shows the status of the dude or dudet */ if ( state & AIM_ICQ_STATE_CHAT ) return g_strdup ( _ ( "Free For Chat" )); else if ( state & AIM_ICQ_STATE_DND ) return g_strdup ( _ ( "Do Not Disturb" )); else if ( state & AIM_ICQ_STATE_OUT ) return g_strdup ( _ ( "Not Available" )); else if ( state & AIM_ICQ_STATE_BUSY ) return g_strdup ( _ ( "Occupied" )); else if ( state & AIM_ICQ_STATE_AWAY ) return g_strdup ( _ ( "Away" )); else if ( state & AIM_ICQ_STATE_WEBAWARE ) return g_strdup ( _ ( "Web Aware" )); else if ( state & AIM_ICQ_STATE_INVISIBLE ) return g_strdup ( _ ( "Invisible" )); else if ( state & AIM_ICQ_STATE_EVIL ) return g_strdup ( _ ( "Evil" )); else if ( state & AIM_ICQ_STATE_DEPRESSION ) return g_strdup ( _ ( "Depression" )); else if ( state & AIM_ICQ_STATE_ATHOME ) return g_strdup ( _ ( "At home" )); else if ( state & AIM_ICQ_STATE_ATWORK ) return g_strdup ( _ ( "At work" )); else if ( state & AIM_ICQ_STATE_LUNCH ) return g_strdup ( _ ( "At lunch" )); return g_strdup ( _ ( "Online" )); static char * extract_name ( const char * name ) { for ( i = 0 , j = 0 ; x [ i ]; i ++ ) { strncpy ( hex , x + ++ i , 2 ); tmp [ j ++ ] = strtol ( hex , NULL , 16 ); static struct chat_connection * find_oscar_chat ( PurpleConnection * gc , int id ) OscarData * od = purple_connection_get_protocol_data ( gc ); struct chat_connection * cc ; for ( cur = od -> oscar_chats ; cur != NULL ; cur = cur -> next ) cc = ( struct chat_connection * ) cur -> data ; static struct chat_connection * find_oscar_chat_by_conn ( PurpleConnection * gc , FlapConnection * conn ) OscarData * od = purple_connection_get_protocol_data ( gc ); struct chat_connection * cc ; for ( cur = od -> oscar_chats ; cur != NULL ; cur = cur -> next ) cc = ( struct chat_connection * ) cur -> data ; static struct chat_connection * find_oscar_chat_by_conv ( PurpleConnection * gc , PurpleConversation * conv ) OscarData * od = purple_connection_get_protocol_data ( gc ); struct chat_connection * cc ; for ( cur = od -> oscar_chats ; cur != NULL ; cur = cur -> next ) cc = ( struct chat_connection * ) cur -> data ; oscar_chat_destroy ( struct chat_connection * cc ) oscar_chat_kill ( PurpleConnection * gc , struct chat_connection * cc ) OscarData * od = purple_connection_get_protocol_data ( gc ); /* Notify the conversation window that we've left the chat */ serv_got_chat_left ( gc , purple_conv_chat_get_id ( PURPLE_CONV_CHAT ( cc -> conv ))); /* Destroy the chat_connection */ od -> oscar_chats = g_slist_remove ( od -> oscar_chats , cc ); * This is called from the callback functions for establishing * a TCP connection with an oscar host if an error occurred. connection_common_error_cb ( FlapConnection * conn , const gchar * error_message ) purple_debug_error ( "oscar" , "unable to connect to FLAP " "server of type 0x%04hx \n " , conn -> type ); if ( conn -> type == SNAC_FAMILY_AUTH ) /* This only happens when connecting with the old-style BUCP login */ msg = g_strdup_printf ( _ ( "Unable to connect to authentication server: %s" ), purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , msg ); else if ( conn -> type == SNAC_FAMILY_LOCATE ) msg = g_strdup_printf ( _ ( "Unable to connect to BOS server: %s" ), purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , msg ); /* Maybe we should call this for BOS connections, too? */ flap_connection_schedule_destroy ( conn , OSCAR_DISCONNECT_COULD_NOT_CONNECT , error_message ); * This is called from the callback functions for establishing * a TCP connection with an oscar host. Depending on the type * of host, we do a few different things here. connection_common_established_cb ( FlapConnection * conn ) account = purple_connection_get_account ( gc ); purple_debug_info ( "oscar" , "connected to FLAP server of type 0x%04hx \n " , if ( conn -> cookie == NULL ) flap_connection_send_version ( od , conn ); if ( purple_account_get_bool ( account , "use_clientlogin" , OSCAR_DEFAULT_USE_CLIENTLOGIN )) ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM ; ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ ; flap_connection_send_version_with_cookie_and_clientinfo ( od , conn , conn -> cookielen , conn -> cookie , od -> icq ? & icqinfo : & aiminfo , purple_account_get_bool ( account , "allow_multiple_logins" , OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS )); flap_connection_send_version_with_cookie ( od , conn , conn -> cookielen , conn -> cookie ); if ( conn -> type == SNAC_FAMILY_AUTH ) /* This only happens when connecting with the old-style BUCP login */ aim_request_login ( od , conn , purple_account_get_username ( account )); purple_debug_info ( "oscar" , "Username sent, waiting for response \n " ); purple_connection_update_progress ( gc , _ ( "Username sent" ), 1 , OSCAR_CONNECT_STEPS ); else if ( conn -> type == SNAC_FAMILY_LOCATE ) purple_connection_update_progress ( gc , _ ( "Connection established, cookie sent" ), 4 , OSCAR_CONNECT_STEPS ); else if ( conn -> type == SNAC_FAMILY_CHAT ) od -> oscar_chats = g_slist_prepend ( od -> oscar_chats , conn -> new_conn_data ); conn -> new_conn_data = NULL ; connection_established_cb ( gpointer data , gint source , const gchar * error_message ) conn -> connect_data = NULL ; connection_common_error_cb ( conn , error_message ); conn -> watcher_incoming = purple_input_add ( conn -> fd , PURPLE_INPUT_READ , flap_connection_recv_cb , conn ); connection_common_established_cb ( conn ); ssl_connection_established_cb ( gpointer data , PurpleSslConnection * gsc , PurpleInputCondition cond ) purple_ssl_input_add ( gsc , flap_connection_recv_cb_ssl , conn ); connection_common_established_cb ( conn ); ssl_connection_error_cb ( PurpleSslConnection * gsc , PurpleSslErrorType error , if ( conn -> watcher_outgoing ) purple_input_remove ( conn -> watcher_outgoing ); conn -> watcher_outgoing = 0 ; /* sslconn frees the connection on error */ connection_common_error_cb ( conn , purple_ssl_strerror ( error )); flap_connection_established_bos ( OscarData * od , FlapConnection * conn ) PurpleConnection * gc = od -> gc ; aim_srv_reqpersonalinfo ( od , conn ); purple_debug_info ( "oscar" , "ssi: requesting rights and list \n " ); if ( od -> getblisttimer > 0 ) purple_timeout_remove ( od -> getblisttimer ); od -> getblisttimer = purple_timeout_add_seconds ( 30 , purple_ssi_rerequestdata , od ); aim_locate_reqrights ( od ); aim_buddylist_reqrights ( od , conn ); aim_bos_reqrights ( od , conn ); /* TODO: Don't call this with ssi */ purple_connection_update_progress ( gc , _ ( "Finalizing connection" ), 5 , OSCAR_CONNECT_STEPS ); flap_connection_established_admin ( OscarData * od , FlapConnection * conn ) aim_srv_clientready ( od , conn ); purple_debug_info ( "oscar" , "connected to admin \n " ); purple_debug_info ( "oscar" , "changing password \n " ); aim_admin_changepasswd ( od , conn , od -> newp , od -> oldp ); purple_debug_info ( "oscar" , "formatting username \n " ); aim_admin_setnick ( od , conn , od -> newformatting ); g_free ( od -> newformatting ); od -> newformatting = NULL ; purple_debug_info ( "oscar" , "confirming account \n " ); aim_admin_reqconfirm ( od , conn ); purple_debug_info ( "oscar" , "requesting email address \n " ); aim_admin_getinfo ( od , conn , 0x0011 ); purple_debug_info ( "oscar" , "setting email address \n " ); aim_admin_setemail ( od , conn , od -> email ); flap_connection_established_chat ( OscarData * od , FlapConnection * conn ) PurpleConnection * gc = od -> gc ; struct chat_connection * chatcon ; aim_srv_clientready ( od , conn ); chatcon = find_oscar_chat_by_conn ( gc , conn ); chatcon -> conv = serv_got_joined_chat ( gc , id ++ , chatcon -> show ); flap_connection_established_chatnav ( OscarData * od , FlapConnection * conn ) aim_srv_clientready ( od , conn ); aim_chatnav_reqrights ( od , conn ); flap_connection_established_alert ( OscarData * od , FlapConnection * conn ) aim_email_sendcookies ( od ); aim_srv_clientready ( od , conn ); flap_connection_established_bart ( OscarData * od , FlapConnection * conn ) PurpleConnection * gc = od -> gc ; aim_srv_clientready ( od , conn ); od -> iconconnecting = FALSE ; flap_connection_established ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) purple_debug_info ( "oscar" , "FLAP connection of type 0x%04hx is " "now fully connected \n " , conn -> type ); if ( conn -> type == SNAC_FAMILY_LOCATE ) flap_connection_established_bos ( od , conn ); else if ( conn -> type == SNAC_FAMILY_ADMIN ) flap_connection_established_admin ( od , conn ); else if ( conn -> type == SNAC_FAMILY_CHAT ) flap_connection_established_chat ( od , conn ); else if ( conn -> type == SNAC_FAMILY_CHATNAV ) flap_connection_established_chatnav ( od , conn ); else if ( conn -> type == SNAC_FAMILY_ALERT ) flap_connection_established_alert ( od , conn ); else if ( conn -> type == SNAC_FAMILY_BART ) flap_connection_established_bart ( od , conn ); idle_reporting_pref_cb ( const char * name , PurplePrefType type , gconstpointer value , gpointer data ) od = purple_connection_get_protocol_data ( gc ); report_idle = strcmp (( const char * ) value , "none" ) != 0 ; presence = aim_ssi_getpresence ( od -> ssi . local ); aim_ssi_setpresence ( od , presence | AIM_SSI_PRESENCE_FLAG_SHOWIDLE ); aim_ssi_setpresence ( od , presence & ~ AIM_SSI_PRESENCE_FLAG_SHOWIDLE ); * Should probably make a "Use recent buddies group" account preference * so that this option is surfaced to the user. recent_buddies_pref_cb ( const char * name , PurplePrefType type , gconstpointer value , gpointer data ) od = purple_connection_get_protocol_data ( gc ); presence = aim_ssi_getpresence ( od -> ssi . local ); aim_ssi_setpresence ( od , presence & ~ AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES ); aim_ssi_setpresence ( od , presence | AIM_SSI_PRESENCE_FLAG_NORECENTBUDDIES ); static const gchar * login_servers [] = { AIM_DEFAULT_LOGIN_SERVER , AIM_DEFAULT_SSL_LOGIN_SERVER , ICQ_DEFAULT_LOGIN_SERVER , ICQ_DEFAULT_SSL_LOGIN_SERVER , get_login_server ( gboolean is_icq , gboolean use_ssl ) return login_servers [( is_icq ? 2 : 0 ) + ( use_ssl ? 1 : 0 )]; compare_handlers ( gconstpointer a , gconstpointer b ) guint aa = GPOINTER_TO_UINT ( a ); guint bb = GPOINTER_TO_UINT ( b ); guint family1 = aa >> 16 ; guint family2 = bb >> 16 ; guint subtype1 = aa & 0xFFFF ; guint subtype2 = bb & 0xFFFF ; if ( family1 != family2 ) { return family1 - family2 ; return subtype1 - subtype2 ; #if !GLIB_CHECK_VERSION(2,14,0) static void hash_table_get_list_of_keys ( gpointer key , gpointer value , gpointer user_data ) GList ** handlers = ( GList ** ) user_data ; * handlers = g_list_prepend ( * handlers , key ); #endif /* GLIB < 2.14.0 */ oscar_login ( PurpleAccount * account ) const gchar * encryption_type ; GString * msg = g_string_new ( "" ); gc = purple_account_get_connection ( account ); purple_connection_set_protocol_data ( gc , od ); oscar_data_addhandler ( od , AIM_CB_FAM_SPECIAL , AIM_CB_SPECIAL_CONNERR , purple_connerr , 0 ); oscar_data_addhandler ( od , AIM_CB_FAM_SPECIAL , AIM_CB_SPECIAL_CONNINITDONE , flap_connection_established , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ADMIN , 0x0003 , purple_info_change , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ADMIN , 0x0005 , purple_info_change , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ADMIN , 0x0007 , purple_account_confirm , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ALERT , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ALERT , SNAC_SUBTYPE_ALERT_MAILSTATUS , purple_email_parseupdate , 0 ); /* These are only needed when connecting with the old-style BUCP login */ oscar_data_addhandler ( od , SNAC_FAMILY_AUTH , 0x0003 , purple_parse_auth_resp , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_AUTH , 0x0007 , purple_parse_login , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_AUTH , SNAC_SUBTYPE_AUTH_SECURID_REQUEST , purple_parse_auth_securid_request , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BART , SNAC_SUBTYPE_BART_RESPONSE , purple_icon_parseicon , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BOS , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BOS , 0x0003 , purple_bosrights , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BUDDY , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BUDDY , SNAC_SUBTYPE_BUDDY_RIGHTSINFO , purple_parse_buddyrights , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BUDDY , SNAC_SUBTYPE_BUDDY_ONCOMING , purple_parse_oncoming , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_BUDDY , SNAC_SUBTYPE_BUDDY_OFFGOING , purple_parse_offgoing , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHAT , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHAT , SNAC_SUBTYPE_CHAT_USERJOIN , purple_conv_chat_join , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHAT , SNAC_SUBTYPE_CHAT_USERLEAVE , purple_conv_chat_leave , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHAT , SNAC_SUBTYPE_CHAT_ROOMINFOUPDATE , purple_conv_chat_info_update , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHAT , SNAC_SUBTYPE_CHAT_INCOMINGMSG , purple_conv_chat_incoming_msg , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHATNAV , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_CHATNAV , SNAC_SUBTYPE_CHATNAV_INFO , purple_chatnav_info , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_ERROR , purple_ssi_parseerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_RIGHTSINFO , purple_ssi_parserights , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_LIST , purple_ssi_parselist , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_SRVACK , purple_ssi_parseack , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_ADD , purple_ssi_parseaddmod , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_MOD , purple_ssi_parseaddmod , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_RECVAUTH , purple_ssi_authgiven , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_RECVAUTHREQ , purple_ssi_authrequest , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_RECVAUTHREP , purple_ssi_authreply , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_FEEDBAG , SNAC_SUBTYPE_FEEDBAG_ADDED , purple_ssi_gotadded , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ICBM , SNAC_SUBTYPE_ICBM_INCOMING , purple_parse_incoming_im , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ICBM , SNAC_SUBTYPE_ICBM_MISSEDCALL , purple_parse_misses , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ICBM , SNAC_SUBTYPE_ICBM_CLIENTAUTORESP , purple_parse_clientauto , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_ICBM , SNAC_SUBTYPE_ICBM_MTN , purple_parse_mtn , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_LOCATE , SNAC_SUBTYPE_LOCATE_RIGHTSINFO , purple_parse_locaterights , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_OSERVICE , 0x0001 , purple_parse_genericerr , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_OSERVICE , 0x000f , purple_selfinfo , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_OSERVICE , 0x001f , purple_memrequest , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_OSERVICE , SNAC_SUBTYPE_OSERVICE_REDIRECT , purple_handle_redirect , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_OSERVICE , SNAC_SUBTYPE_OSERVICE_MOTD , purple_parse_motd , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_POPUP , 0x0002 , purple_popup , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_USERLOOKUP , SNAC_SUBTYPE_USERLOOKUP_ERROR , purple_parse_searcherror , 0 ); oscar_data_addhandler ( od , SNAC_FAMILY_USERLOOKUP , 0x0003 , purple_parse_searchreply , 0 ); g_string_append ( msg , "Registered handlers: " ); #if GLIB_CHECK_VERSION(2,14,0) handlers = g_hash_table_get_keys ( od -> handlerlist ); g_hash_table_foreach ( od -> handlerlist , hash_table_get_list_of_keys , & handlers ); #endif /* GLIB < 2.14.0 */ sorted_handlers = g_list_sort ( g_list_copy ( handlers ), compare_handlers ); for ( cur = sorted_handlers ; cur ; cur = cur -> next ) { guint x = GPOINTER_TO_UINT ( cur -> data ); g_string_append_printf ( msg , "%04x/%04x, " , x >> 16 , x & 0xFFFF ); g_list_free ( sorted_handlers ); purple_debug_misc ( "oscar" , "%s \n " , msg -> str ); g_string_free ( msg , TRUE ); purple_debug_misc ( "oscar" , "oscar_login: gc = %p \n " , gc ); if ( ! oscar_util_valid_name ( purple_account_get_username ( account ))) { buf = g_strdup_printf ( _ ( "Unable to sign on as %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers." ), purple_account_get_username ( account )); purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_INVALID_SETTINGS , buf ); gc -> flags |= PURPLE_CONNECTION_HTML ; if ( g_str_equal ( purple_account_get_protocol_id ( account ), "prpl-icq" )) { gc -> flags |= PURPLE_CONNECTION_AUTO_RESP ; /* Set this flag based on the protocol_id rather than the username, because that is what's tied to the get_moods prpl callback. */ if ( g_str_equal ( purple_account_get_protocol_id ( account ), "prpl-icq" )) gc -> flags |= PURPLE_CONNECTION_SUPPORT_MOODS ; od -> default_port = purple_account_get_int ( account , "port" , OSCAR_DEFAULT_LOGIN_PORT ); encryption_type = purple_account_get_string ( account , "encryption" , OSCAR_DEFAULT_ENCRYPTION ); if ( ! purple_ssl_is_supported () && strcmp ( encryption_type , OSCAR_REQUIRE_ENCRYPTION ) == 0 ) { purple_connection_error_reason ( PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT , _ ( "You required encryption in your account settings, but encryption is not supported by your system." )); od -> use_ssl = purple_ssl_is_supported () && strcmp ( encryption_type , OSCAR_NO_ENCRYPTION ) != 0 ; /* Connect to core Purple signals */ purple_prefs_connect_callback ( gc , "/purple/away/idle_reporting" , idle_reporting_pref_cb , gc ); purple_prefs_connect_callback ( gc , "/plugins/prpl/oscar/recent_buddies" , recent_buddies_pref_cb , gc ); * On 2008-03-05 AOL released some documentation on the OSCAR protocol * which includes a new login method called clientLogin. It is similar * (though not the same?) as what the AIM 6.0 series uses to * AIM 5.9 and lower use an MD5-based login procedure called "BUCP". * This authentication method is used for both ICQ and AIM when * clientLogin is not enabled. if ( purple_account_get_bool ( account , "use_clientlogin" , OSCAR_DEFAULT_USE_CLIENTLOGIN )) { send_client_login ( od , purple_account_get_username ( account )); newconn = flap_connection_new ( od , SNAC_FAMILY_AUTH ); server = purple_account_get_string ( account , "server" , get_login_server ( od -> icq , TRUE )); * If the account's server is what the oscar prpl has offered as * the default login server through the vast eons (all two of * said default options, AFAIK) and the user wants SSL, we'll * do what we know is best for them and change the setting out * from under them to the SSL login server. if ( ! strcmp ( server , get_login_server ( od -> icq , FALSE )) || ! strcmp ( server , AIM_ALT_LOGIN_SERVER )) { purple_debug_info ( "oscar" , "Account uses SSL, so changing server to default SSL server \n " ); purple_account_set_string ( account , "server" , get_login_server ( od -> icq , TRUE )); server = get_login_server ( od -> icq , TRUE ); newconn -> gsc = purple_ssl_connect ( account , server , purple_account_get_int ( account , "port" , OSCAR_DEFAULT_LOGIN_PORT ), ssl_connection_established_cb , ssl_connection_error_cb , newconn ); server = purple_account_get_string ( account , "server" , get_login_server ( od -> icq , FALSE )); * See the comment above. We do the reverse here. If they don't want * SSL but their server is set to OSCAR_DEFAULT_SSL_LOGIN_SERVER, * set it back to the default. if ( ! strcmp ( server , get_login_server ( od -> icq , TRUE ))) { purple_debug_info ( "oscar" , "Account does not use SSL, so changing server back to non-SSL \n " ); purple_account_set_string ( account , "server" , get_login_server ( od -> icq , FALSE )); server = get_login_server ( od -> icq , FALSE ); newconn -> connect_data = purple_proxy_connect ( NULL , account , server , purple_account_get_int ( account , "port" , OSCAR_DEFAULT_LOGIN_PORT ), connection_established_cb , newconn ); if ( newconn -> gsc == NULL && newconn -> connect_data == NULL ) { purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , purple_connection_update_progress ( gc , _ ( "Connecting" ), 0 , OSCAR_CONNECT_STEPS ); oscar_close ( PurpleConnection * gc ) od = purple_connection_get_protocol_data ( gc ); struct chat_connection * cc = od -> oscar_chats -> data ; od -> oscar_chats = g_slist_remove ( od -> oscar_chats , cc ); struct create_room * cr = od -> create_rooms -> data ; od -> create_rooms = g_slist_remove ( od -> create_rooms , cr ); purple_connection_set_protocol_data ( gc , NULL ); purple_prefs_disconnect_by_handle ( gc ); purple_debug_info ( "oscar" , "Signed off. \n " ); /* XXX - Should use purple_util_fetch_url for the below stuff */ static void damn_you ( gpointer data , gint source , PurpleInputCondition c ) struct pieceofcrap * pos = data ; OscarData * od = purple_connection_get_protocol_data ( pos -> gc ); while ( read ( pos -> fd , & in , 1 ) == 1 ) { g_snprintf ( buf , sizeof ( buf ), _ ( "You may be disconnected shortly. " "If so, check %s for updates." ), oscar_get_ui_info_string ( "website" , PURPLE_WEBSITE )); purple_notify_warning ( pos -> gc , NULL , _ ( "Unable to get a valid AIM login hash." ), purple_input_remove ( pos -> inpa ); if ( read ( pos -> fd , m , 16 ) != 16 ) purple_debug_warning ( "oscar" , "Could not read full AIM login hash " "from " AIMHASHDATA "--that's bad. \n " ); msg = g_string_new ( "Sending hash: " ); g_string_append_printf ( msg , "%02hhx " , ( unsigned char ) m [ x ]); g_string_append ( msg , " \n " ); purple_debug_misc ( "oscar" , "%s" , msg -> str ); g_string_free ( msg , TRUE ); purple_input_remove ( pos -> inpa ); aim_sendmemblock ( od , pos -> conn , 0 , 16 , m , AIM_SENDMEMBLOCK_FLAG_ISHASH ); straight_to_hell ( gpointer data , gint source , const gchar * error_message ) struct pieceofcrap * pos = data ; buf = g_strdup_printf ( _ ( "You may be disconnected shortly. " "If so, check %s for updates." ), oscar_get_ui_info_string ( "website" , PURPLE_WEBSITE )); purple_notify_warning ( pos -> gc , NULL , _ ( "Unable to get a valid AIM login hash." ), buf = g_strdup_printf ( "GET " AIMHASHDATA "?offset=%ld&len=%ld&modname=%s HTTP/1.0 \n\n " , pos -> offset , pos -> len , pos -> modname ? pos -> modname : "" ); result = send ( pos -> fd , buf , strlen ( buf ), 0 ); if ( result != strlen ( buf )) { purple_debug_error ( "oscar" , "Error writing %" G_GSIZE_FORMAT " bytes to fetch AIM hash data: %s \n " , strlen ( buf ), g_strerror ( errno )); purple_debug_error ( "oscar" , "Tried to write %" G_GSIZE_FORMAT " bytes to fetch AIM hash data but " "instead wrote %" G_GSSIZE_FORMAT " bytes \n " , pos -> inpa = purple_input_add ( pos -> fd , PURPLE_INPUT_READ , damn_you , pos ); /* size of icbmui.ocm, the largest module in AIM 3.5 */ #define AIM_MAX_FILE_SIZE 98304 static int purple_memrequest ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) offset = va_arg ( ap , guint32 ); len = va_arg ( ap , guint32 ); modname = va_arg ( ap , char * ); purple_debug_misc ( "oscar" , "offset: %u, len: %u, file: %s \n " , offset , len , ( modname ? modname : "aim.exe" )); purple_debug_misc ( "oscar" , "len is 0, hashing NULL \n " ); aim_sendmemblock ( od , conn , offset , len , NULL , AIM_SENDMEMBLOCK_FLAG_ISREQUEST ); pos = g_new0 ( struct pieceofcrap , 1 ); pos -> modname = g_strdup ( modname ); if ( purple_proxy_connect ( pos -> gc , pos -> gc -> account , "pidgin.im" , 80 , straight_to_hell , pos ) == NULL ) g_snprintf ( buf , sizeof ( buf ), _ ( "You may be disconnected shortly. " "If so, check %s for updates." ), oscar_get_ui_info_string ( "website" , PURPLE_WEBSITE )); purple_notify_warning ( pos -> gc , NULL , _ ( "Unable to get a valid login hash." ), int oscar_connect_to_bos ( PurpleConnection * gc , OscarData * od , const char * host , guint16 port , guint8 * cookie , guint16 cookielen , const char * tls_certname ) account = purple_connection_get_account ( gc ); conn = flap_connection_new ( od , SNAC_FAMILY_LOCATE ); conn -> cookielen = cookielen ; conn -> cookie = g_memdup ( cookie , cookielen ); * Use TLS only if the server provided us with a tls_certname. The server might not specify a tls_certname even if we requested to use TLS, * and that is something we should be prepared to. conn -> gsc = purple_ssl_connect_with_ssl_cn ( account , host , port , ssl_connection_established_cb , ssl_connection_error_cb , conn -> connect_data = purple_proxy_connect ( NULL , connection_established_cb , conn ); if ( conn -> gsc == NULL && conn -> connect_data == NULL ) purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , _ ( "Unable to connect" )); purple_connection_update_progress ( gc , _ ( "Received authorization" ), 3 , OSCAR_CONNECT_STEPS ); * Only used when connecting with the old-style BUCP login. purple_parse_auth_resp ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); struct aim_authresp_info * info ; port = purple_account_get_int ( account , "port" , od -> default_port ); info = va_arg ( ap , struct aim_authresp_info * ); purple_debug_info ( "oscar" , "inside auth_resp (Username: %s) \n " , info -> bn ); if ( info -> errorcode || ! info -> bosip || ! info -> cookielen || ! info -> cookie ) { switch ( info -> errorcode ) { /* Unregistered username */ purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_INVALID_USERNAME , _ ( "Username does not exist" )); if ( ! purple_account_get_remember_password ( account )) purple_account_set_password ( account , NULL ); purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED , _ ( "Incorrect password" )); purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED , _ ( "Your account is currently suspended" )); /* service temporarily unavailable */ purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , _ ( "The AOL Instant Messenger service is temporarily unavailable." )); /* username connecting too frequently */ purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_OTHER_ERROR , _ ( "Your username has been connecting and disconnecting too frequently. Wait ten minutes and try again. If you continue to try, you will need to wait even longer." )); g_snprintf ( buf , sizeof ( buf ), _ ( "The client version you are using is too old. Please upgrade at %s" ), oscar_get_ui_info_string ( "website" , PURPLE_WEBSITE )); purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_OTHER_ERROR , buf ); /* IP address connecting too frequently */ purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_OTHER_ERROR , _ ( "Your IP address has been connecting and disconnecting too frequently. Wait a minute and try again. If you continue to try, you will need to wait even longer." )); purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED , _ ( "Unknown reason" )); purple_debug_info ( "oscar" , "Login Error Code 0x%04hx \n " , info -> errorcode ); purple_debug_info ( "oscar" , "Error URL: %s \n " , info -> errorurl ? info -> errorurl : "" ); purple_debug_misc ( "oscar" , "Reg status: %hu \n " info -> email ? info -> email : "null" , info -> bosip ? info -> bosip : "null" ); purple_debug_info ( "oscar" , "Closing auth connection... \n " ); flap_connection_schedule_destroy ( conn , OSCAR_DISCONNECT_DONE , NULL ); for ( i = 0 ; i < strlen ( info -> bosip ); i ++ ) { if ( info -> bosip [ i ] == ':' ) { port = atoi ( & ( info -> bosip [ i + 1 ])); host = g_strndup ( info -> bosip , i ); newconn = flap_connection_new ( od , SNAC_FAMILY_LOCATE ); newconn -> cookielen = info -> cookielen ; newconn -> cookie = g_memdup ( info -> cookie , info -> cookielen ); * This shouldn't be hardcoded to "bos.oscar.aol.com" except that * the server isn't sending us a name to use for comparing the * certificate common name. newconn -> gsc = purple_ssl_connect_with_ssl_cn ( account , host , port , ssl_connection_established_cb , ssl_connection_error_cb , "bos.oscar.aol.com" , newconn ); newconn -> connect_data = purple_proxy_connect ( NULL , account , host , port , connection_established_cb , newconn ); if ( newconn -> gsc == NULL && newconn -> connect_data == NULL ) purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_NETWORK_ERROR , _ ( "Unable to connect" )); purple_connection_update_progress ( gc , _ ( "Received authorization" ), 3 , OSCAR_CONNECT_STEPS ); * Only used when connecting with the old-style BUCP login. purple_parse_auth_securid_request_yes_cb ( gpointer user_data , const char * msg ) PurpleConnection * gc = user_data ; OscarData * od = purple_connection_get_protocol_data ( gc ); aim_auth_securid_send ( od , msg ); * Only used when connecting with the old-style BUCP login. purple_parse_auth_securid_request_no_cb ( gpointer user_data , const char * value ) PurpleConnection * gc = user_data ; purple_connection_error_reason ( gc , PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED , _ ( "The SecurID key entered is invalid" )); * Only used when connecting with the old-style BUCP login. purple_parse_auth_securid_request ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); purple_debug_info ( "oscar" , "Got SecurID request \n " ); primary = g_strdup_printf ( "Enter the SecurID key for %s." , purple_account_get_username ( account )); purple_request_input ( gc , NULL , _ ( "Enter SecurID" ), primary , _ ( "Enter the 6 digit number from the digital display." ), _ ( "_OK" ), G_CALLBACK ( purple_parse_auth_securid_request_yes_cb ), _ ( "_Cancel" ), G_CALLBACK ( purple_parse_auth_securid_request_no_cb ), * Only used when connecting with the old-style BUCP login. purple_parse_login ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) ClientInfo aiminfo = CLIENTINFO_PURPLE_AIM ; ClientInfo icqinfo = CLIENTINFO_PURPLE_ICQ ; account = purple_connection_get_account ( gc ); key = va_arg ( ap , char * ); truncate_pass = va_arg ( ap , int ); aim_send_login ( od , conn , purple_account_get_username ( account ), purple_connection_get_password ( gc ), truncate_pass , od -> icq ? & icqinfo : & aiminfo , key , purple_account_get_bool ( account , "allow_multiple_logins" , OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS )); purple_connection_update_progress ( gc , _ ( "Password sent" ), 2 , OSCAR_CONNECT_STEPS ); purple_handle_redirect ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); struct aim_redirect_data * redir ; redir = va_arg ( ap , struct aim_redirect_data * ); separator = strchr ( redir -> ip , ':' ); host = g_strndup ( redir -> ip , separator - redir -> ip ); port = atoi ( separator + 1 ); host = g_strdup ( redir -> ip ); const gchar * encryption_type = purple_account_get_string ( account , "encryption" , OSCAR_DEFAULT_ENCRYPTION ); if ( strcmp ( encryption_type , OSCAR_OPPORTUNISTIC_ENCRYPTION ) == 0 ) { purple_debug_warning ( "oscar" , "We won't use SSL for FLAP type 0x%04hx. \n " , redir -> group ); } else if ( strcmp ( encryption_type , OSCAR_REQUIRE_ENCRYPTION ) == 0 ) { purple_debug_error ( "oscar" , "FLAP server %s:%d of type 0x%04hx doesn't support encryption." , host , port , redir -> group ); purple_connection_error_reason ( PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT , _ ( "You required encryption in your account settings, but one of the servers doesn't support it." )); * These FLAP servers advertise SSL (type "0x02"), but SSL connections to these hosts * die a painful death. iChat and Miranda, when using SSL, still do these in plaintext. if ( redir -> use_ssl && ( redir -> group == SNAC_FAMILY_ADMIN || redir -> group == SNAC_FAMILY_BART )) purple_debug_info ( "oscar" , "Ignoring broken SSL for FLAP type 0x%04hx. \n " , redir -> group ); purple_debug_info ( "oscar" , "Connecting to FLAP server %s:%d of type 0x%04hx \n " , host , port , redir -> group ); newconn = flap_connection_new ( od , redir -> group ); newconn -> cookielen = redir -> cookielen ; newconn -> cookie = g_memdup ( redir -> cookie , redir -> cookielen ); if ( newconn -> type == SNAC_FAMILY_CHAT ) struct chat_connection * cc ; cc = g_new0 ( struct chat_connection , 1 ); cc -> name = g_strdup ( redir -> chat . room ); cc -> exchange = redir -> chat . exchange ; cc -> instance = redir -> chat . instance ; cc -> show = extract_name ( redir -> chat . room ); newconn -> new_conn_data = cc ; purple_debug_info ( "oscar" , "Connecting to chat room %s exchange %hu \n " , cc -> name , cc -> exchange ); newconn -> gsc = purple_ssl_connect_with_ssl_cn ( account , host , port , ssl_connection_established_cb , ssl_connection_error_cb , redir -> ssl_cert_cn , newconn ); newconn -> connect_data = purple_proxy_connect ( NULL , account , host , port , connection_established_cb , newconn ); if ( newconn -> gsc == NULL && newconn -> connect_data == NULL ) flap_connection_schedule_destroy ( newconn , OSCAR_DISCONNECT_COULD_NOT_CONNECT , _ ( "Unable to initialize connection" )); purple_debug_error ( "oscar" , "Unable to connect to FLAP server " "of type 0x%04hx \n " , redir -> group ); static int purple_parse_oncoming ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleBuddy * buddy = NULL ; PurpleStatus * previous_status = NULL ; time_t time_idle = 0 , signon = 0 ; gboolean buddy_is_away = FALSE ; account = purple_connection_get_account ( gc ); info = va_arg ( ap , aim_userinfo_t * ); g_return_val_if_fail ( info != NULL , 1 ); g_return_val_if_fail ( info -> bn != NULL , 1 ); buddy = purple_find_buddy ( account , info -> bn ); previous_status = purple_presence_get_active_status ( purple_buddy_get_presence ( buddy )); * If this is an AIM buddy and their name has formatting, set their if ( ! oscar_util_valid_name_icq ( info -> bn )) { gboolean bn_has_formatting = FALSE ; for ( c = info -> bn ; * c != '\0' ; c ++ ) { bn_has_formatting = TRUE ; serv_got_alias ( gc , info -> bn , bn_has_formatting ? info -> bn : NULL ); if ( info -> present & AIM_USERINFO_PRESENT_FLAGS ) { if ( info -> flags & AIM_FLAG_AWAY ) if ( info -> present & AIM_USERINFO_PRESENT_ICQEXTSTATUS ) { type = info -> icqinfo . status ; if ( ! ( info -> icqinfo . status & AIM_ICQ_STATE_CHAT ) && ( info -> icqinfo . status != AIM_ICQ_STATE_NORMAL )) { if ( oscar_util_valid_name_icq ( info -> bn )) { if ( type & AIM_ICQ_STATE_CHAT ) status_id = OSCAR_STATUS_ID_FREE4CHAT ; else if ( type & AIM_ICQ_STATE_DND ) status_id = OSCAR_STATUS_ID_DND ; else if ( type & AIM_ICQ_STATE_OUT ) status_id = OSCAR_STATUS_ID_NA ; else if ( type & AIM_ICQ_STATE_BUSY ) status_id = OSCAR_STATUS_ID_OCCUPIED ; else if ( type & AIM_ICQ_STATE_AWAY ) status_id = OSCAR_STATUS_ID_AWAY ; else if ( type & AIM_ICQ_STATE_INVISIBLE ) status_id = OSCAR_STATUS_ID_INVISIBLE ; else if ( type & AIM_ICQ_STATE_EVIL ) status_id = OSCAR_STATUS_ID_EVIL ; else if ( type & AIM_ICQ_STATE_DEPRESSION ) status_id = OSCAR_STATUS_ID_DEPRESSION ; else if ( type & AIM_ICQ_STATE_ATHOME ) status_id = OSCAR_STATUS_ID_ATHOME ; else if ( type & AIM_ICQ_STATE_ATWORK ) status_id = OSCAR_STATUS_ID_ATWORK ; else if ( type & AIM_ICQ_STATE_LUNCH ) status_id = OSCAR_STATUS_ID_LUNCH ; status_id = OSCAR_STATUS_ID_AVAILABLE ; if ( type & AIM_ICQ_STATE_INVISIBLE ) status_id = OSCAR_STATUS_ID_INVISIBLE ; status_id = OSCAR_STATUS_ID_AWAY ; status_id = OSCAR_STATUS_ID_AVAILABLE ; if ( info -> flags & AIM_FLAG_WIRELESS ) { purple_prpl_got_user_status ( account , info -> bn , OSCAR_STATUS_ID_MOBILE , NULL ); purple_prpl_got_user_status_deactive ( account , info -> bn , OSCAR_STATUS_ID_MOBILE ); message = ( info -> status && info -> status_len > 0 ) ? oscar_encoding_to_utf8 ( info -> status_encoding , info -> status , info -> status_len ) if ( strcmp ( status_id , OSCAR_STATUS_ID_AVAILABLE ) == 0 ) { /* TODO: If itmsurl is NULL, does that mean the URL has been cleared? Or does it mean the URL should remain unchanged? */ if ( info -> itmsurl != NULL ) { itmsurl = ( info -> itmsurl_len > 0 ) ? oscar_encoding_to_utf8 ( info -> itmsurl_encoding , info -> itmsurl , info -> itmsurl_len ) : NULL ; } else if ( previous_status != NULL && purple_status_is_available ( previous_status )) { itmsurl = g_strdup ( purple_status_get_attr_string ( previous_status , "itmsurl" )); purple_debug_info ( "oscar" , "Activating status '%s' for buddy %s, message = '%s', itmsurl = '%s' \n " , status_id , info -> bn , message ? message : "(null)" , itmsurl ? itmsurl : "(null)" ); purple_prpl_got_user_status ( account , info -> bn , status_id , "message" , message , "itmsurl" , itmsurl , NULL ); purple_debug_info ( "oscar" , "Activating status '%s' for buddy %s, message = '%s' \n " , status_id , info -> bn , message ? message : "(null)" ); purple_prpl_got_user_status ( account , info -> bn , status_id , "message" , message , NULL ); if ( info -> present & AIM_USERINFO_PRESENT_ONLINESINCE ) signon = info -> onlinesince ; else if ( info -> present & AIM_USERINFO_PRESENT_SESSIONLEN ) signon = time ( NULL ) - info -> sessionlen ; purple_prpl_got_user_login_time ( account , info -> bn , signon ); /* info->idletime is the number of minutes that this user has been idle */ if ( info -> present & AIM_USERINFO_PRESENT_IDLE ) time_idle = time ( NULL ) - info -> idletime * 60 ; purple_prpl_got_user_idle ( account , info -> bn , TRUE , time_idle ); purple_prpl_got_user_idle ( account , info -> bn , FALSE , 0 ); /* Server stored icon stuff */ bi = g_hash_table_lookup ( od -> buddyinfo , purple_normalize ( account , info -> bn )); bi = g_new0 ( struct buddyinfo , 1 ); g_hash_table_insert ( od -> buddyinfo , g_strdup ( purple_normalize ( account , info -> bn )), bi ); bi -> ico_informed = FALSE ; bi -> ipaddr = info -> icqinfo . ipaddr ; const char * saved_b16 = NULL ; b16 = purple_base16_encode ( info -> iconcsum , info -> iconcsumlen ); b = purple_find_buddy ( account , info -> bn ); saved_b16 = purple_buddy_icons_get_checksum_for_user ( b ); if ( ! b16 || ! saved_b16 || strcmp ( b16 , saved_b16 )) { /* Invalidate the old icon for this user */ purple_buddy_icons_set_for_user ( account , info -> bn , NULL , 0 , NULL ); /* Fetch the new icon (if we're not already doing so) */ if ( g_slist_find_custom ( od -> requesticon , info -> bn , ( GCompareFunc ) oscar_util_name_compare ) == NULL ) od -> requesticon = g_slist_prepend ( od -> requesticon , g_strdup ( purple_normalize ( account , info -> bn ))); static int purple_parse_offgoing ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); info = va_arg ( ap , aim_userinfo_t * ); purple_prpl_got_user_status ( account , info -> bn , OSCAR_STATUS_ID_OFFLINE , NULL ); purple_prpl_got_user_status_deactive ( account , info -> bn , OSCAR_STATUS_ID_MOBILE ); g_hash_table_remove ( od -> buddyinfo , purple_normalize ( gc -> account , info -> bn )); static int incomingim_chan1 ( OscarData * od , FlapConnection * conn , aim_userinfo_t * userinfo , struct aim_incomingim_ch1_args * args ) { PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); PurpleMessageFlags flags = 0 ; purple_debug_misc ( "oscar" , "Received IM from %s \n " , userinfo -> bn ); bi = g_hash_table_lookup ( od -> buddyinfo , purple_normalize ( account , userinfo -> bn )); bi = g_new0 ( struct buddyinfo , 1 ); g_hash_table_insert ( od -> buddyinfo , g_strdup ( purple_normalize ( account , userinfo -> bn )), bi ); if ( args -> icbmflags & AIM_IMFLAGS_AWAY ) flags |= PURPLE_MESSAGE_AUTO_RESP ; if ( args -> icbmflags & AIM_IMFLAGS_TYPINGNOT ) if (( args -> icbmflags & AIM_IMFLAGS_HASICON ) && ( args -> iconlen ) && ( args -> iconsum ) && ( args -> iconstamp )) { purple_debug_misc ( "oscar" , "%s has an icon \n " , userinfo -> bn ); if (( args -> iconlen != bi -> ico_len ) || ( args -> iconsum != bi -> ico_csum ) || ( args -> iconstamp != bi -> ico_time )) { bi -> ico_len = args -> iconlen ; bi -> ico_csum = args -> iconsum ; bi -> ico_time = args -> iconstamp ; img = purple_buddy_icons_find_account_icon ( account ); ( args -> icbmflags & AIM_IMFLAGS_BUDDYREQ ) && ! bi -> ico_sent && bi -> ico_informed ) { gconstpointer data = purple_imgstore_get_data ( img ); size_t len = purple_imgstore_get_size ( img ); purple_debug_info ( "oscar" , "Sending buddy icon to %s (%" G_GSIZE_FORMAT " bytes) \n " , aim_im_sendch2_icon ( od , userinfo -> bn , data , len , purple_buddy_icons_get_account_icon_timestamp ( account ), aimutil_iconsum ( data , len )); purple_imgstore_unref ( img ); tmp = g_strdup ( args -> msg ); * Convert iChat color tags to normal font tags. if ( purple_markup_find_tag ( "body" , tmp , & start , & end , & attribs )) const char * ichattextcolor , * ichatballooncolor ; const char * slash_body_start , * slash_body_end = NULL ; /* </body> */ * Find the ending </body> so we can strip off the outer <html/> if ( purple_markup_find_tag ( "/body" , end + 1 , & slash_body_start , & slash_body_end , & unused )) body = g_strndup ( start , slash_body_end - start + 1 ); g_datalist_clear ( & unused ); purple_debug_warning ( "oscar" , "Broken message contains <body> but not </body>! \n " ); /* Take everything after <body> */ ichattextcolor = g_datalist_get_data ( & attribs , "ichattextcolor" ); if ( ichattextcolor != NULL ) tmp2 = g_strdup_printf ( "<font color= \" %s \" >%s</font>" , ichattextcolor , body ); ichatballooncolor = g_datalist_get_data ( & attribs , "ichatballooncolor" ); if ( ichatballooncolor != NULL ) tmp2 = g_strdup_printf ( "<font back= \" %s \" >%s</font>" , ichatballooncolor , body ); g_datalist_clear ( & attribs ); tmp2 = g_strdup_printf ( "%.*s%s%s" , len , tmp , body , slash_body_end ? slash_body_end + 1 : "</body>" ); * Are there <html/> surrounding tags? If so, strip them out, too. if ( purple_markup_find_tag ( "html" , tmp , & start , & end , & attribs )) g_datalist_clear ( & attribs ); tmp2 = g_strdup_printf ( "%.*s%s" , len , tmp , end + 1 ); if ( purple_markup_find_tag ( "/html" , tmp , & start , & end , & attribs )) g_datalist_clear ( & attribs ); tmp2 = g_strdup_printf ( "%.*s%s" , len , tmp , end + 1 ); serv_got_im ( gc , userinfo -> bn , tmp , flags , ( args -> icbmflags & AIM_IMFLAGS_OFFLINE ) ? args -> timestamp : time ( NULL )); incomingim_chan2 ( OscarData * od , FlapConnection * conn , aim_userinfo_t * userinfo , IcbmArgsCh2 * args ) PurpleMessageFlags flags = 0 ; g_return_val_if_fail ( od != NULL , 0 ); g_return_val_if_fail ( od -> gc != NULL , 0 ); account = purple_connection_get_account ( gc ); od = purple_connection_get_protocol_data ( gc ); purple_debug_misc ( "oscar" , "Incoming rendezvous message of type %" G_GUINT64_FORMAT ", user %s, status %hu \n " , args -> type , userinfo -> bn , args -> status ); message = oscar_encoding_to_utf8 ( args -> encoding , args -> msg , args -> msglen ); if ( args -> type & OSCAR_CAPABILITY_CHAT ) if ( ! args -> info . chat . roominfo . name || ! args -> info . chat . roominfo . exchange ) { utf8name = oscar_encoding_to_utf8 ( args -> encoding , args -> info . chat . roominfo . name , args -> info . chat . roominfo . namelen ); tmp = extract_name ( utf8name ); components = g_hash_table_new_full ( g_str_hash , g_str_equal , g_free , g_hash_table_replace ( components , g_strdup ( "room" ), utf8name ); g_hash_table_replace ( components , g_strdup ( "exchange" ), g_strdup_printf ( "%d" , args -> info . chat . roominfo . exchange )); else if (( args -> type & OSCAR_CAPABILITY_SENDFILE ) || ( args -> type & OSCAR_CAPABILITY_DIRECTIM )) if ( args -> status == AIM_RENDEZVOUS_PROPOSE ) peer_connection_got_proposition ( od , userinfo -> bn , message , args ); else if ( args -> status == AIM_RENDEZVOUS_CANCEL ) /* The other user cancelled a peer request */ conn = peer_connection_find_by_cookie ( od , userinfo -> bn , args -> cookie ); * If conn is NULL it means we haven't tried to create * a connection with that user. They may be trying to * do something malicious. peer_connection_destroy ( conn , OSCAR_DISCONNECT_REMOTE_CLOSED , NULL ); else if ( args -> status == AIM_RENDEZVOUS_CONNECTED ) * Remote user has accepted our peer request. If we * wanted to we could look up the PeerConnection using * args->cookie, but we don't need to do anything here. else if ( args -> type & OSCAR_CAPABILITY_GETFILE ) else if ( args -> type & OSCAR_CAPABILITY_TALK ) else if ( args -> type & OSCAR_CAPABILITY_BUDDYICON ) purple_buddy_icons_set_for_user ( account , userinfo -> bn , g_memdup ( args -> info . icon . icon , args -> info . icon . length ), else if ( args -> type & OSCAR_CAPABILITY_ICQSERVERRELAY ) purple_debug_info ( "oscar" , "Got an ICQ Server Relay message of " "type %d \n " , args -> info . rtfmsg . msgtype ); if ( args -> info . rtfmsg . msgtype == 1 ) { if ( args -> info . rtfmsg . msg != NULL ) { const char * encoding = args -> encoding ; size_t len = strlen ( args -> info . rtfmsg . msg ); if ( encoding == NULL && ! g_utf8_validate ( args -> info . rtfmsg . msg , len , NULL )) { /* Yet another wonderful Miranda-related hack. If their user disables the "Send Unicode messages" setting, * Miranda sends us ch2 messages in whatever Windows codepage is set as default on their user's system (instead of UTF-8). * Of course, they don't bother to specify that codepage. Let's just fallback to the encoding OUR users can * specify in account options as a last resort. encoding = purple_account_get_string ( account , "encoding" , OSCAR_DEFAULT_CUSTOM_ENCODING ); purple_debug_info ( "oscar" , "Miranda, is that you? Using '%s' as encoding \n " , encoding ); rtfmsg = oscar_encoding_to_utf8 ( encoding , args -> info . rtfmsg . msg , len ); /* Channel 2 messages are supposed to be plain-text (never mind the name "rtfmsg", even * the official client doesn't parse them as RTF). Therefore, we should escape them before * showing to the user. */ tmp = g_markup_escape_text ( rtfmsg , -1 ); tmp2 = purple_strreplace ( tmp , " \r\n " , "<br>" ); serv_got_im ( gc , userinfo -> bn , tmp2 , flags , time ( NULL )); aim_im_send_icq_confirmation ( od , userinfo -> bn , args -> cookie ); } else if ( args -> info . rtfmsg . msgtype == 26 ) { purple_debug_info ( "oscar" , "Sending X-Status Reply \n " ); icq_relay_xstatus ( od , userinfo -> bn , args -> cookie ); purple_debug_error ( "oscar" , "Unknown request class %" G_GUINT64_FORMAT " \n " , args -> type ); /* When someone sends you buddies */ purple_icq_buddyadd ( struct name_data * data ) PurpleConnection * gc = data -> gc ; purple_blist_request_add_buddy ( purple_connection_get_account ( gc ), data -> name , NULL , data -> nick ); oscar_free_name_data ( data ); incomingim_chan4 ( OscarData * od , FlapConnection * conn , aim_userinfo_t * userinfo , struct aim_incomingim_ch4_args * args , time_t t ) PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); if ( ! args -> type || ! args -> msg || ! args -> uin ) purple_debug_info ( "oscar" , "Received a channel 4 message of type 0x%02hx. \n " , * Split up the message at the delimeter character, then convert each * string to UTF-8. Unless, of course, this is a type 1 message. If * this is a type 1 message, then the delimiter 0xfe could be a valid * character in whatever encoding the message was sent in. Type 1 * messages are always made up of only one part, so we can easily account * for this suck-ass part of the protocol by splitting the string into at msg1 = g_strsplit ( args -> msg , " \376 " , ( args -> type == 0x01 ? 1 : 0 )); for ( numtoks = 0 ; msg1 [ numtoks ]; numtoks ++ ); msg2 = ( gchar ** ) g_malloc (( numtoks + 1 ) * sizeof ( gchar * )); for ( i = 0 ; msg1 [ i ]; i ++ ) { gchar * uin = g_strdup_printf ( "%u" , args -> uin ); purple_str_strip_char ( msg1 [ i ], '\r' ); /* TODO: Should use an encoding other than ASCII? */ msg2 [ i ] = oscar_decode_im ( account , uin , AIM_CHARSET_ASCII , msg1 [ i ], strlen ( msg1 [ i ])); case 0x01 : { /* MacICQ message or basic offline message */ gchar * uin = g_strdup_printf ( "%u" , args -> uin ); /* If the message came from an ICQ user then escape any HTML */ tmp = g_markup_escape_text ( msg2 [ 0 ], -1 ); if ( t ) { /* This is an offline message */ /* The timestamp is UTC-ish, so we need to get the offset */ serv_got_im ( gc , uin , tmp , 0 , t ); } else { /* This is a message from MacICQ/Miranda */ serv_got_im ( gc , uin , tmp , 0 , time ( NULL )); case 0x04 : { /* Someone sent you a URL */ gchar * uin = g_strdup_printf ( "%u" , args -> uin ); gchar * message = g_strdup_printf ( "<A HREF= \" %s \" >%s</A>" , ( msg2 [ 0 ] && msg2 [ 0 ][ 0 ]) ? msg2 [ 0 ] : msg2 [ 1 ]); serv_got_im ( gc , uin , message , 0 , time ( NULL )); case 0x06 : { /* Someone requested authorization */ gchar * bn = g_strdup_printf ( "%u" , args -> uin ); reason = oscar_decode_im ( account , bn , AIM_CHARSET_LATIN_1 , msg2 [ 5 ], strlen ( msg2 [ 5 ])); purple_debug_info ( "oscar" , "Received an authorization request from UIN %u \n " , aim_icq_getalias ( od , bn , TRUE , reason ); case 0x07 : { /* Someone has denied you authorization */ gchar * dialog_msg = g_strdup_printf ( _ ( "The user %u has denied your request to add them to your buddy list for the following reason: \n %s" ), args -> uin , msg2 [ 0 ] ? msg2 [ 0 ] : _ ( "No reason given." )); purple_notify_info ( gc , NULL , _ ( "ICQ authorization denied." ), case 0x08 : { /* Someone has granted you authorization */ gchar * dialog_msg = g_strdup_printf ( _ ( "The user %u has granted your request to add them to your buddy list." ), args -> uin ); purple_notify_info ( gc , NULL , "ICQ authorization accepted." , case 0x09 : { /* Message from the Godly ICQ server itself, I think */ gchar * dialog_msg = g_strdup_printf ( _ ( "You have received a special message \n\n From: %s [%s] \n %s" ), msg2 [ 0 ], msg2 [ 3 ], msg2 [ 5 ]); purple_notify_info ( gc , NULL , "ICQ Server Message" , dialog_msg ); case 0x0d : { /* Someone has sent you a pager message from http://www.icq.com/your_uin */ gchar * dialog_msg = g_strdup_printf ( _ ( "You have received an ICQ page \n\n From: %s [%s] \n %s" ), msg2 [ 0 ], msg2 [ 3 ], msg2 [ 5 ]); purple_notify_info ( gc , NULL , "ICQ Page" , dialog_msg ); case 0x0e : { /* Someone has emailed you at your_uin@pager.icq.com */ gchar * dialog_msg = g_strdup_printf ( _ ( "You have received an ICQ email from %s [%s] \n\n Message is: \n %s" ), msg2 [ 0 ], msg2 [ 3 ], msg2 [ 5 ]); purple_notify_info ( gc , NULL , "ICQ Email" , dialog_msg ); /* Ack for authorizing/denying someone. Or possibly an ack for sending any system notice */ /* Someone added you to their buddy list? */ case 0x13 : { /* Someone has sent you some ICQ buddies */ text = g_strsplit ( args -> msg , " \376 " , 0 ); /* Read the number of contacts that we were sent */ num = text [ 0 ] ? strtoul ( text [ 0 ], NULL , 10 ) : 0 ; if ( num > 0 && errno == 0 ) { if ( ! text [ i * 2 + 1 ] || ! text [ i * 2 + 2 ]) { /* We're missing the contact name or nickname. Bail out. */ gchar * tmp = g_strescape ( args -> msg , NULL ); purple_debug_error ( "oscar" , "Unknown syntax parsing " "ICQ buddies. args->msg=%s \n " , tmp ); message = g_strdup_printf ( _ ( "ICQ user %u has sent you a buddy: %s (%s)" ), args -> uin , text [ i * 2 + 2 ], text [ i * 2 + 1 ]); data = g_new ( struct name_data , 1 ); data -> name = g_strdup ( text [ i * 2 + 1 ]); data -> nick = g_strdup ( text [ i * 2 + 2 ]); purple_request_action ( gc , NULL , message , _ ( "Do you want to add this buddy " PURPLE_DEFAULT_ACTION_NONE , purple_connection_get_account ( gc ), data -> name , NULL , _ ( "_Add" ), G_CALLBACK ( purple_icq_buddyadd ), _ ( "_Decline" ), G_CALLBACK ( oscar_free_name_data )); gchar * tmp = g_strescape ( args -> msg , NULL ); purple_debug_error ( "oscar" , "Unknown syntax parsing " "ICQ buddies. args->msg=%s \n " , tmp ); case 0x1a : { /* Handle SMS or someone has sent you a greeting card or requested buddies? */ char * tagstr = NULL , * smsmsg = NULL ; xmlnode * xmlroot = NULL , * xmltmp = NULL ; gchar * uin = NULL , * message = NULL ; /* From libicq2000-0.3.2/src/ICQ.cpp */ byte_stream_init ( & qbs , ( guint8 * ) args -> msg , args -> msglen ); byte_stream_advance ( & qbs , 21 ); /* expected: 01 00 00 20 00 0e 28 f6 00 11 e7 d3 11 bc f3 00 04 ac 96 9d c2 | 00 00 | 06 00 00 00 | 49 43 51 53 43 53 ...*/ /* unexpected: 00 00 26 00 81 1a 18 bc 0e 6c 18 47 a5 91 6f 18 dc c7 6f 1a | 00 00 | 0d 00 00 00 | 49 43 51 57 65 62 4d 65 73 73 61 67 65 ... */ smstype = byte_stream_getle16 ( & qbs ); taglen = byte_stream_getle32 ( & qbs ); /* Avoid trying to allocate large amounts of memory, in case we get something unexpected. */ tagstr = byte_stream_getstr ( & qbs , taglen ); byte_stream_advance ( & qbs , 3 ); byte_stream_advance ( & qbs , 4 ); smslen = byte_stream_getle32 ( & qbs ); /* Avoid trying to allocate large amounts of memory, in case we get something unexpected. */ smsmsg = byte_stream_getstr ( & qbs , smslen ); /* Check if this is an SMS being sent from server */ if (( smstype == 0 ) && ( ! strcmp ( tagstr , "ICQSMS" )) && ( smsmsg != NULL )) xmlroot = xmlnode_from_str ( smsmsg , -1 ); xmltmp = xmlnode_get_child ( xmlroot , "sender" ); uin = xmlnode_get_data ( xmltmp ); xmltmp = xmlnode_get_child ( xmlroot , "text" ); message = xmlnode_get_data ( xmltmp ); if (( uin != NULL ) && ( message != NULL )) serv_got_im ( gc , uin , message , 0 , time ( NULL )); purple_debug_info ( "oscar" , "Received a channel 4 message of unknown type " "(type 0x%02hhx). \n " , args -> type ); static int purple_parse_incoming_im ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { aim_userinfo_t * userinfo ; channel = ( guint16 ) va_arg ( ap , unsigned int ); userinfo = va_arg ( ap , aim_userinfo_t * ); case 1 : { /* standard message */ struct aim_incomingim_ch1_args * args ; args = va_arg ( ap , struct aim_incomingim_ch1_args * ); ret = incomingim_chan1 ( od , conn , userinfo , args ); case 2 : { /* rendezvous */ args = va_arg ( ap , IcbmArgsCh2 * ); ret = incomingim_chan2 ( od , conn , userinfo , args ); struct aim_incomingim_ch4_args * args ; args = va_arg ( ap , struct aim_incomingim_ch4_args * ); ret = incomingim_chan4 ( od , conn , userinfo , args , 0 ); purple_debug_warning ( "oscar" , "ICBM received on unsupported channel (channel " static int purple_parse_misses ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); guint16 chan , nummissed , reason ; aim_userinfo_t * userinfo ; chan = ( guint16 ) va_arg ( ap , unsigned int ); userinfo = va_arg ( ap , aim_userinfo_t * ); nummissed = ( guint16 ) va_arg ( ap , unsigned int ); reason = ( guint16 ) va_arg ( ap , unsigned int ); case 0 : /* Invalid (0) */ "You missed %hu message from %s because it was invalid." , "You missed %hu messages from %s because they were invalid." , case 1 : /* Message too large */ "You missed %hu message from %s because it was too large." , "You missed %hu messages from %s because they were too large." , case 2 : /* Rate exceeded */ "You missed %hu message from %s because the rate limit has been exceeded." , "You missed %hu messages from %s because the rate limit has been exceeded." , case 3 : /* Evil Sender */ "You missed %hu message from %s because his/her warning level is too high." , "You missed %hu messages from %s because his/her warning level is too high." , case 4 : /* Evil Receiver */ "You missed %hu message from %s because your warning level is too high." , "You missed %hu messages from %s because your warning level is too high." , "You missed %hu message from %s for an unknown reason." , "You missed %hu messages from %s for an unknown reason." , if ( ! purple_conv_present_error ( userinfo -> bn , account , buf )) purple_notify_error ( od -> gc , NULL , buf , NULL ); purple_parse_clientauto_ch2 ( OscarData * od , const char * who , guint16 reason , const guchar * cookie ) /* Rendezvous was refused. */ conn = peer_connection_find_by_cookie ( od , who , cookie ); purple_debug_info ( "oscar" , "Received a rendezvous cancel message " "for a nonexistant connection from %s. \n " , who ); peer_connection_destroy ( conn , OSCAR_DISCONNECT_REMOTE_REFUSED , NULL ); purple_debug_warning ( "oscar" , "Received an unknown rendezvous " "message from %s. Type 0x%04hx \n " , who , reason ); static int purple_parse_clientauto_ch4 ( OscarData * od , char * who , guint16 reason , guint32 state , char * msg ) { PurpleConnection * gc = od -> gc ; case 0x0003 : { /* Reply from an ICQ status message request */ char * statusmsg , ** splitmsg ; PurpleNotifyUserInfo * user_info ; /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ statusmsg = oscar_icqstatus ( state ); splitmsg = g_strsplit ( msg , " \r\n " , 0 ); user_info = purple_notify_user_info_new (); purple_notify_user_info_add_pair ( user_info , _ ( "UIN" ), who ); purple_notify_user_info_add_pair ( user_info , _ ( "Status" ), statusmsg ); purple_notify_user_info_add_section_break ( user_info ); purple_notify_user_info_add_pair ( user_info , NULL , g_strjoinv ( "<BR>" , splitmsg )); purple_notify_userinfo ( gc , who , user_info , NULL , NULL ); purple_notify_user_info_destroy ( user_info ); case 0x0006 : { /* Reply from an ICQ status message request */ char * statusmsg , ** splitmsg ; PurpleNotifyUserInfo * user_info ; /* Split at (carriage return/newline)'s, then rejoin later with BRs between. */ statusmsg = oscar_icqstatus ( state ); splitmsg = g_strsplit ( msg , " \r\n " , 0 ); user_info = purple_notify_user_info_new (); purple_notify_user_info_add_pair ( user_info , _ ( "UIN" ), who ); purple_notify_user_info_add_pair ( user_info , _ ( "Status" ), statusmsg ); purple_notify_user_info_add_section_break ( user_info ); purple_notify_user_info_add_pair ( user_info , NULL , g_strjoinv ( "<BR>" , splitmsg )); purple_notify_userinfo ( gc , who , user_info , NULL , NULL ); purple_notify_user_info_destroy ( user_info ); purple_debug_warning ( "oscar" , "Received an unknown client auto-response from %s. " "Type 0x%04hx \n " , who , reason ); static int purple_parse_clientauto ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { chan = ( guint16 ) va_arg ( ap , unsigned int ); who = va_arg ( ap , char * ); reason = ( guint16 ) va_arg ( ap , unsigned int ); if ( chan == 0x0002 ) { /* File transfer declined */ guchar * cookie = va_arg ( ap , guchar * ); ret = purple_parse_clientauto_ch2 ( od , who , reason , cookie ); } else if ( chan == 0x0004 ) { /* ICQ message */ state = va_arg ( ap , guint32 ); msg = va_arg ( ap , char * ); ret = purple_parse_clientauto_ch4 ( od , who , reason , state , msg ); static int purple_parse_genericerr ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { reason = ( guint16 ) va_arg ( ap , unsigned int ); purple_debug_error ( "oscar" , "snac threw error (reason 0x%04hx: %s) \n " , reason , oscar_get_msgerr_reason ( reason )); static int purple_parse_mtn ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; channel = ( guint16 ) va_arg ( ap , unsigned int ); event = ( guint16 ) va_arg ( ap , unsigned int ); case 0x0000 : { /* Text has been cleared */ serv_got_typing_stopped ( gc , bn ); case 0x0001 : { /* Paused typing */ serv_got_typing ( gc , bn , 0 , PURPLE_TYPED ); case 0x0002 : { /* Typing */ serv_got_typing ( gc , bn , 0 , PURPLE_TYPING ); case 0x000f : { /* Closed IM window */ serv_got_typing_stopped ( gc , bn ); purple_debug_info ( "oscar" , "Received unknown typing " "notification message from %s. Channel is 0x%04x " "and event is 0x%04hx. \n " , bn , channel , event ); static int purple_parse_motd ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) id = ( guint16 ) va_arg ( ap , unsigned int ); msg = va_arg ( ap , char * ); purple_debug_misc ( "oscar" , "MOTD: %s (%hu) \n " , msg ? msg : "Unknown" , id ); purple_notify_warning ( od -> gc , NULL , _ ( "Your AIM connection may be lost." ), NULL ); static int purple_chatnav_info ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { type = ( guint16 ) va_arg ( ap , unsigned int ); GString * msg = g_string_new ( "" ); struct aim_chat_exchangeinfo * exchanges ; maxrooms = ( guint8 ) va_arg ( ap , unsigned int ); exchangecount = va_arg ( ap , int ); exchanges = va_arg ( ap , struct aim_chat_exchangeinfo * ); g_string_append_printf ( msg , "chat info: Max Concurrent Rooms: %hhd, Exchange List (%d total): " , maxrooms , exchangecount ); for ( i = 0 ; i < exchangecount ; i ++ ) { g_string_append_printf ( msg , "%hu" , exchanges [ i ]. number ); g_string_append_printf ( msg , " %s" , exchanges [ i ]. name ); g_string_append ( msg , ", " ); purple_debug_misc ( "oscar" , "%s \n " , msg -> str ); g_string_free ( msg , TRUE ); while ( od -> create_rooms ) { struct create_room * cr = od -> create_rooms -> data ; purple_debug_info ( "oscar" , "creating room %s \n " , cr -> name ); aim_chatnav_createroom ( od , conn , cr -> name , cr -> exchange ); od -> create_rooms = g_slist_remove ( od -> create_rooms , cr ); guint16 instance , flags , maxmsglen , maxoccupancy , unknown , exchange ; fqcn = va_arg ( ap , char * ); instance = ( guint16 ) va_arg ( ap , unsigned int ); exchange = ( guint16 ) va_arg ( ap , unsigned int ); flags = ( guint16 ) va_arg ( ap , unsigned int ); createtime = va_arg ( ap , guint32 ); maxmsglen = ( guint16 ) va_arg ( ap , unsigned int ); maxoccupancy = ( guint16 ) va_arg ( ap , unsigned int ); createperms = ( guint8 ) va_arg ( ap , unsigned int ); unknown = ( guint16 ) va_arg ( ap , unsigned int ); name = va_arg ( ap , char * ); purple_debug_misc ( "oscar" , "created room: %s %hu %hu %hu %u %hu %hu %hhu %hu %s %s \n " , fqcn ? fqcn : "(null)" , exchange , instance , flags , createtime , maxmsglen , maxoccupancy , createperms , unknown , name ? name : "(null)" , ck ); aim_chat_join ( od , exchange , ck , instance ); purple_debug_warning ( "oscar" , "chatnav info: unknown type (%04hx) \n " , type ); static int purple_conv_chat_join ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; struct chat_connection * c = NULL ; info = va_arg ( ap , aim_userinfo_t * ); c = find_oscar_chat_by_conn ( gc , conn ); for ( i = 0 ; i < count ; i ++ ) purple_conv_chat_add_user ( PURPLE_CONV_CHAT ( c -> conv ), info [ i ]. bn , NULL , PURPLE_CBFLAGS_NONE , TRUE ); static int purple_conv_chat_leave ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; struct chat_connection * c = NULL ; info = va_arg ( ap , aim_userinfo_t * ); c = find_oscar_chat_by_conn ( gc , conn ); for ( i = 0 ; i < count ; i ++ ) purple_conv_chat_remove_user ( PURPLE_CONV_CHAT ( c -> conv ), info [ i ]. bn , NULL ); static int purple_conv_chat_info_update ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { guint16 maxmsglen , maxvisiblemsglen ; PurpleConnection * gc = od -> gc ; struct chat_connection * ccon = find_oscar_chat_by_conn ( gc , conn ); maxmsglen = ( guint16 ) va_arg ( ap , unsigned int ); maxvisiblemsglen = ( guint16 ) va_arg ( ap , unsigned int ); purple_debug_misc ( "oscar" , "inside chat_info_update (maxmsglen = %hu, maxvislen = %hu) \n " , maxmsglen , maxvisiblemsglen ); ccon -> maxlen = maxmsglen ; ccon -> maxvis = maxvisiblemsglen ; static int purple_conv_chat_incoming_msg ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; struct chat_connection * ccon = find_oscar_chat_by_conn ( gc , conn ); info = va_arg ( ap , aim_userinfo_t * ); msg = va_arg ( ap , char * ); charset = va_arg ( ap , char * ); utf8 = oscar_encoding_to_utf8 ( charset , msg , len ); serv_got_chat_in ( gc , ccon -> id , info -> bn , 0 , utf8 , time ( NULL )); static int purple_email_parseupdate ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { struct aim_emailinfo * emailinfo ; char * alertitle , * alerturl ; account = purple_connection_get_account ( gc ); emailinfo = va_arg ( ap , struct aim_emailinfo * ); havenewmail = va_arg ( ap , int ); alertitle = va_arg ( ap , char * ); alerturl = va_arg ( ap , char * ); if ( account != NULL && emailinfo != NULL && purple_account_get_check_mail ( account ) && emailinfo -> unread && havenewmail ) { gchar * to = g_strdup_printf ( "%s%s%s" , purple_account_get_username ( account ), emailinfo -> domain ? "@" : "" , emailinfo -> domain ? emailinfo -> domain : "" ); const char * tos [ 2 ] = { to }; const char * urls [ 2 ] = { emailinfo -> url }; purple_notify_emails ( gc , emailinfo -> nummsgs , FALSE , NULL , NULL , purple_debug_misc ( "oscar" , "Got an alert '%s' %s \n " , alertitle , alerturl ? alerturl : "" ); static int purple_icon_parseicon ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; guint8 iconcsumtype , * iconcsum , * icon ; guint16 iconcsumlen , iconlen ; iconcsumtype = va_arg ( ap , int ); iconcsum = va_arg ( ap , guint8 * ); iconcsumlen = va_arg ( ap , int ); icon = va_arg ( ap , guint8 * ); iconlen = va_arg ( ap , int ); * Some AIM clients will send a blank GIF image with iconlen 90 when * no icon is set. Ignore these. if (( iconlen > 0 ) && ( iconlen != 90 )) { char * b16 = purple_base16_encode ( iconcsum , iconcsumlen ); purple_buddy_icons_set_for_user ( purple_connection_get_account ( gc ), bn , g_memdup ( icon , iconlen ), iconlen , b16 ); purple_icons_fetch ( PurpleConnection * gc ) OscarData * od = purple_connection_get_protocol_data ( gc ); aim_userinfo_t * userinfo ; conn = flap_connection_getbytype ( od , SNAC_FAMILY_BART ); if ( ! od -> iconconnecting ) { aim_srv_requestnew ( od , SNAC_FAMILY_BART ); od -> iconconnecting = TRUE ; PurpleAccount * account = purple_connection_get_account ( gc ); PurpleStoredImage * img = purple_buddy_icons_find_account_icon ( account ); purple_debug_info ( "oscar" , "Uploading icon to icon server \n " ); aim_bart_upload ( od , purple_imgstore_get_data ( img ), purple_imgstore_get_size ( img )); purple_imgstore_unref ( img ); while ( od -> requesticon != NULL ) userinfo = aim_locate_finduserinfo ( od , ( char * ) od -> requesticon -> data ); if (( userinfo != NULL ) && ( userinfo -> iconcsumlen > 0 )) aim_bart_request ( od , od -> requesticon -> data , userinfo -> iconcsumtype , userinfo -> iconcsum , userinfo -> iconcsumlen ); g_free ( od -> requesticon -> data ); od -> requesticon = g_slist_delete_link ( od -> requesticon , od -> requesticon ); purple_debug_misc ( "oscar" , "no more icons to request \n " ); static int purple_selfinfo ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { info = va_arg ( ap , aim_userinfo_t * ); purple_connection_set_display_name ( od -> gc , info -> bn ); static int purple_connerr ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; code = ( guint16 ) va_arg ( ap , int ); msg = va_arg ( ap , char * ); purple_debug_info ( "oscar" , "Disconnected. Code is 0x%04x and msg is %s \n " , code , ( msg != NULL ? msg : "" )); g_return_val_if_fail ( conn != NULL , 1 ); if ( conn -> type == SNAC_FAMILY_CHAT ) { struct chat_connection * cc ; PurpleConversation * conv = NULL ; cc = find_oscar_chat_by_conn ( gc , conn ); conv = purple_find_chat ( gc , cc -> id ); * TOOD: Have flap_connection_destroy_cb() send us the * error message stored in 'tmp', which should be * human-friendly, and print that to the chat room. buf = g_strdup_printf ( _ ( "You have been disconnected from chat " purple_conversation_write ( conv , NULL , buf , PURPLE_MESSAGE_ERROR , time ( NULL )); static int purple_parse_locaterights ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); maxsiglen = ( guint16 ) va_arg ( ap , int ); purple_debug_misc ( "oscar" , "locate rights: max sig len = %d \n " , maxsiglen ); od -> rights . maxsiglen = od -> rights . maxawaymsglen = ( guint ) maxsiglen ; aim_locate_setcaps ( od , purple_caps ); oscar_set_info_and_status ( account , TRUE , account -> user_info , TRUE , purple_account_get_active_status ( account )); static int purple_parse_buddyrights ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { guint16 maxbuddies , maxwatchers ; maxbuddies = ( guint16 ) va_arg ( ap , unsigned int ); maxwatchers = ( guint16 ) va_arg ( ap , unsigned int ); purple_debug_misc ( "oscar" , "buddy list rights: Max buddies = %hu / Max watchers = %hu \n " , maxbuddies , maxwatchers ); od -> rights . maxbuddies = ( guint ) maxbuddies ; od -> rights . maxwatchers = ( guint ) maxwatchers ; static void oscar_format_username ( PurpleConnection * gc , const char * new_display_name ) const char * old_display_name , * username ; old_display_name = purple_connection_get_display_name ( gc ); if ( old_display_name && strchr ( old_display_name , '@' )) { purple_debug_info ( "oscar" , "Cowardly refusing to attempt to format " "screen name because the current formatting according to " "the server (%s) appears to be an email address \n " , username = purple_account_get_username ( purple_connection_get_account ( gc )); if ( oscar_util_name_compare ( username , new_display_name )) { purple_notify_error ( gc , NULL , _ ( "The new formatting is invalid." ), _ ( "Username formatting can change only capitalization and whitespace." )); tmp = g_strdup ( new_display_name ); * If our local username is an email address then strip off the domain. * This allows formatting to work if the user entered their username as * 'something@aim.com' or possibly other AOL-owned domains. at_sign = strchr ( tmp , '@' ); od = purple_connection_get_protocol_data ( gc ); if ( ! flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN )) { /* We don't have a connection to an "admin" server. Make one. */ g_free ( od -> newformatting ); aim_srv_requestnew ( od , SNAC_FAMILY_ADMIN ); aim_admin_setnick ( od , flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN ), tmp ); static int purple_bosrights ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurplePresence * presence ; const char * username , * message , * itmsurl ; guint16 maxpermits , maxdenies ; od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); maxpermits = ( guint16 ) va_arg ( ap , unsigned int ); maxdenies = ( guint16 ) va_arg ( ap , unsigned int ); purple_debug_misc ( "oscar" , "BOS rights: Max permit = %hu / Max deny = %hu \n " , maxpermits , maxdenies ); od -> rights . maxpermits = ( guint ) maxpermits ; od -> rights . maxdenies = ( guint ) maxdenies ; purple_debug_info ( "oscar" , "buddy list loaded \n " ); if ( purple_account_get_user_info ( account ) != NULL ) serv_set_info ( gc , purple_account_get_user_info ( account )); username = purple_account_get_username ( account ); if ( ! od -> icq && strcmp ( username , purple_connection_get_display_name ( gc )) != 0 ) { * Format the username for AIM accounts if it's different * than what's currently set. oscar_format_username ( gc , username ); /* Set our available message based on the current status */ status = purple_account_get_active_status ( account ); is_available = purple_status_is_available ( status ); message = purple_status_get_attr_string ( status , "message" ); tmp = purple_markup_strip_html ( message ); itmsurl = purple_status_get_attr_string ( status , "itmsurl" ); aim_srv_setextrainfo ( od , FALSE , 0 , is_available , tmp , itmsurl ); presence = purple_status_get_presence ( status ); aim_srv_setidle ( od , ! purple_presence_is_idle ( presence ) ? 0 : time ( NULL ) - purple_presence_get_idle_time ( presence )); oscar_set_extended_status ( gc ); purple_account_get_bool ( account , "authorization" , OSCAR_DEFAULT_AUTHORIZATION ), purple_account_get_bool ( account , "web_aware" , OSCAR_DEFAULT_WEB_AWARE )); aim_srv_requestnew ( od , SNAC_FAMILY_ALERT ); aim_srv_requestnew ( od , SNAC_FAMILY_CHATNAV ); od -> bos . have_rights = TRUE ; * If we've already received our feedbag data then we're not waiting on * anything else, so send the server clientready. * Normally we get bos rights before we get our feedbag data, so this * rarely (never?) happens. And I'm not sure it actually matters if we * wait for bos rights before calling clientready. But it seems safer if ( od -> ssi . received_data ) { aim_srv_clientready ( od , conn ); /* Request offline messages for AIM and ICQ */ aim_im_reqofflinemsgs ( od ); purple_connection_set_state ( gc , PURPLE_CONNECTED ); static int purple_popup ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; msg = va_arg ( ap , char * ); url = va_arg ( ap , char * ); wid = ( guint16 ) va_arg ( ap , int ); hei = ( guint16 ) va_arg ( ap , int ); delay = ( guint16 ) va_arg ( ap , int ); text = g_strdup_printf ( "%s<br><a href= \" %s \" >%s</a>" , msg , url , url ); purple_notify_formatted ( gc , NULL , _ ( "Pop-Up Message" ), NULL , text , NULL , NULL ); static void oscar_searchresults_add_buddy_cb ( PurpleConnection * gc , GList * row , void * user_data ) purple_blist_request_add_buddy ( purple_connection_get_account ( gc ), g_list_nth_data ( row , 0 ), NULL , NULL ); static int purple_parse_searchreply ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) PurpleConnection * gc = od -> gc ; PurpleNotifySearchResults * results ; PurpleNotifySearchColumn * column ; email = va_arg ( ap , char * ); usernames = va_arg ( ap , char * ); results = purple_notify_searchresults_new (); purple_debug_error ( "oscar" , "purple_parse_searchreply: " "Unable to display the search results. \n " ); purple_notify_error ( gc , NULL , _ ( "Unable to display the search results." ), secondary = g_strdup_printf ( dngettext ( PACKAGE , "The following username is associated with %s" , "The following usernames are associated with %s" , column = purple_notify_searchresults_column_new ( _ ( "Username" )); purple_notify_searchresults_column_add ( results , column ); for ( i = 0 ; i < num ; i ++ ) { row = g_list_append ( NULL , g_strdup ( & usernames [ i * ( MAXSNLEN + 1 )])); purple_notify_searchresults_row_add ( results , row ); purple_notify_searchresults_button_add ( results , PURPLE_NOTIFY_BUTTON_ADD , oscar_searchresults_add_buddy_cb ); purple_notify_searchresults ( gc , NULL , NULL , secondary , results , NULL , NULL ); static int purple_parse_searcherror ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { email = va_arg ( ap , char * ); buf = g_strdup_printf ( _ ( "No results found for email address %s" ), email ); purple_notify_error ( od -> gc , NULL , buf , NULL ); static int purple_account_confirm ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; status = ( guint16 ) va_arg ( ap , unsigned int ); /* status code of confirmation request */ purple_debug_info ( "oscar" , "account confirmation returned status 0x%04x (%s) \n " , status , status ? "unknown" : "email sent" ); g_snprintf ( msg , sizeof ( msg ), _ ( "You should receive an email asking to confirm %s." ), purple_account_get_username ( purple_connection_get_account ( gc ))); purple_notify_info ( gc , NULL , _ ( "Account Confirmation Requested" ), msg ); static int purple_info_change ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; change = va_arg ( ap , int ); perms = ( guint16 ) va_arg ( ap , unsigned int ); err = ( guint16 ) va_arg ( ap , unsigned int ); url = va_arg ( ap , char * ); email = va_arg ( ap , char * ); purple_debug_misc ( "oscar" , "account info: because of %s, perms=0x%04x, err=0x%04x, url=%s, bn=%s, email=%s \n " , change ? "change" : "request" , perms , err , ( url != NULL ) ? url : "(null)" , ( bn != NULL ) ? bn : "(null)" , ( email != NULL ) ? email : "(null)" ); if (( err > 0 ) && ( url != NULL )) { dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to format username because the requested name differs from the original." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to format username because it is invalid." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to format username because the requested name is too long." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to change email address because there is already a request pending for this username." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to change email address because the given address has too many usernames associated with it." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unable to change email address because the given address is invalid." ), err ); dialog_msg = g_strdup_printf ( _ ( "Error 0x%04x: Unknown error." ), err ); purple_notify_error ( gc , NULL , _ ( "Error Changing Account Info" ), dialog_msg ); char * dialog_msg = g_strdup_printf ( _ ( "The email address for %s is %s" ), purple_account_get_username ( purple_connection_get_account ( gc )), email ); purple_notify_info ( gc , NULL , _ ( "Account Info" ), dialog_msg ); oscar_keepalive ( PurpleConnection * gc ) od = purple_connection_get_protocol_data ( gc ); for ( l = od -> oscar_connections ; l ; l = l -> next ) { flap_connection_send_keepalive ( od , l -> data ); oscar_send_typing ( PurpleConnection * gc , const char * name , PurpleTypingState state ) od = purple_connection_get_protocol_data ( gc ); conn = peer_connection_find_by_type ( od , name , OSCAR_CAPABILITY_DIRECTIM ); if (( conn != NULL ) && ( conn -> ready )) peer_odc_send_typing ( conn , state ); /* Don't send if this turkey is in our deny list */ for ( list = gc -> account -> deny ; ( list && oscar_util_name_compare ( name , list -> data )); list = list -> next ); struct buddyinfo * bi = g_hash_table_lookup ( od -> buddyinfo , purple_normalize ( gc -> account , name )); if ( bi && bi -> typingnot ) { if ( state == PURPLE_TYPING ) aim_im_sendmtn ( od , 0x0001 , name , 0x0002 ); else if ( state == PURPLE_TYPED ) aim_im_sendmtn ( od , 0x0001 , name , 0x0001 ); aim_im_sendmtn ( od , 0x0001 , name , 0x0000 ); /* TODO: Move this into odc.c! */ purple_odc_send_im ( PeerConnection * conn , const char * message , PurpleMessageFlags imflags ) const char * start , * end , * last ; msg = g_string_new ( "<HTML><BODY>" ); data = g_string_new ( "<BINARY>" ); /* for each valid IMG tag... */ while ( last && * last && purple_markup_find_tag ( "img" , last , & start , & end , & attribs )) PurpleStoredImage * image = NULL ; g_string_append_len ( msg , last , start - last ); id = g_datalist_get_data ( & attribs , "id" ); /* ... if it refers to a valid purple image ... */ if ( id && ( image = purple_imgstore_find_by_id ( atoi ( id )))) { /* ... append the message from start to the tag ... */ unsigned long size = purple_imgstore_get_size ( image ); const char * filename = purple_imgstore_get_filename ( image ); gconstpointer imgdata = purple_imgstore_get_data ( image ); /* ... insert a new img tag with the oscar id ... */ g_string_append_printf ( msg , "<IMG SRC= \" %s \" ID= \" %d \" DATASIZE= \" %lu \" >" , filename , oscar_id , size ); g_string_append_printf ( msg , "<IMG ID= \" %d \" DATASIZE= \" %lu \" >" , /* ... and append the data to the binary section ... */ g_string_append_printf ( data , "<DATA ID= \" %d \" SIZE= \" %lu \" >" , g_string_append_len ( data , imgdata , size ); g_string_append ( data , "</DATA>" ); /* If the tag is invalid, skip it, thus no else here */ g_datalist_clear ( & attribs ); /* continue from the end of the tag */ /* append any remaining message data */ g_string_append ( msg , last ); g_string_append ( msg , "</BODY></HTML>" ); /* Convert the message to a good encoding */ tmp = oscar_encode_im ( msg -> str , & tmplen , & charset , NULL ); g_string_free ( msg , TRUE ); msg = g_string_new_len ( tmp , tmplen ); /* Append any binary data that we may have */ msg = g_string_append_len ( msg , data -> str , data -> len ); msg = g_string_append ( msg , "</BINARY>" ); g_string_free ( data , TRUE ); purple_debug_info ( "oscar" , "sending direct IM %s using charset %i" , msg -> str , charset ); peer_odc_send_im ( conn , msg -> str , msg -> len , charset , imflags & PURPLE_MESSAGE_AUTO_RESP ); g_string_free ( msg , TRUE ); oscar_send_im ( PurpleConnection * gc , const char * name , const char * message , PurpleMessageFlags imflags ) gboolean is_sms , is_html ; od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); is_sms = oscar_util_valid_name_sms ( name ); * We're sending to a phone number and this is ICQ, * so send the message as an SMS using aim_icq_sendsms() purple_debug_info ( "oscar" , "Sending SMS to %s. \n " , name ); ret = aim_icq_sendsms ( od , name , message , purple_account_get_username ( account )); return ( ret >= 0 ? 1 : ret ); if ( imflags & PURPLE_MESSAGE_AUTO_RESP ) tmp1 = oscar_util_format_string ( message , name ); tmp1 = g_strdup ( message ); conn = peer_connection_find_by_type ( od , name , OSCAR_CAPABILITY_DIRECTIM ); if (( conn != NULL ) && ( conn -> ready )) /* If we're directly connected, send a direct IM */ purple_debug_info ( "oscar" , "Sending direct IM with flags %i \n " , imflags ); purple_odc_send_im ( conn , tmp1 , imflags ); struct aim_sendimext_args args ; PurpleConversation * conv ; conv = purple_find_conversation_with_account ( PURPLE_CONV_TYPE_IM , name , account ); if ( strstr ( tmp1 , "<IMG " )) purple_conversation_write ( conv , "" , _ ( "Your IM Image was not sent. " "You must be Direct Connected to send IM Images." ), PURPLE_MESSAGE_ERROR , time ( NULL )); buddy = purple_find_buddy ( account , name ); bi = g_hash_table_lookup ( od -> buddyinfo , purple_normalize ( account , name )); bi = g_new0 ( struct buddyinfo , 1 ); g_hash_table_insert ( od -> buddyinfo , g_strdup ( purple_normalize ( account , name )), bi ); if ( ! is_sms && ( ! buddy || ! PURPLE_BUDDY_IS_ONLINE ( buddy ))) args . flags |= AIM_IMFLAGS_OFFLINE ; args . features = features_icq ; args . featureslen = sizeof ( features_icq ); args . features = features_aim ; args . featureslen = sizeof ( features_aim ); if ( imflags & PURPLE_MESSAGE_AUTO_RESP ) args . flags |= AIM_IMFLAGS_AWAY ; purple_debug_info ( "oscar" , "Sending buddy icon request with message \n " ); args . flags |= AIM_IMFLAGS_BUDDYREQ ; img = purple_buddy_icons_find_account_icon ( account ); gconstpointer data = purple_imgstore_get_data ( img ); args . iconlen = purple_imgstore_get_size ( img ); args . iconsum = aimutil_iconsum ( data , args . iconlen ); args . iconstamp = purple_buddy_icons_get_account_icon_timestamp ( account ); if (( args . iconlen != bi -> ico_me_len ) || ( args . iconsum != bi -> ico_me_csum ) || ( args . iconstamp != bi -> ico_me_time )) { bi -> ico_informed = FALSE ; * For some reason sending our icon to people only works * when we're the ones who initiated the conversation. If * the other person sends the first IM then they never get * the icon. We should fix that. purple_debug_info ( "oscar" , "Claiming to have a buddy icon \n " ); args . flags |= AIM_IMFLAGS_HASICON ; bi -> ico_me_len = args . iconlen ; bi -> ico_me_csum = args . iconsum ; bi -> ico_me_time = args . iconstamp ; purple_imgstore_unref ( img ); if ( oscar_util_valid_name_sms ( name )) { /* Messaging an SMS (mobile) user--strip HTML */ tmp2 = purple_markup_strip_html ( tmp1 ); /* ICQ 6 wants its HTML wrapped in these tags. Oblige it. */ tmp2 = g_strdup_printf ( "<HTML><BODY>%s</BODY></HTML>" , tmp1 ); args . msg = oscar_encode_im ( tmp1 , & args . msglen , & args . charset , NULL ); if ( is_html && ( args . msglen > MAXMSGLEN )) { /* If the length was too long, try stripping the HTML and then running it back through * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ g_free (( char * ) args . msg ); tmp2 = purple_markup_strip_html ( tmp1 ); /* re-escape the entities */ tmp1 = g_markup_escape_text ( tmp2 , -1 ); tmp2 = purple_strdup_withhtml ( tmp1 ); args . msg = oscar_encode_im ( tmp1 , & args . msglen , & args . charset , NULL ); purple_debug_info ( "oscar" , "Sending %s as %s because the original was too long. \n " , message , ( char * ) args . msg ); purple_debug_info ( "oscar" , "Sending IM, charset=0x%04hx, length=%" G_GSIZE_FORMAT " \n " , args . charset , args . msglen ); ret = aim_im_sendch1_ext ( od , & args ); g_free (( char * ) args . msg ); * As of 26 June 2006, ICQ users can request AIM info from * everyone, and can request ICQ info from ICQ users, and * AIM users can only request AIM info. void oscar_get_info ( PurpleConnection * gc , const char * name ) { OscarData * od = purple_connection_get_protocol_data ( gc ); if ( od -> icq && oscar_util_valid_name_icq ( name )) aim_icq_getallinfo ( od , name ); aim_locate_getinfoshort ( od , name , 0x00000003 ); void oscar_set_idle ( PurpleConnection * gc , int time ) { OscarData * od = purple_connection_get_protocol_data ( gc ); aim_srv_setidle ( od , time ); oscar_set_info ( PurpleConnection * gc , const char * rawinfo ) account = purple_connection_get_account ( gc ); status = purple_account_get_active_status ( account ); oscar_set_info_and_status ( account , TRUE , rawinfo , FALSE , status ); oscar_get_extended_status ( PurpleConnection * gc ) guint32 data = 0x00000000 ; account = purple_connection_get_account ( gc ); status = purple_account_get_active_status ( account ); status_id = purple_status_get_id ( status ); data |= AIM_ICQ_STATE_HIDEIP ; if ( purple_account_get_bool ( account , "web_aware" , OSCAR_DEFAULT_WEB_AWARE )) data |= AIM_ICQ_STATE_WEBAWARE ; if ( ! strcmp ( status_id , OSCAR_STATUS_ID_AVAILABLE )) data |= AIM_ICQ_STATE_NORMAL ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_AWAY )) data |= AIM_ICQ_STATE_AWAY ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_DND )) data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_DND | AIM_ICQ_STATE_BUSY ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_NA )) data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_OCCUPIED )) data |= AIM_ICQ_STATE_AWAY | AIM_ICQ_STATE_BUSY ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_FREE4CHAT )) data |= AIM_ICQ_STATE_CHAT ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_INVISIBLE )) data |= AIM_ICQ_STATE_INVISIBLE ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_EVIL )) data |= AIM_ICQ_STATE_EVIL ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_DEPRESSION )) data |= AIM_ICQ_STATE_DEPRESSION ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_ATWORK )) data |= AIM_ICQ_STATE_ATWORK ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_ATHOME )) data |= AIM_ICQ_STATE_ATHOME ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_LUNCH )) data |= AIM_ICQ_STATE_LUNCH ; else if ( ! strcmp ( status_id , OSCAR_STATUS_ID_CUSTOM )) data |= AIM_ICQ_STATE_OUT | AIM_ICQ_STATE_AWAY ; oscar_set_extended_status ( PurpleConnection * gc ) aim_srv_setextrainfo ( purple_connection_get_protocol_data ( gc ), TRUE , oscar_get_extended_status ( gc ), FALSE , NULL , NULL ); oscar_set_info_and_status ( PurpleAccount * account , gboolean setinfo , const char * rawinfo , gboolean setstatus , PurpleStatus * status ) PurpleConnection * gc = purple_account_get_connection ( account ); OscarData * od = purple_connection_get_protocol_data ( gc ); PurpleStatusType * status_type ; PurpleStatusPrimitive primitive ; char * info_encoding = NULL ; char * away_encoding = NULL ; char * status_text = NULL ; const char * itmsurl = NULL ; status_type = purple_status_get_type ( status ); primitive = purple_status_type_get_primitive ( status_type ); else if ( od -> rights . maxsiglen == 0 ) purple_notify_warning ( gc , NULL , _ ( "Unable to set AIM profile." ), _ ( "You have probably requested to set your " "profile before the login procedure completed. " "Your profile remains unset; try setting it " "again when you are fully connected." )); else if ( rawinfo != NULL ) char * htmlinfo = purple_strdup_withhtml ( rawinfo ); info = oscar_encode_im ( htmlinfo , & infolen , NULL , & info_encoding ); if ( infolen > od -> rights . maxsiglen ) errstr = g_strdup_printf ( dngettext ( PACKAGE , "The maximum profile length of %d byte " "has been exceeded. It has been truncated for you." , "The maximum profile length of %d bytes " "has been exceeded. It has been truncated for you." , od -> rights . maxsiglen ), od -> rights . maxsiglen ); purple_notify_warning ( gc , NULL , _ ( "Profile too long." ), errstr ); status_html = purple_status_get_attr_string ( status , "message" ); if ( status_html == NULL || primitive == PURPLE_STATUS_AVAILABLE || primitive == PURPLE_STATUS_INVISIBLE ) /* This is needed for us to un-set any previous away message. */ /* We do this for icq too so that they work for old third party clients */ linkified = purple_markup_linkify ( status_html ); away = oscar_encode_im ( linkified , & awaylen , NULL , & away_encoding ); if ( awaylen > od -> rights . maxawaymsglen ) errstr = g_strdup_printf ( dngettext ( PACKAGE , "The maximum away message length of %d byte " "has been exceeded. It has been truncated for you." , "The maximum away message length of %d bytes " "has been exceeded. It has been truncated for you." , od -> rights . maxawaymsglen ), od -> rights . maxawaymsglen ); purple_notify_warning ( gc , NULL , _ ( "Away message too long." ), errstr ); aim_locate_setprofile ( od , info_encoding , info , MIN ( infolen , od -> rights . maxsiglen ), away_encoding , away , MIN ( awaylen , od -> rights . maxawaymsglen )); status_html = purple_status_get_attr_string ( status , "message" ); status_text = purple_markup_strip_html ( status_html ); /* If the status_text is longer than 251 characters then truncate it */ if ( strlen ( status_text ) > MAXAVAILMSGLEN ) char * tmp = g_utf8_find_prev_char ( status_text , & status_text [ MAXAVAILMSGLEN - 2 ]); itmsurl = purple_status_get_attr_string ( status , "itmsurl" ); aim_srv_setextrainfo ( od , TRUE , oscar_get_extended_status ( gc ), TRUE , status_text , itmsurl ); oscar_set_icq_permdeny ( PurpleAccount * account ) PurpleConnection * gc = purple_account_get_connection ( account ); OscarData * od = purple_connection_get_protocol_data ( gc ); gboolean invisible = purple_account_is_status_active ( account , OSCAR_STATUS_ID_INVISIBLE ); * For ICQ the permit/deny setting controls who can see you * online. Mimicking the official client's behavior, we use PURPLE_PRIVACY_ALLOW_USERS * when our status is "invisible" and PURPLE_PRIVACY_DENY_USERS otherwise. * In the former case, we are visible only to buddies on our "permanently visible" list. * In the latter, we are invisible only to buddies on our "permanently invisible" list. aim_ssi_setpermdeny ( od , invisible ? PURPLE_PRIVACY_ALLOW_USERS : PURPLE_PRIVACY_DENY_USERS ); oscar_set_status ( PurpleAccount * account , PurpleStatus * status ) purple_debug_info ( "oscar" , "Set status to %s \n " , purple_status_get_name ( status )); /* Either setting a new status active or setting a status inactive. * (Only possible for independent status (i.e. X-Status moods.) */ if ( ! purple_status_is_active ( status ) && ! purple_status_is_independent ( status )) if ( ! purple_account_is_connected ( account )) pc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( pc ); /* There's no need to do the stuff below for mood updates. */ if ( purple_status_type_get_primitive ( purple_status_get_type ( status )) == PURPLE_STATUS_MOOD ) { aim_locate_setcaps ( od , purple_caps ); oscar_set_icq_permdeny ( account ); /* Set the AIM-style away message for both AIM and ICQ accounts */ oscar_set_info_and_status ( account , FALSE , NULL , TRUE , status ); oscar_add_buddy ( PurpleConnection * gc , PurpleBuddy * buddy , PurpleGroup * group , const char * msg ) const char * bname , * gname ; od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); bname = purple_buddy_get_name ( buddy ); gname = purple_group_get_name ( group ); if ( ! oscar_util_valid_name ( bname )) { buf = g_strdup_printf ( _ ( "Unable to add the buddy %s because the username is invalid. Usernames must be a valid email address, or start with a letter and contain only letters, numbers and spaces, or contain only numbers." ), bname ); if ( ! purple_conv_present_error ( bname , account , buf )) purple_notify_error ( gc , NULL , _ ( "Unable to Add" ), buf ); /* Remove from local list */ purple_blist_remove_buddy ( buddy ); if ( od -> ssi . received_data ) { if ( ! aim_ssi_itemlist_finditem ( od -> ssi . local , gname , bname , AIM_SSI_TYPE_BUDDY )) { purple_debug_info ( "oscar" , "ssi: adding buddy %s to group %s \n " , bname , gname ); aim_ssi_addbuddy ( od , bname , gname , NULL , purple_buddy_get_alias_only ( buddy ), NULL , NULL , 0 ); /* Mobile users should always be online */ purple_prpl_got_user_status ( account , bname , OSCAR_STATUS_ID_AVAILABLE , NULL ); purple_prpl_got_user_status ( account , bname , OSCAR_STATUS_ID_MOBILE , NULL ); } else if ( aim_ssi_waitingforauth ( od -> ssi . local , aim_ssi_itemlist_findparentname ( od -> ssi . local , bname ), /* Not authorized -- Re-request authorization */ oscar_auth_sendrequest ( gc , bname , msg ); /* XXX - Should this be done from AIM accounts, as well? */ aim_icq_getalias ( od , bname , FALSE , NULL ); void oscar_remove_buddy ( PurpleConnection * gc , PurpleBuddy * buddy , PurpleGroup * group ) { OscarData * od = purple_connection_get_protocol_data ( gc ); if ( od -> ssi . received_data ) { const char * gname = purple_group_get_name ( group ); const char * bname = purple_buddy_get_name ( buddy ); purple_debug_info ( "oscar" , "ssi: deleting buddy %s from group %s \n " , bname , gname ); aim_ssi_delbuddy ( od , bname , gname ); void oscar_move_buddy ( PurpleConnection * gc , const char * name , const char * old_group , const char * new_group ) { OscarData * od = purple_connection_get_protocol_data ( gc ); if ( od -> ssi . received_data && strcmp ( old_group , new_group )) { purple_debug_info ( "oscar" , "ssi: moving buddy %s from group %s to group %s \n " , name , old_group , new_group ); aim_ssi_movebuddy ( od , old_group , new_group , name ); void oscar_alias_buddy ( PurpleConnection * gc , const char * name , const char * alias ) { OscarData * od = purple_connection_get_protocol_data ( gc ); if ( od -> ssi . received_data ) { char * gname = aim_ssi_itemlist_findparentname ( od -> ssi . local , name ); purple_debug_info ( "oscar" , "ssi: changing the alias for buddy %s to %s \n " , name , alias ? alias : "(none)" ); aim_ssi_aliasbuddy ( od , gname , name , alias ); * FYI, the OSCAR SSI code removes empty groups automatically. void oscar_rename_group ( PurpleConnection * gc , const char * old_name , PurpleGroup * group , GList * moved_buddies ) { OscarData * od = purple_connection_get_protocol_data ( gc ); if ( od -> ssi . received_data ) { const char * gname = purple_group_get_name ( group ); if ( aim_ssi_itemlist_finditem ( od -> ssi . local , gname , NULL , AIM_SSI_TYPE_GROUP )) { GList * cur , * groups = NULL ; PurpleAccount * account = purple_connection_get_account ( gc ); /* Make a list of what the groups each buddy is in */ for ( cur = moved_buddies ; cur != NULL ; cur = cur -> next ) { PurpleBlistNode * node = cur -> data ; /* node is PurpleBuddy, parent is a PurpleContact. * We must go two levels up to get the Group */ groups = g_list_append ( groups , purple_buddy_get_group (( PurpleBuddy * ) node )); purple_account_remove_buddies ( account , moved_buddies , groups ); purple_account_add_buddies ( account , moved_buddies ); purple_debug_info ( "oscar" , "ssi: moved all buddies from group %s to %s \n " , old_name , gname ); aim_ssi_rename_group ( od , old_name , gname ); purple_debug_info ( "oscar" , "ssi: renamed group %s to %s \n " , old_name , gname ); void oscar_remove_group ( PurpleConnection * gc , PurpleGroup * group ) aim_ssi_delgroup ( purple_connection_get_protocol_data ( gc ), purple_group_get_name ( group )); static gboolean purple_ssi_rerequestdata ( gpointer data ) { static int purple_ssi_parseerr ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; reason = ( guint16 ) va_arg ( ap , unsigned int ); purple_debug_error ( "oscar" , "ssi: SNAC error %hu \n " , reason ); if ( od -> getblisttimer > 0 ) purple_timeout_remove ( od -> getblisttimer ); /* We only show this error the first time it happens */ purple_notify_error ( gc , NULL , _ ( "Unable to Retrieve Buddy List" ), _ ( "The AIM servers were temporarily unable to send " "your buddy list. Your buddy list is not lost, and " "will probably become available in a few minutes." )); od -> getblisttimer = purple_timeout_add_seconds ( 30 , purple_ssi_rerequestdata , od ); static int purple_ssi_parserights ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { numtypes = va_arg ( ap , int ); maxitems = va_arg ( ap , guint16 * ); msg = g_string_new ( "ssi rights:" ); for ( i = 0 ; i < numtypes ; i ++ ) g_string_append_printf ( msg , " max type 0x%04x=%hd," , i , maxitems [ i ]); g_string_append ( msg , " \n " ); purple_debug_misc ( "oscar" , "%s" , msg -> str ); g_string_free ( msg , TRUE ); od -> rights . maxbuddies = maxitems [ 0 ]; od -> rights . maxgroups = maxitems [ 1 ]; od -> rights . maxpermits = maxitems [ 2 ]; od -> rights . maxdenies = maxitems [ 3 ]; static int purple_ssi_parselist ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) GSList * cur , * next , * buddies ; struct aim_ssi_item * curitem ; guint16 fmtver , numitems ; guint16 deny_entry_type = aim_ssi_getdenyentrytype ( od ); od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); fmtver = ( guint16 ) va_arg ( ap , int ); numitems = ( guint16 ) va_arg ( ap , int ); timestamp = va_arg ( ap , guint32 ); /* Don't attempt to re-request our buddy list later */ if ( od -> getblisttimer != 0 ) { purple_timeout_remove ( od -> getblisttimer ); purple_debug_info ( "oscar" , "ssi: syncing local list and server list \n " ); /* Clean the buddy list */ /*** Begin code for pruning buddies from local list if they're not in server list ***/ for ( buddies = purple_find_buddies ( account , NULL ); buddies = g_slist_delete_link ( buddies , buddies )) g = purple_buddy_get_group ( b ); gname = purple_group_get_name ( g ); bname = purple_buddy_get_name ( b ); if ( aim_ssi_itemlist_exists ( od -> ssi . local , bname )) { /* If the buddy is an ICQ user then load his nickname */ const char * servernick = purple_blist_node_get_string (( PurpleBlistNode * ) b , "servernick" ); serv_got_alias ( gc , bname , servernick ); /* Store local alias on server */ alias = aim_ssi_getalias ( od -> ssi . local , gname , bname ); balias = purple_buddy_get_local_buddy_alias ( b ); if ( ! alias && balias && * balias ) aim_ssi_aliasbuddy ( od , gname , bname , balias ); purple_debug_info ( "oscar" , "ssi: removing buddy %s from local list \n " , bname ); /* Queue the buddy for removal from the local list */ cur = g_slist_prepend ( cur , b ); purple_blist_remove_buddy ( cur -> data ); cur = g_slist_delete_link ( cur , cur ); /* Permit list (ICQ doesn't have one) */ if ( ! aim_ssi_itemlist_finditem ( od -> ssi . local , NULL , cur -> data , AIM_SSI_TYPE_PERMIT )) { purple_debug_info ( "oscar" , "ssi: removing permit %s from local list \n " , ( const char * ) cur -> data ); purple_privacy_permit_remove ( account , cur -> data , TRUE ); if ( ! aim_ssi_itemlist_finditem ( od -> ssi . local , NULL , cur -> data , deny_entry_type )) { purple_debug_info ( "oscar" , "ssi: removing deny %s from local list \n " , ( const char * ) cur -> data ); purple_privacy_deny_remove ( account , cur -> data , TRUE ); /* Presence settings (idle time visibility) */ tmp = aim_ssi_getpresence ( od -> ssi . local ); const char * idle_reporting_pref ; idle_reporting_pref = purple_prefs_get_string ( "/purple/away/idle_reporting" ); report_idle = strcmp ( idle_reporting_pref , "none" ) != 0 ; aim_ssi_setpresence ( od , tmp | AIM_SSI_PRESENCE_FLAG_SHOWIDLE ); aim_ssi_setpresence ( od , tmp & ~ AIM_SSI_PRESENCE_FLAG_SHOWIDLE ); /*** End code for pruning buddies from local list ***/ /*** Begin code for adding from server list to local list ***/ for ( curitem = od -> ssi . local ; curitem ; curitem = curitem -> next ) { if ( curitem -> name && ! g_utf8_validate ( curitem -> name , -1 , NULL )) { /* Got node with invalid UTF-8 in the name. Skip it. */ purple_debug_warning ( "oscar" , "ssi: server list contains item of " "type 0x%04hhx with a non-utf8 name \n " , curitem -> type ); case AIM_SSI_TYPE_BUDDY : { /* Buddy */ struct aim_ssi_item * groupitem ; char * gname , * gname_utf8 , * alias , * alias_utf8 ; groupitem = aim_ssi_itemlist_find ( od -> ssi . local , curitem -> gid , 0x0000 ); gname = groupitem ? groupitem -> name : NULL ; gname_utf8 = oscar_utf8_try_convert ( account , od , gname ); g = purple_find_group ( gname_utf8 ? gname_utf8 : _ ( "Orphans" )); g = purple_group_new ( gname_utf8 ? gname_utf8 : _ ( "Orphans" )); purple_blist_add_group ( g , NULL ); alias = aim_ssi_getalias ( od -> ssi . local , gname , curitem -> name ); alias_utf8 = oscar_utf8_try_convert ( account , od , alias ); b = purple_find_buddy_in_group ( account , curitem -> name , g ); /* Get server stored alias */ purple_blist_alias_buddy ( b , alias_utf8 ); b = purple_buddy_new ( account , curitem -> name , alias_utf8 ); purple_debug_info ( "oscar" , "ssi: adding buddy %s to group %s to local list \n " , curitem -> name , gname ); purple_blist_add_buddy ( b , NULL , g , NULL ); /* Mobile users should always be online */ if ( curitem -> name [ 0 ] == '+' ) { purple_prpl_got_user_status ( account , purple_buddy_get_name ( b ), OSCAR_STATUS_ID_AVAILABLE , NULL ); purple_prpl_got_user_status ( account , purple_buddy_get_name ( b ), OSCAR_STATUS_ID_MOBILE , NULL ); case AIM_SSI_TYPE_GROUP : { /* Group */ if ( curitem -> name != NULL && purple_find_group ( curitem -> name ) == NULL ) { g = purple_group_new ( curitem -> name ); purple_blist_add_group ( g , NULL ); case AIM_SSI_TYPE_PERMIT : { /* Permit buddy (unless we're on ICQ) */ if ( ! od -> icq && curitem -> name ) { for ( cur = account -> permit ; ( cur && oscar_util_name_compare ( curitem -> name , cur -> data )); cur = cur -> next ); purple_debug_info ( "oscar" , "ssi: adding permit buddy %s to local list \n " , curitem -> name ); purple_privacy_permit_add ( account , curitem -> name , TRUE ); case AIM_SSI_TYPE_ICQDENY : case AIM_SSI_TYPE_DENY : { /* Deny buddy */ if ( curitem -> type == deny_entry_type && curitem -> name ) { for ( cur = account -> deny ; ( cur && oscar_util_name_compare ( curitem -> name , cur -> data )); cur = cur -> next ); purple_debug_info ( "oscar" , "ssi: adding deny buddy %s to local list \n " , curitem -> name ); purple_privacy_deny_add ( account , curitem -> name , TRUE ); case AIM_SSI_TYPE_PDINFO : { /* Permit/deny setting */ * We don't inherit the permit/deny setting from the server * for ICQ because, for ICQ, this setting controls who can * see your online status when you are invisible. Thus it is * a part of your status and not really related to blocking. if ( ! od -> icq && curitem -> data ) { guint8 perm_deny = aim_ssi_getpermdeny ( od -> ssi . local ); if ( perm_deny != 0 && perm_deny != account -> perm_deny ) purple_debug_info ( "oscar" , "ssi: changing permdeny from %d to %hhu \n " , account -> perm_deny , perm_deny ); account -> perm_deny = perm_deny ; case AIM_SSI_TYPE_PRESENCEPREFS : { /* Presence setting */ /* We don't want to change Purple's setting because it applies to all accounts */ } /* End of switch on curitem->type */ /*** End code for adding from server list to local list ***/ oscar_set_icq_permdeny ( account ); oscar_set_aim_permdeny ( gc ); /* Sending the enable causes other people to be able to see you, and you to see them */ /* Make sure your privacy setting/invisibility is set how you want it before this! */ purple_debug_info ( "oscar" , "ssi: activating server-stored buddy list \n " ); * Make sure our server-stored icon is updated correctly in * the event that the local user set a new icon while this img = purple_buddy_icons_find_account_icon ( account ); purple_imgstore_unref ( img ); * If we've already received our bos rights then we're not waiting on * anything else, so send the server clientready. if ( od -> bos . have_rights ) { aim_srv_clientready ( od , conn ); /* Request offline messages for AIM and ICQ */ aim_im_reqofflinemsgs ( od ); purple_connection_set_state ( gc , PURPLE_CONNECTED ); static int purple_ssi_parseack ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; struct aim_ssi_tmp * retval ; retval = va_arg ( ap , struct aim_ssi_tmp * ); purple_debug_misc ( "oscar" , "ssi: status is 0x%04hx for a 0x%04hx action with name %s \n " , retval -> ack , retval -> action , retval -> item ? ( retval -> item -> name ? retval -> item -> name : "no name" ) : "no item" ); if ( retval -> ack != 0xffff ) case 0x0000 : { /* added successfully */ case 0x000c : { /* you are over the limit, the cheat is to the limit, come on fhqwhgads */ buf = g_strdup_printf ( _ ( "Unable to add the buddy %s because you have too many buddies in your buddy list. Please remove one and try again." ), ( retval -> name ? retval -> name : _ ( "(no name)" ))); if (( retval -> name != NULL ) && ! purple_conv_present_error ( retval -> name , purple_connection_get_account ( gc ), buf )) purple_notify_error ( gc , NULL , _ ( "Unable to Add" ), buf ); case 0x000e : { /* buddy requires authorization */ if (( retval -> action == SNAC_SUBTYPE_FEEDBAG_ADD ) && ( retval -> name )) oscar_auth_sendrequest ( gc , retval -> name , NULL ); default : { /* La la la */ purple_debug_error ( "oscar" , "ssi: Action 0x%04hx was unsuccessful with error 0x%04hx \n " , retval -> action , retval -> ack ); buf = g_strdup_printf ( _ ( "Unable to add the buddy %s for an unknown reason." ), ( retval -> name ? retval -> name : _ ( "(no name)" ))); if (( retval -> name != NULL ) && ! purple_conv_present_error ( retval -> name , purple_connection_get_account ( gc ), buf )) purple_notify_error ( gc , NULL , _ ( "Unable to Add" ), buf ); purple_ssi_parseaddmod ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) char * gname , * gname_utf8 , * alias , * alias_utf8 ; struct aim_ssi_item * ssi_item ; guint16 snac_subtype , type ; account = purple_connection_get_account ( gc ); snac_subtype = ( guint16 ) va_arg ( ap , int ); type = ( guint16 ) va_arg ( ap , int ); name = va_arg ( ap , char * ); if (( type != 0x0000 ) || ( name == NULL )) gname = aim_ssi_itemlist_findparentname ( od -> ssi . local , name ); gname_utf8 = gname ? oscar_utf8_try_convert ( account , od , gname ) : NULL ; alias = aim_ssi_getalias ( od -> ssi . local , gname , name ); alias_utf8 = oscar_utf8_try_convert ( account , od , alias ); b = purple_find_buddy ( account , name ); * You're logged in somewhere else and you aliased one * of your buddies, so update our local buddy list with * the person's new alias. purple_blist_alias_buddy ( b , alias_utf8 ); } else if ( snac_subtype == 0x0008 ) { * You're logged in somewhere else and you added a buddy to * your server list, so add them to your local buddy list. b = purple_buddy_new ( account , name , alias_utf8 ); if ( ! ( g = purple_find_group ( gname_utf8 ? gname_utf8 : _ ( "Orphans" )))) { g = purple_group_new ( gname_utf8 ? gname_utf8 : _ ( "Orphans" )); purple_blist_add_group ( g , NULL ); purple_debug_info ( "oscar" , "ssi: adding buddy %s to group %s to local list \n " , name , gname_utf8 ? gname_utf8 : _ ( "Orphans" )); purple_blist_add_buddy ( b , NULL , g , NULL ); /* Mobile users should always be online */ purple_prpl_got_user_status ( account , name , OSCAR_STATUS_ID_AVAILABLE , NULL ); purple_prpl_got_user_status ( account , name , OSCAR_STATUS_ID_MOBILE , NULL ); ssi_item = aim_ssi_itemlist_finditem ( od -> ssi . local , gname , name , AIM_SSI_TYPE_BUDDY ); purple_debug_error ( "oscar" , "purple_ssi_parseaddmod: " "Could not find ssi item for oncoming buddy %s, " "group %s \n " , name , gname ); static int purple_ssi_authgiven ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; gchar * dialog_msg , * nombre ; msg = va_arg ( ap , char * ); purple_debug_info ( "oscar" , "ssi: %s has given you permission to add him to your buddy list \n " , bn ); buddy = purple_find_buddy ( purple_connection_get_account ( gc ), bn ); if ( buddy && ( purple_buddy_get_alias_only ( buddy ))) nombre = g_strdup_printf ( "%s (%s)" , bn , purple_buddy_get_alias_only ( buddy )); dialog_msg = g_strdup_printf ( _ ( "The user %s has given you permission to add him or her to your buddy list. Do you want to add this user?" ), nombre ); data = g_new ( struct name_data , 1 ); data -> name = g_strdup ( bn ); data -> nick = ( buddy ? g_strdup ( purple_buddy_get_alias_only ( buddy )) : NULL ); purple_request_yes_no ( gc , NULL , _ ( "Authorization Given" ), dialog_msg , PURPLE_DEFAULT_ACTION_NONE , purple_connection_get_account ( gc ), bn , NULL , G_CALLBACK ( purple_icq_buddyadd ), G_CALLBACK ( oscar_free_name_data )); static int purple_ssi_authrequest ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) bn = va_arg ( ap , const char * ); msg = va_arg ( ap , char * ); purple_debug_info ( "oscar" , "ssi: received authorization request from %s \n " , bn ); purple_debug_warning ( "oscar" , "Received auth request from %s with " } else if ( ! g_utf8_validate ( msg , -1 , NULL )) { purple_debug_warning ( "oscar" , "Received auth request from %s with " "invalid UTF-8 message \n " , bn ); aim_icq_getalias ( od , bn , TRUE , msg ); static int purple_ssi_authreply ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; gchar * dialog_msg , * nombre ; reply = ( guint8 ) va_arg ( ap , int ); msg = va_arg ( ap , char * ); purple_debug_info ( "oscar" , "ssi: received authorization reply from %s. Reply is 0x%04hhx \n " , bn , reply ); buddy = purple_find_buddy ( purple_connection_get_account ( gc ), bn ); if ( buddy && ( purple_buddy_get_alias_only ( buddy ))) nombre = g_strdup_printf ( "%s (%s)" , bn , purple_buddy_get_alias_only ( buddy )); dialog_msg = g_strdup_printf ( _ ( "The user %s has granted your request to add them to your buddy list." ), nombre ); purple_notify_info ( gc , NULL , _ ( "Authorization Granted" ), dialog_msg ); dialog_msg = g_strdup_printf ( _ ( "The user %s has denied your request to add them to your buddy list for the following reason: \n %s" ), nombre , msg ? msg : _ ( "No reason given." )); purple_notify_info ( gc , NULL , _ ( "Authorization Denied" ), dialog_msg ); static int purple_ssi_gotadded ( OscarData * od , FlapConnection * conn , FlapFrame * fr , ...) { PurpleConnection * gc = od -> gc ; PurpleAccount * account = purple_connection_get_account ( gc ); buddy = purple_find_buddy ( account , bn ); purple_debug_info ( "oscar" , "ssi: %s added you to their buddy list \n " , bn ); purple_account_notify_added ( account , bn , NULL , ( buddy ? purple_buddy_get_alias_only ( buddy ) : NULL ), NULL ); GList * oscar_chat_info ( PurpleConnection * gc ) { struct proto_chat_entry * pce ; pce = g_new0 ( struct proto_chat_entry , 1 ); pce -> label = _ ( "_Room:" ); pce -> identifier = "room" ; m = g_list_append ( m , pce ); pce = g_new0 ( struct proto_chat_entry , 1 ); pce -> label = _ ( "_Exchange:" ); pce -> identifier = "exchange" ; m = g_list_append ( m , pce ); GHashTable * oscar_chat_info_defaults ( PurpleConnection * gc , const char * chat_name ) defaults = g_hash_table_new_full ( g_str_hash , g_str_equal , NULL , g_free ); g_hash_table_insert ( defaults , "room" , g_strdup ( chat_name )); g_hash_table_insert ( defaults , "exchange" , g_strdup ( "4" )); oscar_get_chat_name ( GHashTable * data ) return g_strdup ( g_hash_table_lookup ( data , "room" )); oscar_join_chat ( PurpleConnection * gc , GHashTable * data ) OscarData * od = purple_connection_get_protocol_data ( gc ); name = g_hash_table_lookup ( data , "room" ); exchange = g_hash_table_lookup ( data , "exchange" ); g_return_if_fail ( name != NULL && * name != '\0' ); g_return_if_fail ( exchange != NULL ); exchange_int = strtol ( exchange , NULL , 10 ); g_return_if_fail ( errno == 0 ); purple_debug_info ( "oscar" , "Attempting to join chat room %s. \n " , name ); if (( conn = flap_connection_getbytype ( od , SNAC_FAMILY_CHATNAV ))) purple_debug_info ( "oscar" , "chatnav exists, creating room \n " ); aim_chatnav_createroom ( od , conn , name , exchange_int ); struct create_room * cr = g_new0 ( struct create_room , 1 ); purple_debug_info ( "oscar" , "chatnav does not exist, opening chatnav \n " ); cr -> exchange = exchange_int ; cr -> name = g_strdup ( name ); od -> create_rooms = g_slist_prepend ( od -> create_rooms , cr ); aim_srv_requestnew ( od , SNAC_FAMILY_CHATNAV ); oscar_chat_invite ( PurpleConnection * gc , int id , const char * message , const char * name ) OscarData * od = purple_connection_get_protocol_data ( gc ); struct chat_connection * ccon = find_oscar_chat ( gc , id ); aim_im_sendch2_chatinvite ( od , name , message ? message : "" , ccon -> exchange , ccon -> name , 0x0 ); oscar_chat_leave ( PurpleConnection * gc , int id ) PurpleConversation * conv ; struct chat_connection * cc ; conv = purple_find_chat ( gc , id ); g_return_if_fail ( conv != NULL ); purple_debug_info ( "oscar" , "Leaving chat room %s \n " , purple_conversation_get_name ( conv )); cc = find_oscar_chat ( gc , purple_conv_chat_get_id ( PURPLE_CONV_CHAT ( conv ))); flap_connection_schedule_destroy ( cc -> conn , OSCAR_DISCONNECT_DONE , NULL ); int oscar_send_chat ( PurpleConnection * gc , int id , const char * message , PurpleMessageFlags flags ) OscarData * od = purple_connection_get_protocol_data ( gc ); PurpleConversation * conv = NULL ; struct chat_connection * c = NULL ; if ( ! ( conv = purple_find_chat ( gc , id ))) if ( ! ( c = find_oscar_chat_by_conv ( gc , conv ))) buf = purple_strdup_withhtml ( message ); if ( strstr ( buf , "<IMG " )) purple_conversation_write ( conv , "" , _ ( "Your IM Image was not sent. " "You cannot send IM Images in AIM chats." ), PURPLE_MESSAGE_ERROR , time ( NULL )); buf2 = oscar_encode_im ( buf , & len , & charset , & charsetstr ); * Evan S. suggested that maxvis really does mean "number of * visible characters" and not "number of bytes" if (( len > c -> maxlen ) || ( len > c -> maxvis )) { /* If the length was too long, try stripping the HTML and then running it back through * purple_strdup_withhtml() and the encoding process. The result may be shorter. */ buf3 = purple_markup_strip_html ( buf ); buf = purple_strdup_withhtml ( buf3 ); buf2 = oscar_encode_im ( buf , & len , & charset , & charsetstr ); if (( len > c -> maxlen ) || ( len > c -> maxvis )) { purple_debug_warning ( "oscar" , "Could not send %s because (%" G_GSIZE_FORMAT " > maxlen %i) or (%" G_GSIZE_FORMAT " > maxvis %i) \n " , buf2 , len , c -> maxlen , len , c -> maxvis ); purple_debug_info ( "oscar" , "Sending %s as %s because the original was too long. \n " , aim_chat_send_im ( od , c -> conn , 0 , buf2 , len , charsetstr , "en" ); PurpleMood * oscar_get_purple_moods ( PurpleAccount * account ) return icq_get_purple_moods ( account ); const char * oscar_list_icon_icq ( PurpleAccount * a , PurpleBuddy * b ) const char * name = b ? purple_buddy_get_name ( b ) : NULL ; if ( name && ! oscar_util_valid_name_sms ( name ) && oscar_util_valid_name_icq ( name )) const char * oscar_list_icon_aim ( PurpleAccount * a , PurpleBuddy * b ) const char * name = b ? purple_buddy_get_name ( b ) : NULL ; if ( name && ! oscar_util_valid_name_sms ( name ) && oscar_util_valid_name_icq ( name )) const char * oscar_list_emblem ( PurpleBuddy * b ) PurpleConnection * gc = NULL ; PurpleAccount * account = NULL ; PurplePresence * presence ; aim_userinfo_t * userinfo = NULL ; account = purple_buddy_get_account ( b ); name = purple_buddy_get_name ( b ); gc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( gc ); userinfo = aim_locate_finduserinfo ( od , name ); presence = purple_buddy_get_presence ( b ); if ( purple_presence_is_online ( presence ) == FALSE ) { if (( name ) && ( od ) && ( od -> ssi . received_data ) && ( gname = aim_ssi_itemlist_findparentname ( od -> ssi . local , name )) && ( aim_ssi_waitingforauth ( od -> ssi . local , gname , name ))) { if ( userinfo -> flags & AIM_FLAG_ADMINISTRATOR ) if ( userinfo -> flags & AIM_FLAG_ACTIVEBUDDY ) if ( userinfo -> capabilities & OSCAR_CAPABILITY_SECUREIM ) if ( userinfo -> icqinfo . status & AIM_ICQ_STATE_BIRTHDAY ) /* Make the mood icon override anything below this. */ if ( purple_presence_is_status_primitive_active ( presence , PURPLE_STATUS_MOOD )) if ( userinfo -> capabilities & OSCAR_CAPABILITY_HIPTOP ) void oscar_tooltip_text ( PurpleBuddy * b , PurpleNotifyUserInfo * user_info , gboolean full ) aim_userinfo_t * userinfo ; if ( ! PURPLE_BUDDY_IS_ONLINE ( b )) account = purple_buddy_get_account ( b ); gc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( gc ); userinfo = aim_locate_finduserinfo ( od , purple_buddy_get_name ( b )); oscar_user_info_append_status ( gc , user_info , b , userinfo , /* use_html_status */ FALSE ); oscar_user_info_append_extra_info ( gc , user_info , b , userinfo ); char * oscar_status_text ( PurpleBuddy * b ) const PurplePresence * presence ; const PurpleStatus * status ; gc = purple_account_get_connection ( purple_buddy_get_account ( b )); account = purple_connection_get_account ( gc ); od = purple_connection_get_protocol_data ( gc ); presence = purple_buddy_get_presence ( b ); status = purple_presence_get_active_status ( presence ); if (( od != NULL ) && ! purple_presence_is_online ( presence )) const char * name = purple_buddy_get_name ( b ); char * gname = aim_ssi_itemlist_findparentname ( od -> ssi . local , name ); if ( aim_ssi_waitingforauth ( od -> ssi . local , gname , name )) ret = g_strdup ( _ ( "Not Authorized" )); ret = g_strdup ( _ ( "Offline" )); message = purple_status_get_attr_string ( status , "message" ); gchar * tmp = oscar_util_format_string ( message , purple_account_get_username ( account )); ret = purple_markup_escape_text ( tmp , -1 ); else if ( purple_status_is_available ( status )) /* Don't show "Available" as status message in case buddy doesn't have a status message */ ret = g_strdup ( purple_status_get_name ( status )); void oscar_set_aim_permdeny ( PurpleConnection * gc ) { PurpleAccount * account = purple_connection_get_account ( gc ); OscarData * od = purple_connection_get_protocol_data ( gc ); * Conveniently there is a one-to-one mapping between the * values of libpurple's PurplePrivacyType and the values used aim_ssi_setpermdeny ( od , account -> perm_deny ); void oscar_add_permit ( PurpleConnection * gc , const char * who ) { OscarData * od = purple_connection_get_protocol_data ( gc ); purple_debug_info ( "oscar" , "ssi: About to add a permit \n " ); aim_ssi_add_to_private_list ( od , who , AIM_SSI_TYPE_PERMIT ); void oscar_add_deny ( PurpleConnection * gc , const char * who ) { OscarData * od = purple_connection_get_protocol_data ( gc ); purple_debug_info ( "oscar" , "ssi: About to add a deny \n " ); aim_ssi_add_to_private_list ( od , who , aim_ssi_getdenyentrytype ( od )); void oscar_rem_permit ( PurpleConnection * gc , const char * who ) { OscarData * od = purple_connection_get_protocol_data ( gc ); purple_debug_info ( "oscar" , "ssi: About to delete a permit \n " ); aim_ssi_del_from_private_list ( od , who , AIM_SSI_TYPE_PERMIT ); void oscar_rem_deny ( PurpleConnection * gc , const char * who ) { OscarData * od = purple_connection_get_protocol_data ( gc ); purple_debug_info ( "oscar" , "ssi: About to delete a deny \n " ); aim_ssi_del_from_private_list ( od , who , aim_ssi_getdenyentrytype ( od )); oscar_status_types ( PurpleAccount * account ) GList * status_types = NULL ; g_return_val_if_fail ( account != NULL , NULL ); /* Used to flag some statuses as "user settable" or not */ is_icq = oscar_util_valid_name_icq ( purple_account_get_username ( account )); /* Common status types */ /* Really the available message should only be settable for AIM accounts */ type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , OSCAR_STATUS_ID_AVAILABLE , purple_value_new ( PURPLE_TYPE_STRING ), "itmsurl" , _ ( "iTunes Music Store Link" ), purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , OSCAR_STATUS_ID_FREE4CHAT , _ ( "Free For Chat" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , _ ( "Evil" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , OSCAR_STATUS_ID_DEPRESSION , _ ( "Depression" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , _ ( "At home" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , _ ( "At work" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AVAILABLE , _ ( "Lunch" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_AWAY , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_INVISIBLE , OSCAR_STATUS_ID_INVISIBLE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_full ( PURPLE_STATUS_MOBILE , OSCAR_STATUS_ID_MOBILE , NULL , FALSE , FALSE , TRUE ); status_types = g_list_prepend ( status_types , type ); /* ICQ-specific status types */ type = purple_status_type_new_with_attrs ( PURPLE_STATUS_UNAVAILABLE , OSCAR_STATUS_ID_OCCUPIED , _ ( "Occupied" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_UNAVAILABLE , _ ( "Do Not Disturb" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_EXTENDED_AWAY , _ ( "Not Available" ), TRUE , is_icq , FALSE , purple_value_new ( PURPLE_TYPE_STRING ), NULL ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_full ( PURPLE_STATUS_OFFLINE , NULL , TRUE , TRUE , FALSE ); status_types = g_list_prepend ( status_types , type ); type = purple_status_type_new_with_attrs ( PURPLE_STATUS_MOOD , "mood" , NULL , TRUE , is_icq , TRUE , PURPLE_MOOD_NAME , _ ( "Mood Name" ), purple_value_new ( PURPLE_TYPE_STRING ), PURPLE_MOOD_COMMENT , _ ( "Mood Comment" ), purple_value_new ( PURPLE_TYPE_STRING ), status_types = g_list_prepend ( status_types , type ); return g_list_reverse ( status_types ); static void oscar_ssi_editcomment ( struct name_data * data , const char * text ) { od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); b = purple_find_buddy ( account , data -> name ); oscar_free_name_data ( data ); g = purple_buddy_get_group ( b ); oscar_free_name_data ( data ); aim_ssi_editcomment ( od , purple_group_get_name ( g ), data -> name , text ); oscar_free_name_data ( data ); static void oscar_buddycb_edit_comment ( PurpleBlistNode * node , gpointer ignore ) { g_return_if_fail ( PURPLE_BLIST_NODE_IS_BUDDY ( node )); buddy = ( PurpleBuddy * ) node ; name = purple_buddy_get_name ( buddy ); account = purple_buddy_get_account ( buddy ); gc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( gc ); if ( ! ( g = purple_buddy_get_group ( buddy ))) data = g_new ( struct name_data , 1 ); comment = aim_ssi_getcomment ( od -> ssi . local , purple_group_get_name ( g ), name ); comment_utf8 = comment ? oscar_utf8_try_convert ( account , od , comment ) : NULL ; data -> name = g_strdup ( name ); data -> nick = g_strdup ( purple_buddy_get_alias_only ( buddy )); title = g_strdup_printf ( _ ( "Buddy Comment for %s" ), data -> name ); purple_request_input ( gc , title , _ ( "Buddy Comment:" ), NULL , comment_utf8 , TRUE , FALSE , NULL , _ ( "_OK" ), G_CALLBACK ( oscar_ssi_editcomment ), _ ( "_Cancel" ), G_CALLBACK ( oscar_free_name_data ), account , data -> name , NULL , oscar_ask_directim_yes_cb ( struct oscar_ask_directim_data * data ) peer_connection_propose ( data -> od , OSCAR_CAPABILITY_DIRECTIM , data -> who ); oscar_ask_directim_no_cb ( struct oscar_ask_directim_data * data ) /* This is called from right-click menu on a buddy node. */ oscar_ask_directim ( gpointer object , gpointer ignored ) struct oscar_ask_directim_data * data ; g_return_if_fail ( PURPLE_BLIST_NODE_IS_BUDDY ( node )); buddy = ( PurpleBuddy * ) node ; account = purple_buddy_get_account ( buddy ); gc = purple_account_get_connection ( account ); data = g_new0 ( struct oscar_ask_directim_data , 1 ); data -> who = g_strdup ( purple_buddy_get_name ( buddy )); data -> od = purple_connection_get_protocol_data ( gc ); buf = g_strdup_printf ( _ ( "You have selected to open a Direct IM connection with %s." ), purple_request_action ( gc , NULL , buf , _ ( "Because this reveals your IP address, it " "may be considered a security risk. Do you " 0 , /* Default action is "connect" */ account , data -> who , NULL , _ ( "C_onnect" ), G_CALLBACK ( oscar_ask_directim_yes_cb ), _ ( "_Cancel" ), G_CALLBACK ( oscar_ask_directim_no_cb )); oscar_close_directim ( gpointer object , gpointer ignored ) PurpleConversation * conv ; g_return_if_fail ( PURPLE_BLIST_NODE_IS_BUDDY ( node )); buddy = ( PurpleBuddy * ) node ; name = purple_buddy_get_name ( buddy ); account = purple_buddy_get_account ( buddy ); gc = purple_account_get_connection ( account ); conn = peer_connection_find_by_type ( od , name , OSCAR_CAPABILITY_DIRECTIM ); aim_im_sendch2_cancel ( conn ); peer_connection_destroy ( conn , OSCAR_DISCONNECT_LOCAL_CLOSED , NULL ); /* OSCAR_DISCONNECT_LOCAL_CLOSED doesn't write anything to the convo * window. Let the user know that we cancelled the Direct IM. */ conv = purple_conversation_new ( PURPLE_CONV_TYPE_IM , account , name ); purple_conversation_write ( conv , NULL , _ ( "You closed the connection." ), PURPLE_MESSAGE_SYSTEM , time ( NULL )); static void oscar_get_icqxstatusmsg ( PurpleBlistNode * node , gpointer ignore ) g_return_if_fail ( PURPLE_BLIST_NODE_IS_BUDDY ( node )); buddy = ( PurpleBuddy * ) node ; bname = purple_buddy_get_name ( buddy ); account = purple_buddy_get_account ( buddy ); gc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( gc ); purple_debug_info ( "oscar" , "Manual X-Status Get From %s to %s: \n " , bname , purple_account_get_username ( account )); icq_im_xstatus_request ( od , bname ); oscar_get_aim_info_cb ( PurpleBlistNode * node , gpointer ignore ) g_return_if_fail ( PURPLE_BLIST_NODE_IS_BUDDY ( node )); buddy = ( PurpleBuddy * ) node ; gc = purple_account_get_connection ( purple_buddy_get_account ( buddy )); aim_locate_getinfoshort ( purple_connection_get_protocol_data ( gc ), purple_buddy_get_name ( buddy ), 0x00000003 ); oscar_buddy_menu ( PurpleBuddy * buddy ) { aim_userinfo_t * userinfo ; const char * bname = purple_buddy_get_name ( buddy ); account = purple_buddy_get_account ( buddy ); gc = purple_account_get_connection ( account ); od = purple_connection_get_protocol_data ( gc ); userinfo = aim_locate_finduserinfo ( od , bname ); if ( od -> icq && oscar_util_valid_name_icq ( bname )) act = purple_menu_action_new ( _ ( "Get AIM Info" ), PURPLE_CALLBACK ( oscar_get_aim_info_cb ), menu = g_list_prepend ( menu , act ); if ( purple_buddy_get_group ( buddy ) != NULL ) /* We only do this if the user is in our buddy list */ act = purple_menu_action_new ( _ ( "Edit Buddy Comment" ), PURPLE_CALLBACK ( oscar_buddycb_edit_comment ), menu = g_list_prepend ( menu , act ); act = purple_menu_action_new ( _ ( "Get X-Status Msg" ), PURPLE_CALLBACK ( oscar_get_icqxstatusmsg ), menu = g_list_prepend ( menu , act ); menu = g_list_prepend ( menu , create_visibility_menu_item ( od , bname )); oscar_util_name_compare ( purple_account_get_username ( account ), bname ) && PURPLE_BUDDY_IS_ONLINE ( buddy )) conn = peer_connection_find_by_type ( od , bname , OSCAR_CAPABILITY_DIRECTIM ); if ( userinfo -> capabilities & OSCAR_CAPABILITY_DIRECTIM ) act = purple_menu_action_new ( _ ( "End Direct IM Session" ), PURPLE_CALLBACK ( oscar_close_directim ), act = purple_menu_action_new ( _ ( "Direct IM" ), PURPLE_CALLBACK ( oscar_ask_directim ), menu = g_list_prepend ( menu , act ); if ( od -> ssi . received_data && purple_buddy_get_group ( buddy ) != NULL ) * We only do this if the user is in our buddy list and we're * waiting for authorization. gname = aim_ssi_itemlist_findparentname ( od -> ssi . local , bname ); if ( gname && aim_ssi_waitingforauth ( od -> ssi . local , gname , bname )) act = purple_menu_action_new ( _ ( "Re-request Authorization" ), PURPLE_CALLBACK ( oscar_auth_sendrequest_menu ), menu = g_list_prepend ( menu , act ); menu = g_list_reverse ( menu ); GList * oscar_blist_node_menu ( PurpleBlistNode * node ) { if ( PURPLE_BLIST_NODE_IS_BUDDY ( node )) { return oscar_buddy_menu (( PurpleBuddy * ) node ); oscar_icq_privacy_opts ( PurpleConnection * gc , PurpleRequestFields * fields ) OscarData * od = purple_connection_get_protocol_data ( gc ); PurpleAccount * account = purple_connection_get_account ( gc ); gboolean auth , web_aware ; f = purple_request_fields_get_field ( fields , "authorization" ); auth = purple_request_field_bool_get_value ( f ); f = purple_request_fields_get_field ( fields , "web_aware" ); web_aware = purple_request_field_bool_get_value ( f ); purple_account_set_bool ( account , "authorization" , auth ); purple_account_set_bool ( account , "web_aware" , web_aware ); oscar_set_extended_status ( gc ); aim_icq_setsecurity ( od , auth , web_aware ); oscar_show_icq_privacy_opts ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; PurpleAccount * account = purple_connection_get_account ( gc ); PurpleRequestFields * fields ; PurpleRequestFieldGroup * g ; gboolean auth , web_aware ; auth = purple_account_get_bool ( account , "authorization" , OSCAR_DEFAULT_AUTHORIZATION ); web_aware = purple_account_get_bool ( account , "web_aware" , OSCAR_DEFAULT_WEB_AWARE ); fields = purple_request_fields_new (); g = purple_request_field_group_new ( NULL ); f = purple_request_field_bool_new ( "authorization" , _ ( "Require authorization" ), auth ); purple_request_field_group_add_field ( g , f ); f = purple_request_field_bool_new ( "web_aware" , _ ( "Web aware (enabling this will cause you to receive SPAM!)" ), web_aware ); purple_request_field_group_add_field ( g , f ); purple_request_fields_add_group ( fields , g ); purple_request_fields ( gc , _ ( "ICQ Privacy Options" ), _ ( "ICQ Privacy Options" ), _ ( "OK" ), G_CALLBACK ( oscar_icq_privacy_opts ), purple_connection_get_account ( gc ), NULL , NULL , static void oscar_confirm_account ( PurplePluginAction * action ) gc = ( PurpleConnection * ) action -> context ; od = purple_connection_get_protocol_data ( gc ); conn = flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN ); aim_admin_reqconfirm ( od , conn ); aim_srv_requestnew ( od , SNAC_FAMILY_ADMIN ); static void oscar_show_email ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; OscarData * od = purple_connection_get_protocol_data ( gc ); FlapConnection * conn = flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN ); aim_admin_getinfo ( od , conn , 0x11 ); aim_srv_requestnew ( od , SNAC_FAMILY_ADMIN ); static void oscar_change_email ( PurpleConnection * gc , const char * email ) OscarData * od = purple_connection_get_protocol_data ( gc ); FlapConnection * conn = flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN ); aim_admin_setemail ( od , conn , email ); od -> email = g_strdup ( email ); aim_srv_requestnew ( od , SNAC_FAMILY_ADMIN ); static void oscar_show_change_email ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_request_input ( gc , NULL , _ ( "Change Address To:" ), NULL , NULL , _ ( "_OK" ), G_CALLBACK ( oscar_change_email ), purple_connection_get_account ( gc ), NULL , NULL , static void oscar_show_awaitingauth ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; OscarData * od = purple_connection_get_protocol_data ( gc ); PurpleAccount * account = purple_connection_get_account ( gc ); GSList * buddies , * filtered_buddies , * cur ; buddies = purple_find_buddies ( account , NULL ); for ( cur = buddies ; cur != NULL ; cur = cur -> next ) { const gchar * bname , * gname ; bname = purple_buddy_get_name ( buddy ); gname = purple_group_get_name ( purple_buddy_get_group ( buddy )); if ( aim_ssi_waitingforauth ( od -> ssi . local , gname , bname )) { filtered_buddies = g_slist_prepend ( filtered_buddies , buddy ); filtered_buddies = g_slist_reverse ( filtered_buddies ); text = oscar_format_buddies ( filtered_buddies , _ ( "you are not waiting for authorization" )); g_slist_free ( filtered_buddies ); purple_notify_formatted ( gc , NULL , _ ( "You are awaiting authorization from " "the following buddies" ), _ ( "You can re-request " "authorization from these buddies by " "right-clicking on them and selecting " " \" Re-request Authorization. \" " ), text , NULL , NULL ); static void search_by_email_cb ( PurpleConnection * gc , const char * email ) OscarData * od = purple_connection_get_protocol_data ( gc ); aim_search_address ( od , email ); static void oscar_show_find_email ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_request_input ( gc , _ ( "Find Buddy by Email" ), _ ( "Search for a buddy by email address" ), _ ( "Type the email address of the buddy you are " NULL , FALSE , FALSE , NULL , _ ( "_Search" ), G_CALLBACK ( search_by_email_cb ), purple_connection_get_account ( gc ), NULL , NULL , static void oscar_show_set_info ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_account_request_change_user_info ( purple_connection_get_account ( gc )); static void oscar_show_set_info_icqurl ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_notify_uri ( gc , "http://www.icq.com/whitepages/user_details.php" ); static void oscar_change_pass ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_account_request_change_password ( purple_connection_get_account ( gc )); * Only used when connecting with the old-style BUCP login. static void oscar_show_chpassurl ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; OscarData * od = purple_connection_get_protocol_data ( gc ); gchar * substituted = purple_strreplace ( od -> authinfo -> chpassurl , "%s" , purple_account_get_username ( purple_connection_get_account ( gc ))); purple_notify_uri ( gc , substituted ); static void oscar_show_imforwardingurl ( PurplePluginAction * action ) PurpleConnection * gc = ( PurpleConnection * ) action -> context ; purple_notify_uri ( gc , "http://mymobile.aol.com/dbreg/register?action=imf&clientID=1" ); void oscar_set_icon ( PurpleConnection * gc , PurpleStoredImage * img ) OscarData * od = purple_connection_get_protocol_data ( gc ); PurpleCipherContext * context ; gconstpointer data = purple_imgstore_get_data ( img ); size_t len = purple_imgstore_get_size ( img ); context = purple_cipher_context_new_by_name ( "md5" , NULL ); purple_cipher_context_append ( context , data , len ); purple_cipher_context_digest ( context , 16 , md5 , NULL ); purple_cipher_context_destroy ( context ); aim_ssi_seticon ( od , md5 , 16 ); * Called by the Purple core to determine whether or not we're * allowed to send a file to this user. oscar_can_receive_file ( PurpleConnection * gc , const char * who ) od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); aim_userinfo_t * userinfo ; userinfo = aim_locate_finduserinfo ( od , who ); * Don't allowing sending a file to a user that does not support * file transfer, and don't allow sending to ourselves. if ((( userinfo == NULL ) || ( userinfo -> capabilities & OSCAR_CAPABILITY_SENDFILE )) && oscar_util_name_compare ( who , purple_account_get_username ( account ))) oscar_new_xfer ( PurpleConnection * gc , const char * who ) od = purple_connection_get_protocol_data ( gc ); account = purple_connection_get_account ( gc ); xfer = purple_xfer_new ( account , PURPLE_XFER_SEND , who ); purple_xfer_set_init_fnc ( xfer , peer_oft_sendcb_init ); purple_xfer_set_cancel_send_fnc ( xfer , peer_oft_cb_generic_cancel ); purple_xfer_set_request_denied_fnc ( xfer , peer_oft_cb_generic_cancel ); purple_xfer_set_ack_fnc ( xfer , peer_oft_sendcb_ack ); conn = peer_connection_new ( od , OSCAR_CAPABILITY_SENDFILE , who ); conn -> flags |= PEER_CONNECTION_FLAG_INITIATED_BY_ME ; conn -> flags |= PEER_CONNECTION_FLAG_APPROVED ; aim_icbm_makecookie ( conn -> cookie ); * Called by the Purple core when the user indicates that a * file is to be sent to a special someone. oscar_send_file ( PurpleConnection * gc , const char * who , const char * file ) xfer = oscar_new_xfer ( gc , who ); purple_xfer_request_accepted ( xfer , file ); purple_xfer_request ( xfer ); oscar_actions ( PurplePlugin * plugin , gpointer context ) PurpleConnection * gc = ( PurpleConnection * ) context ; OscarData * od = purple_connection_get_protocol_data ( gc ); act = purple_plugin_action_new ( _ ( "Set User Info..." ), menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Set User Info (web)..." ), oscar_show_set_info_icqurl ); menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Change Password..." ), menu = g_list_prepend ( menu , act ); if ( od -> authinfo != NULL && od -> authinfo -> chpassurl != NULL ) /* This only happens when connecting with the old-style BUCP login */ act = purple_plugin_action_new ( _ ( "Change Password (web)" ), menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Configure IM Forwarding (web)" ), oscar_show_imforwardingurl ); menu = g_list_prepend ( menu , act ); menu = g_list_prepend ( menu , NULL ); act = purple_plugin_action_new ( _ ( "Set Privacy Options..." ), oscar_show_icq_privacy_opts ); menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Show Visible List" ), oscar_show_visible_list ); menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Show Invisible List" ), oscar_show_invisible_list ); menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Confirm Account" ), menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Display Currently Registered Email Address" ), menu = g_list_prepend ( menu , act ); act = purple_plugin_action_new ( _ ( "Change Currently Registered Email Address..." ), oscar_show_change_email ); menu = g_list_prepend ( menu , act ); menu = g_list_prepend ( menu , NULL ); act = purple_plugin_action_new ( _ ( "Show Buddies Awaiting Authorization" ), oscar_show_awaitingauth ); menu = g_list_prepend ( menu , act ); menu = g_list_prepend ( menu , NULL ); act = purple_plugin_action_new ( _ ( "Search for Buddy by Email Address..." ), menu = g_list_prepend ( menu , act ); menu = g_list_reverse ( menu ); void oscar_change_passwd ( PurpleConnection * gc , const char * old , const char * new ) OscarData * od = purple_connection_get_protocol_data ( gc ); aim_icq_changepasswd ( od , new ); conn = flap_connection_getbytype ( od , SNAC_FAMILY_ADMIN ); aim_admin_changepasswd ( od , conn , new , old ); od -> oldp = g_strdup ( old ); od -> newp = g_strdup ( new ); aim_srv_requestnew ( od , SNAC_FAMILY_ADMIN ); oscar_convo_closed ( PurpleConnection * gc , const char * who ) od = purple_connection_get_protocol_data ( gc ); conn = peer_connection_find_by_type ( od , who , OSCAR_CAPABILITY_DIRECTIM ); aim_im_sendch2_cancel ( conn ); peer_connection_destroy ( conn , OSCAR_DISCONNECT_LOCAL_CLOSED , NULL ); oscar_normalize ( const PurpleAccount * account , const char * str ) static char buf [ BUF_LEN ]; g_return_val_if_fail ( str != NULL , NULL ); /* copy str to buf and skip all blanks */ for ( j = 0 ; str [ j ]; j ++ ) { tmp1 = g_utf8_strdown ( buf , -1 ); tmp2 = g_utf8_normalize ( tmp1 , -1 , G_NORMALIZE_DEFAULT ); if ( strlen ( tmp2 ) > sizeof ( buf ) - 1 ) { purple_debug_error ( "oscar" , "normalized string exceeds buffer length! \n " ); g_strlcpy ( buf , tmp2 , sizeof ( buf )); oscar_offline_message ( const PurpleBuddy * buddy ) /* TODO: Find somewhere to put this instead of including it in a bunch of places. * Maybe just change purple_accounts_find() to return anything for the prpl if there is no acct_id. static PurpleAccount * find_acct ( const char * prpl , const char * acct_id ) PurpleAccount * acct = NULL ; /* If we have a specific acct, use it */ acct = purple_accounts_find ( acct_id , prpl ); if ( acct && ! purple_account_is_connected ( acct )) } else { /* Otherwise find an active account for the protocol */ GList * l = purple_accounts_get_all (); if ( ! strcmp ( prpl , purple_account_get_protocol_id ( l -> data )) && purple_account_is_connected ( l -> data )) { static gboolean oscar_uri_handler ( const char * proto , const char * cmd , GHashTable * params ) char * acct_id = g_hash_table_lookup ( params , "account" ); if ( g_ascii_strcasecmp ( proto , "aim" ) && g_ascii_strcasecmp ( proto , "icq" )) g_snprintf ( prpl , sizeof ( prpl ), "prpl-%s" , proto ); acct = find_acct ( prpl , acct_id ); /* aim:GoIM?screenname=SCREENNAME&message=MESSAGE */ if ( ! g_ascii_strcasecmp ( cmd , "GoIM" )) { char * bname = g_hash_table_lookup ( params , "screenname" ); char * message = g_hash_table_lookup ( params , "message" ); PurpleConversation * conv = purple_find_conversation_with_account ( PURPLE_CONV_TYPE_IM , bname , acct ); conv = purple_conversation_new ( PURPLE_CONV_TYPE_IM , acct , bname ); purple_conversation_present ( conv ); /* Spaces are encoded as '+' */ g_strdelimit ( message , "+" , ' ' ); purple_conv_send_confirm ( conv , message ); **If pidgindialogs_im() was in the core, we could use it here. * It is all purple_request_* based, but I'm not sure it really belongs in the core /* aim:GoChat?roomname=CHATROOMNAME&exchange=4 */ else if ( ! g_ascii_strcasecmp ( cmd , "GoChat" )) { char * rname = g_hash_table_lookup ( params , "roomname" ); /* This is somewhat hacky, but the params aren't useful after this command */ g_hash_table_insert ( params , g_strdup ( "exchange" ), g_strdup ( "4" )); g_hash_table_insert ( params , g_strdup ( "room" ), g_strdup ( rname )); serv_join_chat ( purple_account_get_connection ( acct ), params ); ** Same as above (except that this would have to be re-written using purple_request_*) pidgin_blist_joinchat_show(); */ /* aim:AddBuddy?screenname=SCREENNAME&groupname=GROUPNAME*/ else if ( ! g_ascii_strcasecmp ( cmd , "AddBuddy" )) { char * bname = g_hash_table_lookup ( params , "screenname" ); char * gname = g_hash_table_lookup ( params , "groupname" ); purple_blist_request_add_buddy ( acct , bname , gname , NULL ); void oscar_init ( PurplePlugin * plugin , gboolean is_icq ) PurplePluginProtocolInfo * prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO ( plugin ); PurpleAccountOption * option ; static gboolean init = FALSE ; static const gchar * encryption_keys [] = { N_ ( "Use encryption if available" ), N_ ( "Require encryption" ), N_ ( "Don't use encryption" ), static const gchar * encryption_values [] = { OSCAR_OPPORTUNISTIC_ENCRYPTION , OSCAR_REQUIRE_ENCRYPTION , GList * encryption_options = NULL ; option = purple_account_option_string_new ( _ ( "Server" ), "server" , get_login_server ( is_icq , TRUE )); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); option = purple_account_option_int_new ( _ ( "Port" ), "port" , OSCAR_DEFAULT_LOGIN_PORT ); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); for ( i = 0 ; encryption_keys [ i ]; i ++ ) { PurpleKeyValuePair * kvp = g_new0 ( PurpleKeyValuePair , 1 ); kvp -> key = g_strdup ( _ ( encryption_keys [ i ])); kvp -> value = g_strdup ( encryption_values [ i ]); encryption_options = g_list_append ( encryption_options , kvp ); option = purple_account_option_list_new ( _ ( "Connection security" ), "encryption" , encryption_options ); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); option = purple_account_option_bool_new ( _ ( "Use clientLogin" ), "use_clientlogin" , OSCAR_DEFAULT_USE_CLIENTLOGIN ); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); option = purple_account_option_bool_new ( _ ( "Always use AIM/ICQ proxy server for \n file transfers and direct IM (slower, \n but does not reveal your IP address)" ), "always_use_rv_proxy" , OSCAR_DEFAULT_ALWAYS_USE_RV_PROXY ); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); if ( g_str_equal ( purple_plugin_get_id ( plugin ), "prpl-aim" )) { option = purple_account_option_bool_new ( _ ( "Allow multiple simultaneous logins" ), "allow_multiple_logins" , OSCAR_DEFAULT_ALLOW_MULTIPLE_LOGINS ); prpl_info -> protocol_options = g_list_append ( prpl_info -> protocol_options , option ); purple_prefs_add_none ( "/plugins/prpl/oscar" ); purple_prefs_add_bool ( "/plugins/prpl/oscar/recent_buddies" , FALSE ); purple_prefs_remove ( "/plugins/prpl/oscar/show_idle" ); purple_prefs_remove ( "/plugins/prpl/oscar/always_use_rv_proxy" ); /* TODO: figure out a good instance to use here */ purple_signal_connect ( purple_get_core (), "uri-handler" , & init , PURPLE_CALLBACK ( oscar_uri_handler ), NULL );