From cfb2353a35c2275d1f8d45323817503ee6ddc4a4 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 14 Nov 2023 20:10:01 +0300 Subject: =?UTF-8?q?fixes=20#3757=20(ICQ:=20=D0=9C=D0=B8=D1=80=D0=B0=D0=BD?= =?UTF-8?q?=D0=B4=D0=B0=20=D0=BD=D0=B5=20=D0=BC=D0=BE=D0=B6=D0=B5=D1=82=20?= =?UTF-8?q?=D0=BE=D0=BF=D1=80=D0=B5=D0=B4=D0=B5=D0=BB=D0=B8=D1=82=D1=8C,?= =?UTF-8?q?=20=D1=87=D1=82=D0=BE=20=D1=81=D0=BE=D0=B1=D0=B5=D1=81=D0=B5?= =?UTF-8?q?=D0=B4=D0=BD=D0=B8=D0=BA=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C?= =?UTF-8?q?=D0=B7=D1=83=D0=B5=D1=82=20=D0=9C=D0=B8=D1=80=D0=B0=D0=BD=D0=B4?= =?UTF-8?q?=D1=83)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocols/ICQ-WIM/src/avatars.cpp | 2 +- protocols/ICQ-WIM/src/groupchats.cpp | 4 +- protocols/ICQ-WIM/src/groups.cpp | 4 +- protocols/ICQ-WIM/src/http.cpp | 7 ++++ protocols/ICQ-WIM/src/http.h | 2 +- protocols/ICQ-WIM/src/ignore.cpp | 4 +- protocols/ICQ-WIM/src/proto.cpp | 14 +++---- protocols/ICQ-WIM/src/proto.h | 5 ++- protocols/ICQ-WIM/src/server.cpp | 78 +++++++++++++++++++++++++++--------- protocols/ICQ-WIM/src/utils.cpp | 3 ++ protocols/ICQ-WIM/src/version.h | 4 +- 11 files changed, 88 insertions(+), 39 deletions(-) (limited to 'protocols') diff --git a/protocols/ICQ-WIM/src/avatars.cpp b/protocols/ICQ-WIM/src/avatars.cpp index c7576ca60c..452a9da444 100644 --- a/protocols/ICQ-WIM/src/avatars.cpp +++ b/protocols/ICQ-WIM/src/avatars.cpp @@ -93,7 +93,7 @@ INT_PTR __cdecl CIcqProto::SetAvatar(WPARAM, LPARAM lParam) GetAvatarFileName(0, wszOldName, _countof(wszOldName)); _wremove(wszOldName); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/expressions/upload"); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "/expressions/upload"); pReq->m_szUrl.AppendFormat("?f=json&aimsid=%s&r=%s&type=largeBuddyIcon", mir_urlEncode(m_aimsid.c_str()).c_str(), pReq->m_reqId); if (pwszFileName == nullptr) diff --git a/protocols/ICQ-WIM/src/groupchats.cpp b/protocols/ICQ-WIM/src/groupchats.cpp index c45eaecfa4..aef323b1c9 100644 --- a/protocols/ICQ-WIM/src/groupchats.cpp +++ b/protocols/ICQ-WIM/src/groupchats.cpp @@ -178,7 +178,7 @@ public: } } - m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/mchat/AddChat") + m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/mchat/AddChat") << AIMSID(m_proto) << WCHAR_PARAM("chat_id", m_si->ptszID) << WCHAR_PARAM("members", szMembers)); return true; } @@ -194,7 +194,7 @@ void CIcqProto::InviteUserToChat(SESSION_INFO *si) void CIcqProto::LeaveDestroyChat(SESSION_INFO *si) { - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/hideChat") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/hideChat") << AIMSID(this) << WCHAR_PARAM("buddy", si->ptszID) << INT64_PARAM("lastMsgId", getId(si->hContact, DB_KEY_LASTMSGID))); db_delete_contact(si->hContact); diff --git a/protocols/ICQ-WIM/src/groups.cpp b/protocols/ICQ-WIM/src/groups.cpp index 93c7ef6e8b..29e1a97673 100644 --- a/protocols/ICQ-WIM/src/groups.cpp +++ b/protocols/ICQ-WIM/src/groups.cpp @@ -98,13 +98,13 @@ public: if (!EnterString(&es)) return; - m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/renameGroup") + m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/renameGroup") << AIMSID(m_proto) << WCHAR_PARAM("oldGroup", pGroup->wszSrvName) << GROUP_PARAM("newGroup", es.ptszResult)); mir_free(es.ptszResult); } else if (cmd == 2) { // delete - m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/removeGroup") + m_proto->Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/removeGroup") << AIMSID(m_proto) << WCHAR_PARAM("group", pGroup->wszSrvName)); } } diff --git a/protocols/ICQ-WIM/src/http.cpp b/protocols/ICQ-WIM/src/http.cpp index 79910dad11..b422c0d57b 100644 --- a/protocols/ICQ-WIM/src/http.cpp +++ b/protocols/ICQ-WIM/src/http.cpp @@ -132,6 +132,13 @@ AsyncHttpRequest::AsyncHttpRequest(IcqConnection conn, int iType, const char *sz m_pFunc = pFunc; timeout = 10000; + if (conn == CONN_OLD) { + m_conn = CONN_MAIN; + m_szUrl.Insert(0, "https://u.icq.net/wim/v17"); + } + else if (*szUrl == '/') + m_szUrl.Insert(0, "https://u.icq.net/wim"); + GUID packetId; UuidCreate(&packetId); diff --git a/protocols/ICQ-WIM/src/http.h b/protocols/ICQ-WIM/src/http.h index c2262a53b4..5bbccd0be7 100644 --- a/protocols/ICQ-WIM/src/http.h +++ b/protocols/ICQ-WIM/src/http.h @@ -3,7 +3,7 @@ class CIcqProto; enum IcqConnection { - CONN_NONE = -1, CONN_MAIN = 0, CONN_FETCH = 1, CONN_RAPI = 2, CONN_LAST = 3 + CONN_OLD = -2, CONN_NONE = -1, CONN_MAIN = 0, CONN_FETCH = 1, CONN_RAPI = 2, CONN_LAST = 3 }; struct AsyncHttpRequest : public MTHttpRequest diff --git a/protocols/ICQ-WIM/src/ignore.cpp b/protocols/ICQ-WIM/src/ignore.cpp index 7d64edceba..a7b6cfe66b 100644 --- a/protocols/ICQ-WIM/src/ignore.cpp +++ b/protocols/ICQ-WIM/src/ignore.cpp @@ -23,7 +23,7 @@ void CIcqProto::GetPermitDeny() { - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/getPermitDeny", &CIcqProto::OnGetPermitDeny) << AIMSID(this)); + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/preference/getPermitDeny", &CIcqProto::OnGetPermitDeny) << AIMSID(this)); } void CIcqProto::OnGetPermitDeny(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) @@ -74,7 +74,7 @@ void CIcqProto::ProcessPermissions(const JSONNode &ev) void CIcqProto::SetPermitDeny(const CMStringW &userId, bool bAllow) { - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/preference/setPermitDeny") + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/preference/setPermitDeny") << AIMSID(this) << WCHAR_PARAM((bAllow) ? "pdIgnoreRemove" : "pdIgnore", userId); if (!m_bIgnoreListEmpty) pReq << CHAR_PARAM("pdMode", "denySome"); diff --git a/protocols/ICQ-WIM/src/proto.cpp b/protocols/ICQ-WIM/src/proto.cpp index b4239637d6..63c7c7418c 100644 --- a/protocols/ICQ-WIM/src/proto.cpp +++ b/protocols/ICQ-WIM/src/proto.cpp @@ -165,7 +165,7 @@ void CIcqProto::OnContactDeleted(MCONTACT hContact) m_arCache.remove(FindUser(szId)); } - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/removeBuddy") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/removeBuddy") << AIMSID(this) << WCHAR_PARAM("buddy", szId) << INT_PARAM("allGroups", 1)); } @@ -409,15 +409,15 @@ int CIcqProto::OnGroupChange(WPARAM hContact, LPARAM lParam) if (it->wszName == pParam->pszNewName) return 0; - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/addGroup") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/addGroup") << AIMSID(this) << GROUP_PARAM("group", pParam->pszNewName)); } else if (pParam->pszNewName == nullptr) { - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/removeGroup") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/removeGroup") << AIMSID(this) << GROUP_PARAM("group", pParam->pszOldName)); } else { - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/renameGroup") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/renameGroup") << AIMSID(this) << GROUP_PARAM("oldGroup", pParam->pszOldName) << GROUP_PARAM("newGroup", pParam->pszNewName)); } } @@ -462,7 +462,7 @@ int CIcqProto::AuthRequest(MCONTACT hContact, const wchar_t* szMessage) if (!wszGroup) wszGroup = mir_wstrdup(L"General"); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/buddylist/addBuddy", &CIcqProto::OnAddBuddy); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "/buddylist/addBuddy", &CIcqProto::OnAddBuddy); pReq << AIMSID(this) << WCHAR_PARAM("authorizationMsg", szMessage) << WCHAR_PARAM("buddy", GetUserId(hContact)) << WCHAR_PARAM("group", wszGroup) << INT_PARAM("preAuthorized", 1); pReq->hContact = hContact; Push(pReq); @@ -570,7 +570,7 @@ int CIcqProto::SendMsg(MCONTACT hContact, const char *pszSrc) return 0; int id = InterlockedIncrement(&m_msgId); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/im/sendIM", &CIcqProto::OnSendMessage); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "/im/sendIM", &CIcqProto::OnSendMessage); auto *pOwn = new IcqOwnMessage(hContact, id, pReq->m_reqId, pszSrc); pReq->pUserInfo = pOwn; @@ -640,7 +640,7 @@ int CIcqProto::SetStatus(int iNewStatus) int CIcqProto::UserIsTyping(MCONTACT hContact, int type) { - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/im/setTyping") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/im/setTyping") << AIMSID(this) << WCHAR_PARAM("t", GetUserId(hContact)) << CHAR_PARAM("typingStatus", (type == PROTOTYPE_SELFTYPING_ON) ? "typing" : "typed")); return 0; } diff --git a/protocols/ICQ-WIM/src/proto.h b/protocols/ICQ-WIM/src/proto.h index fdd552a1cc..b3826be1d4 100644 --- a/protocols/ICQ-WIM/src/proto.h +++ b/protocols/ICQ-WIM/src/proto.h @@ -35,7 +35,6 @@ #define MRA_APP_ID "ic1pzYNtEU6dDnEQ" #define ICQ_APP_ID "ic1nmMjqg7Yu-0hL" -#define ICQ_API_SERVER "https://u.icq.net/wim" #define ICQ_FILE_SERVER "https://u.icq.net/files/api/v1.1" #define ICQ_FAKE_EVENT_ID 0xBABAEB #define ICQ_ROBUST_SERVER "https://u.icq.net/rapi" @@ -116,7 +115,7 @@ struct IcqUser : public MZeroedObject CMStringW m_aimid; MCONTACT m_hContact; - bool m_bInList; + bool m_bInList, m_bGotCaps; __int64 m_iProcessedMsgId; int m_iApparentMode; time_t m_timer1, m_timer2; @@ -218,6 +217,7 @@ class CIcqProto : public PROTO wchar_t* GetUIN(MCONTACT hContact); void MoveContactToGroup(MCONTACT hContact, const wchar_t *pwszGroup, const wchar_t *pwszNewGroup); bool RetrievePassword(); + void RetrieveUserCaps(IcqUser *pUser); void RetrieveUserHistory(MCONTACT, __int64 startMsgId, bool bCreateRead); void RetrieveUserInfo(MCONTACT hContact); void SendMrimLogin(NETLIBHTTPREQUEST *pReply); @@ -266,6 +266,7 @@ class CIcqProto : public PROTO void OnGetChatInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); void OnGetPermitDeny(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); void OnGetSticker(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); + void OnGetUserCaps(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); void OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); void OnGetUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); void OnLastSeen(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq); diff --git a/protocols/ICQ-WIM/src/server.cpp b/protocols/ICQ-WIM/src/server.cpp index 1af5cbd52c..211882f9bc 100644 --- a/protocols/ICQ-WIM/src/server.cpp +++ b/protocols/ICQ-WIM/src/server.cpp @@ -41,7 +41,7 @@ void CIcqProto::CheckAvatarChange(MCONTACT hContact, const JSONNode &ev) setWString(hContact, "IconId", wszIconId); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/expressions/get", &CIcqProto::OnReceiveAvatar); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/expressions/get", &CIcqProto::OnReceiveAvatar); pReq << CHAR_PARAM("f", "native") << WCHAR_PARAM("t", GetUserId(hContact)) << CHAR_PARAM("type", "bigBuddyIcon"); pReq->hContact = hContact; Push(pReq); @@ -285,7 +285,7 @@ void CIcqProto::MoveContactToGroup(MCONTACT hContact, const wchar_t *pwszGroup, if (!mir_wstrlen(pwszGroup)) return; - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/buddylist/moveBuddy") << AIMSID(this) << WCHAR_PARAM("buddy", GetUserId(hContact)) + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/buddylist/moveBuddy") << AIMSID(this) << WCHAR_PARAM("buddy", GetUserId(hContact)) << GROUP_PARAM("group", pwszGroup); if (mir_wstrlen(pwszNewGroup)) pReq << GROUP_PARAM("newGroup", pwszNewGroup); @@ -674,14 +674,65 @@ LBL_Error: return bRet; } +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::OnGetUserCaps(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) +{ + JsonReply root(pReply); + if (root.error() != 200) + return; + + auto &data = root.data(); + for (auto &it : data["users"]) { + ParseBuddyInfo(it, pReq->hContact, true); + + if (auto *pUser = (IcqUser *)pReq->pUserInfo) + pUser->m_bGotCaps = true; + } +} + +void CIcqProto::RetrieveUserCaps(IcqUser *pUser) +{ + auto *pReq = new AsyncHttpRequest(CONN_OLD, REQUEST_GET, "/presence/get", &CIcqProto::OnGetUserCaps); + pReq->hContact = pUser->m_hContact; + pReq->pUserInfo = pUser; + pReq << CHAR_PARAM("a", m_szAToken) << CHAR_PARAM("f", "json") << CHAR_PARAM("k", appId()) << CHAR_PARAM("r", pReq->m_reqId) + << WCHAR_PARAM("t", GetUserId(pUser->m_hContact)) << INT_PARAM("mdir", 0) << INT_PARAM("capabilities", 1); + Push(pReq); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::OnGetUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) +{ + RobustReply root(pReply); + if (root.error() != 20000) { + ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, nullptr); + return; + } + + ParseBuddyInfo(root.results(), pReq->hContact, true); + + ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, nullptr); +} + void CIcqProto::RetrieveUserInfo(MCONTACT hContact) { + CMStringW wszId(GetUserId(hContact)); + auto *pReq = new AsyncRapiRequest(this, "getUserInfo", &CIcqProto::OnGetUserInfo); - pReq->params << WCHAR_PARAM("sn", GetUserId(hContact)); + pReq->params << WCHAR_PARAM("sn", wszId); pReq->hContact = hContact; Push(pReq); + + if (hContact) + if (auto *pUser = FindUser(wszId)) + if (!pUser->m_bGotCaps) + RetrieveUserCaps(pUser); } +///////////////////////////////////////////////////////////////////////////////////////// + void CIcqProto::RetrieveUserHistory(MCONTACT hContact, __int64 startMsgId, bool bCreateRead) { if (startMsgId == 0) @@ -716,11 +767,11 @@ void CIcqProto::SetServerStatus(int iStatus) invisible = 1; } - Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, ICQ_API_SERVER "/presence/setState") + Push(new AsyncHttpRequest(CONN_MAIN, REQUEST_GET, "/presence/setState") << AIMSID(this) << CHAR_PARAM("view", szStatus) << INT_PARAM("invisible", invisible)); if (iStatus == ID_STATUS_OFFLINE && !getByte(DB_KEY_PHONEREG)) { - auto *pReq = new AsyncHttpRequest(CONN_NONE, REQUEST_GET, ICQ_API_SERVER "/aim/endSession", &CIcqProto::OnSessionEnd); + auto *pReq = new AsyncHttpRequest(CONN_NONE, REQUEST_GET, "/aim/endSession", &CIcqProto::OnSessionEnd); pReq << AIMSID(this) << INT_PARAM("invalidateToken", 1); ExecuteRequest(pReq); } @@ -783,7 +834,7 @@ void CIcqProto::StartSession() caps.AppendFormat(",%02x%02x%02x%02x%02x%02x%02x%02x%04x%04x%04x%04x", 'M', 'i', 'N', 'G', __MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM, v[0], v[1], v[2], v[3]); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/aim/startSession", &CIcqProto::OnStartSession); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "/aim/startSession", &CIcqProto::OnStartSession); pReq << CHAR_PARAM("a", m_szAToken) << INT_PARAM("activeTimeout", 180) << CHAR_PARAM("assertCaps", caps) << INT_PARAM("buildNumber", __BUILD_NUM) << CHAR_PARAM("deviceId", szDeviceId) << CHAR_PARAM("events", EVENTS) << CHAR_PARAM("f", "json") << CHAR_PARAM("imf", "plain") << CHAR_PARAM("inactiveView", "offline") @@ -927,7 +978,7 @@ LBL_Error: wszUrl += L" " + pTransfer->m_wszDescr; int id = InterlockedIncrement(&m_msgId); - auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/im/sendIM", &CIcqProto::OnSendMessage); + auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "/im/sendIM", &CIcqProto::OnSendMessage); auto *pOwn = new IcqOwnMessage(pTransfer->pfts.hContact, id, pReq->m_reqId, T2Utf(wszUrl)); pReq->pUserInfo = pOwn; @@ -1046,19 +1097,6 @@ void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pR RetrieveUserHistory(pReq->hContact, lastMsgId, pReq->pUserInfo != nullptr); } -void CIcqProto::OnGetUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) -{ - RobustReply root(pReply); - if (root.error() != 20000) { - ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, nullptr); - return; - } - - ParseBuddyInfo(root.results(), pReq->hContact, true); - - ProtoBroadcastAck(pReq->hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, nullptr); -} - void CIcqProto::OnStartSession(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *) { JsonReply root(pReply); diff --git a/protocols/ICQ-WIM/src/utils.cpp b/protocols/ICQ-WIM/src/utils.cpp index ffaccc4747..56ef3dce88 100644 --- a/protocols/ICQ-WIM/src/utils.cpp +++ b/protocols/ICQ-WIM/src/utils.cpp @@ -219,6 +219,9 @@ void CIcqProto::ProcessStatus(IcqUser *pUser, int iStatus) // if a client returns back online, we clear timers not to play with statuses anymore else pUser->m_timer1 = pUser->m_timer2 = 0; + if (iStatus == ID_STATUS_ONLINE && !pUser->m_bGotCaps) + RetrieveUserCaps(pUser); + setWord(pUser->m_hContact, "Status", iStatus); } diff --git a/protocols/ICQ-WIM/src/version.h b/protocols/ICQ-WIM/src/version.h index bc77648b0b..f3c575a2c8 100644 --- a/protocols/ICQ-WIM/src/version.h +++ b/protocols/ICQ-WIM/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 96 -#define __RELEASE_NUM 3 -#define __BUILD_NUM 4 +#define __RELEASE_NUM 4 +#define __BUILD_NUM 1 #include -- cgit v1.2.3