/* Facebook plugin for Miranda Instant Messenger _____________________________________________ Copyright © 2009-11 Michal Zelinka 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, see . */ #include "common.h" void FacebookProto::ChangeStatus(void*) { ScopedLock s(signon_lock_); ScopedLock b(facy.buddies_lock_); int new_status = m_iDesiredStatus; int old_status = m_iStatus; if ( new_status == ID_STATUS_OFFLINE ) { // Logout LOG("##### Beginning SignOff process"); m_iStatus = facy.self_.status_id = ID_STATUS_OFFLINE; SetEvent(update_loop_lock_); Netlib_Shutdown(facy.hMsgCon); if ( getByte(FACEBOOK_KEY_DISCONNECT_CHAT, DEFAULT_DISCONNECT_CHAT)) facy.chat_state( false ); facy.logout( ); deleteSetting( "LogonTS" ); facy.clear_cookies( ); facy.buddies.clear( ); ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); OnLeaveChat(NULL, NULL); SetAllContactStatuses( ID_STATUS_OFFLINE, true ); ToggleStatusMenuItems(false); if (facy.hMsgCon) Netlib_CloseHandle(facy.hMsgCon); facy.hMsgCon = NULL; LOG("##### SignOff complete"); return; } else if ( old_status == ID_STATUS_OFFLINE ) { // Login SYSTEMTIME t; GetLocalTime( &t ); Log("[%d.%d.%d] Using Facebook Protocol RM %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING); LOG("***** Beginning SignOn process"); m_iStatus = facy.self_.status_id = ID_STATUS_CONNECTING; ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); ResetEvent(update_loop_lock_); if (NegotiateConnection() && facy.home()) { facy.reconnect(); facy.load_friends(); // Process Friends requests ForkThread( &FacebookProto::ProcessFriendRequests, this, NULL ); // Get unread messages ForkThread( &FacebookProto::ProcessUnreadMessages, this ); // Get notifications ForkThread( &FacebookProto::ProcessNotifications, this ); setDword( "LogonTS", (DWORD)time(NULL)); ForkThread( &FacebookProto::UpdateLoop, this ); ForkThread( &FacebookProto::MessageLoop, this ); if (getByte(FACEBOOK_KEY_SET_MIRANDA_STATUS, DEFAULT_SET_MIRANDA_STATUS)) { ForkThread(&FacebookProto::SetAwayMsgWorker, this, NULL); } } else { ProtoBroadcastAck(m_szModuleName,0,ACKTYPE_STATUS,ACKRESULT_FAILED, (HANDLE)old_status,m_iStatus); // Set to offline m_iStatus = m_iDesiredStatus = facy.self_.status_id = ID_STATUS_OFFLINE; ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); LOG("***** SignOn failed"); return; } ToggleStatusMenuItems(true); LOG("***** SignOn complete"); } else if ( new_status == ID_STATUS_INVISIBLE ) { facy.buddies.clear( ); this->SetAllContactStatuses( ID_STATUS_OFFLINE, true ); } facy.chat_state( m_iDesiredStatus != ID_STATUS_INVISIBLE ); facy.buddy_list( ); m_iStatus = facy.self_.status_id = m_iDesiredStatus; ProtoBroadcastAck(m_szModuleName, 0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); LOG("***** ChangeStatus complete"); } /** Return true on success, false on error. */ bool FacebookProto::NegotiateConnection( ) { LOG("***** Negotiating connection with Facebook"); bool error; std::string user, pass; DBVARIANT dbv = {0}; error = true; if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_LOGIN,&dbv)) { user = dbv.pszVal; DBFreeVariant(&dbv); error = user.empty(); } if (error) { NotifyEvent(m_tszUserName,TranslateT("Please enter a username."),NULL,FACEBOOK_EVENT_CLIENT); return false; } error = true; if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_PASS,&dbv)) { CallService(MS_DB_CRYPT_DECODESTRING,strlen(dbv.pszVal)+1, reinterpret_cast(dbv.pszVal)); pass = dbv.pszVal; DBFreeVariant(&dbv); error = pass.empty(); } if (error) { NotifyEvent(m_tszUserName,TranslateT("Please enter a password."),NULL,FACEBOOK_EVENT_CLIENT); return false; } // Load machine name if ( !DBGetContactSettingString(NULL,m_szModuleName,FACEBOOK_KEY_DEVICE_ID,&dbv)) { facy.cookies["datr"] = dbv.pszVal; DBFreeVariant(&dbv); } // Refresh last time of feeds update facy.last_feeds_update_ = ::time(NULL); // Get info about secured connection facy.https_ = DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_FORCE_HTTPS, DEFAULT_FORCE_HTTPS ) != 0; // Create default group for new contacts if (!DBGetContactSettingTString(NULL, m_szModuleName, FACEBOOK_KEY_DEF_GROUP, &dbv) && lstrlen(dbv.ptszVal) > 0) { CallService(MS_CLIST_GROUPCREATE, 0, (LPARAM)dbv.ptszVal); } return facy.login( user, pass ); } void FacebookProto::UpdateLoop(void *) { time_t tim = ::time(NULL); LOG( ">>>>> Entering Facebook::UpdateLoop[%d]", tim ); for ( int i = -1; !isOffline(); i = ++i % 50 ) { if ( i != -1 ) { if ( !facy.invisible_ ) if ( !facy.buddy_list( )) break; } if ( i == 2 && getByte( FACEBOOK_KEY_EVENT_FEEDS_ENABLE, DEFAULT_EVENT_FEEDS_ENABLE )) if ( !facy.feeds( )) break; if ( i == 49 ) ForkThread( &FacebookProto::ProcessFriendRequests, this, NULL ); LOG( "***** FacebookProto::UpdateLoop[%d] going to sleep...", tim ); if ( WaitForSingleObjectEx( update_loop_lock_, GetPollRate( ) * 1000, true ) != WAIT_TIMEOUT ) break; LOG( "***** FacebookProto::UpdateLoop[%d] waking up...", tim ); } ResetEvent(update_loop_lock_); LOG( "<<<<< Exiting FacebookProto::UpdateLoop[%d]", tim ); } void FacebookProto::MessageLoop(void *) { time_t tim = ::time(NULL); LOG( ">>>>> Entering Facebook::MessageLoop[%d]", tim ); while ( facy.channel( )) { if ( isOffline()) break; LOG( "***** FacebookProto::MessageLoop[%d] refreshing...", tim ); } LOG( "<<<<< Exiting FacebookProto::MessageLoop[%d]", tim ); } BYTE FacebookProto::GetPollRate( ) { BYTE poll_rate = getByte( FACEBOOK_KEY_POLL_RATE, FACEBOOK_DEFAULT_POLL_RATE ); return ( ( poll_rate >= FACEBOOK_MINIMAL_POLL_RATE && poll_rate <= FACEBOOK_MAXIMAL_POLL_RATE ) ? poll_rate : FACEBOOK_DEFAULT_POLL_RATE ); }