diff options
author | George Hazan <ghazan@miranda.im> | 2020-02-18 23:22:20 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2020-02-18 23:22:20 +0300 |
commit | 845d6d07ee1c6c87c7dacae4f0ba0a803a5aff3d (patch) | |
tree | 7ac585bc9808977c7c1bb5fac2b795e1a536bf04 /protocols/Twitter/src | |
parent | 5f1b32a8d66e21430457a5e33b58b27fa10110af (diff) |
Twitter:
- partially implements #2218 (support for reading direct messages and marking them as read);
- user id parameter added to database;
- support added for server message ids;
- code cleaning;
Diffstat (limited to 'protocols/Twitter/src')
-rw-r--r-- | protocols/Twitter/src/connection.cpp | 39 | ||||
-rw-r--r-- | protocols/Twitter/src/contacts.cpp | 34 | ||||
-rw-r--r-- | protocols/Twitter/src/proto.cpp | 12 | ||||
-rw-r--r-- | protocols/Twitter/src/proto.h | 108 | ||||
-rw-r--r-- | protocols/Twitter/src/stdafx.h | 1 | ||||
-rw-r--r-- | protocols/Twitter/src/twitter.cpp | 11 | ||||
-rw-r--r-- | protocols/Twitter/src/utility.cpp | 35 |
7 files changed, 161 insertions, 79 deletions
diff --git a/protocols/Twitter/src/connection.cpp b/protocols/Twitter/src/connection.cpp index 278afcb4ae..b927de5c4d 100644 --- a/protocols/Twitter/src/connection.cpp +++ b/protocols/Twitter/src/connection.cpp @@ -373,11 +373,13 @@ void CTwitterProto::UpdateFriends() if (m_szUserName == username.c_str())
continue;
+ std::string id = one["id_str"].as_string();
std::string real_name = one["name"].as_string();
std::string profile_image_url = one["profile_image_url"].as_string();
std::string status_text = one["status"]["text"].as_string();
MCONTACT hContact = AddToClientList(username.c_str(), status_text.c_str());
+ setString(hContact, TWITTER_KEY_ID, id.c_str());
setUString(hContact, "Nick", real_name.c_str());
UpdateAvatar(hContact, profile_image_url.c_str());
}
@@ -539,13 +541,10 @@ void CTwitterProto::UpdateStatuses(bool pre_read, bool popups, bool tweetToMsg) db_pod_set(0, m_szModuleName, TWITTER_KEY_SINCEID, since_id_);
disconnectionCount = 0;
debugLogA("***** Status messages updated");
-
}
void CTwitterProto::UpdateMessages(bool pre_read)
{
- OBJLIST<twitter_user> messages(50);
-
auto *req = new AsyncHttpRequest(REQUEST_GET, m_szBaseUrl + "1.1/direct_messages/events/list.json");
req << INT_PARAM("count", 50);
if (dm_since_id_ != 0)
@@ -564,25 +563,35 @@ void CTwitterProto::UpdateMessages(bool pre_read) }
for (auto &one : root["events"]) {
- twitter_user *u = new twitter_user();
- u->username = one["sender_screen_name"].as_string();
- u->status.text = one["text"].as_string();
- u->status.time = parse_time(one["created_at"].as_string().c_str());
- messages.insert(u);
+ std::string type = one["type"].as_string();
+ if (type != "message_create")
+ continue;
- twitter_id id = _atoi64(one["id"].as_string().c_str());
+ auto &msgCreate = one["message_create"];
+ std::string sender = msgCreate["sender_id"].as_string();
+ MCONTACT hContact = FindContactById(sender.c_str());
+ if (hContact == INVALID_CONTACT_ID) {
+ debugLogA("Message from unknown sender %s, ignored", sender.c_str());
+ continue;
+ }
+
+ std::string text = msgCreate["message_data"]["text"].as_string();
+ __time64_t time = _atoi64(one["created_timestamp"].as_string().c_str()) / 1000;
+
+ std::string msgid = one["id"].as_string();
+ if (db_event_getById(m_szModuleName, msgid.c_str()))
+ continue;
+
+ twitter_id id = _atoi64(msgid.c_str());
if (id > dm_since_id_)
dm_since_id_ = id;
- }
-
- for (auto &it : messages.rev_iter()) {
- MCONTACT hContact = AddToClientList(it->username.c_str(), "");
PROTORECVEVENT recv = { 0 };
if (pre_read)
recv.flags |= PREF_CREATEREAD;
- recv.szMessage = const_cast<char*>(it->status.text.c_str());
- recv.timestamp = static_cast<DWORD>(it->status.time);
+ recv.szMessage = const_cast<char*>(text.c_str());
+ recv.timestamp = static_cast<DWORD>(time);
+ recv.szMsgId = msgid.c_str();
ProtoChainRecvMsg(hContact, &recv);
}
diff --git a/protocols/Twitter/src/contacts.cpp b/protocols/Twitter/src/contacts.cpp index 7cdf32b6e3..01524b6a12 100644 --- a/protocols/Twitter/src/contacts.cpp +++ b/protocols/Twitter/src/contacts.cpp @@ -175,6 +175,26 @@ int CTwitterProto::OnContactDeleted(WPARAM wParam, LPARAM) return 0;
}
+int CTwitterProto::OnMarkedRead(WPARAM, LPARAM hDbEvent)
+{
+ MCONTACT hContact = db_event_getContact(hDbEvent);
+ if (!hContact)
+ return 0;
+
+ // filter out only events of my protocol
+ const char *szProto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(szProto, m_szModuleName))
+ return 0;
+
+ auto *pMark = (m_arChatMarks.find((CChatMark *)&hDbEvent));
+ if (pMark) {
+ mark_read(hContact, pMark->szId);
+ m_arChatMarks.remove(pMark);
+ }
+
+ return 0;
+}
+
// *************************
bool CTwitterProto::IsMyContact(MCONTACT hContact, bool include_chat)
@@ -201,6 +221,20 @@ MCONTACT CTwitterProto::UsernameToHContact(const char *name) return 0;
}
+MCONTACT CTwitterProto::FindContactById(const char *id)
+{
+ for (auto &hContact : AccContacts()) {
+ if (getByte(hContact, "ChatRoom"))
+ continue;
+
+ if (getMStringA(hContact, TWITTER_KEY_ID) == id)
+ return hContact;
+ }
+
+ return INVALID_CONTACT_ID;
+}
+
+
MCONTACT CTwitterProto::AddToClientList(const char *name, const char *status)
{
// First, check if this contact exists
diff --git a/protocols/Twitter/src/proto.cpp b/protocols/Twitter/src/proto.cpp index 1a6996192c..01da0ec206 100644 --- a/protocols/Twitter/src/proto.cpp +++ b/protocols/Twitter/src/proto.cpp @@ -26,7 +26,8 @@ static volatile LONG g_msgid = 1; CTwitterProto::CTwitterProto(const char *proto_name, const wchar_t *username) :
PROTO<CTwitterProto>(proto_name, username),
m_szChatId(mir_utf8encodeW(username)),
- m_szBaseUrl("https://api.twitter.com/")
+ m_szBaseUrl("https://api.twitter.com/"),
+ m_arChatMarks(10, NumericKeySortT)
{
CreateProtoService(PS_CREATEACCMGRUI, &CTwitterProto::SvcCreateAccMgrUI);
@@ -38,6 +39,7 @@ CTwitterProto::CTwitterProto(const char *proto_name, const wchar_t *username) : HookProtoEvent(ME_OPT_INITIALISE, &CTwitterProto::OnOptionsInit);
HookProtoEvent(ME_DB_CONTACT_DELETED, &CTwitterProto::OnContactDeleted);
+ HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CTwitterProto::OnMarkedRead);
HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &CTwitterProto::OnBuildStatusMenu);
// Initialize hotkeys
@@ -148,6 +150,14 @@ void CTwitterProto::SendSuccess(void *p) delete data;
}
+MEVENT CTwitterProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre)
+{
+ MEVENT res = CSuper::RecvMsg(hContact, pre);
+ if (pre->szMsgId)
+ m_arChatMarks.insert(new CChatMark(res, pre->szMsgId));
+
+ return res;
+}
int CTwitterProto::SendMsg(MCONTACT hContact, int, const char *msg)
{
if (m_iStatus != ID_STATUS_ONLINE)
diff --git a/protocols/Twitter/src/proto.h b/protocols/Twitter/src/proto.h index 147fee84c8..6067841973 100644 --- a/protocols/Twitter/src/proto.h +++ b/protocols/Twitter/src/proto.h @@ -44,6 +44,18 @@ struct AsyncHttpRequest : public MHttpRequest AsyncHttpRequest(int type, const char *szUrl);
};
+struct CChatMark
+{
+ CChatMark(MEVENT _p1, const CMStringA &_p2) :
+ hEvent(_p1),
+ szId(_p2)
+ {
+ }
+
+ MEVENT hEvent;
+ CMStringA szId;
+};
+
class CTwitterProto : public PROTO<CTwitterProto>
{
ptrA m_szChatId;
@@ -51,14 +63,14 @@ class CTwitterProto : public PROTO<CTwitterProto> http::response request_token();
http::response request_access_tokens();
- void set_base_url(const CMStringA &base_url);
-
bool get_info(const CMStringA &name, twitter_user *);
bool get_info_by_email(const CMStringA &email, twitter_user *);
bool add_friend(const CMStringA &name, twitter_user &u);
void remove_friend(const CMStringA &name);
+ void mark_read(MCONTACT hContact, const CMStringA &msgId);
+
void set_status(const CMStringA &text);
void send_direct(const CMStringA &name, const CMStringA &text);
@@ -73,6 +85,24 @@ class CTwitterProto : public PROTO<CTwitterProto> CMStringA m_szAccessTokenSecret;
CMStringA m_szPin;
+ CMStringW GetAvatarFolder();
+
+ mir_cs signon_lock_;
+ mir_cs avatar_lock_;
+ mir_cs twitter_lock_;
+
+ OBJLIST<CChatMark> m_arChatMarks;
+
+ HNETLIBUSER hAvatarNetlib_;
+ HANDLE hMsgLoop_;
+
+ twitter_id since_id_;
+ twitter_id dm_since_id_;
+
+ bool in_chat_;
+
+ int disconnectionCount;
+
// OAuthWebRequest used for all OAuth related queries
//
// consumerKey and consumerSecret - must be provided for every call, they identify the application
@@ -91,6 +121,32 @@ class CTwitterProto : public PROTO<CTwitterProto> HNETLIBCONN m_hConnHttp;
void Disconnect(void) { if (m_hConnHttp) Netlib_CloseHandle(m_hConnHttp); m_hConnHttp = nullptr; }
+ bool NegotiateConnection();
+
+ void UpdateStatuses(bool pre_read, bool popups, bool tweetToMsg);
+ void UpdateMessages(bool pre_read);
+ void UpdateFriends();
+ void UpdateAvatar(MCONTACT, const CMStringA &, bool force = false);
+
+ int ShowPinDialog();
+ void ShowPopup(const wchar_t *, int Error = 0);
+ void ShowPopup(const char *, int Error = 0);
+ void ShowContactPopup(MCONTACT, const CMStringA &, const CMStringA *);
+
+ bool IsMyContact(MCONTACT, bool include_chat = false);
+ MCONTACT UsernameToHContact(const char *);
+ MCONTACT AddToClientList(const char *, const char *);
+ MCONTACT FindContactById(const char *);
+
+ static void CALLBACK APC_callback(ULONG_PTR p);
+
+ void UpdateChat(const twitter_user &update);
+ void AddChatContact(const char *name, const char *nick = nullptr);
+ void DeleteChatContact(const char *name);
+ void SetChatStatus(int);
+
+ void resetOAuthKeys();
+
public:
CTwitterProto(const char*,const wchar_t*);
~CTwitterProto();
@@ -106,6 +162,7 @@ public: HANDLE SearchBasic(const wchar_t *) override;
HANDLE SearchByEmail(const wchar_t *) override;
+ MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT *) override;
int SendMsg(MCONTACT, int, const char *) override;
int SetStatus(int) override;
@@ -133,18 +190,18 @@ public: //////////////////////////////////////////////////////////////////////////////////////
// Events
+ int __cdecl OnBuildStatusMenu(WPARAM, LPARAM);
+ int __cdecl OnChatOutgoing(WPARAM, LPARAM);
int __cdecl OnContactDeleted(WPARAM,LPARAM);
- int __cdecl OnBuildStatusMenu(WPARAM,LPARAM);
+ int __cdecl OnMarkedRead(WPARAM, LPARAM);
int __cdecl OnOptionsInit(WPARAM,LPARAM);
int __cdecl OnPrebuildContactMenu(WPARAM,LPARAM);
- int __cdecl OnChatOutgoing(WPARAM,LPARAM);
void __cdecl SendTweetWorker(void *);
//////////////////////////////////////////////////////////////////////////////////////
// Threads
-private:
void __cdecl AddToListWorker(void *p);
void __cdecl SendSuccess(void *);
void __cdecl DoSearch(void *);
@@ -153,47 +210,6 @@ private: void __cdecl GetAwayMsgWorker(void *);
void __cdecl UpdateAvatarWorker(void *);
void __cdecl UpdateInfoWorker(void *);
-
- bool NegotiateConnection();
-
- void UpdateStatuses(bool pre_read,bool popups, bool tweetToMsg);
- void UpdateMessages(bool pre_read);
- void UpdateFriends();
- void UpdateAvatar(MCONTACT, const CMStringA &, bool force = false);
-
- int ShowPinDialog();
- void ShowPopup(const wchar_t *, int Error = 0);
- void ShowPopup(const char *, int Error = 0);
- void ShowContactPopup(MCONTACT, const CMStringA &, const CMStringA *);
-
- bool IsMyContact(MCONTACT, bool include_chat = false);
- MCONTACT UsernameToHContact(const char *);
- MCONTACT AddToClientList(const char *, const char *);
-
- static void CALLBACK APC_callback(ULONG_PTR p);
-
- void UpdateChat(const twitter_user &update);
- void AddChatContact(const char *name,const char *nick = nullptr);
- void DeleteChatContact(const char *name);
- void SetChatStatus(int);
-
- void CTwitterProto::resetOAuthKeys();
-
- CMStringW GetAvatarFolder();
-
- mir_cs signon_lock_;
- mir_cs avatar_lock_;
- mir_cs twitter_lock_;
-
- HNETLIBUSER hAvatarNetlib_;
- HANDLE hMsgLoop_;
-
- twitter_id since_id_;
- twitter_id dm_since_id_;
-
- bool in_chat_;
-
- int disconnectionCount;
};
struct CMPlugin : public ACCPROTOPLUGIN<CTwitterProto>
diff --git a/protocols/Twitter/src/stdafx.h b/protocols/Twitter/src/stdafx.h index 5e2d67dd7b..f7bc9d7241 100644 --- a/protocols/Twitter/src/stdafx.h +++ b/protocols/Twitter/src/stdafx.h @@ -62,6 +62,7 @@ using std::map; #define TWITTER_KEY_NICK "Nick" // we need one called Nick for the chat thingo to work
#define TWITTER_KEY_UN "Username"
+#define TWITTER_KEY_ID "ID"
#define TWITTER_KEY_PASS "Password"
#define TWITTER_KEY_OAUTH_PIN "OAuthPIN"
#define TWITTER_KEY_OAUTH_TOK "OAuthToken"
diff --git a/protocols/Twitter/src/twitter.cpp b/protocols/Twitter/src/twitter.cpp index 2a8625e10b..16b105ab67 100644 --- a/protocols/Twitter/src/twitter.cpp +++ b/protocols/Twitter/src/twitter.cpp @@ -108,6 +108,17 @@ void CTwitterProto::remove_friend(const CMStringA &name) Execute(req);
}
+void CTwitterProto::mark_read(MCONTACT hContact, const CMStringA &msgId)
+{
+ CMStringA id(getMStringA(hContact, TWITTER_KEY_ID));
+ if (id.IsEmpty())
+ return;
+
+ auto *req = new AsyncHttpRequest(REQUEST_POST, m_szBaseUrl + "1.1/direct_messages/mark_read.json");
+ req << CHAR_PARAM("recipient_id", id) << CHAR_PARAM("last_read_event_id", msgId);
+ Execute(req);
+}
+
void CTwitterProto::set_status(const CMStringA &text)
{
if (text.IsEmpty())
diff --git a/protocols/Twitter/src/utility.cpp b/protocols/Twitter/src/utility.cpp index f839bb4838..38452f9608 100644 --- a/protocols/Twitter/src/utility.cpp +++ b/protocols/Twitter/src/utility.cpp @@ -20,34 +20,34 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. #include <io.h>
-http::response CTwitterProto::Execute(AsyncHttpRequest *req)
+http::response CTwitterProto::Execute(AsyncHttpRequest *pReq)
{
- if (!req->m_szParam.IsEmpty()) {
- if (req->requestType == REQUEST_POST) {
- req->AddHeader("Content-Type", "application/x-www-form-urlencoded");
- req->AddHeader("Cache-Control", "no-cache");
+ if (!pReq->m_szParam.IsEmpty()) {
+ if (pReq->requestType == REQUEST_POST) {
+ pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded");
+ pReq->AddHeader("Cache-Control", "no-cache");
- req->dataLength = (int)req->m_szParam.GetLength();
- req->pData = req->m_szParam.GetBuffer();
+ pReq->dataLength = (int)pReq->m_szParam.GetLength();
+ pReq->pData = pReq->m_szParam.GetBuffer();
}
else {
- req->m_szUrl.AppendChar('?');
- req->m_szUrl += req->m_szParam;
+ pReq->m_szUrl.AppendChar('?');
+ pReq->m_szUrl += pReq->m_szParam;
}
}
CMStringA auth;
- if (req->requestType == REQUEST_GET)
- auth = OAuthWebRequestSubmit(req->m_szUrl, "GET", "");
+ if (pReq->requestType == REQUEST_GET)
+ auth = OAuthWebRequestSubmit(pReq->m_szUrl, "GET", "");
else
- auth = OAuthWebRequestSubmit(req->m_szUrl, "POST", req->m_szParam);
- req->AddHeader("Authorization", auth);
+ auth = OAuthWebRequestSubmit(pReq->m_szUrl, "POST", pReq->m_szParam);
+ pReq->AddHeader("Authorization", auth);
- req->szUrl = req->m_szUrl.GetBuffer();
- req->flags = NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT;
- req->nlc = m_hConnHttp;
+ pReq->szUrl = pReq->m_szUrl.GetBuffer();
+ pReq->flags = NLHRF_HTTP11 | NLHRF_PERSISTENT | NLHRF_REDIRECT;
+ pReq->nlc = m_hConnHttp;
http::response resp_data;
- NLHR_PTR resp(Netlib_HttpTransaction(m_hNetlibUser, req));
+ NLHR_PTR resp(Netlib_HttpTransaction(m_hNetlibUser, pReq));
if (resp) {
debugLogA("**SLURP - the server has responded!");
m_hConnHttp = resp->nlc;
@@ -61,6 +61,7 @@ http::response CTwitterProto::Execute(AsyncHttpRequest *req) debugLogA("SLURP - there was no response!");
}
+ delete pReq;
return resp_data;
}
|