/* Facebook plugin for Miranda Instant Messenger _____________________________________________ Copyright © 2009-11 Michal Zelinka, 2011-12 Robert Pösel 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" int FacebookProto::RecvMsg(HANDLE hContact, PROTORECVEVENT *pre) { DBVARIANT dbv; if ( !DBGetContactSettingString(hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv)) { ForkThread( &FacebookProto::MessagingWorker, this, new send_messaging(dbv.pszVal, FACEBOOK_RECV_MESSAGE )); DBFreeVariant(&dbv); } CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_CONTACTTYPING_OFF); return Proto_RecvMessage(hContact, pre); } void FacebookProto::SendMsgWorker(void *p) { if(p == NULL) return; // ScopedLock s( facy.send_message_lock_, 500 ); send_direct *data = static_cast(p); DBVARIANT dbv; if ( !isOnline( )) { ProtoBroadcastAck(m_szModuleName, data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, data->msgid, (LPARAM)Translate("You cannot send messages when you are offline.")); } else if ( !DBGetContactSettingString(data->hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv)) { int retries = 5; std::string error_text = ""; bool result = false; while (!result && retries > 0) { result = facy.send_message(dbv.pszVal, data->msg, &error_text, retries % 2 == 0 ? MESSAGE_INBOX : MESSAGE_MERCURY); retries--; } if (result) { ProtoBroadcastAck(m_szModuleName,data->hContact,ACKTYPE_MESSAGE,ACKRESULT_SUCCESS, data->msgid,0); MessagingWorker( new send_messaging(dbv.pszVal, FACEBOOK_SEND_MESSAGE )); } else { char *err = mir_utf8decodeA(error_text.c_str()); ProtoBroadcastAck(m_szModuleName,data->hContact,ACKTYPE_MESSAGE,ACKRESULT_FAILED, data->msgid,(LPARAM)err); } DBFreeVariant(&dbv); } delete data; } void FacebookProto::SendChatMsgWorker(void *p) { if(p == NULL) return; send_chat *data = static_cast(p); std::string err_message = ""; HANDLE hContact = ChatIDToHContact(data->chat_id); if (hContact) { std::string tid; DBVARIANT dbv; if (!DBGetContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_TID, &dbv)) { tid = dbv.pszVal; DBFreeVariant(&dbv); } else { std::string post_data = "threads[group_ids][0]=" + data->chat_id; post_data += "&fb_dtsg=" + (facy.dtsg_.length() ? facy.dtsg_ : "0"); post_data += "&__user=" + facy.self_.user_id; post_data += "&phstamp=0"; http::response resp = facy.flap( FACEBOOK_REQUEST_THREAD_INFO, &post_data ); facy.validate_response(&resp); tid = utils::text::source_get_value(&resp.data, 2, "\"thread_id\":\"", "\""); DBWriteContactSettingString(hContact, m_szModuleName, FACEBOOK_KEY_TID, tid.c_str()); Log(" Got thread info: %s = %s", data->chat_id.c_str(), tid.c_str()); } if (!tid.empty()) facy.send_message(tid, data->msg, &err_message, MESSAGE_TID); } delete data; } int FacebookProto::SendMsg(HANDLE hContact, int flags, const char *msg) { // TODO: msg comes as Unicode (retyped wchar_t*), why should we convert it as ANSI to UTF-8? o_O if ( flags & PREF_UNICODE ) msg = mir_utf8encode(msg); facy.msgid_ = (facy.msgid_ % 1024)+1; ForkThread( &FacebookProto::SendMsgWorker, this, new send_direct(hContact, msg, (HANDLE)facy.msgid_)); return facy.msgid_; } int FacebookProto::UserIsTyping(HANDLE hContact,int type) { if (hContact && isOnline()) ForkThread(&FacebookProto::SendTypingWorker, this, new send_typing(hContact, type)); return 0; } void FacebookProto::SendTypingWorker(void *p) { if(p == NULL) return; send_typing *typing = static_cast(p); // Dont send typing notifications to contacts, that are offline or not friends if ( DBGetContactSettingWord(typing->hContact,m_szModuleName,"Status", 0) == ID_STATUS_OFFLINE || DBGetContactSettingByte(typing->hContact, m_szModuleName, FACEBOOK_KEY_CONTACT_TYPE, 0) != FACEBOOK_CONTACT_FRIEND) return; // TODO RM: maybe better send typing optimalization facy.is_typing_ = (typing->status == PROTOTYPE_SELFTYPING_ON); SleepEx( 2000, true ); if ( !facy.is_typing_ == (typing->status == PROTOTYPE_SELFTYPING_ON)) { delete typing; return; } DBVARIANT dbv; if ( !DBGetContactSettingString(typing->hContact,m_szModuleName,FACEBOOK_KEY_ID,&dbv)) { std::string data = "typ="; data += ( typing->status == PROTOTYPE_SELFTYPING_ON ) ? "1" : "0"; // PROTOTYPE_SELFTYPING_OFF data += "&to="; data += dbv.pszVal; data += "&source=mercury-chat"; data += "&fb_dtsg=" + facy.dtsg_; data += "&post_form_id="; data += ( facy.post_form_id_.length( )) ? facy.post_form_id_ : "0"; data += "&post_form_id_source=AsyncRequest&lsd=&phstamp=0&__user="; data += facy.self_.user_id; http::response resp = facy.flap( FACEBOOK_REQUEST_TYPING_SEND, &data ); DBFreeVariant(&dbv); } delete typing; } void FacebookProto::MessagingWorker(void *p) { if (p == NULL) return; send_messaging *data = static_cast(p); if (data->type == FACEBOOK_RECV_MESSAGE) facy.chat_mark_read( data->user_id ); // if ( DBGetContactSettingByte(NULL, m_szModuleName, FACEBOOK_KEY_CLOSE_WINDOWS_ENABLE, DEFAULT_CLOSE_WINDOWS_ENABLE )) // facy.close_chat( data->user_id ); delete data; }