From 5e77e8a1665382c76fee1bc3ca12e44aca9af2e7 Mon Sep 17 00:00:00 2001 From: Alexander Lantsev Date: Thu, 20 Dec 2012 17:25:21 +0000 Subject: - third approach of group chat support - added connection options - fixed connection via proxy git-svn-id: http://svn.miranda-ng.org/main/trunk@2772 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/Skype/src/resource.h | 7 +- protocols/Skype/src/skype.cpp | 14 +- protocols/Skype/src/skype_chat.cpp | 248 ++++++++++++++++++++++-------- protocols/Skype/src/skype_contacts.cpp | 45 +++++- protocols/Skype/src/skype_dialogs.cpp | 70 ++++++++- protocols/Skype/src/skype_events.cpp | 145 +++++++++++++++-- protocols/Skype/src/skype_proto.cpp | 29 ++-- protocols/Skype/src/skype_proto.h | 86 +++++++++-- protocols/Skype/src/skype_subclassing.cpp | 17 +- protocols/Skype/src/skype_subclassing.h | 6 +- protocols/Skype/src/skype_utils.cpp | 51 ++++++ 11 files changed, 595 insertions(+), 123 deletions(-) (limited to 'protocols/Skype/src') diff --git a/protocols/Skype/src/resource.h b/protocols/Skype/src/resource.h index 715b1b9b1c..12cd98774d 100644 --- a/protocols/Skype/src/resource.h +++ b/protocols/Skype/src/resource.h @@ -1,6 +1,6 @@ //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. -// Used by e:\Projects\C++\MirandaNG\protocols\Skype\res\Resource.rc +// Used by D:\Projects\CPlusPlus\MirandaNG\protocols\Skype\res\Resource.rc // #define IDD_SKYPEACCOUNT 9 #define IDD_OPTIONS 10 @@ -32,6 +32,9 @@ #define IDC_SAVE 1013 #define IDC_LIST 1014 #define IDC_UPLOADING 1015 +#define IDC_PORT 1016 +#define IDC_CHECK1 1017 +#define IDC_USE_ALT_PORTS 1017 // Next default values for new objects // @@ -39,7 +42,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 108 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1016 +#define _APS_NEXT_CONTROL_VALUE 1018 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/protocols/Skype/src/skype.cpp b/protocols/Skype/src/skype.cpp index ad23c7c14e..f2b22adf17 100644 --- a/protocols/Skype/src/skype.cpp +++ b/protocols/Skype/src/skype.cpp @@ -124,7 +124,7 @@ unsigned char decode(char * data, unsigned char *buf, int len) } } #undef BASE64DECODE_READ_NEXT_CHAR - + unsigned char *decode(char * data, int *outlen) { if ( !data) { *outlen = 0; return (unsigned char*)""; } @@ -142,15 +142,15 @@ char* LoadKeyPair() if (hRes) { HGLOBAL hResource = LoadResource(g_hInstance, hRes); if (hResource) { - aes_context ctx; - + aes_context ctx; + int basedecodedkey = decodeSize((char*)MY_KEY); unsigned char *tmpK = (unsigned char*)malloc(basedecodedkey + 1); decode((char*)MY_KEY, tmpK, basedecodedkey); tmpK[basedecodedkey] = 0; - - - aes_set_key( &ctx, tmpK, 128); + + + aes_set_key( &ctx, tmpK, 128); int dwResSize = SizeofResource(g_hInstance, hRes); char *pData = (char*)GlobalLock(hResource); char *pCopy = (char*)_alloca(dwResSize+1); @@ -165,7 +165,7 @@ char* LoadKeyPair() aes_decrypt(&ctx, tmpD+i, bufD+i); } mir_free(tmpD); - bufD[basedecoded] = 0; //cert should be null terminated + bufD[basedecoded] = 0; //cert should be null terminated return (char*)bufD; } return NULL; diff --git a/protocols/Skype/src/skype_chat.cpp b/protocols/Skype/src/skype_chat.cpp index 25cd462268..57a5a2faff 100644 --- a/protocols/Skype/src/skype_chat.cpp +++ b/protocols/Skype/src/skype_chat.cpp @@ -8,13 +8,61 @@ bool CSkypeProto::IsChatRoom(HANDLE hContact) return ::DBGetContactSettingByte(hContact, this->m_szModuleName, "ChatRoom", 0) > 0; } -void CSkypeProto::ChatValidateContact(HANDLE hItem, HWND hwndList) +HANDLE CSkypeProto::GetChatRoomByID(const char *cid) +{ + HANDLE hContact = ::db_find_first(); + while (hContact) + { + if (this->IsProtoContact(hContact) && this->IsChatRoom(hContact)) + { + char *chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatRoomID"); + if (chatID && ::strcmp(cid, chatID) == 0) + return hContact; + } + + hContact = ::db_find_next(hContact); + } + + return 0; +} + +HANDLE CSkypeProto::AddChatRoomByID(const char* cid, const char* name, DWORD flags) +{ + HANDLE hContact = this->GetChatRoomByID(cid); + if ( !hContact) + { + hContact = (HANDLE)::CallService(MS_DB_CONTACT_ADD, 0, 0); + ::CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)this->m_szModuleName); + + ::DBWriteContactSettingByte(hContact, this->m_szModuleName, "ChatRoom", 1); + ::DBWriteContactSettingString(hContact, this->m_szModuleName, "ChatRoomID", cid); + ::DBWriteContactSettingString(hContact, this->m_szModuleName, "Nick", name); + ::DBWriteContactSettingWord(hContact, this->m_szModuleName, "Status", ID_STATUS_OFFLINE); + ::DBWriteContactSettingWord(hContact, this->m_szModuleName, "ApparentMode", ID_STATUS_OFFLINE); + + wchar_t *defaultGroup = ::DBGetStringW(NULL, "Chat", "AddToGroup"); + if (defaultGroup) + { + ::DBWriteContactSettingWString(hContact, "CList", "Group", defaultGroup); + } + } + + return hContact; +} + +void CSkypeProto::ChatValidateContact(HANDLE hItem, HWND hwndList, const char *contacts) { if ( !this->IsProtoContact(hItem) || this->IsChatRoom(hItem)) - ::SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0); + { + /*char *sid = ::DBGetString(hItem, this->m_szModuleName, "sid"); + if (!sid) + ::SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0); + else if(contacts && ::strstr(contacts, sid))*/ + ::SendMessage(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0); + } } -void CSkypeProto::ChatPrepare(HANDLE hItem, HWND hwndList) +void CSkypeProto::ChatPrepare(HANDLE hItem, HWND hwndList, const char *contacts) { if (hItem == NULL) hItem = (HANDLE)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0); @@ -26,10 +74,10 @@ void CSkypeProto::ChatPrepare(HANDLE hItem, HWND hwndList) if (IsHContactGroup(hItem)) { HANDLE hItemT = (HANDLE)::SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); - if (hItemT) this->ChatPrepare(hItemT, hwndList); + if (hItemT) this->ChatPrepare(hItemT, hwndList, contacts); } else if (IsHContactContact(hItem)) - this->ChatValidateContact(hItem, hwndList); + this->ChatValidateContact(hItem, hwndList, contacts); hItem = hItemN; } @@ -88,38 +136,31 @@ void CSkypeProto::InitChat() this->HookEvent(ME_GC_BUILDMENU, &CSkypeProto::OnGCMenuHook); } -void CSkypeProto::StartChat(HANDLE hContact, SEStringList &chatTargets) +char *CSkypeProto::StartChat(const char *cid) { char *chatID; SEString data; - CConversation::Ref conversation; + CConversation::Ref conversation; - if (hContact) + if (cid) { - chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatRoomID"); - g_skype->GetConversationByIdentity(chatID, conversation); + g_skype->GetConversationByIdentity(cid, conversation); conversation->GetJoinBlob(data); - char *blob = ::mir_strdup((const char *)data); - g_skype->GetConversationByBlob(blob, conversation, false); + g_skype->GetConversationByBlob(data, conversation, false); conversation->Join(); - CParticipant::Refs participants; - conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); - for (uint i = 0; i < participants.size(); i++) - { - participants[i]->GetPropIdentity(data); - chatTargets.append(data); - } + chatID = ::mir_strdup(cid); } - else if ( !g_skype->GetConversationByParticipants(chatTargets, conversation)) + else { g_skype->CreateConference(conversation); - conversation->SetOption(CConversation::P_OPT_JOINING_ENABLED, true); - conversation->AddConsumers(chatTargets); + conversation->SetOption(CConversation::P_OPT_JOINING_ENABLED, true); + conversation->SetOption(CConversation::P_OPT_ENTRY_LEVEL_RANK, CParticipant::WRITER); + conversation->SetOption(CConversation::P_OPT_DISCLOSE_HISTORY, 1); conversation->GetPropIdentity(data); - chatID = ::mir_strdup((const char *)data); - } + char *chatID = ::mir_strdup(data); + } conversation->GetPropDisplayname(data); char *chatName = ::mir_utf8decodeA((const char *)data); @@ -145,33 +186,94 @@ void CSkypeProto::StartChat(HANDLE hContact, SEStringList &chatTargets) gce.pszStatus = ::Translate("Others"); ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); - for (uint i = 0; i < chatTargets.size(); i++) - { - HANDLE hContact = this->GetContactBySid(chatTargets[i]); - gcd.iType = GC_EVENT_JOIN; - gce.pszNick = ::DBGetString(hContact, this->m_szModuleName, "Nick"); - gce.pszUID = chatTargets[i]; - ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); - } - gcd.iType = GC_EVENT_CONTROL; ::CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce); ::CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); ::CallServiceSync(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce); ::mir_free(chatName); + + return chatID; +} + +void CSkypeProto::JoinToChat(const char *cid, bool showWindow) +{ + char *chatID = ::mir_strdup(cid); + + SEString data; + CConversation::Ref conversation; + + g_skype->GetConversationByIdentity(cid, conversation); + conversation->GetJoinBlob(data); + g_skype->GetConversationByBlob(data, conversation, false); + conversation->Join(); + + conversation->GetPropDisplayname(data); + char *chatName = ::mir_utf8decodeA((const char *)data); + + GCSESSION gcw = {0}; + gcw.cbSize = sizeof(gcw); + gcw.iType = GCW_CHATROOM; + gcw.pszModule = this->m_szModuleName; + gcw.pszName = chatName; + gcw.pszID = chatID; + ::CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); + + GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_ADDGROUP }; + gcd.pszID = chatID; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + gce.pszStatus = ::Translate("Me"); + ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + + gcd.iType = GC_EVENT_ADDGROUP; + gce.pszStatus = ::Translate("Others"); + ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + + gcd.iType = GC_EVENT_CONTROL; + ::CallServiceSync(MS_GC_EVENT, showWindow ? SESSION_INITDONE : WINDOW_HIDDEN, (LPARAM)&gce); + ::CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); + //::CallServiceSync(MS_GC_EVENT, showWindow ? WINDOW_VISIBLE : WINDOW_HIDDEN, (LPARAM)&gce); + + CParticipant::Refs participants; + conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); + for (uint i = 0; i < participants.size(); i++) + { + participants[i]->GetPropIdentity(data); + this->AddChatContact(cid, ::mir_strdup(data)); + } + + ::mir_free(chatName); + ::mir_free(chatID); +} + +void CSkypeProto::LeaveChat(const char *cid) +{ + char *chatID = ::mir_strdup(cid); + + GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_CONTROL }; + gcd.pszID = chatID; + + GCEVENT gce = {0}; + gce.cbSize = sizeof(GCEVENT); + gce.pDest = &gcd; + ::CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce); + ::CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); + ::mir_free(chatID); } -void CSkypeProto::ChatEvent(const char *chatID, const char *sid, int evt, const char *msg) +void CSkypeProto::RaiseChatEvent(const char *cid, const char *sid, int evt, const char *message) { - char *idt = ::mir_strdup(chatID); + char *idt = ::mir_strdup(cid); char *snt = ::mir_strdup(sid); HANDLE hContact = this->GetContactBySid(sid); char *nick = hContact ? (char *)::CallService(MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM(hContact), 0) : snt; - GCDEST gcd = { m_szModuleName, { NULL }, evt }; + GCDEST gcd = { this->m_szModuleName, { NULL }, evt }; gcd.pszID = idt; GCEVENT gce = {0}; @@ -182,7 +284,7 @@ void CSkypeProto::ChatEvent(const char *chatID, const char *sid, int evt, const gce.pszUID = snt; gce.bIsMe = ::stricmp(sid, this->login) == 0; gce.pszStatus = gce.bIsMe ? ::Translate("Me") : ::Translate("Others"); - gce.pszText = msg; + gce.pszText = message; gce.time = time(NULL); ::CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); @@ -190,39 +292,49 @@ void CSkypeProto::ChatEvent(const char *chatID, const char *sid, int evt, const ::mir_free(idt); } -INT_PTR __cdecl CSkypeProto::OnJoinChat(WPARAM wParam, LPARAM) +void CSkypeProto::SendChatMessage(const char *cid, const char *sid, const char *message) { - HANDLE hContact = (HANDLE)wParam; - SEStringList list; - this->StartChat(hContact, list); + this->RaiseChatEvent(cid, sid, GC_EVENT_MESSAGE, message); +} - return 0; +void CSkypeProto::AddChatContact(const char *cid, const char *sid) +{ + this->RaiseChatEvent(cid, sid, GC_EVENT_JOIN); } -INT_PTR __cdecl CSkypeProto::OnLeaveChat(WPARAM wParam, LPARAM) +void CSkypeProto::KickChatContact(const char *cid, const char *sid) { - HANDLE hContact = (HANDLE)wParam; - char *chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatID"); - this->ChatLeave(chatID); + this->RaiseChatEvent(cid, sid, GC_EVENT_KICK); +} - return 0; +void CSkypeProto::RemoveChatContact(const char *cid, const char *sid) +{ + this->RaiseChatEvent(cid, sid, GC_EVENT_QUIT); } -void CSkypeProto::ChatLeave(const char *chatID) +INT_PTR __cdecl CSkypeProto::OnJoinChat(WPARAM wParam, LPARAM) { - char *idt = ::mir_strdup(chatID); + HANDLE hContact = (HANDLE)wParam; + if (hContact) + { + this->JoinToChat(::DBGetString(hContact, this->m_szModuleName, "ChatRoomID")); + } - GCDEST gcd = { m_szModuleName, { NULL }, GC_EVENT_CONTROL }; - gcd.pszID = idt; + return 0; +} - GCEVENT gce = {0}; - gce.cbSize = sizeof(GCEVENT); - //gce.dwFlags = GCEF_REMOVECONTACT; - gce.pDest = &gcd; - ::CallServiceSync(MS_GC_EVENT, SESSION_OFFLINE, (LPARAM)&gce); - ::CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); +INT_PTR __cdecl CSkypeProto::OnLeaveChat(WPARAM wParam, LPARAM) +{ + HANDLE hContact = (HANDLE)wParam; + if (hContact) + { + char *cid = ::DBGetString(hContact, this->m_szModuleName, "ChatRoomID"); + this->LeaveChat(cid); + + ::mir_free(cid); + } - ::mir_free(idt); + return 0; } int __cdecl CSkypeProto::OnGCEventHook(WPARAM, LPARAM lParam) @@ -289,7 +401,7 @@ int __cdecl CSkypeProto::OnGCEventHook(WPARAM, LPARAM lParam) break; case 20: - this->ChatLeave(chatID); + this->LeaveChat(chatID); break; } break; @@ -306,7 +418,7 @@ int __cdecl CSkypeProto::OnGCEventHook(WPARAM, LPARAM lParam) break; case 110: - this->ChatLeave(chatID); + this->LeaveChat(chatID); break; } break; @@ -365,4 +477,20 @@ int __cdecl CSkypeProto::OnGCMenuHook(WPARAM, LPARAM lParam) } return 0; +} + + +char *CSkypeProto::GetChatUsers(const char *cid) +{ + GC_INFO gci = {0}; + gci.Flags = USERS; + gci.pszModule = this->m_szModuleName; + gci.pszID = ::mir_a2t(cid); + ::CallService(MS_GC_GETINFO, 0, (LPARAM)(GC_INFO *) &gci); + + ::mir_free(gci.pszID); + + //StringList users(gci.pszUsers, " "); + + return gci.pszUsers; } \ No newline at end of file diff --git a/protocols/Skype/src/skype_contacts.cpp b/protocols/Skype/src/skype_contacts.cpp index eae999ef92..116149cd55 100644 --- a/protocols/Skype/src/skype_contacts.cpp +++ b/protocols/Skype/src/skype_contacts.cpp @@ -531,16 +531,17 @@ bool CSkypeProto::IsProtoContact(HANDLE hContact) HANDLE CSkypeProto::GetContactBySid(const char *sid) { - HANDLE hContact = db_find_first(); + HANDLE hContact = ::db_find_first(); while (hContact) { if (this->IsProtoContact(hContact) && !this->IsChatRoom(hContact)) { - if (::strcmp(sid, ::DBGetString(hContact, this->m_szModuleName, "sid")) == 0) + char *contactSid = ::DBGetString(hContact, this->m_szModuleName, "sid"); + if (contactSid && ::strcmp(sid, contactSid) == 0) return hContact; } - hContact = db_find_next(hContact); + hContact = ::db_find_next(hContact); } return 0; @@ -721,6 +722,44 @@ void __cdecl CSkypeProto::LoadContactList(void*) this->UpdateContactStatusMessage(hContact, contact); } + CConversation::Refs conversations; + g_skype->GetConversationList(conversations); + for (uint i = 0; i < conversations.size(); i++) + { + CConversation::TYPE type; + conversations[i]->GetPropType(type); + + CConversation::MY_STATUS status; + conversations[i]->GetPropMyStatus(status); + if (type == CConversation::CONFERENCE) + { + SEString data; + + conversations[i]->GetPropIdentity(data); + char *cid = ::mir_strdup((const char *)data); + + conversations[i]->GetPropDisplayname(data); + char *name = ::mir_utf8decodeA((const char *)data); + + HANDLE hContact = this->AddChatRoomByID(cid, name); + + CConversation::LOCAL_LIVESTATUS live; + conversations[i]->GetPropLocalLivestatus(live); + + if (status == CConversation::CONSUMER)// && live != CConversation::NONE) + { + this->JoinToChat(cid, false); + } + } + } + + /*CConversation::Refs conversations; + g_skype->GetConversationList(conversations); + for (uint i = 0; i < conversations.size(); i++) + { + conversations[i]->Delete(); + }*/ + // raise auth event for all non auth contacts CContact::Refs authContacts; g_skype->GetHardwiredContactGroup(CContactGroup::CONTACTS_WAITING_MY_AUTHORIZATION, this->authWaitList); diff --git a/protocols/Skype/src/skype_dialogs.cpp b/protocols/Skype/src/skype_dialogs.cpp index a2464e6843..fd41a16407 100644 --- a/protocols/Skype/src/skype_dialogs.cpp +++ b/protocols/Skype/src/skype_dialogs.cpp @@ -89,10 +89,20 @@ INT_PTR CALLBACK CSkypeProto::SkypeOptionsProc(HWND hwnd, UINT message, WPARAM w SetDlgItemTextA(hwnd, IDC_PW, data); ::mir_free(data); } + { + int port; + g_skype->GetInt(SETUPKEY_PORT, port); + SetDlgItemInt(hwnd, IDC_PORT, proto->GetSettingWord("Port", port), FALSE); + } + { + CheckDlgButton(hwnd, IDC_USE_ALT_PORTS, proto->GetSettingByte("UseAlternativePorts", 1)); + } if (proto->m_iStatus != ID_STATUS_OFFLINE) { SendMessage(GetDlgItem(hwnd, IDC_SL), EM_SETREADONLY, 1, 0); SendMessage(GetDlgItem(hwnd, IDC_PW), EM_SETREADONLY, 1, 0); + SendMessage(GetDlgItem(hwnd, IDC_PORT), EM_SETREADONLY, 1, 0); + SendMessage(GetDlgItem(hwnd, IDC_USE_ALT_PORTS), EM_SETREADONLY, 1, 0); } } return TRUE; @@ -105,6 +115,8 @@ INT_PTR CALLBACK CSkypeProto::SkypeOptionsProc(HWND hwnd, UINT message, WPARAM w { case IDC_SL: case IDC_PW: + case IDC_PORT: + case IDC_USE_ALT_PORTS: SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); } } @@ -125,6 +137,9 @@ INT_PTR CALLBACK CSkypeProto::SkypeOptionsProc(HWND hwnd, UINT message, WPARAM w GetDlgItemTextA(hwnd, IDC_PW, data, sizeof(data)); proto->SetDecodeSettingString(NULL, SKYPE_SETTINGS_PASSWORD, data); + proto->SetSettingWord("Port", GetDlgItemInt(hwnd, IDC_PORT, NULL, FALSE)); + proto->GetSettingByte("UseAlternativePorts", IsDlgButtonChecked( hwnd, IDC_USE_ALT_PORTS ) > 0); + proto->SetSettingByte("RememberPassword", true); return TRUE; @@ -471,13 +486,33 @@ INT_PTR CALLBACK CSkypeProto::InviteToChatProc(HWND hwndDlg, UINT msg, WPARAM wP case CLN_NEWCONTACT: if (param && (nmc->flags & (CLNF_ISGROUP | CLNF_ISINFO)) == 0) { - param->ppro->ChatValidateContact(nmc->hItem, nmc->hdr.hwndFrom); + char *contacts = NULL; + if (param->id) + { + HANDLE hContact = param->ppro->GetChatRoomByID(param->id); + if (hContact && ::DBGetContactSettingWord(hContact, param->ppro->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + { + contacts = param->ppro->GetChatUsers(param->id); + } + } + param->ppro->ChatValidateContact(nmc->hItem, nmc->hdr.hwndFrom, contacts); } break; case CLN_LISTREBUILT: if (param) - param->ppro->ChatPrepare(NULL, nmc->hdr.hwndFrom); + { + char *contacts = NULL; + if (param->id) + { + HANDLE hContact = param->ppro->GetChatRoomByID(param->id); + if (hContact && ::DBGetContactSettingWord(hContact, param->ppro->m_szModuleName, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) + { + contacts = param->ppro->GetChatUsers(param->id); + } + } + param->ppro->ChatPrepare(NULL, nmc->hdr.hwndFrom, contacts); + } break; } } @@ -511,12 +546,35 @@ INT_PTR CALLBACK CSkypeProto::InviteToChatProc(HWND hwndDlg, UINT msg, WPARAM wP case IDOK: { - char sid[SKYPE_SID_LIMIT] = ""; HWND hwndList = ::GetDlgItem(hwndDlg, IDC_CCLIST); - SEStringList inviteContacts; - param->ppro->GetInviteContacts(NULL, hwndList, inviteContacts); - param->ppro->StartChat(NULL, inviteContacts); + SEStringList invitedContacts; + param->ppro->GetInviteContacts(NULL, hwndList, invitedContacts); + + CConversation::Ref conversation; + char *chatID = ::mir_strdup(param->id); + if (chatID) + { + g_skype->GetConversationByIdentity(chatID, conversation); + conversation->AddConsumers(invitedContacts); + } + else + { + chatID = param->ppro->StartChat(NULL); + + g_skype->GetConversationByIdentity(chatID, conversation); + conversation->AddConsumers(invitedContacts); + + /*SEString data; + + conversation->GetPropIdentity(data); + char *cid = ::mir_strdup((const char *)data); + + for (uint i = 0; i < invitedContacts.size(); i++) + { + param->ppro->AddChatContact(cid, invitedContacts[i]); + }*/ + } } EndDialog(hwndDlg, IDOK); diff --git a/protocols/Skype/src/skype_events.cpp b/protocols/Skype/src/skype_events.cpp index a3a89b9a6e..61b9724cb8 100644 --- a/protocols/Skype/src/skype_events.cpp +++ b/protocols/Skype/src/skype_events.cpp @@ -22,7 +22,21 @@ int CSkypeProto::OnPreShutdown(WPARAM, LPARAM) int CSkypeProto::OnContactDeleted(WPARAM wParam, LPARAM lParam) { - this->RevokeAuth(wParam, lParam); + HANDLE hContact = (HANDLE)wParam; + if (hContact && this->IsOnline()) + { + if (this->IsChatRoom(hContact)) + { + char *chatID = ::DBGetString(hContact, this->m_szModuleName, "ChatRoomID"); + this->LeaveChat(chatID); + + CConversation::Ref conversation; + g_skype->GetConversationByIdentity(chatID, conversation); + conversation->Delete(); + } + else + this->RevokeAuth(wParam, lParam); + } return 0; } @@ -38,7 +52,7 @@ void CSkypeProto::OnMessageSended(CConversation::Ref conversation, CMessage::Ref char *sid = ::mir_strdup((const char*)data); message->GetPropBodyXml(data); - char *text = ::mir_strdup((const char*)data); + char *text = ::mir_utf8decodeA((const char*)data); CConversation::TYPE type; conversation->GetPropType(type); @@ -62,9 +76,16 @@ void CSkypeProto::OnMessageSended(CConversation::Ref conversation, CMessage::Ref else { conversation->GetPropIdentity(data); - char *chatID = ::mir_utf8encode((const char*)data); + char *cid = ::mir_strdup((const char*)data); + + /*HANDLE hContact = this->GetChatRoomByID(cid); + if ( !hContact || ::DBGetContactSettingWord(hContact, this->m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + { + this->JoinChat(cid); + }*/ + this->SendChatMessage(cid, sid, text); - this->ChatEvent(chatID, sid, /*GC_EVENT_MESSAGE*/0x0040, text); + ::mir_free(cid); } } @@ -86,7 +107,7 @@ void CSkypeProto::OnMessageReceived(CConversation::Ref conversation, CMessage::R if (type == CConversation::DIALOG) { message->GetPropAuthorDisplayname(data); - char *nick = ::mir_strdup((const char*)data); + char *nick = ::mir_utf8encode((const char*)data); this->RaiseMessageReceivedEvent( (DWORD)timestamp, @@ -97,9 +118,16 @@ void CSkypeProto::OnMessageReceived(CConversation::Ref conversation, CMessage::R else { conversation->GetPropIdentity(data); - char *chatID = ::mir_strdup((const char*)data); + char *cid = ::mir_strdup((const char*)data); + + /*HANDLE hContact = this->GetChatRoomByID(cid); + if ( !hContact || ::DBGetContactSettingWord(hContact, this->m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + { + this->JoinChat(cid); + }*/ + this->SendChatMessage(cid, sid, text); - this->ChatEvent(chatID, sid, /*GC_EVENT_MESSAGE*/ 0x0040, text); + ::mir_free(cid); } /*const char *msg = (const char*)propValues[2]; @@ -119,11 +147,110 @@ void CSkypeProto::OnMessage(CConversation::Ref conversation, CMessage::Ref messa CMessage::SENDING_STATUS sendingStatus; message->GetPropSendingStatus(sendingStatus); - if (messageType == CMessage::POSTED_TEXT) + switch (messageType) { + case CMessage::POSTED_EMOTE: + case CMessage::POSTED_TEXT: if (sendingStatus == CMessage::SENT) this->OnMessageSended(conversation, message); else if (!sendingStatus) this->OnMessageReceived(conversation, message); + break; + + case CMessage::ADDED_CONSUMERS: + { + SEString data; + + conversation->GetPropIdentity(data); + char *cid = ::mir_strdup(data); + + HANDLE hContact = this->GetChatRoomByID(cid); + if ( !hContact || ::DBGetContactSettingWord(hContact, this->m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + { + this->StartChat(cid); + + CParticipant::Refs participants; + conversation->GetParticipants(participants, CConversation::OTHER_CONSUMERS); + for (uint i = 0; i < participants.size(); i++) + { + participants[i]->GetPropIdentity(data); + this->AddChatContact(cid, data); + } + } + + { + message->GetPropIdentities(data); + + StringList alreadyInChat(this->GetChatUsers(cid), " "); + StringList needToAdd(data, " "); + + for (int i = 0; i < needToAdd.getCount(); i++) + { + char *sid = needToAdd[i]; + if (::stricmp(sid, this->login) != 0 && !alreadyInChat.contains(sid)) + this->AddChatContact(cid, sid); + } + } + } + break; + + case CMessage::RETIRED: + { + SEString data; + + conversation->GetPropIdentity(data); + char *cid = ::mir_strdup(data); + + StringList alreadyInChat(this->GetChatUsers(cid), " "); + + message->GetPropAuthor(data); + char *sid = ::mir_strdup(data); + if (::stricmp(sid, this->login) != 0 && alreadyInChat.contains(sid)) + this->RemoveChatContact(cid, sid); + } + break; + case CMessage::RETIRED_OTHERS: + { + SEString data; + + conversation->GetPropIdentity(data); + char *cid = ::mir_strdup(data); + + message->GetPropIdentities(data); + + StringList alreadyInChat(this->GetChatUsers(cid), " "); + StringList needToKick(data, " "); + + for (int i = 0; i < needToKick.getCount(); i++) + { + char *sid = needToKick[i]; + if (::stricmp(sid, this->login) != 0 && !alreadyInChat.contains(sid)) + this->KickChatContact(cid, sid); + } + } + break; + + case CMessage::SPAWNED_CONFERENCE: + { + SEString data; + conversation->GetPropIdentity(data); + char *cid = ::mir_strdup(data); + + /*HANDLE hContact = this->GetChatRoomByID(cid); + if ( !hContact || ::DBGetContactSettingWord(hContact, this->m_szModuleName, "Status", ID_STATUS_OFFLINE) == ID_STATUS_OFFLINE) + { + this->JoinChat(cid); + }*/ + } + break; + + //case CMessage::REQUESTED_AUTH: + // break; + + //case CMessage::GRANTED_AUTH: + // break; + + //case CMessage::BLOCKED: + // break; } -} \ No newline at end of file +} diff --git a/protocols/Skype/src/skype_proto.cpp b/protocols/Skype/src/skype_proto.cpp index 1e33a9a5a7..54d43d56c9 100644 --- a/protocols/Skype/src/skype_proto.cpp +++ b/protocols/Skype/src/skype_proto.cpp @@ -29,6 +29,11 @@ CSkypeProto::CSkypeProto(const char* protoName, const TCHAR* userName) this->InitNetLib(); this->InitCustomFolders(); + + // + g_skype->SetOnMessageCallback( + (CSkype::OnMessaged)&CSkypeProto::OnMessage, + this); } CSkypeProto::~CSkypeProto() @@ -243,7 +248,7 @@ int __cdecl CSkypeProto::SendMsg(HANDLE hContact, int flags, const char* msg) if (conversation) { Message::Ref message; - conversation->PostText(msg, message); + conversation->PostText(::mir_utf8encode(msg), message); } this->SendBroadcastAsync( @@ -358,10 +363,6 @@ int __cdecl CSkypeProto::OnEvent(PROTOEVENTTYPE eventType, WPARAM wParam, LPA void __cdecl CSkypeProto::SignInAsync(void*) { - g_skype->SetOnMessageCallback( - (CSkype::OnMessaged)&CSkypeProto::OnMessage, - this); - this->SetStatus(this->m_iDesiredStatus); this->LoadOwnInfo(this); @@ -393,12 +394,17 @@ bool CSkypeProto::SignIn(bool isReadPassword) (CAccount::OnAccountChanged)&CSkypeProto::OnAccountChanged, this); // + int port; + g_skype->GetInt(SETUPKEY_PORT, port); + g_skype->SetInt(SETUPKEY_PORT, this->GetSettingWord("Port", port)); + g_skype->SetInt(SETUPKEY_DISABLE_PORT80, (int)!this->GetSettingByte("UseAlternativePorts", 1)); + // if (this->hNetlibUser) { NETLIBUSERSETTINGS nlus = { sizeof(NETLIBUSERSETTINGS) }; - if ( - !::CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)this->hNetlibUser, (LPARAM)&nlus) && - nlus.useProxy) + ::CallService(MS_NETLIB_GETUSERSETTINGS, (WPARAM)this->hNetlibUser, (LPARAM)&nlus); + + if (nlus.useProxy) { char address[MAX_PATH]; ::mir_snprintf(address, MAX_PATH, "%s:%d", nlus.szProxyServer, nlus.wProxyPort); @@ -413,7 +419,12 @@ bool CSkypeProto::SignIn(bool isReadPassword) if (nlus.useProxyAuth) { g_skype->SetStr(SETUPKEY_HTTPS_PROXY_USER, nlus.szProxyAuthUser); - g_skype->SetStr(SETUPKEY_HTTPS_PROXY_PWD, nlus.szProxyAuthPassword); + + char *encodedPass = new char[MAX_PATH]; + + CSkypeProto::Base64Encode(nlus.szProxyAuthPassword, encodedPass, MAX_PATH); + + g_skype->SetStr(SETUPKEY_HTTPS_PROXY_PWD, encodedPass); } break; diff --git a/protocols/Skype/src/skype_proto.h b/protocols/Skype/src/skype_proto.h index ba35c31fa5..294a1d1a0b 100644 --- a/protocols/Skype/src/skype_proto.h +++ b/protocols/Skype/src/skype_proto.h @@ -11,6 +11,59 @@ typedef INT_PTR (__cdecl CSkypeProto::* SkypeServiceFunc)(WPARAM, LPARAM); typedef int (__cdecl CSkypeProto::* SkypeEventFunc)(WPARAM, LPARAM); typedef INT_PTR (__cdecl CSkypeProto::* SkypeServiceFuncParam)(WPARAM, LPARAM, LPARAM); +struct StringList : public LIST +{ + static int compare(const char* p1, const char* p2) + { return _stricmp(p1, p2); } + + StringList() : LIST(2, compare) {} + StringList(const char* string, const char *delimeters) : LIST(2, compare) + { + char *data = ::mir_strdup(string); + if (data) + { + char *p = ::strtok(data, delimeters); + if (p) + { + this->insert(::mir_strdup(p)); + while (p = strtok(NULL, delimeters)) + { + this->insert(::mir_strdup(p)); + } + } + ::mir_free(data); + } + } + ~StringList() { destroy(); } + + void destroy( void ) + { + for (int i=0; i < count; i++) + mir_free(items[i]); + + List_Destroy((SortedList*)this); + } + + int insertn(const char* p) { return insert(mir_strdup(p)); } + + int remove(int idx) + { + mir_free(items[idx]); + return List_Remove((SortedList*)this, idx); + } + + int remove(const char* p) + { + int idx; + return List_GetIndex((SortedList*)this, (char*)p, &idx) == 1 ? remove(idx) : -1; + } + + bool contains(char* p) + { + return indexOf(p) >= 0; + } +}; + struct _tag_iconList { wchar_t* Description; @@ -194,15 +247,26 @@ protected: // chat bool IsChatRoom(HANDLE hContact); + HANDLE GetChatRoomByID(const char *cid); + HANDLE AddChatRoomByID(const char* cid, const char* name, DWORD flags = 0); - void ChatValidateContact(HANDLE hItem, HWND hwndList); - void ChatPrepare(HANDLE hItem, HWND hwndList); - void GetInviteContacts(HANDLE hItem, HWND hwndList, SEStringList &inviteContacts); + char *CSkypeProto::GetChatUsers(const char *cid); + + void ChatValidateContact(HANDLE hItem, HWND hwndList, const char *contacts); + void ChatPrepare(HANDLE hItem, HWND hwndList, const char *contacts); + + void GetInviteContacts(HANDLE hItem, HWND hwndList, SEStringList &invitedContacts); void InitChat(); - void StartChat(HANDLE hContact, SEStringList &invitedContacts); - void ChatEvent(const char *chatID, const char *sid, int evt, const char* msg); - void ChatLeave(const char *chatID); + char *StartChat(const char *cid); + void JoinToChat(const char *cid, bool showWindow = true); + void LeaveChat(const char *cid); + + void RaiseChatEvent(const char *cid, const char *sid, int evt, const char *message = NULL); + void SendChatMessage(const char *cid, const char *sid, const char *message); + void AddChatContact(const char *cid, const char *sid); + void KickChatContact(const char *cid, const char *sid); + void RemoveChatContact(const char *cid, const char *sid); INT_PTR __cdecl OnJoinChat(WPARAM wParam, LPARAM); INT_PTR __cdecl OnLeaveChat(WPARAM wParam, LPARAM); @@ -289,6 +353,10 @@ protected: void ShowNotification(const char *nick, const wchar_t *message, int flags = 0); + // + static char CharBase64[]; + static ULONG Base64Encode(char *inputString, char *outputBuffer, SIZE_T nMaxLength); + // instances static LIST instanceList; static int CompareProtos(const CSkypeProto *p1, const CSkypeProto *p2); @@ -360,9 +428,9 @@ protected: WORD GetSettingWord(HANDLE hContact, const char *setting, WORD errorValue = 0); DWORD GetSettingDword(const char *setting, DWORD defVal = 0); DWORD GetSettingDword(HANDLE hContact, const char *setting, DWORD errorValue = 0); - wchar_t* GetSettingString(const char *setting, wchar_t* errorValue = NULL); - wchar_t* GetSettingString(HANDLE hContact, const char *setting, wchar_t* errorValue = NULL); - char* GetDecodeSettingString(HANDLE hContact, const char *setting, char* errorValue = NULL); + wchar_t *GetSettingString(const char *setting, wchar_t* errorValue = NULL); + wchar_t *GetSettingString(HANDLE hContact, const char *setting, wchar_t* errorValue = NULL); + char *GetDecodeSettingString(HANDLE hContact, const char *setting, char* errorValue = NULL); // bool SetSettingByte(const char *setting, BYTE value); bool SetSettingByte(HANDLE hContact, const char *setting, BYTE value); diff --git a/protocols/Skype/src/skype_subclassing.cpp b/protocols/Skype/src/skype_subclassing.cpp index 5eb2882e4d..6289bc1f98 100644 --- a/protocols/Skype/src/skype_subclassing.cpp +++ b/protocols/Skype/src/skype_subclassing.cpp @@ -55,8 +55,6 @@ void CSkype::OnMessage ( if (this->proto) (proto->*onMessagedCallback)(conversation->ref(), message->ref()); - - } void CSkype::SetOnMessageCallback(OnMessaged callback, CSkypeProto* proto) @@ -99,11 +97,6 @@ void CContactGroup::SetOnContactListChangedCallback(OnContactListChanged callbac this->callback = callback; } -//bool CContactGroup::Contains(const ContactRef& contact) -//{ -// return this->ContactList.contains(contact); -//} - void CContactGroup::OnChange(const ContactRef& contact) { if (this->proto) @@ -132,10 +125,6 @@ void CContactSearch::OnChange(int prop) (proto->*SearchCompletedCallback)(this->hSearch); } } - - //SEString value = GetProp(prop); - //List_String dbg = getPropDebug(prop, value); - //fprintf(stdout,"CONTACTSEARCH.%d:%s = %s\n", getOID(), (const char*)dbg[1], (const char*)dbg[2]); } void CContactSearch::OnNewResult(const ContactRef& contact, const uint& rankValue) @@ -197,13 +186,13 @@ void CContact::OnChange(int prop) CConversation::CConversation(unsigned int oid, SERootObject* root) : Conversation(oid, root) { this->proto = NULL; - this->callback == NULL; + this->messageReceivedCallback = NULL; } void CConversation::OnMessage(const MessageRef & message) { if (this->proto) - (proto->*callback)(message->ref()); + (proto->*messageReceivedCallback)(message->ref()); } CConversation::Ref CConversation::FindBySid(CSkype *skype, SEString sid) @@ -220,7 +209,7 @@ CConversation::Ref CConversation::FindBySid(CSkype *skype, SEString sid) void CConversation::SetOnMessageReceivedCallback(OnMessageReceived callback, CSkypeProto* proto) { this->proto = proto; - this->callback = callback; + this->messageReceivedCallback = callback; } // CMessage diff --git a/protocols/Skype/src/skype_subclassing.h b/protocols/Skype/src/skype_subclassing.h index b2798316e9..0993cde7d9 100644 --- a/protocols/Skype/src/skype_subclassing.h +++ b/protocols/Skype/src/skype_subclassing.h @@ -44,7 +44,8 @@ public: private: CSkypeProto* proto; - OnMessageReceived callback; + OnMessageReceived messageReceivedCallback; + void OnMessage(const MessageRef & message); }; @@ -105,11 +106,8 @@ public: typedef DRefs Refs; CContactGroup(unsigned int oid, SERootObject* root); - //CContact::Refs ContactList; void SetOnContactListChangedCallback(OnContactListChanged callback, CSkypeProto* proto); - //bool Contains(const ContactRef& contact); - private: CSkypeProto* proto; OnContactListChanged callback; diff --git a/protocols/Skype/src/skype_utils.cpp b/protocols/Skype/src/skype_utils.cpp index 73df520aa0..5fdcb0dff1 100644 --- a/protocols/Skype/src/skype_utils.cpp +++ b/protocols/Skype/src/skype_utils.cpp @@ -473,4 +473,55 @@ void CSkypeProto::ShowNotification(const char *nick, const wchar_t *message, int ::CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0); } +} + +char CSkypeProto::CharBase64[] = +{ + 'A','B','C','D','E','F','G','H','I','J','K','L','M ','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c ','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s ','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8 ','9','+','/' +}; + +ULONG CSkypeProto::Base64Encode(char *inputString, char *outputBuffer, SIZE_T nMaxLength) +{ + int outpos = 0; + char chr[3], enc[4]; + + for (uint i = 0; i < ::strlen(inputString); i += 3) + { + if (outpos + 4 >= nMaxLength) + break; + + chr[0] = inputString[i]; + chr[1] = inputString[i+1]; + chr[2] = inputString[i+2]; + + enc[0] = chr[0] >> 2; + enc[1] = ((chr[0] & 0x03) << 4) | (chr[1] >> 4); + enc[2] = ((chr[1] & 0x0F) << 2) | (chr[2] >> 6); + enc[3] = chr[2] & 0x3F; + + outputBuffer[outpos++] = CSkypeProto::CharBase64[enc[0]]; + outputBuffer[outpos++] = CSkypeProto::CharBase64[enc[1]]; + + if (i + 1 >= ::strlen(inputString)) + { + outputBuffer[outpos++] = '='; + outputBuffer[outpos++] = '='; + } + else if (i + 2 >= ::strlen(inputString)) + { + outputBuffer[outpos++] = CSkypeProto::CharBase64[enc[2]]; + outputBuffer[outpos++] = '='; + } + else + { + outputBuffer[outpos++] = CSkypeProto::CharBase64[enc[2]]; + outputBuffer[outpos++] = CSkypeProto::CharBase64[enc[3]]; + } + } + + outputBuffer[outpos] = 0; + return outpos; } \ No newline at end of file -- cgit v1.2.3