/* Plugin of Miranda IM for communicating with users of the MSN Messenger protocol. Copyright (c) 2012-2018 Miranda NG team Copyright (c) 2006-2012 Boris Krasnovskiy. Copyright (c) 2003-2005 George Hazan. Copyright (c) 2002-2003 Richard Hughes (original version). This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "stdafx.h" #include "msn_proto.h" extern int avsPresent; ///////////////////////////////////////////////////////////////////////////////////////// // GetMyAwayMsg - obtain the current away message INT_PTR CMsnProto::GetMyAwayMsg(WPARAM wParam, LPARAM lParam) { char** msgptr = GetStatusMsgLoc(wParam ? wParam : m_iStatus); if (msgptr == nullptr) return 0; return (lParam & SGMA_UNICODE) ? (INT_PTR)mir_utf8decodeW(*msgptr) : (INT_PTR)mir_utf8decodeA(*msgptr); } ///////////////////////////////////////////////////////////////////////////////////////// // MsnGetAvatar - retrieves the file name of my own avatar INT_PTR CMsnProto::GetAvatar(WPARAM wParam, LPARAM lParam) { wchar_t* buf = (wchar_t*)wParam; int size = (int)lParam; if (buf == nullptr || size <= 0) return -1; MSN_GetAvatarFileName(NULL, buf, size, nullptr); return _waccess(buf, 0); } ///////////////////////////////////////////////////////////////////////////////////////// // MsnGetAvatarInfo - retrieve the avatar info void CMsnProto::sttFakeAvatarAck(void* arg) { Sleep(100); ProtoBroadcastAck(((PROTO_AVATAR_INFORMATION*)arg)->hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, arg); } INT_PTR CMsnProto::GetAvatarInfo(WPARAM wParam, LPARAM lParam) { PROTO_AVATAR_INFORMATION *pai = (PROTO_AVATAR_INFORMATION*)lParam; wchar_t filename[MAX_PATH]; MsnContact *cont = nullptr; if (pai->hContact) { cont = Lists_Get(pai->hContact); if (cont == nullptr) return GAIR_NOAVATAR; /* if ((cont->cap1 & 0xf0000000) == 0) return GAIR_NOAVATAR; */ } if (pai->hContact == NULL || _stricmp(cont->email, MyOptions.szEmail) == 0) { MSN_GetAvatarFileName(NULL, filename, _countof(filename), nullptr); pai->format = ProtoGetAvatarFormat(filename); if (pai->format != PA_FORMAT_UNKNOWN) mir_wstrcpy(pai->filename, filename); return pai->format == PA_FORMAT_UNKNOWN ? GAIR_NOAVATAR : GAIR_SUCCESS; } char *szContext; DBVARIANT dbv; if (getString(pai->hContact, pai->hContact ? "PictContext" : "PictObject", &dbv) == 0) { szContext = (char*)NEWSTR_ALLOCA(dbv.pszVal); db_free(&dbv); } else return GAIR_NOAVATAR; MSN_GetAvatarFileName(pai->hContact, filename, _countof(filename), nullptr); pai->format = ProtoGetAvatarFormat(filename); if (pai->format != PA_FORMAT_UNKNOWN) { bool needupdate = true; if (getString(pai->hContact, "PictSavedContext", &dbv) == 0) { needupdate = mir_strcmp(dbv.pszVal, szContext) != 0; db_free(&dbv); } if (needupdate) { setString(pai->hContact, "PictSavedContext", szContext); // Store also avatar hash char* szAvatarHash = MSN_GetAvatarHash(szContext); if (szAvatarHash != nullptr) { setString(pai->hContact, "AvatarSavedHash", szAvatarHash); mir_free(szAvatarHash); } } mir_wstrcpy(pai->filename, filename); return GAIR_SUCCESS; } if ((wParam & GAIF_FORCE) != 0 && pai->hContact != NULL) { if (avsPresent < 0) avsPresent = ServiceExists(MS_AV_SETMYAVATARW) != 0; if (!avsPresent) return GAIR_NOAVATAR; WORD wStatus = getWord(pai->hContact, "Status", ID_STATUS_OFFLINE); if (wStatus == ID_STATUS_OFFLINE) { delSetting(pai->hContact, "AvatarHash"); PROTO_AVATAR_INFORMATION *fakeAI = new PROTO_AVATAR_INFORMATION; *fakeAI = *pai; ForkThread(&CMsnProto::sttFakeAvatarAck, fakeAI); } else if (!getString(pai->hContact, "AvatarUrl", &dbv)) { pushAvatarRequest(pai->hContact, dbv.pszVal); db_free(&dbv); } return GAIR_WAITFOR; } return GAIR_NOAVATAR; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnGetAvatarCaps - retrieves avatar capabilities INT_PTR CMsnProto::GetAvatarCaps(WPARAM wParam, LPARAM lParam) { int res = 0; switch (wParam) { case AF_MAXSIZE: ((POINT*)lParam)->x = 96; ((POINT*)lParam)->y = 96; break; case AF_PROPORTION: res = PIP_NONE; break; case AF_FORMATSUPPORTED: res = lParam == PA_FORMAT_PNG || lParam == PA_FORMAT_GIF || lParam == PA_FORMAT_JPEG; break; case AF_ENABLED: res = 1; break; } return res; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnSetAvatar - sets an avatar without UI INT_PTR CMsnProto::SetAvatar(WPARAM, LPARAM lParam) { wchar_t* szFileName = (wchar_t*)lParam; wchar_t tFileName[MAX_PATH]; MSN_GetAvatarFileName(NULL, tFileName, _countof(tFileName), nullptr); _wremove(tFileName); if (szFileName == nullptr) { delSetting("PictObject"); delSetting("AvatarHash"); ForkThread(&CMsnProto::msn_storeAvatarThread, nullptr); } else { int fileId = _wopen(szFileName, _O_RDONLY | _O_BINARY, _S_IREAD); if (fileId < 0) return 1; size_t dwPngSize = _filelengthi64(fileId); unsigned char* pData = (unsigned char*)mir_alloc(dwPngSize); if (pData == nullptr) { _close(fileId); return 2; } _read(fileId, pData, (unsigned)dwPngSize); _close(fileId); wchar_t drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT]; _wsplitpath(szFileName, drive, dir, fname, ext); MSN_SetMyAvatar(fname, pData, dwPngSize); StoreAvatarData* par = (StoreAvatarData*)mir_alloc(sizeof(StoreAvatarData)); par->szName = mir_wstrdup(fname); par->data = pData; par->dataSize = dwPngSize; par->szMimeType = "image/png"; ForkThread(&CMsnProto::msn_storeAvatarThread, par); } MSN_SetServerStatus(m_iStatus); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // SetNickname - sets a nick name without UI INT_PTR CMsnProto::SetNickName(WPARAM wParam, LPARAM lParam) { if (wParam & SMNN_UNICODE) MSN_SendNickname((wchar_t*)lParam); else MSN_SendNickname((char*)lParam); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnSendNudge - Sending a nudge INT_PTR CMsnProto::SendNudge(WPARAM hContact, LPARAM) { if (!msnLoggedIn) return 0; char tEmail[MSN_MAX_EMAIL_LEN]; if (MSN_IsMeByContact(hContact, tEmail)) return 0; int netId = Lists_GetNetId(tEmail); msnNsThread->sendMessage('3', tEmail, netId, "", MSG_NUDGE); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnContactDeleted - called when a contact is deleted from list void CMsnProto::OnContactDeleted(MCONTACT hContact) { if (!msnLoggedIn) //should never happen for MSN contacts return; if (isChatRoom(hContact)) { DBVARIANT dbv; if (!getWString(hContact, "ChatRoomID", &dbv)) { MSN_KillChatSession(dbv.pwszVal); db_free(&dbv); } } else { char szEmail[MSN_MAX_EMAIL_LEN]; if (MSN_IsMeByContact(hContact, szEmail)) g_clistApi.pfnRemoveEvent(hContact, 1); if (szEmail[0]) { debugLogA("Deleted Handler Email"); if (Lists_IsInList(LIST_FL, szEmail)) { DeleteParam param = { this, MCONTACT(hContact) }; DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DELETECONTACT), nullptr, DlgDeleteContactUI, (LPARAM)¶m); MsnContact *msc = Lists_Get(szEmail); if (msc) msc->hContact = NULL; } if (Lists_IsInList(LIST_LL, szEmail)) MSN_AddUser(hContact, szEmail, 0, LIST_LL | LIST_REMOVE); } } } int CMsnProto::OnGroupChange(WPARAM hContact, LPARAM lParam) { if (!msnLoggedIn || !MyOptions.ManageServer) return 0; const CLISTGROUPCHANGE* grpchg = (CLISTGROUPCHANGE*)lParam; if (hContact == NULL) { if (grpchg->pszNewName == nullptr && grpchg->pszOldName != nullptr) { LPCSTR szId = MSN_GetGroupByName(UTF8(grpchg->pszOldName)); if (szId != nullptr) MSN_DeleteServerGroup(szId); } else if (grpchg->pszNewName != nullptr && grpchg->pszOldName != nullptr) { LPCSTR szId = MSN_GetGroupByName(UTF8(grpchg->pszOldName)); if (szId != nullptr) MSN_RenameServerGroup(szId, UTF8(grpchg->pszNewName)); } } else { if (MSN_IsMyContact(hContact)) MSN_MoveContactToGroup(hContact, T2Utf(grpchg->pszNewName)); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnDbSettingChanged - look for contact's settings changes int CMsnProto::OnDbSettingChanged(WPARAM hContact, LPARAM lParam) { DBCONTACTWRITESETTING* cws = (DBCONTACTWRITESETTING*)lParam; if (!msnLoggedIn || MyOptions.netId != NETID_MSN) return 0; if (hContact == NULL) { if (MyOptions.SlowSend && strcmp(cws->szSetting, "MessageTimeout") == 0 && (strcmp(cws->szModule, "SRMM") == 0 || strcmp(cws->szModule, "SRMsg") == 0)) { if (cws->value.dVal < 60000) MessageBox(nullptr, TranslateT("MSN requires message send timeout in your Message window plugin to be not less then 60 sec. Please correct the timeout value."), TranslateT("MSN Protocol"), MB_OK | MB_ICONINFORMATION); } return 0; } if (!strcmp(cws->szSetting, "ApparentMode")) { char tEmail[MSN_MAX_EMAIL_LEN]; if (!db_get_static(hContact, m_szModuleName, "wlid", tEmail, sizeof(tEmail)) || !db_get_static(hContact, m_szModuleName, "e-mail", tEmail, sizeof(tEmail))) { bool isBlocked = Lists_IsInList(LIST_BL, tEmail); if (isBlocked && (cws->value.type == DBVT_DELETED || cws->value.wVal == 0)) { MSN_AddUser(hContact, tEmail, 0, LIST_BL + LIST_REMOVE); MSN_AddUser(hContact, tEmail, 0, LIST_AL); } else if (!isBlocked && cws->value.wVal == ID_STATUS_OFFLINE) { MSN_AddUser(hContact, tEmail, 0, LIST_AL + LIST_REMOVE); MSN_AddUser(hContact, tEmail, 0, LIST_BL); } } } if (!strcmp(cws->szSetting, "MyHandle") && !strcmp(cws->szModule, "CList")) { bool isMe = MSN_IsMeByContact(hContact); if (!isMe || !nickChg) { char szContactID[100]; if (!db_get_static(hContact, m_szModuleName, "ID", szContactID, sizeof(szContactID))) { if (cws->value.type != DBVT_DELETED) { if (cws->value.type == DBVT_UTF8) MSN_ABUpdateNick(cws->value.pszVal, szContactID); else MSN_ABUpdateNick(UTF8(cws->value.pszVal), szContactID); } else MSN_ABUpdateNick(nullptr, szContactID); } if (isMe) displayEmailCount(hContact); } } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // OnIdleChanged - transitions to Idle int CMsnProto::OnIdleChanged(WPARAM, LPARAM lParam) { if (m_iStatus == ID_STATUS_INVISIBLE || m_iStatus <= ID_STATUS_OFFLINE) return 0; bool bIdle = (lParam & IDF_ISIDLE) != 0; bool bPrivacy = (lParam & IDF_PRIVACY) != 0; if (isIdle && !bIdle) { isIdle = false; MSN_SetServerStatus(m_iDesiredStatus); } else if (!isIdle && bIdle && !bPrivacy && m_iDesiredStatus != ID_STATUS_AWAY) { isIdle = true; MSN_SetServerStatus(ID_STATUS_IDLE); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // OnWindowEvent - creates session on window open int CMsnProto::OnWindowPopup(WPARAM, LPARAM lParam) { MessageWindowPopupData *mwpd = (MessageWindowPopupData *)lParam; if (!MSN_IsMyContact(mwpd->hContact) || isChatRoom(mwpd->hContact)) return 0; switch (mwpd->uType) { case MSG_WINDOWPOPUP_SHOWING: AppendMenu(mwpd->hMenu, MF_STRING, 13465, TranslateT("Convert to Chat")); break; case MSG_WINDOWPOPUP_SELECTED: if (mwpd->selection == 13465) DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_CHATROOM_INVITE), nullptr, DlgInviteToChat, LPARAM(new InviteChatParam(nullptr, mwpd->hContact, this))); break; } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // MsnGetUnread - returns the actual number of unread emails in the INBOX INT_PTR CMsnProto::GetUnreadEmailCount(WPARAM, LPARAM) { if (!msnLoggedIn) return 0; return mUnreadMessages; } ///////////////////////////////////////////////////////////////////////////////////////// // OnLeaveChat - closes MSN chat window INT_PTR CMsnProto::OnLeaveChat(WPARAM hContact, LPARAM) { if (isChatRoom(hContact) != 0) { DBVARIANT dbv; if (getWString(hContact, "ChatRoomID", &dbv) == 0) { MSN_KillChatSession(dbv.pwszVal); db_free(&dbv); } } return 0; }