#include "stdafx.h" CToxProto::CToxProto(const char* protoName, const wchar_t* userName) : PROTO(protoName, userName), m_toxThread(nullptr), isTerminated(false), hCheckingThread(nullptr), hPollingThread(nullptr), hMessageProcess(1) { InitNetlib(); m_accountName = mir_wstrdup(userName); m_defaultGroup = getWStringA(TOX_SETTINGS_GROUP); if (m_defaultGroup == nullptr) m_defaultGroup = mir_wstrdup(L"Tox"); CreateProtoService(PS_CREATEACCMGRUI, &CToxProto::OnAccountManagerInit); setAllContactStatuses(ID_STATUS_OFFLINE); // avatars CreateProtoService(PS_GETAVATARCAPS, &CToxProto::GetAvatarCaps); CreateProtoService(PS_GETAVATARINFO, &CToxProto::GetAvatarInfo); CreateProtoService(PS_GETMYAVATAR, &CToxProto::GetMyAvatar); CreateProtoService(PS_SETMYAVATAR, &CToxProto::SetMyAvatar); // menus CreateProtoService(PS_MENU_REQAUTH, &CToxProto::OnRequestAuth); CreateProtoService(PS_MENU_GRANTAUTH, &CToxProto::OnGrantAuth); // nick CreateProtoService(PS_SETMYNICKNAME, &CToxProto::SetMyNickname); // events CreateServiceFunction(MODULE "/GetEventIcon", &CToxProto::EventGetIcon); HookProtoEvent(ME_CLIST_PREBUILDCONTACTMENU, &CToxProto::OnPrebuildContactMenu); hTerminateEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); } CToxProto::~CToxProto() { UninitNetlib(); } DWORD_PTR CToxProto::GetCaps(int type, MCONTACT) { switch (type) { case PFLAGNUM_1: return PF1_IM | PF1_FILE | PF1_AUTHREQ | PF1_MODEMSG | PF1_EXTSEARCH | PF1_SERVERCLIST; case PFLAGNUM_2: return PF2_ONLINE | PF2_SHORTAWAY | PF2_LIGHTDND; case PFLAGNUM_3: return PF2_ONLINE | PF2_SHORTAWAY | PF2_LIGHTDND; case PFLAGNUM_4: return PF4_SINGLEFILEONLY | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_FORCEADDED | PF4_NOAUTHDENYREASON | PF4_FORCEAUTH; case PFLAG_UNIQUEIDTEXT: return (INT_PTR)"Tox ID"; case PFLAG_MAXLENOFMESSAGE: return TOX_MAX_MESSAGE_LENGTH; } return 0; } MCONTACT CToxProto::AddToList(int flags, PROTOSEARCHRESULT *psr) { ptrA myAddress(getStringA(NULL, TOX_SETTINGS_ID)); if (strnicmp(psr->id.a, myAddress, TOX_PUBLIC_KEY_SIZE) == 0) { ShowNotification(TranslateT("You cannot add yourself to your contact list"), 0); return NULL; } if (MCONTACT hContact = GetContact(psr->id.a)) { ShowNotification(TranslateT("Contact already in your contact list"), 0, hContact); return NULL; } return AddContact(psr->id.a, psr->nick.a, psr->email.a, flags & PALF_TEMPORARY); } int CToxProto::Authorize(MEVENT hDbEvent) { MCONTACT hContact = GetContactFromAuthEvent(hDbEvent); if (hContact == INVALID_CONTACT_ID) return 1; return OnGrantAuth(hContact, 0); } int CToxProto::AuthRecv(MCONTACT, PROTORECVEVENT* pre) { return Proto_AuthRecv(m_szModuleName, pre); } int CToxProto::AuthRequest(MCONTACT hContact, const wchar_t *szMessage) { ptrA reason(mir_utf8encodeW(szMessage)); return OnRequestAuth(hContact, (LPARAM)reason); } HANDLE CToxProto::FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *tszPath) { return OnFileAllow(m_toxThread->Tox(), hContact, hTransfer, tszPath); } int CToxProto::FileCancel(MCONTACT hContact, HANDLE hTransfer) { return CancelTransfer(hContact, hTransfer); } int CToxProto::FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t*) { return FileCancel(hContact, hTransfer); } int CToxProto::FileResume(HANDLE hTransfer, int *action, const wchar_t **szFilename) { return OnFileResume(m_toxThread->Tox(), hTransfer, action, szFilename); } HWND CToxProto::SearchAdvanced(HWND owner) { return OnSearchAdvanced(owner); } HWND CToxProto::CreateExtendedSearchUI(HWND owner) { return OnCreateExtendedSearchUI(owner); } int CToxProto::SendMsg(MCONTACT hContact, int, const char *msg) { return OnSendMessage(hContact, msg); } HANDLE CToxProto::SendFile(MCONTACT hContact, const wchar_t *msg, wchar_t **ppszFiles) { return OnSendFile(m_toxThread->Tox(), hContact, msg, ppszFiles); } int CToxProto::SetStatus(int iNewStatus) { if (iNewStatus == m_iDesiredStatus) return 0; iNewStatus = MapStatus(iNewStatus); debugLogA(__FUNCTION__": changing status from %i to %i", m_iStatus, iNewStatus); int old_status = m_iStatus; m_iDesiredStatus = iNewStatus; // logout if (iNewStatus == ID_STATUS_OFFLINE) { isTerminated = true; SetEvent(hTerminateEvent); if (!Miranda_IsTerminated()) setAllContactStatuses(ID_STATUS_OFFLINE); m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); UpdateStatusMenu(NULL, NULL); return 0; } if (old_status >= ID_STATUS_CONNECTING && old_status < ID_STATUS_OFFLINE) return 0; // login if (old_status == ID_STATUS_OFFLINE && !IsOnline()) { isTerminated = false; m_iStatus = ID_STATUS_CONNECTING; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); hPollingThread = ForkThreadEx(&CToxProto::PollingThread, nullptr, nullptr); return 0; } // change status m_iStatus = iNewStatus; tox_self_set_status(m_toxThread->Tox(), MirandaToToxStatus(iNewStatus)); ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); return 0; } HANDLE CToxProto::GetAwayMsg(MCONTACT hContact) { if (IsOnline()) { ForkThread(&CToxProto::GetStatusMessageAsync, (void*)hContact); return (HANDLE)hContact; } return nullptr; } int CToxProto::SetAwayMsg(int, const wchar_t *msg) { if (IsOnline()) { T2Utf statusMessage(msg); TOX_ERR_SET_INFO error; if (!tox_self_set_status_message(m_toxThread->Tox(), (uint8_t*)(char*)statusMessage, min(TOX_MAX_STATUS_MESSAGE_LENGTH, mir_strlen(statusMessage)), &error)) debugLogA(__FUNCTION__": failed to set status status message %s (%d)", msg, error); } return 0; } int CToxProto::UserIsTyping(MCONTACT hContact, int type) { return OnUserIsTyping(hContact, type); } int CToxProto::OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam) { switch (iEventType) { case EV_PROTO_ONLOAD: return OnAccountLoaded(wParam, lParam); case EV_PROTO_ONRENAME: return OnAccountRenamed(wParam, lParam); case EV_PROTO_ONCONTACTDELETED: return OnContactDeleted(wParam, lParam); case EV_PROTO_ONMENU: return OnInitStatusMenu(); case EV_PROTO_ONERASE: return OnDeleteToxProfile(); } return 1; }