/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (с) 2012-15 Miranda NG project (http://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 "global.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(NULL), m_pszFileDesc(NULL), m_URL(NULL), m_URLthumb(NULL), m_pszSendTyp(NULL), m_pszProto(NULL), // m_hContact(hContact), // initialized below m_EnableItem(0), m_ChatRoom(0), // m_PFflag(0), m_cbEventMsg(0), m_szEventMsg(NULL), m_hSend(0), m_hOnSend(0), m_ErrorMsg(NULL), m_ErrorTitle(NULL) { SetContact(hContact); } CSend::~CSend(){ mir_free(m_pszFile); mir_free(m_pszFileDesc); mir_free(m_URL); mir_free(m_URLthumb); mir_free(m_szEventMsg); 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 = GetContactProto(hContact); m_ChatRoom = db_get_b(hContact, m_pszProto, "ChatRoom", 0); /* m_PFflag = hasCap(PF1_URLSEND); m_PFflag = hasCap(PF1_CHAT); m_PFflag = hasCap(PF1_IMSEND);// */ } } //--------------------------------------------------------------------------- /*bool CSend::hasCap(unsigned int Flag) { return (Flag & CallContactService(m_hContact, PS_GETCAPS, PFLAGNUM_1, NULL)) == Flag; }// */ //--------------------------------------------------------------------------- INT_PTR CALLBACK CSend::ResultDialogProc(HWND hwndDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ switch(uMsg){ case WM_INITDIALOG:{ SendMessage(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM)GetIcon(ICO_MAIN)); CSend* self=(CSend*)lParam; TCHAR* tmp=mir_tstrdup(TranslateT("Resulting URL from\n")); mir_tstradd(tmp,self->m_pszSendTyp); SetDlgItemText(hwndDlg,IDC_HEADERBAR,tmp); mir_free(tmp); 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)LPGENT("Copy"),BATF_TCHAR); break; case ID_btnBBC: case ID_btnThumbBBC: SendDlgItemMessage(hwndDlg,i,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetIconBtn(ICO_BTN_BBC)); SendDlgItemMessage(hwndDlg,i,BUTTONADDTOOLTIP,(WPARAM)LPGENT("Copy BBCode"),BATF_TCHAR); break; default: SendDlgItemMessage(hwndDlg,i,BM_SETIMAGE,IMAGE_ICON,(LPARAM)GetIconBtn(ICO_BTN_BBCLNK)); SendDlgItemMessage(hwndDlg,i,BUTTONADDTOOLTIP,(WPARAM)LPGENT("Copy BBCode w/ link"),BATF_TCHAR); } } TranslateDialogDefault(hwndDlg); return TRUE;} case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: case ID_btnCopy: case ID_btnThumbCopy: case ID_btnBBC: case ID_btnThumbBBC: case ID_btnThumbBBC2:{ TCHAR 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,_T("[img]"),5*sizeof(TCHAR)); len=5; len+=GetDlgItemText(hwndDlg,edtID,tmp+len,2048-11); memcpy(tmp+len,_T("[/img]"),7*sizeof(TCHAR)); len+=7; }else{ memcpy(tmp,_T("[url="),5*sizeof(TCHAR)); len=5; len+=GetDlgItemText(hwndDlg,ID_edtURL,tmp+len,1024); memcpy(tmp+len,_T("][img]"),6*sizeof(TCHAR)); len+=6; len+=GetDlgItemText(hwndDlg,edtID,tmp+len,1024); memcpy(tmp+len,_T("[/img][/url]"),13*sizeof(TCHAR)); len+=12; } }else len=GetDlgItemText(hwndDlg,edtID,tmp,SIZEOF(tmp)); int retries=3; do{ if(!OpenClipboard(hwndDlg)){ Sleep(100); continue; } EmptyClipboard(); HGLOBAL clipbuffer=GlobalAlloc(GMEM_MOVEABLE, len*sizeof(TCHAR)+sizeof(TCHAR)); TCHAR* tmp2=(TCHAR*)GlobalLock(clipbuffer); mir_tstrncpy(tmp2,tmp,len+1); tmp2[len]='\0'; GlobalUnlock(clipbuffer); SetClipboardData(CF_UNICODETEXT,clipbuffer); CloseClipboard(); break; }while(--retries); if(LOWORD(wParam)==IDOK) DestroyWindow(hwndDlg); return TRUE;} case IDCANCEL: 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_a2t(szMessage); Exit(CSEND_DIALOG); return; } if(m_ChatRoom){ TCHAR* tmp = mir_a2t(szMessage); if (m_pszFileDesc) { mir_tstradd(tmp, _T("\r\n")); mir_tstradd(tmp, m_pszFileDesc); } GC_INFO gci = {0}; int res = GC_RESULT_NOSESSION; int cnt = (int)CallService(MS_GC_GETSESSIONCOUNT, 0, (LPARAM)m_pszProto); //loop on all gc session to get the right (save) ptszID for the chatroom from m_hContact gci.pszModule = m_pszProto; for (int i = 0; i < cnt ; i++ ) { gci.iItem = i; gci.Flags = GCF_BYINDEX | GCF_HCONTACT | GCF_ID; CallService(MS_GC_GETINFO, 0, (LPARAM)&gci); if (gci.hContact == m_hContact) { GCDEST gcd = { m_pszProto, gci.pszID, GC_EVENT_SENDMESSAGE }; GCEVENT gce = { sizeof(gce), &gcd }; gce.bIsMe = TRUE; gce.dwFlags = GCEF_ADDTOLOG; gce.ptszText = tmp; gce.time = time(NULL); //* returns 0 on success or error code on failure res = 200 + (int)CallService(MS_GC_EVENT, 0, (LPARAM)&gce); break; } } Exit(res); return; }else{ mir_freeAndNil(m_szEventMsg); m_cbEventMsg=mir_strlen(szMessage)+1; m_szEventMsg=(char*)mir_realloc(m_szEventMsg, (sizeof(char) * m_cbEventMsg)); memset(m_szEventMsg, 0, (sizeof(char) * m_cbEventMsg)); mir_strcpy(m_szEventMsg,szMessage); if (m_pszFileDesc && m_pszFileDesc[0] != NULL) { char *temp = mir_t2a(m_pszFileDesc); mir_stradd(m_szEventMsg, "\r\n"); mir_stradd(m_szEventMsg, temp); m_cbEventMsg = mir_strlen(m_szEventMsg)+1; mir_free(temp); } //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)CallContactService(m_hContact, PSS_MESSAGE, NULL, (LPARAM)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(LPGENT("%s requires a valid contact!"), m_pszSendTyp); Exit(ACKRESULT_FAILED); return; } mir_freeAndNil(m_szEventMsg); char* szFile = mir_t2a(m_pszFile); m_cbEventMsg=mir_strlen(szFile)+2; m_szEventMsg=(char*)mir_realloc(m_szEventMsg, (sizeof(char) * m_cbEventMsg)); memset(m_szEventMsg, 0, (sizeof(char) * m_cbEventMsg)); mir_strcpy(m_szEventMsg,szFile); if (m_pszFileDesc && m_pszFileDesc[0] != NULL) { char* temp = mir_t2a(m_pszFileDesc); m_cbEventMsg += mir_strlen(temp); m_szEventMsg=(char*)mir_realloc(m_szEventMsg, sizeof(char)*m_cbEventMsg); mir_strcpy(m_szEventMsg+mir_strlen(szFile)+1,temp); m_szEventMsg[m_cbEventMsg-1] = 0; mir_free(temp); } mir_free(szFile); //create 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) TCHAR* ppFile[2]={0,0}; TCHAR* pDesc = mir_tstrdup(m_pszFileDesc); ppFile[0] = mir_tstrdup (m_pszFile); ppFile[1] = NULL; m_hSend = (HANDLE)CallContactService(m_hContact, PSS_FILET, (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 wParam, LPARAM lParam){ CSend* self=(CSend*)obj; ACKDATA *ack=(ACKDATA*)lParam; if(ack->hProcess!= self->m_hSend) return 0; /* if(dat->waitingForAcceptance) { SetTimer(hwndDlg,1,1000,NULL); dat->waitingForAcceptance=0; } */ switch(ack->result) { case ACKRESULT_INITIALISING: //SetFtStatus(hwndDlg, LPGENT("Initialising..."), FTS_TEXT); break; case ACKRESULT_CONNECTING: //SetFtStatus(hwndDlg, LPGENT("Connecting..."), FTS_TEXT); break; case ACKRESULT_CONNECTPROXY: //SetFtStatus(hwndDlg, LPGENT("Connecting to proxy..."), FTS_TEXT); break; case ACKRESULT_LISTENING: //SetFtStatus(hwndDlg, LPGENT("Waiting for connection..."), FTS_TEXT); break; case ACKRESULT_CONNECTED: //SetFtStatus(hwndDlg, LPGENT("Connected"), FTS_TEXT); break; case ACKRESULT_SENTREQUEST: //SetFtStatus(hwndDlg, LPGENT("Decision sent"), FTS_TEXT); break; case ACKRESULT_NEXTFILE: //SetFtStatus(hwndDlg, LPGENT("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_URL, 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((WORD)EVENTTYPE_MESSAGE); break; case ACKTYPE_URL: self->DB_EventAdd((WORD)EVENTTYPE_URL); break; case ACKTYPE_FILE: self->m_szEventMsg = (char*) mir_realloc(self->m_szEventMsg, sizeof(DWORD) + self->m_cbEventMsg); memmove(self->m_szEventMsg+sizeof(DWORD), self->m_szEventMsg, self->m_cbEventMsg); self->m_cbEventMsg += sizeof(DWORD); self->DB_EventAdd((WORD)EVENTTYPE_FILE); break; } self->Exit(ack->result); break; } return 0; } void CSend::DB_EventAdd(WORD EventType) { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.szModule = m_pszProto; dbei.eventType = EventType; dbei.flags = DBEF_SENT; dbei.timestamp = time(NULL); dbei.flags |= DBEF_UTF; dbei.cbBlob= m_cbEventMsg; dbei.pBlob = (PBYTE)m_szEventMsg; db_event_add(m_hContact, &dbei); } //--------------------------------------------------------------------------- void CSend::Error(LPCTSTR pszFormat, ...) { TCHAR tszMsg[MAX_SECONDLINE]; mir_sntprintf(tszMsg, SIZEOF(tszMsg),_T("%s - %s") ,_T(SZ_SENDSS), TranslateT("Error")); mir_free(m_ErrorTitle), m_ErrorTitle = mir_tstrdup(tszMsg); va_list vl; va_start(vl, pszFormat); mir_vsntprintf(tszMsg, SIZEOF(tszMsg), TranslateTS(pszFormat), vl); va_end(vl); mir_free(m_ErrorMsg), m_ErrorMsg = mir_tstrdup(tszMsg); memset(&m_box, 0, sizeof(MSGBOX)); m_box.cbSize = sizeof(MSGBOX); m_box.hParent = NULL; m_box.hiLogo = GetIcon(ICO_MAIN); m_box.hiMsg = NULL; 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: SkinPlaySound("FileDone"); DialogBoxParam(g_hSendSS, MAKEINTRESOURCE(IDD_UResultForm),0, ResultDialogProc,(LPARAM)this); err = false; break; case ACKRESULT_SUCCESS: case GC_RESULT_SUCCESS: SkinPlaySound("FileDone"); err = false; break; case ACKRESULT_DENIED: SkinPlaySound("FileDenied"); Error(_T("%s (%i):\nFile transfer denied."),TranslateTS(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(_T("%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(_T("%s (%i):\nAn internal GC error occurred."),TranslateT("GCHAT error"),Result); break; case GC_RESULT_NOSESSION: // contact has no open GC session Error(_T("%s (%i):\nContact has no open GC session."),TranslateT("GCHAT error"),Result); break; case ACKRESULT_FAILED: default: break; } if(err){ SkinPlaySound("FileFailed"); if(m_ErrorMsg) MsgBoxService(NULL, (LPARAM)&m_box); else MsgErr(NULL, LPGENT("An unknown error has occurred.")); } } if(m_pszFile && *m_pszFile && m_bDeleteAfterSend && m_EnableItem&SS_DLG_DELETEAFTERSSEND) { DeleteFile(m_pszFile), m_pszFile=NULL; } 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 NULL; begin+=strlen(startTag)-1; for(; *begin!='>' && *begin; ++begin); if(*begin){ char* end=strstr(++begin,endTag); if(end) *end=0; } return begin; } int JSON_ParseData_(const char** jsondata,size_t jsonlen,const char** rawdata){ const char* c=*jsondata; const char* jsonend=*jsondata+jsonlen; int len=0; *rawdata=NULL; if(c==jsonend) return 0; if(*c=='{'){ // scope (object) *rawdata=c; do{ if(*c=='{') ++len; else if(*c=='}') --len; if(++c==jsonend) return 0; }while(len>0); len=c-*rawdata; if(*c==',') ++c; }else if(*c=='"' || *c=='\''){ // string char needle=*c; if(++c==jsonend) return 0; *rawdata=c; do{ if(c==jsonend || (*c=='\\' && ++c==jsonend)) return 0; }while(*c++!=needle); len=c-*rawdata-1; if(*c==',') ++c; }else{ // other for(*rawdata=c; c=jsonend || *++c!=':') break; /// read data ++c; if(!strcmp(var,needle)){ int datalen=JSON_ParseData_(&c,jsonend-c,value); if(!datalen) return 0; if(*needlechild && **value=='{'){ // we need a child value, parse child object return JSON_Get_(*value,datalen,needlechild,value); } return datalen; }else{ JSON_ParseData_(&c,jsonend-c,value); } } *value=NULL; return 0; } int CSend::GetJSONString(const char* json, size_t jsonlen, const char* variable, char* value, size_t valuesize) { if(!jsonlen || !valuesize) return 0; const char* rawvalue; int rawlen=JSON_Get_(json,jsonlen,variable,&rawvalue); if(rawlen){ size_t out=0; --valuesize; /// copy & parse escape sequences for(int in=0; in'9') break; defvalue*=10; defvalue+=rawvalue[offset]-'0'; } } return defvalue; } bool CSend::GetJSONBool(const char* json, size_t jsonlen, const char* variable) { const char* rawvalue; int rawlen=JSON_Get_(json,jsonlen,variable,&rawvalue); if(rawlen){ if(rawlen==4 && !memcmp(rawvalue,"true",4)) return true; if(*rawvalue>'0' && *rawvalue<='9') return true; } return false; } 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+=len; // not necessary } } void CSend::HTTPFormDestroy(NETLIBHTTPREQUEST* nlhr) { mir_free(nlhr->headers[0].szValue), nlhr->headers[0].szValue=NULL; mir_free(nlhr->headers), nlhr->headers=NULL; mir_free(nlhr->pData), nlhr->pData=NULL; } int CSend::HTTPFormCreate(NETLIBHTTPREQUEST* nlhr,int requestType,char* url,HTTPFormData* frm,size_t frmNum) { char boundary[16]; memcpy(boundary,"--M461C/",8); { union{ DWORD 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 =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,NULL,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=strlen(iter->name), valuelen; if(!(iter->flags&HTTPFF_INT)) valuelen=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=strlen(filename); HTTPFormAppendData(nlhr,&dataMax,&dataPos,NULL,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(!strcmp(fileext,".jpg") || !strcmp(fileext,".jpeg") || !strcmp(fileext,".jpe")) mime="image/jpeg"; else if(!strcmp(fileext,".bmp")) mime="image/bmp"; else if(!strcmp(fileext,".png")) mime="image/png"; else if(!strcmp(fileext,".gif")) mime="image/gif"; else if(!strcmp(fileext,".tif") || !strcmp(fileext,".tiff")) mime="image/tiff"; } HTTPFormAppendData(nlhr,&dataMax,&dataPos,mime,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,NULL,filesize+2); if(fread(dataPos,1,filesize,fp)!=filesize){ fclose(fp), fp=NULL; } } if(!fp){ HTTPFormDestroy(nlhr); Error(_T("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,NULL,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,NULL,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,NULL,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,NULL,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; iheadersCount; ++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; }