diff options
Diffstat (limited to 'protocols')
-rwxr-xr-x | protocols/JabberG/src/jabber_caps.h | 1 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_disco.cpp | 29 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_file.cpp | 6 | ||||
-rw-r--r-- | protocols/JabberG/src/jabber_ft.cpp | 127 | ||||
-rwxr-xr-x | protocols/JabberG/src/jabber_proto.cpp | 51 | ||||
-rwxr-xr-x | protocols/JabberG/src/jabber_proto.h | 5 | ||||
-rwxr-xr-x | protocols/JabberG/src/stdafx.h | 2 |
7 files changed, 173 insertions, 48 deletions
diff --git a/protocols/JabberG/src/jabber_caps.h b/protocols/JabberG/src/jabber_caps.h index 9e78c0dfb6..caa18b88f0 100755 --- a/protocols/JabberG/src/jabber_caps.h +++ b/protocols/JabberG/src/jabber_caps.h @@ -195,6 +195,7 @@ typedef unsigned __int64 JabberCapsBits; #define JABBER_FEAT_CSI "urn:xmpp:csi:0"
#define JABBER_FEAT_JUD "jabber:iq:search"
#define JABBER_FEAT_SERVER_AVATAR "storage:client:avatar"
+#define JABBER_FEAT_UPLOAD "urn:xmpp:http:upload"
#define JABBER_FEAT_PUBSUB_EVENT "http://jabber.org/protocol/pubsub#event"
#define JABBER_FEAT_PUBSUB_NODE_CONFIG "http://jabber.org/protocol/pubsub#node_config"
diff --git a/protocols/JabberG/src/jabber_disco.cpp b/protocols/JabberG/src/jabber_disco.cpp index 40d3c0a53f..bf2dbac1fd 100644 --- a/protocols/JabberG/src/jabber_disco.cpp +++ b/protocols/JabberG/src/jabber_disco.cpp @@ -86,12 +86,12 @@ static sttNodeIcons[] = { nullptr, "store", nullptr, IDI_NODE_STORE, 0 },
- // icons for non-standard identities
+ // icons for non-standard identities
{ nullptr, "x-service", "x-rss", IDI_NODE_RSS, 0 },
{ nullptr, "application", "x-weather", IDI_NODE_WEATHER, 0 },
{ nullptr, "user", nullptr, 0, SKINICON_STATUS_ONLINE },
- // icon suggestions based on supported features
+ // icon suggestions based on supported features
{ "jabber:iq:gateway", nullptr, nullptr, IDI_AGENTS, 0 },
{ JABBER_FEAT_JUD, nullptr, nullptr, 0, SKINICON_OTHER_FINDUSER },
{ JABBER_FEAT_COMMANDS, nullptr, nullptr, IDI_COMMAND, 0 },
@@ -1026,7 +1026,7 @@ void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM SD_ACT_LOGON = 100, SD_ACT_LOGOFF, SD_ACT_UNREGISTER,
SD_ACT_REGISTER = 200, SD_ACT_ADHOC, SD_ACT_ADDDIRECTORY,
- SD_ACT_JOIN, SD_ACT_BOOKMARK, SD_ACT_PROXY, SD_ACT_VCARD
+ SD_ACT_JOIN, SD_ACT_BOOKMARK, SD_ACT_PROXY, SD_ACT_VCARD, SD_ACT_UPLOAD
};
enum
@@ -1063,6 +1063,7 @@ void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM { JABBER_FEAT_MUC, LPGENW("Bookmark chatroom"), SD_ACT_BOOKMARK, SD_FLG_NORESOURCE | SD_FLG_HASUSER},
{ JABBER_FEAT_JUD, LPGENW("Add search directory"), SD_ACT_ADDDIRECTORY},
{ JABBER_FEAT_BYTESTREAMS, LPGENW("Use this proxy"), SD_ACT_PROXY},
+ { JABBER_FEAT_UPLOAD, LPGENW("Use for uploads"), SD_ACT_UPLOAD},
{ nullptr },
{ JABBER_FEAT_REGISTER, LPGENW("Register"), SD_ACT_REGISTER},
{ "jabber:iq:gateway", LPGENW("Unregister"), SD_ACT_UNREGISTER, SD_FLG_ONROSTER | SD_FLG_SUBSCRIBED},
@@ -1129,7 +1130,20 @@ void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM if (bFeatureOk) {
if (it.title) {
- AppendMenu(hMenu, MF_STRING, it.action, TranslateW(it.title));
+ UINT dwFlags = MF_STRING;
+ switch (it.action) {
+ case SD_ACT_PROXY:
+ if (m_bBsProxyManual)
+ dwFlags += MF_CHECKED;
+ break;
+
+ case SD_ACT_UPLOAD:
+ if (m_bUseHttpUpload)
+ dwFlags += MF_CHECKED;
+ break;
+ }
+
+ AppendMenu(hMenu, dwFlags, it.action, TranslateW(it.title));
lastSeparator = FALSE;
}
else if (!lastSeparator) {
@@ -1231,10 +1245,15 @@ void CJabberProto::ServiceDiscoveryShowMenu(CJabberSDNode *pNode, HTREELISTITEM break;
case SD_ACT_PROXY:
- m_bBsProxyManual = true;
+ m_bBsProxyManual = !m_bBsProxyManual;
setUString("BsProxyServer", pNode->GetJid());
break;
+ case SD_ACT_UPLOAD:
+ m_bUseHttpUpload = !m_bUseHttpUpload;
+ setUString("HttpUpload", pNode->GetJid());
+ break;
+
case SD_ACT_JOIN:
GroupchatJoinRoomByJid(m_pDlgServiceDiscovery->GetHwnd(), pNode->GetJid());
break;
diff --git a/protocols/JabberG/src/jabber_file.cpp b/protocols/JabberG/src/jabber_file.cpp index 7d6d767e52..097eb62789 100644 --- a/protocols/JabberG/src/jabber_file.cpp +++ b/protocols/JabberG/src/jabber_file.cpp @@ -372,8 +372,6 @@ int CJabberProto::FileSendParse(HNETLIBCONN s, filetransfer *ft, char* buffer, i }
else { // FT_INITIALIZING
if (str[0] == '\0') {
- struct _stati64 statbuf;
-
mir_free(str);
num += 2;
@@ -393,7 +391,7 @@ int CJabberProto::FileSendParse(HNETLIBCONN s, filetransfer *ft, char* buffer, i break;
}
debugLogW(L"Sending [%s]", ft->std.pszFiles.w[currentFile]);
- _wstat64(ft->std.pszFiles.w[currentFile], &statbuf); // file size in statbuf.st_size
+
if ((fileId = _wopen(ft->std.pszFiles.w[currentFile], _O_BINARY | _O_RDONLY)) < 0) {
debugLogA("File cannot be opened");
ft->state = FT_ERROR;
@@ -402,7 +400,7 @@ int CJabberProto::FileSendParse(HNETLIBCONN s, filetransfer *ft, char* buffer, i }
char fileBuffer[2048];
- int bytes = mir_snprintf(fileBuffer, "HTTP/1.1 200 OK\r\nContent-Length: %I64u\r\n\r\n", statbuf.st_size);
+ int bytes = mir_snprintf(fileBuffer, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n", _filelength(fileId));
WsSend(s, fileBuffer, bytes, MSG_DUMPASTEXT);
ft->std.flags |= PFTS_SENDING;
diff --git a/protocols/JabberG/src/jabber_ft.cpp b/protocols/JabberG/src/jabber_ft.cpp index e832925e2a..19fc9f0c44 100644 --- a/protocols/JabberG/src/jabber_ft.cpp +++ b/protocols/JabberG/src/jabber_ft.cpp @@ -75,27 +75,43 @@ void CJabberProto::FtCancel(filetransfer *ft) ///////////////// File sending using stream initiation /////////////////////////
-void CJabberProto::FtInitiate(char* jid, filetransfer *ft)
+void CJabberProto::FtInitiate(const char* jid, filetransfer *ft)
{
- char *rs;
- int i;
- char sid[9];
-
- if (jid == nullptr || ft == nullptr || !m_bJabberOnline || (rs = ListGetBestClientResourceNamePtr(jid)) == nullptr) {
+ char *rs = ListGetBestClientResourceNamePtr(jid);
+ if (ft == nullptr || !m_bJabberOnline || rs == nullptr) {
if (ft) {
ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0);
delete ft;
}
return;
}
+
+ wchar_t *filename = ft->std.pszFiles.w[ft->std.currentFileNumber];
+ if (wchar_t *p = wcsrchr(filename, '\\'))
+ filename = p + 1;
+
+ // if we use XEP-0363, send a slot allocation request
+ if (m_bUseHttpUpload) {
+ ptrA szUploadService(getStringA("HttpUpload"));
+ if (szUploadService != nullptr) {
+ ft->type = FT_HTTP;
+
+ struct _stat64 st;
+ _wstat64(ft->std.szCurrentFile.w, &st);
+
+ XmlNodeIq iq(AddIQ(&CJabberProto::OnHttpSlotAllocated, JABBER_IQ_TYPE_GET, szUploadService, ft));
+ iq << XCHILDNS("request", "urn:xmpp:http:upload:0") << XATTR("filename", T2Utf(filename)) << XATTRI64("size", st.st_size);
+ m_ThreadInfo->send(iq);
+ return;
+ }
+ }
+
ft->type = FT_SI;
- for (i = 0; i < 8; i++)
+ char sid[9];
+ for (int i = 0; i < 8; i++)
sid[i] = (rand() % 10) + '0';
sid[8] = '\0';
replaceStr(ft->sid, sid);
- wchar_t *filename = ft->std.pszFiles.w[ft->std.currentFileNumber];
- if (wchar_t *p = wcsrchr(filename, '\\'))
- filename = p + 1;
auto *pIq = AddIQ(&CJabberProto::OnFtSiResult, JABBER_IQ_TYPE_SET, MakeJid(jid, rs), ft);
pIq->SetParamsToParse(JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_TO);
@@ -178,12 +194,13 @@ void CJabberProto::OnFtSiResult(const TiXmlElement *iqNode, CJabberIqInfo *pInfo BOOL CJabberProto::FtSend(HNETLIBCONN hConn, filetransfer *ft)
{
- struct _stati64 statbuf;
int fd;
char* buffer;
int numRead;
debugLogW(L"Sending [%s]", ft->std.pszFiles.w[ft->std.currentFileNumber]);
+
+ struct _stat64 statbuf;
_wstat64(ft->std.pszFiles.w[ft->std.currentFileNumber], &statbuf); // file size in statbuf.st_size
if ((fd = _wopen(ft->std.pszFiles.w[ft->std.currentFileNumber], _O_BINARY | _O_RDONLY)) < 0) {
debugLogA("File cannot be opened");
@@ -215,7 +232,7 @@ BOOL CJabberProto::FtIbbSend(int blocksize, filetransfer *ft) {
debugLogW(L"Sending [%s]", ft->std.pszFiles.w[ft->std.currentFileNumber]);
- struct _stati64 statbuf;
+ struct _stat64 statbuf;
_wstat64(ft->std.pszFiles.w[ft->std.currentFileNumber], &statbuf); // file size in statbuf.st_size
int fd = _wopen(ft->std.pszFiles.w[ft->std.currentFileNumber], _O_BINARY | _O_RDONLY);
@@ -527,3 +544,89 @@ void CJabberProto::FtReceiveFinal(BOOL success, filetransfer *ft) delete ft;
}
+
+void CJabberProto::OnHttpSlotAllocated(const TiXmlElement *iqNode, CJabberIqInfo *pInfo)
+{
+ filetransfer *ft = (filetransfer *)pInfo->GetUserData();
+ if (!ft)
+ return;
+
+ if (pInfo->GetIqType() != JABBER_IQ_TYPE_RESULT) {
+ debugLogA("HTTP upload aborted");
+LBL_Fail:
+ ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, pInfo->GetIqType() == JABBER_IQ_TYPE_ERROR ? ACKRESULT_DENIED : ACKRESULT_FAILED, ft, 0);
+ delete ft;
+ return;
+ }
+
+ if (auto *slotNode = XmlFirstChild(iqNode, "slot")) {
+ if (auto *putNode = XmlFirstChild(slotNode, "put")) {
+ if (auto *szUrl = putNode->Attribute("url")) {
+ NETLIBHTTPHEADER hdr[10];
+
+ NETLIBHTTPREQUEST nlhr = {};
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_PUT;
+ nlhr.flags = NLHRF_NODUMPSEND | NLHRF_SSL | NLHRF_REDIRECT;
+ nlhr.szUrl = (char *)szUrl;
+
+ for (auto *it : TiXmlFilter(putNode, "header")) {
+ auto *szName = it->Attribute("name");
+ auto *szValue = it->GetText();
+ if (szName && szValue && nlhr.headersCount < _countof(hdr)) {
+ nlhr.headers = hdr;
+ hdr[nlhr.headersCount].szName = (char *)szName;
+ hdr[nlhr.headersCount].szValue = (char *)szValue;
+ nlhr.headersCount++;
+ }
+ }
+
+ const wchar_t *pwszFileName = ft->std.pszFiles.w[ft->std.currentFileNumber];
+
+ int fileId = _wopen(pwszFileName, _O_BINARY | _O_RDONLY);
+ if (fileId < 0) {
+ debugLogA("error opening file %S", pwszFileName);
+ goto LBL_Fail;
+ }
+
+ nlhr.dataLength = _filelength(fileId);
+ nlhr.pData = new char[nlhr.dataLength];
+ _read(fileId, nlhr.pData, nlhr.dataLength);
+ _close(fileId);
+
+ NETLIBHTTPREQUEST *res = Netlib_HttpTransaction(m_hNetlibUser, &nlhr);
+ if (res == nullptr) {
+ debugLogA("error uploading file %S", pwszFileName);
+ goto LBL_Fail;
+ }
+
+ switch (res->resultCode) {
+ case 200: // ok
+ case 201: // created
+ break;
+
+ default:
+ debugLogA("error uploading file %S: error %d", pwszFileName, res->resultCode);
+ Netlib_FreeHttpRequest(res);
+ goto LBL_Fail;
+ }
+
+ Netlib_FreeHttpRequest(res);
+
+ // this parameter is optional, if not specified we simply use upload URL
+ auto *szGetUrl = XmlGetAttr(XmlFirstChild(slotNode, "get"), "url");
+ if (szGetUrl)
+ SendMsg(ft->std.hContact, 0, szGetUrl);
+ else
+ SendMsg(ft->std.hContact, 0, szUrl);
+
+ ProtoBroadcastAck(ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0);
+ delete ft;
+ return;
+ }
+ }
+ }
+
+ debugLogA("wrong or not recognizable http slot received");
+ goto LBL_Fail;
+}
diff --git a/protocols/JabberG/src/jabber_proto.cpp b/protocols/JabberG/src/jabber_proto.cpp index 916022987e..8619ad0e2b 100755 --- a/protocols/JabberG/src/jabber_proto.cpp +++ b/protocols/JabberG/src/jabber_proto.cpp @@ -128,6 +128,7 @@ CJabberProto::CJabberProto(const char *aProtoName, const wchar_t *aUserName) : m_bProcessXMPPLinks(this, "ProcessXMPPLinks", false),
m_bIgnoreRosterGroups(this, "IgnoreRosterGroups", false),
m_bEnableCarbons(this, "EnableCarbons", true),
+ m_bUseHttpUpload(this, "UseHttpUpload", false),
m_bUseOMEMO(this, "UseOMEMO", false),
m_bEnableStreamMgmt(this, "UseStreamMgmt", false)
{
@@ -839,31 +840,31 @@ HANDLE CJabberProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, w if (item->ft != nullptr)
return nullptr;
- JabberCapsBits jcb = GetResourceCapabilities(item->jid);
- if (jcb == JABBER_RESOURCE_CAPS_IN_PROGRESS) {
- Sleep(600);
- jcb = GetResourceCapabilities(item->jid);
- }
+ JabberCapsBits jcb = 0;
+ if (!m_bUseHttpUpload) {
+ GetResourceCapabilities(item->jid);
+ if (jcb == JABBER_RESOURCE_CAPS_IN_PROGRESS) {
+ Sleep(600);
+ jcb = GetResourceCapabilities(item->jid);
+ }
- // fix for very smart clients, like gajim
- if (!m_bBsDirect && !m_bBsProxyManual) {
- // disable bytestreams
- jcb &= ~JABBER_CAPS_BYTESTREAMS;
- }
+ // fix for very smart clients, like gajim
+ if (!m_bBsDirect && !m_bBsProxyManual) {
+ // disable bytestreams
+ jcb &= ~JABBER_CAPS_BYTESTREAMS;
+ }
- // if only JABBER_CAPS_SI_FT feature set (without BS or IBB), disable JABBER_CAPS_SI_FT
- if ((jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_BYTESTREAMS)) == JABBER_CAPS_SI_FT)
- jcb &= ~JABBER_CAPS_SI_FT;
+ // if only JABBER_CAPS_SI_FT feature set (without BS or IBB), disable JABBER_CAPS_SI_FT
+ if ((jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_BYTESTREAMS)) == JABBER_CAPS_SI_FT)
+ jcb &= ~JABBER_CAPS_SI_FT;
- if (
- // can't get caps
- (jcb & JABBER_RESOURCE_CAPS_ERROR)
- // caps not already received
- || (jcb == JABBER_RESOURCE_CAPS_NONE)
- // XEP-0096 and OOB not supported?
- || !(jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_OOB))) {
- MsgPopup(hContact, TranslateT("No compatible file transfer mechanism exists"), Utf2T(item->jid));
- return nullptr;
+ if ((jcb & JABBER_RESOURCE_CAPS_ERROR) // can't get caps
+ || (jcb == JABBER_RESOURCE_CAPS_NONE) // caps not already received
+ || !(jcb & (JABBER_CAPS_SI_FT | JABBER_CAPS_OOB))) // XEP-0096 and OOB not supported?
+ {
+ MsgPopup(hContact, TranslateT("No compatible file transfer mechanism exists"), Utf2T(item->jid));
+ return nullptr;
+ }
}
filetransfer *ft = new filetransfer(this);
@@ -876,7 +877,7 @@ HANDLE CJabberProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, w int i, j;
for (i = j = 0; i < ft->std.totalFiles; i++) {
- struct _stati64 statbuf;
+ struct _stat64 statbuf;
if (_wstat64(ppszFiles[i], &statbuf))
debugLogW(L"'%s' is an invalid filename", ppszFiles[i]);
else {
@@ -895,7 +896,7 @@ HANDLE CJabberProto::SendFile(MCONTACT hContact, const wchar_t *szDescription, w ft->szDescription = mir_wstrdup(szDescription);
ft->jid = mir_strdup(jid);
- if (jcb & JABBER_CAPS_SI_FT)
+ if (m_bUseHttpUpload || (jcb & JABBER_CAPS_SI_FT))
FtInitiate(item->jid, ft);
else if (jcb & JABBER_CAPS_OOB)
ForkThread((MyThreadFunc)&CJabberProto::FileServerThread, ft);
@@ -951,7 +952,7 @@ int CJabberProto::SendMsg(MCONTACT hContact, int unused_unknown, const char *psz }
}
- int isEncrypted, id = SerialNext();
+ int isEncrypted, id = SerialNext();
if (!strncmp(pszSrc, PGP_PROLOG, mir_strlen(PGP_PROLOG))) {
const char *szEnd = strstr(pszSrc, PGP_EPILOG);
char *tempstring = (char*)alloca(mir_strlen(pszSrc) + 2);
diff --git a/protocols/JabberG/src/jabber_proto.h b/protocols/JabberG/src/jabber_proto.h index 76996d45b3..b06ccb8ef3 100755 --- a/protocols/JabberG/src/jabber_proto.h +++ b/protocols/JabberG/src/jabber_proto.h @@ -186,6 +186,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface CMOption<BYTE> m_bProcessXMPPLinks;
CMOption<BYTE> m_bIgnoreRosterGroups;
CMOption<BYTE> m_bEnableCarbons;
+ CMOption<BYTE> m_bUseHttpUpload;
CMOption<BYTE> m_bUseOMEMO;
CMOption<BYTE> m_bEnableStreamMgmt;
@@ -457,7 +458,7 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface void __cdecl FileServerThread(filetransfer *ft);
void FtCancel(filetransfer *ft);
- void FtInitiate(char* jid, filetransfer *ft);
+ void FtInitiate(const char* jid, filetransfer *ft);
void FtHandleSiRequest(const TiXmlElement *iqNode);
void FtAcceptSiRequest(filetransfer *ft);
void FtAcceptIbbRequest(filetransfer *ft);
@@ -550,6 +551,8 @@ struct CJabberProto : public PROTO<CJabberProto>, public IJabberInterface BOOL OnFtHandleIbbIq(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
BOOL OnIbbRecvdData(const char *data, const char *sid, const char *seq);
+ void OnHttpSlotAllocated(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
+
void OnFtSiResult(const TiXmlElement *iqNode, CJabberIqInfo *pInfo);
BOOL FtIbbSend(int blocksize, filetransfer *ft);
BOOL FtSend(HNETLIBCONN hConn, filetransfer *ft);
diff --git a/protocols/JabberG/src/stdafx.h b/protocols/JabberG/src/stdafx.h index 5651ca7f9b..cb2c171274 100755 --- a/protocols/JabberG/src/stdafx.h +++ b/protocols/JabberG/src/stdafx.h @@ -405,7 +405,7 @@ struct JABBER_MODEMSGS char *szFreechat;
};
-typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM, FT_IBB } JABBER_FT_TYPE;
+typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM, FT_IBB, FT_HTTP } JABBER_FT_TYPE;
typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED } JABBER_FILE_STATE;
struct filetransfer
|