summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-01-10 21:10:31 +0200
committerGeorge Hazan <ghazan@miranda.im>2019-01-10 21:10:31 +0200
commit1e86f4d089a1748ce1449074498a283a8639663b (patch)
tree0746fa3af1a43b3063ede213b6b43c10729e58ba /protocols
parentaec99075210e9d107eb0f4231c0bb040ba6c1eee (diff)
fixes #1740 (ICQ10: add groupchats support)
Diffstat (limited to 'protocols')
-rw-r--r--protocols/Icq10/res/resources.rc8
-rw-r--r--protocols/Icq10/src/options.cpp7
-rw-r--r--protocols/Icq10/src/proto.cpp86
-rw-r--r--protocols/Icq10/src/proto.h210
-rw-r--r--protocols/Icq10/src/resource.h2
-rw-r--r--protocols/Icq10/src/server.cpp159
-rw-r--r--protocols/Icq10/src/stdafx.h21
-rw-r--r--protocols/Icq10/src/utils.cpp13
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")