#include "stdafx.h" CToxProto::CToxProto(const char* protoName, const wchar_t* userName) : PROTO(protoName, userName), m_tox(nullptr), m_hTimerQueue(nullptr), m_hPollingTimer(nullptr), m_hCheckingTimer(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); HookProtoEvent(ME_OPT_INITIALISE, &CToxProto::OnOptionsInit); HookProtoEvent(ME_PROTO_ACCLISTCHANGED, &CToxProto::OnAccountRenamed); m_hTimerQueue = CreateTimerQueue(); } CToxProto::~CToxProto() { DeleteTimerQueue(m_hTimerQueue); } void CToxProto::OnModulesLoaded() { Clist_GroupCreate(0, m_defaultGroup); HookProtoEvent(ME_MSG_PRECREATEEVENT, &CToxProto::OnPreCreateMessage); HookProtoEvent(ME_USERINFO_INITIALISE, &CToxProto::OnUserInfoInit); InitCustomDbEvents(); } INT_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_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.w, psr->email.w, 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_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) { if (hTransfer == nullptr) // file resume canceled return 1; return OnFileResume(m_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_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) { /*if (m_toxThread != nullptr) { m_toxThread->Terminate(); SetEvent(hTerminateEvent); }*/ DeleteTimerQueueTimer(m_hTimerQueue, m_hCheckingTimer, nullptr); DeleteTimerQueueTimer(m_hTimerQueue, m_hPollingTimer, nullptr); m_hPollingTimer = nullptr; m_hCheckingTimer = nullptr; if (m_tox) { UninitToxCore(m_tox); tox_kill(m_tox); m_tox = nullptr; } 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()) { m_iStatus = ID_STATUS_CONNECTING; ProtoBroadcastAck(NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); m_retriesCount = getByte("MaxConnectRetries", TOX_MAX_CONNECT_RETRIES); Tox_Options *options = GetToxOptions(); TOX_ERR_NEW error; m_tox = tox_new(options, &error); tox_options_free(options); if (error != TOX_ERR_NEW_OK) { debugLogA(__FUNCTION__": failed to initialize tox core (%d)", error); m_iStatus = m_iDesiredStatus = ID_STATUS_OFFLINE; ProtoBroadcastAck(NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, nullptr); ShowNotification(TranslateT("Unable to initialize Tox core"), ToxErrorToString(error), MB_ICONERROR); return 0; } InitToxCore(m_tox); CreateTimerQueueTimer(&m_hPollingTimer, m_hTimerQueue, &CToxProto::OnToxPoll, this, TOX_DEFAULT_INTERVAL, TOX_DEFAULT_INTERVAL, WT_EXECUTEINPERSISTENTTHREAD); CreateTimerQueueTimer(&m_hCheckingTimer, m_hTimerQueue, &CToxProto::OnToxCheck, this, TOX_CHECKING_INTERVAL, TOX_CHECKING_INTERVAL, WT_EXECUTEINPERSISTENTTHREAD); return 0; } // change status m_iStatus = iNewStatus; tox_self_set_status(m_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_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); }