diff options
author | dartraiden <wowemuh@gmail.com> | 2023-01-02 21:10:29 +0300 |
---|---|---|
committer | dartraiden <wowemuh@gmail.com> | 2023-01-02 21:10:29 +0300 |
commit | 1979fd80424d16b2e489f9b57d01d9c7811d25a2 (patch) | |
tree | 960d42c5fe4a51f0fe2850bea91256e226bce221 /plugins/SendScreenshotPlus/src/CSend.cpp | |
parent | adfbbb217d4f4a05acf198755f219a5223d31c27 (diff) |
Update copyrights
Diffstat (limited to 'plugins/SendScreenshotPlus/src/CSend.cpp')
-rw-r--r-- | plugins/SendScreenshotPlus/src/CSend.cpp | 1226 |
1 files changed, 613 insertions, 613 deletions
diff --git a/plugins/SendScreenshotPlus/src/CSend.cpp b/plugins/SendScreenshotPlus/src/CSend.cpp index 5a5e72e03e..3e83d4b6c6 100644 --- a/plugins/SendScreenshotPlus/src/CSend.cpp +++ b/plugins/SendScreenshotPlus/src/CSend.cpp @@ -1,613 +1,613 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-09 Miranda ICQ/IM project, - -This file is part of Send Screenshot Plus, a Miranda IM plugin. -Copyright (c) 2010 Ing.U.Horn - -Parts of this file based on original sorce code -(c) 2004-2006 Sérgio Vieira Rolanski (portet from Borland C++) - -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, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ - -#include "stdafx.h" -#define CSEND_DIALOG 8800 - -///////////////////////////////////////////////////////////////////////////////////////// - -CSend::CSend(HWND /*Owner*/, MCONTACT hContact, bool bAsync, bool bSilent) : - m_bDeleteAfterSend(false), - m_bAsync(bAsync), - m_bSilent(bSilent), - m_pszFile(nullptr), - m_pszFileDesc(nullptr), - m_pszSendTyp(nullptr), - m_pszProto(nullptr), - m_EnableItem(0), - m_ChatRoom(0), - m_cbEventMsg(0), - m_hSend(nullptr), - m_hOnSend(nullptr), - m_ErrorMsg(nullptr), - m_ErrorTitle(nullptr) -{ - SetContact(hContact); -} - -CSend::~CSend() -{ - mir_free(m_pszFile); - mir_free(m_pszFileDesc); - mir_free(m_ErrorMsg); - mir_free(m_ErrorTitle); - if (m_hOnSend) UnhookEvent(m_hOnSend); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CSend::SetContact(MCONTACT hContact) -{ - m_hContact = hContact; - if (hContact) { - m_pszProto = Proto_GetBaseAccountName(hContact); - m_ChatRoom = Contact::IsGroupChat(hContact, m_pszProto); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CALLBACK CSend::ResultDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - switch (uMsg) { - case WM_INITDIALOG: - TranslateDialogDefault(hwndDlg); - Window_SetIcon_IcoLib(hwndDlg, GetIconHandle(ICO_MAIN)); - { - CSend *self = (CSend*)lParam; - SetDlgItemText(hwndDlg, IDC_HEADERBAR, CMStringW(TranslateT("Resulting URL from\n")) + self->m_pszSendTyp); - - SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_SETICON, ICON_BIG, (LPARAM)GetIconBtn(ICO_BTN_ARROWR)); - SetDlgItemTextA(hwndDlg, ID_edtURL, self->m_URL); - if (self->m_URLthumb) { - SetDlgItemTextA(hwndDlg, ID_edtURLthumb, self->m_URLthumb); - } - else { - SetDlgItemTextA(hwndDlg, ID_edtURLthumb, "-"); - for (int i = ID_btnThumbCopy; i <= ID_edtURLthumb; ++i) { - EnableWindow(GetDlgItem(hwndDlg, i), FALSE); - } - } - if (!self->m_pszFileDesc) - SetDlgItemText(hwndDlg, ID_bvlDesc, self->m_ErrorTitle); - else - SetDlgItemText(hwndDlg, ID_bvlDesc, self->m_pszFileDesc); - SendDlgItemMessage(hwndDlg, IDOK, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_COPY)); - SendDlgItemMessage(hwndDlg, IDOK, BUTTONTRANSLATE, 0, 0); - SendDlgItemMessage(hwndDlg, IDCANCEL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_CANCEL)); - SendDlgItemMessage(hwndDlg, IDCANCEL, BUTTONTRANSLATE, 0, 0); - for (int i = ID_btnCopy; i <= ID_btnThumbBBC2; ++i) { - SendDlgItemMessage(hwndDlg, i, BUTTONSETASTHEMEDBTN, 0, 0); - SendDlgItemMessage(hwndDlg, i, BUTTONSETASFLATBTN, 1, 0); - switch (i) { - case ID_btnCopy: - case ID_btnThumbCopy: - SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_COPY)); - SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy"), BATF_UNICODE); - break; - case ID_btnBBC: - case ID_btnThumbBBC: - SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_BBC)); - SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy BBCode"), BATF_UNICODE); - break; - default: - SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_BBCLNK)); - SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy BBCode w/ link"), BATF_UNICODE); - } - } - } - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - DestroyWindow(hwndDlg); - return TRUE; - - case IDOK: - case ID_btnCopy: - case ID_btnThumbCopy: - case ID_btnBBC: - case ID_btnThumbBBC: - case ID_btnThumbBBC2: - wchar_t tmp[2048]; - int edtID = ID_edtURL; - int bbc = 0; - switch (LOWORD(wParam)) { - case ID_btnThumbBBC2: ++bbc; - case ID_btnThumbBBC: ++bbc; - case ID_btnThumbCopy: - edtID = ID_edtURLthumb; - break; - case ID_btnBBC: ++bbc; - break; - } - size_t len; - if (bbc) { - if (bbc == 1) { - memcpy(tmp, L"[img]", 5 * sizeof(wchar_t)); len = 5; - len += GetDlgItemText(hwndDlg, edtID, tmp + len, 2048 - 11); - memcpy(tmp + len, L"[/img]", 7 * sizeof(wchar_t)); len += 7; - } - else { - memcpy(tmp, L"[url=", 5 * sizeof(wchar_t)); len = 5; - len += GetDlgItemText(hwndDlg, ID_edtURL, tmp + len, 1024); - memcpy(tmp + len, L"][img]", 6 * sizeof(wchar_t)); len += 6; - len += GetDlgItemText(hwndDlg, edtID, tmp + len, 1024); - memcpy(tmp + len, L"[/img][/url]", 13 * sizeof(wchar_t)); len += 12; - } - } - else len = GetDlgItemText(hwndDlg, edtID, tmp, _countof(tmp)); - - Utils_ClipboardCopy(CMStringW(tmp, len + 1)); - - if (LOWORD(wParam) == IDOK) - DestroyWindow(hwndDlg); - return TRUE; - } - } - return FALSE; -} - -void CSend::svcSendMsgExit(const char* szMessage) -{ - if (m_bSilent) { - Exit(ACKRESULT_SUCCESS); return; - } - if (!m_hContact) { - if (!m_pszFileDesc) - m_pszFileDesc = mir_a2u(szMessage); - Exit(CSEND_DIALOG); return; - } - - if (m_ChatRoom) { - CMStringW tmp(szMessage); - if (m_pszFileDesc) { - tmp.Append(L"\r\n"); - tmp.Append(m_pszFileDesc); - } - - int res = GC_RESULT_NOSESSION; - int cnt = g_chatApi.SM_GetCount(m_pszProto); - - // loop on all gc session to get the right (save) ptszID for the chatroom from m_hContact - GC_INFO gci = { 0 }; - gci.pszModule = m_pszProto; - for (int i = 0; i < cnt; i++) { - gci.iItem = i; - gci.Flags = GCF_BYINDEX | GCF_HCONTACT | GCF_ID; - Chat_GetInfo(&gci); - if (gci.hContact == m_hContact) { - Chat_SendUserMessage(m_pszProto, gci.pszID, tmp); - res = 200; - break; - } - } - Exit(res); return; - } - else { - m_szEventMsg = szMessage; - if (m_pszFileDesc && m_pszFileDesc[0] != NULL) { - m_szEventMsg.Append("\r\n"); - m_szEventMsg.Append(_T2A(m_pszFileDesc)); - m_cbEventMsg = m_szEventMsg.GetLength() + 1; - } - - // create a HookEventObj on ME_PROTO_ACK - if (!m_hOnSend) - m_hOnSend = HookEventObj(ME_PROTO_ACK, OnSend, this); - - // start PSS_MESSAGE service - m_hSend = (HANDLE)ProtoChainSend(m_hContact, PSS_MESSAGE, NULL, ptrA(mir_utf8encode(m_szEventMsg))); - - // check we actually got an ft handle back from the protocol - if (!m_hSend) { - Unhook(); - Error(SS_ERR_INIT, m_pszSendTyp); - Exit(ACKRESULT_FAILED); return; - } - } -} - -void CSend::svcSendFileExit() -{ - // szMessage should be encoded as the File followed by the description, the - // separator being a single nul (\0). If there is no description, do not forget - // to end the File with two nuls. - if (m_bSilent) { - Exit(ACKRESULT_SUCCESS); return; - } - - if (!m_hContact) { - Error(LPGENW("%s requires a valid contact!"), m_pszSendTyp); - Exit(ACKRESULT_FAILED); return; - } - - m_szEventMsg = _T2A(m_pszFile); - - if (m_pszFileDesc && m_pszFileDesc[0] != NULL) { - m_szEventMsg.AppendChar(0); - m_szEventMsg.Append(_T2A(m_pszFileDesc)); - } - - m_cbEventMsg = m_szEventMsg.GetLength() + 1; - - // Сreate a HookEventObj on ME_PROTO_ACK - if (!m_hOnSend) { - m_hOnSend = HookEventObj(ME_PROTO_ACK, OnSend, this); - } - - // Start miranda PSS_FILE based on mir ver (T) - wchar_t* ppFile[2] = { nullptr, nullptr }; - wchar_t* pDesc = mir_wstrdup(m_pszFileDesc); - ppFile[0] = mir_wstrdup(m_pszFile); - ppFile[1] = nullptr; - m_hSend = (HANDLE)ProtoChainSend(m_hContact, PSS_FILE, (WPARAM)pDesc, (LPARAM)ppFile); - mir_free(pDesc); - mir_free(ppFile[0]); - - // check we actually got an ft handle back from the protocol - if (!m_hSend) { - Unhook(); - Error(SS_ERR_INIT, m_pszSendTyp); - Exit(ACKRESULT_FAILED); return; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CSend::OnSend(void *obj, WPARAM, LPARAM lParam) -{ - CSend* self = (CSend*)obj; - ACKDATA *ack = (ACKDATA*)lParam; - if (ack->hProcess != self->m_hSend) - return 0; - - switch (ack->result) { - case ACKRESULT_INITIALISING: // SetFtStatus(hwndDlg, LPGENW("Initialising..."), FTS_TEXT); break; - case ACKRESULT_CONNECTING: // SetFtStatus(hwndDlg, LPGENW("Connecting..."), FTS_TEXT); break; - case ACKRESULT_CONNECTPROXY: // SetFtStatus(hwndDlg, LPGENW("Connecting to proxy..."), FTS_TEXT); break; - case ACKRESULT_LISTENING: // SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); break; - case ACKRESULT_CONNECTED: // SetFtStatus(hwndDlg, LPGENW("Connected"), FTS_TEXT); break; - case ACKRESULT_SENTREQUEST: // SetFtStatus(hwndDlg, LPGENW("Decision sent"), FTS_TEXT); break; - case ACKRESULT_NEXTFILE: // SetFtStatus(hwndDlg, LPGENW("Moving to next file..."), FTS_TEXT); - case ACKRESULT_FILERESUME: - case ACKRESULT_DATA: // transfer is on progress - break; - case ACKRESULT_DENIED: - self->Unhook(); - self->Exit(ack->result); - break; - case ACKRESULT_FAILED: - self->Unhook(); - self->Exit(ack->result); - // type=ACKTYPE_MESSAGE, result=success/failure, (char*)lParam=error message or NULL. - // type=ACKTYPE_FILE, result=ACKRESULT_FAILED then lParam=(LPARAM)(const char*)szReason - break; - case ACKRESULT_SUCCESS: - self->Unhook(); - switch (ack->type) { - case ACKTYPE_CHAT: - break; - case ACKTYPE_MESSAGE: - self->DB_EventAdd((uint16_t)EVENTTYPE_MESSAGE); - break; - case ACKTYPE_FILE: - self->m_szEventMsg.Insert(0, "aaaa"); - self->m_cbEventMsg += sizeof(uint32_t); - self->DB_EventAdd((uint16_t)EVENTTYPE_FILE); - break; - } - self->Exit(ack->result); - break; - } - return 0; -} - -void CSend::DB_EventAdd(uint16_t EventType) -{ - DBEVENTINFO dbei = {}; - dbei.szModule = m_pszProto; - dbei.eventType = EventType; - dbei.flags = DBEF_SENT; - dbei.timestamp = time(0); - dbei.flags |= DBEF_UTF; - dbei.cbBlob = m_cbEventMsg; - dbei.pBlob = (uint8_t*)m_szEventMsg.GetString(); - db_event_add(m_hContact, &dbei); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CSend::Error(LPCTSTR pszFormat, ...) -{ - wchar_t tszMsg[MAX_SECONDLINE]; - - mir_snwprintf(tszMsg, L"%s - %s", _A2W(MODULENAME), TranslateT("Error")); - mir_free(m_ErrorTitle), m_ErrorTitle = mir_wstrdup(tszMsg); - - va_list vl; - va_start(vl, pszFormat); - mir_vsnwprintf(tszMsg, _countof(tszMsg), TranslateW(pszFormat), vl); - va_end(vl); - mir_free(m_ErrorMsg), m_ErrorMsg = mir_wstrdup(tszMsg); - - memset(&m_box, 0, sizeof(MSGBOX)); - m_box.cbSize = sizeof(MSGBOX); - m_box.hParent = nullptr; - m_box.hiLogo = GetIcon(ICO_MAIN); - m_box.hiMsg = nullptr; - m_box.ptszTitle = m_ErrorTitle; - m_box.ptszMsg = m_ErrorMsg; - m_box.uType = MB_OK | MB_ICON_ERROR; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CSend::Exit(unsigned int Result) -{ - if (!m_bSilent) { - bool err = true; - switch (Result) { - case CSEND_DIALOG: - Skin_PlaySound("FileDone"); - DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_UResultForm), nullptr, ResultDialogProc, (LPARAM)this); - err = false; - break; - case ACKRESULT_SUCCESS: - case GC_RESULT_SUCCESS: - Skin_PlaySound("FileDone"); - err = false; - break; - case ACKRESULT_DENIED: - Skin_PlaySound("FileDenied"); - Error(L"%s (%i):\nFile transfer denied.", TranslateW(m_pszSendTyp), Result); - MsgBoxService(NULL, (LPARAM)&m_box); - err = false; - break; - case GC_RESULT_WRONGVER: // You appear to be using the wrong version of GC API. - Error(L"%s (%i):\nYou appear to be using the wrong version of GC API", TranslateT("GCHAT error"), Result); - break; - case GC_RESULT_ERROR: // An internal GC error occurred. - Error(L"%s (%i):\nAn internal GC error occurred.", TranslateT("GCHAT error"), Result); - break; - case GC_RESULT_NOSESSION: // contact has no open GC session - Error(L"%s (%i):\nContact has no open GC session.", TranslateT("GCHAT error"), Result); - break; - case ACKRESULT_FAILED: - default: - break; - } - if (err) { - Skin_PlaySound("FileFailed"); - if (m_ErrorMsg) MsgBoxService(NULL, (LPARAM)&m_box); - else MsgErr(nullptr, LPGENW("An unknown error has occurred.")); - } - } - if (m_pszFile && *m_pszFile && m_bDeleteAfterSend && m_EnableItem&SS_DLG_DELETEAFTERSSEND) { - DeleteFile(m_pszFile), m_pszFile = nullptr; - } - if (m_bAsync) - delete this; // deletes derived class since destructor is virtual (which also auto-calls base dtor) -} - -///////////////////////////////////////////////////////////////////////////////////////// -// helper functions used for HTTP uploads - -#define snprintf _snprintf - -const char* CSend::GetHTMLContent(char* str, const char* startTag, const char* endTag) -{ - char* begin = strstr(str, startTag); - if (!begin) return nullptr; - begin += mir_strlen(startTag) - 1; - for (; *begin != '>' && *begin; ++begin); - if (*begin) { - char* end = strstr(++begin, endTag); - if (end) *end = 0; - } - return begin; -} - -static void HTTPFormAppendData(NETLIBHTTPREQUEST* nlhr, size_t* dataMax, char** dataPos, const char* data, size_t len) -{ - nlhr->dataLength = (*dataPos - nlhr->pData); - if (nlhr->dataLength + len >= *dataMax) { - *dataPos = nlhr->pData; - *dataMax += 0x1000 + 0x1000 * (len >> 12); - nlhr->pData = (char*)mir_realloc(nlhr->pData, *dataMax); - if (!nlhr->pData) mir_free(*dataPos); - *dataPos = nlhr->pData; - if (!*dataPos) - return; - *dataPos += nlhr->dataLength; - } - if (data) { - memcpy(*dataPos, data, sizeof(char)*len); *dataPos += len; - nlhr->dataLength += (int)len; // not necessary - } -} - -void CSend::HTTPFormDestroy(NETLIBHTTPREQUEST* nlhr) -{ - mir_free(nlhr->headers[0].szValue), nlhr->headers[0].szValue = nullptr; - mir_free(nlhr->headers), nlhr->headers = nullptr; - mir_free(nlhr->pData), nlhr->pData = nullptr; -} - -int CSend::HTTPFormCreate(NETLIBHTTPREQUEST* nlhr, int requestType, const char* url, HTTPFormData* frm, size_t frmNum) -{ - char boundary[16]; - memcpy(boundary, "--M461C/", 8); - { - union - { - uint32_t num; - unsigned char cr[4]; - }; num = GetTickCount() ^ 0x8000; - for (int i = 0; i < 4; ++i) { - unsigned char chcode = cr[i] >> 4; - boundary[8 + i * 2] = (chcode < 0x0a ? '0' : 'a' - 0x0a) + chcode; - chcode = cr[i] & 0x0f; - boundary[9 + i * 2] = (chcode < 0x0a ? '0' : 'a' - 0x0a) + chcode; - } - } - nlhr->cbSize = sizeof(NETLIBHTTPREQUEST); - nlhr->requestType = requestType; - nlhr->flags = NLHRF_HTTP11; - if (!strncmp(url, "https://", 8)) nlhr->flags |= NLHRF_SSL; - nlhr->szUrl = (char*)url; - nlhr->headersCount = 3; - for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) { - if (!(iter->flags&HTTPFF_HEADER)) break; - ++nlhr->headersCount; - } - nlhr->headers = (NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhr->headersCount); - { - char* contenttype = (char*)mir_alloc(sizeof(char)*(30 + 1 + sizeof(boundary))); - memcpy(contenttype, "multipart/form-data; boundary=", 30); - memcpy(contenttype + 30, boundary, sizeof(boundary)); - contenttype[30 + sizeof(boundary)] = '\0'; - nlhr->headers[0].szName = "Content-Type"; - nlhr->headers[0].szValue = contenttype; - nlhr->headers[1].szName = "User-Agent"; - nlhr->headers[1].szValue = __USER_AGENT_STRING; - nlhr->headers[2].szName = "Accept-Language"; - nlhr->headers[2].szValue = "en-us,en;q=0.8"; - int i = 3; - for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) { - if (!(iter->flags&HTTPFF_HEADER)) break; - nlhr->headers[i].szName = (char*)iter->name; - nlhr->headers[i++].szValue = (char*)iter->value_str; - } - } - char* dataPos = nlhr->pData; - size_t dataMax = 0; - for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) { - if (iter->flags&HTTPFF_HEADER) continue; - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, 2 + sizeof(boundary) + 40); - memset(dataPos, '-', 2); dataPos += 2; - memcpy(dataPos, boundary, sizeof(boundary)); dataPos += sizeof(boundary); - memcpy(dataPos, "\r\nContent-Disposition: form-data; name=\"", 40); dataPos += 40; - size_t namelen = mir_strlen(iter->name), valuelen = 0; - if (!(iter->flags&HTTPFF_INT)) - valuelen = mir_strlen(iter->value_str); - if (iter->flags&HTTPFF_FILE) { - const char* filename = strrchr(iter->value_str, '\\'); - if (!filename) filename = strrchr(iter->value_str, '/'); - if (!filename) filename = iter->value_str; - else ++filename; - valuelen = mir_strlen(filename); - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 13 + valuelen + 17); - memcpy(dataPos, iter->name, namelen); dataPos += namelen; - memcpy(dataPos, "\"; filename=\"", 13); dataPos += 13; - memcpy(dataPos, filename, valuelen); dataPos += valuelen; - memcpy(dataPos, "\"\r\nContent-Type: ", 17); dataPos += 17; - /// add mime type - const char* mime = "application/octet-stream"; - const char* fileext = strrchr(filename, '.'); - if (fileext) { - if (!mir_strcmp(fileext, ".jpg") || !mir_strcmp(fileext, ".jpeg") || !mir_strcmp(fileext, ".jpe")) - mime = "image/jpeg"; - else if (!mir_strcmp(fileext, ".bmp")) - mime = "image/bmp"; - else if (!mir_strcmp(fileext, ".png")) - mime = "image/png"; - else if (!mir_strcmp(fileext, ".gif")) - mime = "image/gif"; - else if (!mir_strcmp(fileext, ".tif") || !mir_strcmp(fileext, ".tiff")) - mime = "image/tiff"; - } - HTTPFormAppendData(nlhr, &dataMax, &dataPos, mime, mir_strlen(mime)); - HTTPFormAppendData(nlhr, &dataMax, &dataPos, "\r\n\r\n", 4); - /// add file content - size_t filesize = 0; - FILE* fp = fopen(iter->value_str, "rb"); - if (fp) { - fseek(fp, 0, SEEK_END); - filesize = ftell(fp); fseek(fp, 0, SEEK_SET); - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, filesize + 2); - if (fread(dataPos, 1, filesize, fp) != filesize) { - fclose(fp), fp = nullptr; - } - } - if (!fp) { - HTTPFormDestroy(nlhr); - Error(L"Error occurred when opening local file.\nAborting file upload..."); - Exit(ACKRESULT_FAILED); - return 1; - } - else - fclose(fp); - dataPos += filesize; - memcpy(dataPos, "\r\n", 2); dataPos += 2; - } - else if (iter->flags&HTTPFF_8BIT) { - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 38 + valuelen + 2); - memcpy(dataPos, iter->name, namelen); dataPos += namelen; - memcpy(dataPos, "\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n", 38); dataPos += 38; - memcpy(dataPos, iter->value_str, valuelen); dataPos += valuelen; - memcpy(dataPos, "\r\n", 2); dataPos += 2; - } - else if (iter->flags&HTTPFF_INT) { - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 5 + 17/*max numbers*/ + 2); - memcpy(dataPos, iter->name, namelen); dataPos += namelen; - memcpy(dataPos, "\"\r\n\r\n", 5); dataPos += 5; - int ret = snprintf(dataPos, 17, "%Id", iter->value_int); - if (ret < 17 && ret>0) dataPos += ret; - memcpy(dataPos, "\r\n", 2); dataPos += 2; - } - else { - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 5 + valuelen + 2); - memcpy(dataPos, iter->name, namelen); dataPos += namelen; - memcpy(dataPos, "\"\r\n\r\n", 5); dataPos += 5; - memcpy(dataPos, iter->value_str, valuelen); dataPos += valuelen; - memcpy(dataPos, "\r\n", 2); dataPos += 2; - } - } - HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, 2 + sizeof(boundary) + 4); - memset(dataPos, '-', 2); dataPos += 2; - memcpy(dataPos, boundary, sizeof(boundary)); dataPos += sizeof(boundary); - memcpy(dataPos, "--\r\n", 4); dataPos += 4; - nlhr->dataLength = dataPos - nlhr->pData; -#ifdef _DEBUG /// print request content to "_sendss_tmp" file for debugging - { - FILE* fp = fopen("_sendss_tmp", "wb"); - if (fp) { - fprintf(fp, "--Target-- %s\n", nlhr->szUrl); - for (int i = 0; i < nlhr->headersCount; ++i) { - fprintf(fp, "%s: %s\n", nlhr->headers[i].szName, nlhr->headers[i].szValue); - } - fprintf(fp, "\n\n"); - fwrite(nlhr->pData, 1, nlhr->dataLength, fp); - fclose(fp); - } - } -#endif // _DEBUG - return 0; -} +/*
+
+Miranda NG: the free IM client for Microsoft* Windows*
+
+Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org),
+Copyright (c) 2000-09 Miranda ICQ/IM project,
+
+This file is part of Send Screenshot Plus, a Miranda IM plugin.
+Copyright (c) 2010 Ing.U.Horn
+
+Parts of this file based on original sorce code
+(c) 2004-2006 Sérgio Vieira Rolanski (portet from Borland C++)
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+#define CSEND_DIALOG 8800
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CSend::CSend(HWND /*Owner*/, MCONTACT hContact, bool bAsync, bool bSilent) :
+ m_bDeleteAfterSend(false),
+ m_bAsync(bAsync),
+ m_bSilent(bSilent),
+ m_pszFile(nullptr),
+ m_pszFileDesc(nullptr),
+ m_pszSendTyp(nullptr),
+ m_pszProto(nullptr),
+ m_EnableItem(0),
+ m_ChatRoom(0),
+ m_cbEventMsg(0),
+ m_hSend(nullptr),
+ m_hOnSend(nullptr),
+ m_ErrorMsg(nullptr),
+ m_ErrorTitle(nullptr)
+{
+ SetContact(hContact);
+}
+
+CSend::~CSend()
+{
+ mir_free(m_pszFile);
+ mir_free(m_pszFileDesc);
+ mir_free(m_ErrorMsg);
+ mir_free(m_ErrorTitle);
+ if (m_hOnSend) UnhookEvent(m_hOnSend);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CSend::SetContact(MCONTACT hContact)
+{
+ m_hContact = hContact;
+ if (hContact) {
+ m_pszProto = Proto_GetBaseAccountName(hContact);
+ m_ChatRoom = Contact::IsGroupChat(hContact, m_pszProto);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CALLBACK CSend::ResultDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, GetIconHandle(ICO_MAIN));
+ {
+ CSend *self = (CSend*)lParam;
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, CMStringW(TranslateT("Resulting URL from\n")) + self->m_pszSendTyp);
+
+ SendDlgItemMessage(hwndDlg, IDC_HEADERBAR, WM_SETICON, ICON_BIG, (LPARAM)GetIconBtn(ICO_BTN_ARROWR));
+ SetDlgItemTextA(hwndDlg, ID_edtURL, self->m_URL);
+ if (self->m_URLthumb) {
+ SetDlgItemTextA(hwndDlg, ID_edtURLthumb, self->m_URLthumb);
+ }
+ else {
+ SetDlgItemTextA(hwndDlg, ID_edtURLthumb, "-");
+ for (int i = ID_btnThumbCopy; i <= ID_edtURLthumb; ++i) {
+ EnableWindow(GetDlgItem(hwndDlg, i), FALSE);
+ }
+ }
+ if (!self->m_pszFileDesc)
+ SetDlgItemText(hwndDlg, ID_bvlDesc, self->m_ErrorTitle);
+ else
+ SetDlgItemText(hwndDlg, ID_bvlDesc, self->m_pszFileDesc);
+ SendDlgItemMessage(hwndDlg, IDOK, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_COPY));
+ SendDlgItemMessage(hwndDlg, IDOK, BUTTONTRANSLATE, 0, 0);
+ SendDlgItemMessage(hwndDlg, IDCANCEL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_CANCEL));
+ SendDlgItemMessage(hwndDlg, IDCANCEL, BUTTONTRANSLATE, 0, 0);
+ for (int i = ID_btnCopy; i <= ID_btnThumbBBC2; ++i) {
+ SendDlgItemMessage(hwndDlg, i, BUTTONSETASTHEMEDBTN, 0, 0);
+ SendDlgItemMessage(hwndDlg, i, BUTTONSETASFLATBTN, 1, 0);
+ switch (i) {
+ case ID_btnCopy:
+ case ID_btnThumbCopy:
+ SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_COPY));
+ SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy"), BATF_UNICODE);
+ break;
+ case ID_btnBBC:
+ case ID_btnThumbBBC:
+ SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_BBC));
+ SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy BBCode"), BATF_UNICODE);
+ break;
+ default:
+ SendDlgItemMessage(hwndDlg, i, BM_SETIMAGE, IMAGE_ICON, (LPARAM)GetIconBtn(ICO_BTN_BBCLNK));
+ SendDlgItemMessage(hwndDlg, i, BUTTONADDTOOLTIP, (WPARAM)LPGENW("Copy BBCode w/ link"), BATF_UNICODE);
+ }
+ }
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ case IDOK:
+ case ID_btnCopy:
+ case ID_btnThumbCopy:
+ case ID_btnBBC:
+ case ID_btnThumbBBC:
+ case ID_btnThumbBBC2:
+ wchar_t tmp[2048];
+ int edtID = ID_edtURL;
+ int bbc = 0;
+ switch (LOWORD(wParam)) {
+ case ID_btnThumbBBC2: ++bbc;
+ case ID_btnThumbBBC: ++bbc;
+ case ID_btnThumbCopy:
+ edtID = ID_edtURLthumb;
+ break;
+ case ID_btnBBC: ++bbc;
+ break;
+ }
+ size_t len;
+ if (bbc) {
+ if (bbc == 1) {
+ memcpy(tmp, L"[img]", 5 * sizeof(wchar_t)); len = 5;
+ len += GetDlgItemText(hwndDlg, edtID, tmp + len, 2048 - 11);
+ memcpy(tmp + len, L"[/img]", 7 * sizeof(wchar_t)); len += 7;
+ }
+ else {
+ memcpy(tmp, L"[url=", 5 * sizeof(wchar_t)); len = 5;
+ len += GetDlgItemText(hwndDlg, ID_edtURL, tmp + len, 1024);
+ memcpy(tmp + len, L"][img]", 6 * sizeof(wchar_t)); len += 6;
+ len += GetDlgItemText(hwndDlg, edtID, tmp + len, 1024);
+ memcpy(tmp + len, L"[/img][/url]", 13 * sizeof(wchar_t)); len += 12;
+ }
+ }
+ else len = GetDlgItemText(hwndDlg, edtID, tmp, _countof(tmp));
+
+ Utils_ClipboardCopy(CMStringW(tmp, len + 1));
+
+ if (LOWORD(wParam) == IDOK)
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void CSend::svcSendMsgExit(const char* szMessage)
+{
+ if (m_bSilent) {
+ Exit(ACKRESULT_SUCCESS); return;
+ }
+ if (!m_hContact) {
+ if (!m_pszFileDesc)
+ m_pszFileDesc = mir_a2u(szMessage);
+ Exit(CSEND_DIALOG); return;
+ }
+
+ if (m_ChatRoom) {
+ CMStringW tmp(szMessage);
+ if (m_pszFileDesc) {
+ tmp.Append(L"\r\n");
+ tmp.Append(m_pszFileDesc);
+ }
+
+ int res = GC_RESULT_NOSESSION;
+ int cnt = g_chatApi.SM_GetCount(m_pszProto);
+
+ // loop on all gc session to get the right (save) ptszID for the chatroom from m_hContact
+ GC_INFO gci = { 0 };
+ gci.pszModule = m_pszProto;
+ for (int i = 0; i < cnt; i++) {
+ gci.iItem = i;
+ gci.Flags = GCF_BYINDEX | GCF_HCONTACT | GCF_ID;
+ Chat_GetInfo(&gci);
+ if (gci.hContact == m_hContact) {
+ Chat_SendUserMessage(m_pszProto, gci.pszID, tmp);
+ res = 200;
+ break;
+ }
+ }
+ Exit(res); return;
+ }
+ else {
+ m_szEventMsg = szMessage;
+ if (m_pszFileDesc && m_pszFileDesc[0] != NULL) {
+ m_szEventMsg.Append("\r\n");
+ m_szEventMsg.Append(_T2A(m_pszFileDesc));
+ m_cbEventMsg = m_szEventMsg.GetLength() + 1;
+ }
+
+ // create a HookEventObj on ME_PROTO_ACK
+ if (!m_hOnSend)
+ m_hOnSend = HookEventObj(ME_PROTO_ACK, OnSend, this);
+
+ // start PSS_MESSAGE service
+ m_hSend = (HANDLE)ProtoChainSend(m_hContact, PSS_MESSAGE, NULL, ptrA(mir_utf8encode(m_szEventMsg)));
+
+ // check we actually got an ft handle back from the protocol
+ if (!m_hSend) {
+ Unhook();
+ Error(SS_ERR_INIT, m_pszSendTyp);
+ Exit(ACKRESULT_FAILED); return;
+ }
+ }
+}
+
+void CSend::svcSendFileExit()
+{
+ // szMessage should be encoded as the File followed by the description, the
+ // separator being a single nul (\0). If there is no description, do not forget
+ // to end the File with two nuls.
+ if (m_bSilent) {
+ Exit(ACKRESULT_SUCCESS); return;
+ }
+
+ if (!m_hContact) {
+ Error(LPGENW("%s requires a valid contact!"), m_pszSendTyp);
+ Exit(ACKRESULT_FAILED); return;
+ }
+
+ m_szEventMsg = _T2A(m_pszFile);
+
+ if (m_pszFileDesc && m_pszFileDesc[0] != NULL) {
+ m_szEventMsg.AppendChar(0);
+ m_szEventMsg.Append(_T2A(m_pszFileDesc));
+ }
+
+ m_cbEventMsg = m_szEventMsg.GetLength() + 1;
+
+ // Сreate a HookEventObj on ME_PROTO_ACK
+ if (!m_hOnSend) {
+ m_hOnSend = HookEventObj(ME_PROTO_ACK, OnSend, this);
+ }
+
+ // Start miranda PSS_FILE based on mir ver (T)
+ wchar_t* ppFile[2] = { nullptr, nullptr };
+ wchar_t* pDesc = mir_wstrdup(m_pszFileDesc);
+ ppFile[0] = mir_wstrdup(m_pszFile);
+ ppFile[1] = nullptr;
+ m_hSend = (HANDLE)ProtoChainSend(m_hContact, PSS_FILE, (WPARAM)pDesc, (LPARAM)ppFile);
+ mir_free(pDesc);
+ mir_free(ppFile[0]);
+
+ // check we actually got an ft handle back from the protocol
+ if (!m_hSend) {
+ Unhook();
+ Error(SS_ERR_INIT, m_pszSendTyp);
+ Exit(ACKRESULT_FAILED); return;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CSend::OnSend(void *obj, WPARAM, LPARAM lParam)
+{
+ CSend* self = (CSend*)obj;
+ ACKDATA *ack = (ACKDATA*)lParam;
+ if (ack->hProcess != self->m_hSend)
+ return 0;
+
+ switch (ack->result) {
+ case ACKRESULT_INITIALISING: // SetFtStatus(hwndDlg, LPGENW("Initialising..."), FTS_TEXT); break;
+ case ACKRESULT_CONNECTING: // SetFtStatus(hwndDlg, LPGENW("Connecting..."), FTS_TEXT); break;
+ case ACKRESULT_CONNECTPROXY: // SetFtStatus(hwndDlg, LPGENW("Connecting to proxy..."), FTS_TEXT); break;
+ case ACKRESULT_LISTENING: // SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); break;
+ case ACKRESULT_CONNECTED: // SetFtStatus(hwndDlg, LPGENW("Connected"), FTS_TEXT); break;
+ case ACKRESULT_SENTREQUEST: // SetFtStatus(hwndDlg, LPGENW("Decision sent"), FTS_TEXT); break;
+ case ACKRESULT_NEXTFILE: // SetFtStatus(hwndDlg, LPGENW("Moving to next file..."), FTS_TEXT);
+ case ACKRESULT_FILERESUME:
+ case ACKRESULT_DATA: // transfer is on progress
+ break;
+ case ACKRESULT_DENIED:
+ self->Unhook();
+ self->Exit(ack->result);
+ break;
+ case ACKRESULT_FAILED:
+ self->Unhook();
+ self->Exit(ack->result);
+ // type=ACKTYPE_MESSAGE, result=success/failure, (char*)lParam=error message or NULL.
+ // type=ACKTYPE_FILE, result=ACKRESULT_FAILED then lParam=(LPARAM)(const char*)szReason
+ break;
+ case ACKRESULT_SUCCESS:
+ self->Unhook();
+ switch (ack->type) {
+ case ACKTYPE_CHAT:
+ break;
+ case ACKTYPE_MESSAGE:
+ self->DB_EventAdd((uint16_t)EVENTTYPE_MESSAGE);
+ break;
+ case ACKTYPE_FILE:
+ self->m_szEventMsg.Insert(0, "aaaa");
+ self->m_cbEventMsg += sizeof(uint32_t);
+ self->DB_EventAdd((uint16_t)EVENTTYPE_FILE);
+ break;
+ }
+ self->Exit(ack->result);
+ break;
+ }
+ return 0;
+}
+
+void CSend::DB_EventAdd(uint16_t EventType)
+{
+ DBEVENTINFO dbei = {};
+ dbei.szModule = m_pszProto;
+ dbei.eventType = EventType;
+ dbei.flags = DBEF_SENT;
+ dbei.timestamp = time(0);
+ dbei.flags |= DBEF_UTF;
+ dbei.cbBlob = m_cbEventMsg;
+ dbei.pBlob = (uint8_t*)m_szEventMsg.GetString();
+ db_event_add(m_hContact, &dbei);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CSend::Error(LPCTSTR pszFormat, ...)
+{
+ wchar_t tszMsg[MAX_SECONDLINE];
+
+ mir_snwprintf(tszMsg, L"%s - %s", _A2W(MODULENAME), TranslateT("Error"));
+ mir_free(m_ErrorTitle), m_ErrorTitle = mir_wstrdup(tszMsg);
+
+ va_list vl;
+ va_start(vl, pszFormat);
+ mir_vsnwprintf(tszMsg, _countof(tszMsg), TranslateW(pszFormat), vl);
+ va_end(vl);
+ mir_free(m_ErrorMsg), m_ErrorMsg = mir_wstrdup(tszMsg);
+
+ memset(&m_box, 0, sizeof(MSGBOX));
+ m_box.cbSize = sizeof(MSGBOX);
+ m_box.hParent = nullptr;
+ m_box.hiLogo = GetIcon(ICO_MAIN);
+ m_box.hiMsg = nullptr;
+ m_box.ptszTitle = m_ErrorTitle;
+ m_box.ptszMsg = m_ErrorMsg;
+ m_box.uType = MB_OK | MB_ICON_ERROR;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void CSend::Exit(unsigned int Result)
+{
+ if (!m_bSilent) {
+ bool err = true;
+ switch (Result) {
+ case CSEND_DIALOG:
+ Skin_PlaySound("FileDone");
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_UResultForm), nullptr, ResultDialogProc, (LPARAM)this);
+ err = false;
+ break;
+ case ACKRESULT_SUCCESS:
+ case GC_RESULT_SUCCESS:
+ Skin_PlaySound("FileDone");
+ err = false;
+ break;
+ case ACKRESULT_DENIED:
+ Skin_PlaySound("FileDenied");
+ Error(L"%s (%i):\nFile transfer denied.", TranslateW(m_pszSendTyp), Result);
+ MsgBoxService(NULL, (LPARAM)&m_box);
+ err = false;
+ break;
+ case GC_RESULT_WRONGVER: // You appear to be using the wrong version of GC API.
+ Error(L"%s (%i):\nYou appear to be using the wrong version of GC API", TranslateT("GCHAT error"), Result);
+ break;
+ case GC_RESULT_ERROR: // An internal GC error occurred.
+ Error(L"%s (%i):\nAn internal GC error occurred.", TranslateT("GCHAT error"), Result);
+ break;
+ case GC_RESULT_NOSESSION: // contact has no open GC session
+ Error(L"%s (%i):\nContact has no open GC session.", TranslateT("GCHAT error"), Result);
+ break;
+ case ACKRESULT_FAILED:
+ default:
+ break;
+ }
+ if (err) {
+ Skin_PlaySound("FileFailed");
+ if (m_ErrorMsg) MsgBoxService(NULL, (LPARAM)&m_box);
+ else MsgErr(nullptr, LPGENW("An unknown error has occurred."));
+ }
+ }
+ if (m_pszFile && *m_pszFile && m_bDeleteAfterSend && m_EnableItem&SS_DLG_DELETEAFTERSSEND) {
+ DeleteFile(m_pszFile), m_pszFile = nullptr;
+ }
+ if (m_bAsync)
+ delete this; // deletes derived class since destructor is virtual (which also auto-calls base dtor)
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// helper functions used for HTTP uploads
+
+#define snprintf _snprintf
+
+const char* CSend::GetHTMLContent(char* str, const char* startTag, const char* endTag)
+{
+ char* begin = strstr(str, startTag);
+ if (!begin) return nullptr;
+ begin += mir_strlen(startTag) - 1;
+ for (; *begin != '>' && *begin; ++begin);
+ if (*begin) {
+ char* end = strstr(++begin, endTag);
+ if (end) *end = 0;
+ }
+ return begin;
+}
+
+static void HTTPFormAppendData(NETLIBHTTPREQUEST* nlhr, size_t* dataMax, char** dataPos, const char* data, size_t len)
+{
+ nlhr->dataLength = (*dataPos - nlhr->pData);
+ if (nlhr->dataLength + len >= *dataMax) {
+ *dataPos = nlhr->pData;
+ *dataMax += 0x1000 + 0x1000 * (len >> 12);
+ nlhr->pData = (char*)mir_realloc(nlhr->pData, *dataMax);
+ if (!nlhr->pData) mir_free(*dataPos);
+ *dataPos = nlhr->pData;
+ if (!*dataPos)
+ return;
+ *dataPos += nlhr->dataLength;
+ }
+ if (data) {
+ memcpy(*dataPos, data, sizeof(char)*len); *dataPos += len;
+ nlhr->dataLength += (int)len; // not necessary
+ }
+}
+
+void CSend::HTTPFormDestroy(NETLIBHTTPREQUEST* nlhr)
+{
+ mir_free(nlhr->headers[0].szValue), nlhr->headers[0].szValue = nullptr;
+ mir_free(nlhr->headers), nlhr->headers = nullptr;
+ mir_free(nlhr->pData), nlhr->pData = nullptr;
+}
+
+int CSend::HTTPFormCreate(NETLIBHTTPREQUEST* nlhr, int requestType, const char* url, HTTPFormData* frm, size_t frmNum)
+{
+ char boundary[16];
+ memcpy(boundary, "--M461C/", 8);
+ {
+ union
+ {
+ uint32_t num;
+ unsigned char cr[4];
+ }; num = GetTickCount() ^ 0x8000;
+ for (int i = 0; i < 4; ++i) {
+ unsigned char chcode = cr[i] >> 4;
+ boundary[8 + i * 2] = (chcode < 0x0a ? '0' : 'a' - 0x0a) + chcode;
+ chcode = cr[i] & 0x0f;
+ boundary[9 + i * 2] = (chcode < 0x0a ? '0' : 'a' - 0x0a) + chcode;
+ }
+ }
+ nlhr->cbSize = sizeof(NETLIBHTTPREQUEST);
+ nlhr->requestType = requestType;
+ nlhr->flags = NLHRF_HTTP11;
+ if (!strncmp(url, "https://", 8)) nlhr->flags |= NLHRF_SSL;
+ nlhr->szUrl = (char*)url;
+ nlhr->headersCount = 3;
+ for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) {
+ if (!(iter->flags&HTTPFF_HEADER)) break;
+ ++nlhr->headersCount;
+ }
+ nlhr->headers = (NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER)*nlhr->headersCount);
+ {
+ char* contenttype = (char*)mir_alloc(sizeof(char)*(30 + 1 + sizeof(boundary)));
+ memcpy(contenttype, "multipart/form-data; boundary=", 30);
+ memcpy(contenttype + 30, boundary, sizeof(boundary));
+ contenttype[30 + sizeof(boundary)] = '\0';
+ nlhr->headers[0].szName = "Content-Type";
+ nlhr->headers[0].szValue = contenttype;
+ nlhr->headers[1].szName = "User-Agent";
+ nlhr->headers[1].szValue = __USER_AGENT_STRING;
+ nlhr->headers[2].szName = "Accept-Language";
+ nlhr->headers[2].szValue = "en-us,en;q=0.8";
+ int i = 3;
+ for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) {
+ if (!(iter->flags&HTTPFF_HEADER)) break;
+ nlhr->headers[i].szName = (char*)iter->name;
+ nlhr->headers[i++].szValue = (char*)iter->value_str;
+ }
+ }
+ char* dataPos = nlhr->pData;
+ size_t dataMax = 0;
+ for (HTTPFormData* iter = frm, *end = frm + frmNum; iter != end; ++iter) {
+ if (iter->flags&HTTPFF_HEADER) continue;
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, 2 + sizeof(boundary) + 40);
+ memset(dataPos, '-', 2); dataPos += 2;
+ memcpy(dataPos, boundary, sizeof(boundary)); dataPos += sizeof(boundary);
+ memcpy(dataPos, "\r\nContent-Disposition: form-data; name=\"", 40); dataPos += 40;
+ size_t namelen = mir_strlen(iter->name), valuelen = 0;
+ if (!(iter->flags&HTTPFF_INT))
+ valuelen = mir_strlen(iter->value_str);
+ if (iter->flags&HTTPFF_FILE) {
+ const char* filename = strrchr(iter->value_str, '\\');
+ if (!filename) filename = strrchr(iter->value_str, '/');
+ if (!filename) filename = iter->value_str;
+ else ++filename;
+ valuelen = mir_strlen(filename);
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 13 + valuelen + 17);
+ memcpy(dataPos, iter->name, namelen); dataPos += namelen;
+ memcpy(dataPos, "\"; filename=\"", 13); dataPos += 13;
+ memcpy(dataPos, filename, valuelen); dataPos += valuelen;
+ memcpy(dataPos, "\"\r\nContent-Type: ", 17); dataPos += 17;
+ /// add mime type
+ const char* mime = "application/octet-stream";
+ const char* fileext = strrchr(filename, '.');
+ if (fileext) {
+ if (!mir_strcmp(fileext, ".jpg") || !mir_strcmp(fileext, ".jpeg") || !mir_strcmp(fileext, ".jpe"))
+ mime = "image/jpeg";
+ else if (!mir_strcmp(fileext, ".bmp"))
+ mime = "image/bmp";
+ else if (!mir_strcmp(fileext, ".png"))
+ mime = "image/png";
+ else if (!mir_strcmp(fileext, ".gif"))
+ mime = "image/gif";
+ else if (!mir_strcmp(fileext, ".tif") || !mir_strcmp(fileext, ".tiff"))
+ mime = "image/tiff";
+ }
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, mime, mir_strlen(mime));
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, "\r\n\r\n", 4);
+ /// add file content
+ size_t filesize = 0;
+ FILE* fp = fopen(iter->value_str, "rb");
+ if (fp) {
+ fseek(fp, 0, SEEK_END);
+ filesize = ftell(fp); fseek(fp, 0, SEEK_SET);
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, filesize + 2);
+ if (fread(dataPos, 1, filesize, fp) != filesize) {
+ fclose(fp), fp = nullptr;
+ }
+ }
+ if (!fp) {
+ HTTPFormDestroy(nlhr);
+ Error(L"Error occurred when opening local file.\nAborting file upload...");
+ Exit(ACKRESULT_FAILED);
+ return 1;
+ }
+ else
+ fclose(fp);
+ dataPos += filesize;
+ memcpy(dataPos, "\r\n", 2); dataPos += 2;
+ }
+ else if (iter->flags&HTTPFF_8BIT) {
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 38 + valuelen + 2);
+ memcpy(dataPos, iter->name, namelen); dataPos += namelen;
+ memcpy(dataPos, "\"\r\nContent-Transfer-Encoding: 8bit\r\n\r\n", 38); dataPos += 38;
+ memcpy(dataPos, iter->value_str, valuelen); dataPos += valuelen;
+ memcpy(dataPos, "\r\n", 2); dataPos += 2;
+ }
+ else if (iter->flags&HTTPFF_INT) {
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 5 + 17/*max numbers*/ + 2);
+ memcpy(dataPos, iter->name, namelen); dataPos += namelen;
+ memcpy(dataPos, "\"\r\n\r\n", 5); dataPos += 5;
+ int ret = snprintf(dataPos, 17, "%Id", iter->value_int);
+ if (ret < 17 && ret>0) dataPos += ret;
+ memcpy(dataPos, "\r\n", 2); dataPos += 2;
+ }
+ else {
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, namelen + 5 + valuelen + 2);
+ memcpy(dataPos, iter->name, namelen); dataPos += namelen;
+ memcpy(dataPos, "\"\r\n\r\n", 5); dataPos += 5;
+ memcpy(dataPos, iter->value_str, valuelen); dataPos += valuelen;
+ memcpy(dataPos, "\r\n", 2); dataPos += 2;
+ }
+ }
+ HTTPFormAppendData(nlhr, &dataMax, &dataPos, nullptr, 2 + sizeof(boundary) + 4);
+ memset(dataPos, '-', 2); dataPos += 2;
+ memcpy(dataPos, boundary, sizeof(boundary)); dataPos += sizeof(boundary);
+ memcpy(dataPos, "--\r\n", 4); dataPos += 4;
+ nlhr->dataLength = dataPos - nlhr->pData;
+#ifdef _DEBUG /// print request content to "_sendss_tmp" file for debugging
+ {
+ FILE* fp = fopen("_sendss_tmp", "wb");
+ if (fp) {
+ fprintf(fp, "--Target-- %s\n", nlhr->szUrl);
+ for (int i = 0; i < nlhr->headersCount; ++i) {
+ fprintf(fp, "%s: %s\n", nlhr->headers[i].szName, nlhr->headers[i].szValue);
+ }
+ fprintf(fp, "\n\n");
+ fwrite(nlhr->pData, 1, nlhr->dataLength, fp);
+ fclose(fp);
+ }
+ }
+#endif // _DEBUG
+ return 0;
+}
|