diff options
author | George Hazan <ghazan@miranda.im> | 2019-01-10 21:10:31 +0200 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-01-10 21:10:31 +0200 |
commit | 1e86f4d089a1748ce1449074498a283a8639663b (patch) | |
tree | 0746fa3af1a43b3063ede213b6b43c10729e58ba /protocols | |
parent | aec99075210e9d107eb0f4231c0bb040ba6c1eee (diff) |
fixes #1740 (ICQ10: add groupchats support)
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/Icq10/res/resources.rc | 8 | ||||
-rw-r--r-- | protocols/Icq10/src/options.cpp | 7 | ||||
-rw-r--r-- | protocols/Icq10/src/proto.cpp | 86 | ||||
-rw-r--r-- | protocols/Icq10/src/proto.h | 210 | ||||
-rw-r--r-- | protocols/Icq10/src/resource.h | 2 | ||||
-rw-r--r-- | protocols/Icq10/src/server.cpp | 159 | ||||
-rw-r--r-- | protocols/Icq10/src/stdafx.h | 21 | ||||
-rw-r--r-- | protocols/Icq10/src/utils.cpp | 13 |
8 files changed, 364 insertions, 142 deletions
diff --git a/protocols/Icq10/res/resources.rc b/protocols/Icq10/res/resources.rc index a5dc252683..7fd47458c3 100644 --- a/protocols/Icq10/res/resources.rc +++ b/protocols/Icq10/res/resources.rc @@ -96,19 +96,20 @@ BEGIN PUSHBUTTON "Create a new ICQ account",IDC_REGISTER,183,61,122,14 END -IDD_OPTIONS_FULL DIALOGEX 0, 0, 310, 80 +IDD_OPTIONS_FULL DIALOGEX 0, 0, 310, 98 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD EXSTYLE WS_EX_CONTROLPARENT FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - GROUPBOX "ICQ",IDC_STATIC,4,0,302,58 + GROUPBOX "ICQ",IDC_STATIC,4,0,302,74 RTEXT "ICQ number:",IDC_STATIC,12,14,51,8 EDITTEXT IDC_UIN,68,12,106,12,ES_AUTOHSCROLL RTEXT "Password:",IDC_STATIC,12,28,51,8 EDITTEXT IDC_PASSWORD,68,26,106,12,ES_PASSWORD | ES_AUTOHSCROLL CONTROL "Use friendly names instead of contact nicks",IDC_USEFRIENDLY, "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,43,285,10 - PUSHBUTTON "Create a new ICQ account",IDC_REGISTER,183,61,122,14 + PUSHBUTTON "Create a new ICQ account",IDC_REGISTER,183,78,122,14 + CONTROL "Hide group chats on startup",IDC_HIDECHATS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,57,285,10 END @@ -126,6 +127,7 @@ BEGIN IDD_OPTIONS_FULL, DIALOG BEGIN + BOTTOMMARGIN, 78 END END #endif // APSTUDIO_INVOKED diff --git a/protocols/Icq10/src/options.cpp b/protocols/Icq10/src/options.cpp index 6eaa2e6114..3ff4494232 100644 --- a/protocols/Icq10/src/options.cpp +++ b/protocols/Icq10/src/options.cpp @@ -156,7 +156,7 @@ void CIcqProto::OnLoginViaPhone(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pRe class CIcqOptionsDlg : public CProtoDlgBase<CIcqProto> { CCtrlEdit edtUin, edtPassword; - CCtrlCheck chkUseFriendly; + CCtrlCheck chkUseFriendly, chkHideChats; CCtrlButton btnCreate; CMStringW wszOldPass; @@ -166,14 +166,17 @@ public: edtUin(this, IDC_UIN), btnCreate(this, IDC_REGISTER), edtPassword(this, IDC_PASSWORD), + chkHideChats(this, IDC_HIDECHATS), chkUseFriendly(this, IDC_USEFRIENDLY) { btnCreate.OnClick = Callback(this, &CIcqOptionsDlg::onClick_Register); CreateLink(edtUin, ppro->m_dwUin); CreateLink(edtPassword, ppro->m_szPassword); - if (bFullDlg) + if (bFullDlg) { + CreateLink(chkHideChats, ppro->m_bHideGroupchats); CreateLink(chkUseFriendly, ppro->m_bUseFriendly); + } wszOldPass = ppro->m_szPassword; } diff --git a/protocols/Icq10/src/proto.cpp b/protocols/Icq10/src/proto.cpp index 349de4f259..67c1ae8c9c 100644 --- a/protocols/Icq10/src/proto.cpp +++ b/protocols/Icq10/src/proto.cpp @@ -42,7 +42,8 @@ CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)), m_dwUin(this, DB_KEY_UIN, 0), m_szPassword(this, "Password"), - m_bUseFriendly(this, "UseFriendly", 1) + m_bUseFriendly(this, "UseFriendly", 1), + m_bHideGroupchats(this, "HideChats", 1) { // services CreateProtoService(PS_CREATEACCMGRUI, &CIcqProto::CreateAccMgrUI); @@ -52,8 +53,10 @@ CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : CreateProtoService(PS_SETMYAVATAR, &CIcqProto::SetAvatar); // events - HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit); HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CIcqProto::OnDbEventRead); + HookProtoEvent(ME_GC_EVENT, &CIcqProto::GroupchatEventHook); + HookProtoEvent(ME_GC_BUILDMENU, &CIcqProto::GroupchatMenuHook); + HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit); // netlib handle CMStringW descr(FORMAT, TranslateT("%s server connection"), m_tszUserName); @@ -79,6 +82,11 @@ CIcqProto::~CIcqProto() void CIcqProto::OnModulesLoaded() { + GCREGISTER gcr = {}; + gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR; + gcr.ptszDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + Chat_Register(&gcr); } void CIcqProto::OnShutdown() @@ -99,6 +107,74 @@ void CIcqProto::OnContactDeleted(MCONTACT hContact) } ///////////////////////////////////////////////////////////////////////////////////////// +// Group chats + +static gc_item sttLogListItems[] = +{ + { LPGENW("&Invite a user"), IDM_INVITE, MENU_ITEM }, +}; + +int CIcqProto::GroupchatMenuHook(WPARAM, LPARAM lParam) +{ + GCMENUITEMS* gcmi = (GCMENUITEMS*)lParam; + if (gcmi == nullptr) + return 0; + + if (mir_strcmpi(gcmi->pszModule, m_szModuleName)) + return 0; + + SESSION_INFO *si = g_chatApi.SM_FindSession(gcmi->pszID, gcmi->pszModule); + if (si == nullptr) + return 0; + + if (gcmi->Type == MENU_ON_LOG) + Chat_AddMenuItems(gcmi->hMenu, _countof(sttLogListItems), sttLogListItems, &g_plugin); + + return 0; +} + +int CIcqProto::GroupchatEventHook(WPARAM, LPARAM lParam) +{ + GCHOOK *gch = (GCHOOK*)lParam; + if (gch == nullptr) + return 0; + + if (mir_strcmpi(gch->pszModule, m_szModuleName)) + return 0; + + SESSION_INFO *si = g_chatApi.SM_FindSession(gch->ptszID, gch->pszModule); + if (si == nullptr) + return 0; + + switch (gch->iType) { + case GC_USER_MESSAGE: + rtrimw(gch->ptszText); + if (!mir_wstrlen(gch->ptszText)) + break; + + if (m_bOnline) { + wchar_t *wszText = NEWWSTR_ALLOCA(gch->ptszText); + Chat_UnescapeTags(wszText); + SendMsg(si->hContact, 0, T2Utf(wszText)); + } + break; + + case GC_USER_PRIVMESS: + // Chat_SendPrivateMessage(gch); + break; + + case GC_USER_LOGMENU: + // Chat_ProcessLogMenu(gch); + break; + + case GC_USER_NICKLISTMENU: + break; + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// void CIcqProto::MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD) { @@ -290,8 +366,8 @@ HANDLE CIcqProto::SendFile(MCONTACT, const wchar_t*, wchar_t**) int CIcqProto::SendMsg(MCONTACT hContact, int, const char *pszSrc) { - DWORD dwUin = getDword(hContact, DB_KEY_UIN); - if (dwUin == 0) + CMStringA szUserid(GetUserId(hContact)); + if (szUserid.IsEmpty()) return 0; int id = InterlockedIncrement(&m_msgId); @@ -303,7 +379,7 @@ int CIcqProto::SendMsg(MCONTACT hContact, int, const char *pszSrc) pReq << CHAR_PARAM("a", m_szAToken) << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("f", "json") << CHAR_PARAM("k", ICQ_APP_ID) << CHAR_PARAM("mentions", "") << CHAR_PARAM("message", pszSrc) << CHAR_PARAM("offlineIM", "true") << CHAR_PARAM("r", pReq->m_reqId) - << INT_PARAM("t", dwUin) << INT_PARAM("ts", time(0)); + << CHAR_PARAM("t", szUserid) << INT_PARAM("ts", time(0)); Push(pReq); return id; } diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h index 85feaee05a..6d350a7275 100644 --- a/protocols/Icq10/src/proto.h +++ b/protocols/Icq10/src/proto.h @@ -37,6 +37,11 @@ #define ICQ_API_SERVER "https://api.icq.net" #define ICQ_ROBUST_SERVER "https://rapi.icq.net" +enum ChatMenuItems +{ + IDM_INVITE = 10, IDM_EXIT, IDM_DESTROY +}; + struct IcqCacheItem { IcqCacheItem(DWORD _uin, MCONTACT _contact) : @@ -72,53 +77,57 @@ class CIcqProto : public PROTO<CIcqProto> { friend struct CIcqRegistrationDlg; - bool m_bOnline = false, m_bTerminated = false; - void CheckAvatarChange(MCONTACT hContact, const JSONNode&); - void CheckLastId(MCONTACT hContact, const JSONNode&); - void CheckNickChange(MCONTACT hContact, const JSONNode&); - MCONTACT CheckOwnMessage(const CMStringA &reqId, const CMStringA &msgId, bool bRemove); - void CheckPassword(void); - void ConnectionFailed(int iReason); - void OnLoggedIn(void); - void OnLoggedOut(void); - MCONTACT ParseBuddyInfo(const JSONNode &buddy, MCONTACT hContact = -1); - void ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &msg); - void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId); - void RetrieveUserInfo(MCONTACT); - void SetServerStatus(int iNewStatus); - void ShutdownSession(void); - void StartSession(void); - - mir_cs csMarkReadQueue; + bool m_bOnline = false, m_bTerminated = false; + void CheckAvatarChange(MCONTACT hContact, const JSONNode&); + void CheckLastId(MCONTACT hContact, const JSONNode&); + void CheckNickChange(MCONTACT hContact, const JSONNode&); + MCONTACT CheckOwnMessage(const CMStringA &reqId, const CMStringA &msgId, bool bRemove); + void CheckPassword(void); + void ConnectionFailed(int iReason); + CMStringA GetUserId(MCONTACT); + void LoadChatInfo(SESSION_INFO*); + MCONTACT ParseBuddyInfo(const JSONNode &buddy, MCONTACT hContact = -1); + void ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &msg); + void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId); + void RetrieveUserInfo(MCONTACT); + void SetServerStatus(int iNewStatus); + void ShutdownSession(void); + void StartSession(void); + + void OnLoggedIn(void); + void OnLoggedOut(void); + + mir_cs csMarkReadQueue; LIST<IcqCacheItem> arMarkReadQueue; - static void CALLBACK MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD); + static void CALLBACK MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD); - __int64 getId(MCONTACT hContact, const char *szSetting); - void setId(MCONTACT hContact, const char *szSetting, __int64 iValue); + __int64 getId(MCONTACT hContact, const char *szSetting); + void setId(MCONTACT hContact, const char *szSetting, __int64 iValue); - void OnAddBuddy(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnAddClient(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnCheckPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnFetchEvents(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnGetUserHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnGetUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnLoginViaPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnNormalizePhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnSearchResults(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnSendMessage(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - void OnValidateSms(NETLIBHTTPREQUEST*, AsyncHttpRequest*); - - void ProcessBuddyList(const JSONNode&); - void ProcessDiff(const JSONNode&); - void ProcessEvent(const JSONNode&); - void ProcessHistData(const JSONNode&); - void ProcessImState(const JSONNode&); - void ProcessMyInfo(const JSONNode&); - void ProcessPresence(const JSONNode&); - void ProcessTyping(const JSONNode&); + void OnAddBuddy(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnAddClient(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnCheckPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnFetchEvents(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnGetChatInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnGetUserHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnGetUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnLoginViaPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnNormalizePhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnSearchResults(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnSendMessage(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnValidateSms(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + + void ProcessBuddyList(const JSONNode&); + void ProcessDiff(const JSONNode&); + void ProcessEvent(const JSONNode&); + void ProcessHistData(const JSONNode&); + void ProcessImState(const JSONNode&); + void ProcessMyInfo(const JSONNode&); + void ProcessPresence(const JSONNode&); + void ProcessTyping(const JSONNode&); IcqConn m_ConnPool[CONN_LAST]; CMStringA m_szSessionKey; @@ -134,95 +143,96 @@ class CIcqProto : public PROTO<CIcqProto> //////////////////////////////////////////////////////////////////////////////////////// // http queue - mir_cs m_csHttpQueue; - HANDLE m_evRequestsQueue; + mir_cs m_csHttpQueue; + HANDLE m_evRequestsQueue; LIST<AsyncHttpRequest> m_arHttpQueue; - void CalcHash(AsyncHttpRequest*); - void ExecuteRequest(AsyncHttpRequest*); - void Push(MHttpRequest*); - bool RefreshRobustToken(); + void CalcHash(AsyncHttpRequest*); + void ExecuteRequest(AsyncHttpRequest*); + void Push(MHttpRequest*); + bool RefreshRobustToken(); //////////////////////////////////////////////////////////////////////////////////////// // cache - mir_cs m_csCache; + mir_cs m_csCache; OBJLIST<IcqCacheItem> m_arCache; - void InitContactCache(void); + void InitContactCache(void); IcqCacheItem* FindContactByUIN(DWORD); - MCONTACT CreateContact(DWORD dwUin, bool bTemporary); + MCONTACT CreateContact(DWORD dwUin, bool bTemporary); - void GetAvatarFileName(MCONTACT hContact, wchar_t *pszDest, size_t cbLen); + void GetAvatarFileName(MCONTACT hContact, wchar_t *pszDest, size_t cbLen); //////////////////////////////////////////////////////////////////////////////////////// // threads - HANDLE m_hWorkerThread; - void __cdecl ServerThread(void*); - - HANDLE m_hPollThread; - void __cdecl PollThread(void*); + HANDLE m_hWorkerThread; + void __cdecl ServerThread(void*); - void __cdecl SendAckThread(void*); + HANDLE m_hPollThread; + void __cdecl PollThread(void*); //////////////////////////////////////////////////////////////////////////////////////// // services - INT_PTR __cdecl GetAvatar(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); - INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); - INT_PTR __cdecl SetAvatar(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatar(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatarCaps(WPARAM, LPARAM); + INT_PTR __cdecl GetAvatarInfo(WPARAM, LPARAM); + INT_PTR __cdecl SetAvatar(WPARAM, LPARAM); - INT_PTR __cdecl CreateAccMgrUI(WPARAM, LPARAM); + INT_PTR __cdecl CreateAccMgrUI(WPARAM, LPARAM); //////////////////////////////////////////////////////////////////////////////////////// // events + int __cdecl GroupchatEventHook(WPARAM, LPARAM); + int __cdecl GroupchatMenuHook(WPARAM, LPARAM); - int __cdecl OnDbEventRead(WPARAM, LPARAM); - int __cdecl OnOptionsInit(WPARAM, LPARAM); + int __cdecl OnDbEventRead(WPARAM, LPARAM); + int __cdecl OnOptionsInit(WPARAM, LPARAM); //////////////////////////////////////////////////////////////////////////////////////// // PROTO_INTERFACE - MCONTACT AddToList( int flags, PROTOSEARCHRESULT *psr) override; - - int AuthRequest(MCONTACT hContact, const wchar_t *szMessage) override; - - HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath) override; - int FileCancel(MCONTACT hContact, HANDLE hTransfer) override; - int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason) override; - int FileResume( HANDLE hTransfer, int *action, const wchar_t **szFilename) override; - - INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; - int GetInfo(MCONTACT hContact, int infoType) override; - - HANDLE SearchBasic(const wchar_t *id) override; - - HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; - int SendMsg(MCONTACT hContact, int flags, const char *msg) override; - int SendUrl(MCONTACT hContact, int flags, const char *url) override; - - int SetApparentMode(MCONTACT hContact, int mode) override; - int SetStatus(int iNewStatus) override; - - HANDLE GetAwayMsg(MCONTACT hContact) override; - int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) override; - int SetAwayMsg(int m_iStatus, const wchar_t *msg) override; - - int UserIsTyping(MCONTACT hContact, int type) override; - - void OnContactDeleted(MCONTACT) override; - void OnModulesLoaded() override; - void OnShutdown() override; + MCONTACT AddToList( int flags, PROTOSEARCHRESULT *psr) override; + + int AuthRequest(MCONTACT hContact, const wchar_t *szMessage) override; + + HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath) override; + int FileCancel(MCONTACT hContact, HANDLE hTransfer) override; + int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason) override; + int FileResume( HANDLE hTransfer, int *action, const wchar_t **szFilename) override; + + INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override; + int GetInfo(MCONTACT hContact, int infoType) override; + + HANDLE SearchBasic(const wchar_t *id) override; + + HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles) override; + int SendMsg(MCONTACT hContact, int flags, const char *msg) override; + int SendUrl(MCONTACT hContact, int flags, const char *url) override; + + int SetApparentMode(MCONTACT hContact, int mode) override; + int SetStatus(int iNewStatus) override; + + HANDLE GetAwayMsg(MCONTACT hContact) override; + int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt) override; + int SetAwayMsg(int m_iStatus, const wchar_t *msg) override; + + int UserIsTyping(MCONTACT hContact, int type) override; + + void OnContactDeleted(MCONTACT) override; + void OnModulesLoaded() override; + void OnShutdown() override; public: CIcqProto(const char*, const wchar_t*); ~CIcqProto(); - CMOption<DWORD> m_dwUin; - CMOption<wchar_t*> m_szPassword; - CMOption<BYTE> m_bUseFriendly; + CMOption<DWORD> m_dwUin; // our own id + CMOption<wchar_t*> m_szPassword; // password, if present + CMOption<BYTE> m_bUseFriendly; // use friendly names instead of old icq nicks + CMOption<BYTE> m_bHideGroupchats; // don't pop up group chat windows on startup }; struct CMPlugin : public ACCPROTOPLUGIN<CIcqProto> diff --git a/protocols/Icq10/src/resource.h b/protocols/Icq10/src/resource.h index cb5dfd3c17..964e8a2095 100644 --- a/protocols/Icq10/src/resource.h +++ b/protocols/Icq10/src/resource.h @@ -8,6 +8,8 @@ #define IDC_PASSWORD 1001 #define IDC_UIN 1002 #define IDC_USEFRIENDLY 1003 +#define IDC_USEFRIENDLY2 1004 +#define IDC_HIDECHATS 1004 #define IDC_REGISTER 1005 #define IDC_PHONE 1006 #define IDC_SENDSMS 1008 diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp index c852883e6a..550f0d6a0e 100644 --- a/protocols/Icq10/src/server.cpp +++ b/protocols/Icq10/src/server.cpp @@ -95,6 +95,33 @@ void CIcqProto::ConnectionFailed(int iReason) ShutdownSession(); } +void CIcqProto::LoadChatInfo(SESSION_INFO *si) +{ + int memberCount = getDword(si->hContact, "MemberCount"); + for (int i = 0; i < memberCount; i++) { + char buf[100]; + mir_snprintf(buf, "m%d", i); + ptrW szSetting(getWStringA(si->hContact, buf)); + JSONNode *node = json_parse(T2Utf(szSetting)); + if (node == nullptr) + continue; + + CMStringW nick((*node)["nick"].as_mstring()); + CMStringW role((*node)["role"].as_mstring()); + CMStringW sn((*node)["sn"].as_mstring()); + + GCEVENT gce = { m_szModuleName, si->ptszID, GC_EVENT_JOIN }; + gce.ptszNick = nick; + gce.ptszUID = sn; + gce.time = ::time(0); + gce.bIsMe = _wtoi(sn) == (int)m_dwUin; + gce.ptszStatus = TranslateW(role); + Chat_Event(&gce); + + json_delete(node); + } +} + void CIcqProto::OnLoggedIn() { debugLogA("CIcqProto::OnLoggedIn"); @@ -116,6 +143,19 @@ void CIcqProto::OnLoggedOut() MCONTACT CIcqProto::ParseBuddyInfo(const JSONNode &buddy, MCONTACT hContact) { + // user chat? + if (buddy["userType"].as_mstring() == "interop") { + CMStringW wszChatId(buddy["aimId"].as_mstring()); + CMStringW wszChatName(buddy["friendly"].as_mstring()); + + SESSION_INFO *si = Chat_NewSession(GCW_CHATROOM, m_szModuleName, wszChatId, wszChatName); + Chat_AddGroup(si, TranslateT("admin")); + Chat_AddGroup(si, TranslateT("member")); + Chat_Control(m_szModuleName, wszChatId, m_bHideGroupchats ? WINDOW_HIDDEN : SESSION_INITDONE); + Chat_Control(m_szModuleName, wszChatId, SESSION_ONLINE); + return si->hContact; + } + DWORD dwUin = _wtol(buddy["aimId"].as_mstring()); if (hContact == -1) { @@ -201,25 +241,43 @@ void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNo if (type != "text" && !type.IsEmpty()) return; - // ignore duplicates - MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId); - if (hDbEvent != 0) - return; - - // skip own messages, just set the server msgid - CMStringA reqId(it["reqId"].as_mstring()); - if (CheckOwnMessage(reqId, szMsgId, true)) - return; - - bool bIsOutgoing = it["outgoing"].as_bool(); - ptrA szUtf(mir_utf8encodeW(it["text"].as_mstring())); - - PROTORECVEVENT pre = {}; - pre.flags = (bIsOutgoing) ? PREF_SENT : 0; - pre.szMsgId = szMsgId; - pre.timestamp = it["time"].as_int(); - pre.szMessage = szUtf; - ProtoChainRecvMsg(hContact, &pre); + CMStringW wszText(it["text"].as_mstring()); + if (isChatRoom(hContact)) { + CMStringA reqId(it["reqId"].as_mstring()); + CheckOwnMessage(reqId, szMsgId, true); + + CMStringW wszSender(it["chat"]["sender"].as_mstring()); + CMStringW wszChatId(getMStringW(hContact, "ChatRoomID")); + + GCEVENT gce = { m_szModuleName, wszChatId, GC_EVENT_MESSAGE }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = wszSender; + gce.ptszText = wszText; + gce.time = it["time"].as_int(); + gce.bIsMe = _wtoi(wszSender) == (int)m_dwUin; + Chat_Event(&gce); + } + else { + // skip own messages, just set the server msgid + CMStringA reqId(it["reqId"].as_mstring()); + if (CheckOwnMessage(reqId, szMsgId, true)) + return; + + // ignore duplicates + MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId); + if (hDbEvent != 0) + return; + + bool bIsOutgoing = it["outgoing"].as_bool(); + ptrA szUtf(mir_utf8encodeW(wszText)); + + PROTORECVEVENT pre = {}; + pre.flags = (bIsOutgoing) ? PREF_SENT : 0; + pre.szMsgId = szMsgId; + pre.timestamp = it["time"].as_int(); + pre.szMessage = szUtf; + ProtoChainRecvMsg(hContact, &pre); + } } bool CIcqProto::RefreshRobustToken() @@ -451,6 +509,37 @@ void CIcqProto::OnCheckPassword(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) StartSession(); } +void CIcqProto::OnGetChatInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) +{ + SESSION_INFO *si = (SESSION_INFO*)pReq->pUserInfo; + + RobustReply root(pReply); + if (root.error() != 20000) + return; + + int n = 0; + char buf[100]; + const JSONNode &results = root.results(); + for (auto &it : results["members"]) { + mir_snprintf(buf, "m%d", n++); + + CMStringW friendly = it["friendly"].as_mstring(); + CMStringW role = it["role"].as_mstring(); + CMStringW sn = it["sn"].as_mstring(); + + JSONNode member; + member << WCHAR_PARAM("nick", friendly) << WCHAR_PARAM("role", role) << WCHAR_PARAM("sn", sn); + ptrW text(json_write(&member)); + setWString(si->hContact, buf, text); + } + + setDword(si->hContact, "MemberCount", n); + setId(si->hContact, "InfoVersion", _wtoi64(results["infoVersion"].as_mstring())); + setId(si->hContact, "MembersVersion", _wtoi64(results["membersVersion"].as_mstring())); + + LoadChatInfo(si); +} + void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) { MCONTACT hContact = (MCONTACT)pReq->pUserInfo; @@ -676,9 +765,33 @@ void CIcqProto::ProcessEvent(const JSONNode &ev) void CIcqProto::ProcessHistData(const JSONNode &ev) { - DWORD dwUin = _wtol(ev["sn"].as_mstring()); - - MCONTACT hContact = CreateContact(dwUin, true); + MCONTACT hContact; + + CMStringW wszId(ev["sn"].as_mstring()); + if (IsChat(wszId)) { + SESSION_INFO *si = g_chatApi.SM_FindSession(wszId, m_szModuleName); + if (si == nullptr) + return; + + hContact = si->hContact; + + if (si->arUsers.getCount() == 0) { + __int64 srvInfoVer = _wtoi64(ev["mchatState"]["infoVersion"].as_mstring()); + __int64 srvMembersVer = _wtoi64(ev["mchatState"]["membersVersion"].as_mstring()); + if (srvInfoVer != getId(hContact, "InfoVersion") || srvMembersVer != getId(hContact, "MembersVersion")) { + auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnGetChatInfo); + JSONNode request, params; params.set_name("params"); + params << WCHAR_PARAM("sn", wszId) << INT_PARAM("memberLimit", 100) << CHAR_PARAM("aimSid", m_aimsid); + request << CHAR_PARAM("method", "getChatInfo") << CHAR_PARAM("reqId", pReq->m_reqId) << CHAR_PARAM("authToken", m_szRToken) << INT_PARAM("clientId", m_iRClientId) << params; + pReq->m_szParam = ptrW(json_write(&request)); + pReq->pUserInfo = si; + Push(pReq); + } + else LoadChatInfo(si); + } + } + else hContact = CreateContact(_wtol(wszId), true); + __int64 lastMsgId = getId(hContact, DB_KEY_LASTMSGID); __int64 srvLastId = _wtoi64(ev["lastMsgId"].as_mstring()); __int64 srvUnreadId = _wtoi64(ev["yours"]["lastRead"].as_mstring()); @@ -768,7 +881,7 @@ void __cdecl CIcqProto::PollThread(void*) bFirst = false; szUrl.Append("&first=1"); } - else szUrl.Append("&timeout=60000"); + else szUrl.Append("&timeout=25000"); auto *pReq = new AsyncHttpRequest(CONN_FETCH, REQUEST_GET, szUrl, &CIcqProto::OnFetchEvents); if (!bFirst) diff --git a/protocols/Icq10/src/stdafx.h b/protocols/Icq10/src/stdafx.h index b9770142f0..929854990c 100644 --- a/protocols/Icq10/src/stdafx.h +++ b/protocols/Icq10/src/stdafx.h @@ -43,27 +43,28 @@ // Miranda IM SDK includes #include <newpluginapi.h> // This must be included first +#include <m_avatars.h> +#include <m_chat_int.h> #include <m_clist.h> #include <m_database.h> +#include <m_gui.h> +#include <m_idle.h> +#include <m_icolib.h> +#include <m_ignore.h> +#include <m_json.h> #include <m_langpack.h> #include <m_message.h> #include <m_netlib.h> #include <m_protocols.h> #include <m_protosvc.h> #include <m_options.h> +#include <m_popup.h> +#include <m_skin.h> #include <m_system.h> +#include <m_timezones.h> #include <m_userinfo.h> #include <m_utils.h> -#include <m_idle.h> -#include <m_skin.h> -#include <m_popup.h> -#include <m_ignore.h> -#include <m_json.h> -#include <m_icolib.h> -#include <m_avatars.h> -#include <m_timezones.h> #include <win2k.h> -#include <m_gui.h> #include <openssl/evp.h> #include <openssl/hmac.h> @@ -87,6 +88,8 @@ #include "http.h" #include "proto.h" +bool IsChat(const CMStringW &aimid); + int StatusFromString(const CMStringW&); extern HWND g_hwndHeartbeat;
\ No newline at end of file diff --git a/protocols/Icq10/src/utils.cpp b/protocols/Icq10/src/utils.cpp index c99f4f7915..5f1273716f 100644 --- a/protocols/Icq10/src/utils.cpp +++ b/protocols/Icq10/src/utils.cpp @@ -187,6 +187,19 @@ INT_PTR __cdecl CIcqProto::SetAvatar(WPARAM, LPARAM lParam) ///////////////////////////////////////////////////////////////////////////////////////// +CMStringA CIcqProto::GetUserId(MCONTACT hContact) +{ + if (isChatRoom(hContact)) + return getMStringA(hContact, "ChatRoomID"); + + return CMStringA(FORMAT, "%d", getDword(hContact, DB_KEY_UIN)); +} + +bool IsChat(const CMStringW &aimid) +{ + return aimid.Right(11) == "@chat.agent"; +} + int StatusFromString(const CMStringW &wszStatus) { if (wszStatus == "online") |