I'm using c++ and curl for sending an email with attachments, a zip archive in this example. I receive the email on gmail but when I download the .zip if I try to extract the content with WinRar I got the error:
The archive is either in unknown format or damaged
The zip is okay, I can extract it before sending.
This is the function for sending the file:
int sendFile()
{
CURL *curl;
CURLcode res = CURLE_OK;
curl = curl_easy_init();
if(curl) {
struct curl_slist *headers = NULL;
struct curl_slist *recipients = NULL;
struct curl_slist *slist = NULL;
curl_mime *mime;
curl_mime *alt;
curl_mimepart *part;
const char **cpp;
/* This is the URL for your mailserver */
curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");
curl_easy_setopt(curl, CURLOPT_USERNAME, "email");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR);
recipients = curl_slist_append(recipients, TO_ADDR);
recipients = curl_slist_append(recipients, CC_ADDR);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
for(cpp = headers_text; *cpp; cpp++)
headers = curl_slist_append(headers, *cpp);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
mime = curl_mime_init(curl);
alt = curl_mime_init(curl);
/* Text message. */
part = curl_mime_addpart(alt);
curl_mime_data(part, inline_text, CURL_ZERO_TERMINATED);
part = curl_mime_addpart(mime);
curl_mime_subparts(part, alt);
curl_mime_type(part, "multipart/alternative");
slist = curl_slist_append(NULL, "Content-Disposition: inline");
curl_mime_headers(part, slist, 1);
/* File */
std::string attachment = "D:/report.zip";
part = curl_mime_addpart(mime);
curl_mime_type(part, "application/zip");
curl_mime_filedata(part, attachment.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_slist_free_all(recipients);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
curl_mime_free(mime);
}
return (int)res;
}
Can you help me to understand what' s wrong? The zip is in the email but I can' t open it once downloaded because is damaged.
Thank you!
I had a similar problem sending jpeg files and was able to solve it by encoding the data with curl_mime_encoder.
curl_mime_filedata(part, attachment.c_str());
curl_mime_encoder(part, "base64");
Perhaps this might work for your case as well.
Related
I am trying trying to make a POST request on a url with protobuf data. I don't know how/ where to add binary data. Below is my C++ program.
"
void sendContent()
{
using namespace std;
int Error = 0;
//CString str;
CURL* curl;
CURLcode res;
struct curl_slist *headerlist = NULL;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
//Set URL to recevie POST
curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_HEADER, true);
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
}"
You should set the data pointer by curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);. In the meantime, you should set the data size by curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);.
You can find the libcurl post example in there.
And I copy the program below.
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if(curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
/* Now specify the POST data */
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);
/* binary data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Fixing your original suggestion would probably make it something like this (based on the simplepost example from the libcurl web site):
#include <curl/curl.h>
int binarypost(char *binaryptr, long binarysize)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *headerlist = NULL;
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, binaryptr);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, binarysize);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return (int)res;
}
I am trying to send a SOAP request in xml format to a SOAP service using libcurl but i am getting error like" 500 internal server error" while posting the request in soap service.
I have tried almost all the approaches available online.
#include <stdio.h>
#include <curl/curl.h>
int main()
{
FILE * wfp = fopen("res.xml", "w+"); //File pointer to write the soap response
if (!wfp) {
perror("Write File Open:");
// exit(0);
}
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Content-type: text/xml; charset=utf-8");
header = curl_slist_append(header, "SOAPAction: http://localhost:62634/Service1.svc");
header = curl_slist_append(header, "Transfer-Encoding: chunked");
header = curl_slist_append(header, "Expect:");
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:62634/Service1.svc");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:AddNumbers=\"http://localhost:62634/Service1.svc\"><soapenv:Header/><soapenv:Body><AddNumbers xmlns=\"http://tempuri.org/\"><number1>4</number1><number2>5</number2></AddNumbers></soapenv:Body></soapenv:Envelope>");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); //Gets data to be written to file
curl_easy_setopt(curl, CURLOPT_WRITEDATA, wfp); //Writes result to file
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)-1);
//curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return 1;
}
}
I succeed to upload an image file to my blog by using curl command like this.
curl -F 'access_token=xxx' -F 'blogName=xxx' -F 'uploadedfile=#xxx.png' https://www.tistory.com/apis/post/attach
And... to use it on my c++ project, I converted it to libcurl like this.
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://www.tistory.com/apis/post/attach");
curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.61.0");
curl_mime *formpost = curl_mime_init(curl);
curl_mimepart *part = nullptr;
part = curl_mime_addpart(formpost);
curl_mime_name(part, "access_token");
curl_mime_data(part, "xxx", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(formpost);
curl_mime_name(part, "blogName");
curl_mime_data(part, "xxx", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(formpost);
curl_mime_name(part, "uploadedfile");
curl_mime_filename(part, "xxx.png");
curl_mime_type(part, "image/png");
curl_easy_setopt(curl, CURLOPT_MIMEPOST, formpost);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
res = curl_easy_perform(curl);
...
}
This converted code doesn't work. And the result is response code 400. Actually I don't know what function of libcurl is correspond to -F option of curl command. Somebody let me know how to convert this curl command at the top to libcurl, or what function do I have to study about. Thanks in advance.
After running the following command (useful life hack here!):
curl -F 'access_token=xxx' -F 'blogName=xxx' -F 'uploadedfile=#xxx.png' https://www.tistory.com/apis/post/attach --libcurl example.cc && cat example.cc
I got the following code (tidied up a bit for legibility on SO):
#include <curl/curl.h>
int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd;
curl_mime *mime1;
curl_mimepart *part1;
mime1 = NULL;
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_BUFFERSIZE, 102400L);
curl_easy_setopt(hnd, CURLOPT_URL, "https://www.tistory.com/apis/post/attach");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
mime1 = curl_mime_init(hnd);
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, "xxx", CURL_ZERO_TERMINATED);
curl_mime_name(part1, "access_token");
part1 = curl_mime_addpart(mime1);
curl_mime_data(part1, "xxx", CURL_ZERO_TERMINATED);
curl_mime_name(part1, "blogName");
part1 = curl_mime_addpart(mime1);
curl_mime_filedata(part1, "xxx.png");
curl_mime_name(part1, "uploadedfile");
curl_easy_setopt(hnd, CURLOPT_MIMEPOST, mime1);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.60.0");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_HTTP_VERSION, (long)CURL_HTTP_VERSION_2TLS);
curl_easy_setopt(hnd, CURLOPT_SSH_KNOWNHOSTS, "/home/MY_USER/.ssh/known_hosts");
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
ret = curl_easy_perform(hnd);
curl_easy_cleanup(hnd);
hnd = NULL;
curl_mime_free(mime1);
mime1 = NULL;
return (int)ret;
}
I'm trying to upload pictures using c++ application with libcurl to my server, the file in my server is a protected directory, I tried everything I know but it didn't work.
struct curl_slist *headerlist = NULL;
const char * Picture = "C:\xxxx";
FILE *fd = fopen(Picture, "rb");
struct stat file_info;
fstat(fileno(fd), &file_info);
headerlist = curl_slist_append(headerlist, "user : xxxx");
headerlist = curl_slist_append(headerlist, "password : xxxxx");
headerlist = curl_slist_append(headerlist, "Content-Type: image/jpeg");
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://xxxx.000webhostapp.com/Pictures");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)file_info.st_size);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
MessageBox::Show("Picture Failed");
}
curl_easy_cleanup(curl);
curl_global_cleanup();
user and password are not HTTP headers, so you should not be passing them via CURLOPT_HTTPHEADER. Use CURLOPT_USERNAME and CURLOPT_PASSWORD instead. Also look at CURLOPT_HTTPAUTH.
Try this:
curl_global_init(CURL_GLOBAL_ALL);
...
const char *Picture = "C:\\xxxx";
FILE *fd = fopen(Picture, "rb");
if (!fd)
{
MessageBox::Show("Cannot Open Picture File");
}
else
{
struct stat file_info;
fstat(fileno(fd), &file_info);
curl = curl_easy_init();
if (!curl)
{
MessageBox::Show("Cannot Initialize CURL Session");
}
else
{
struct curl_slist *headerlist = curl_slist_append(NULL, "Content-Type: image/jpeg");
curl_easy_setopt(curl, CURLOPT_URL, "http://xxxx.000webhostapp.com/Pictures");
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxxx");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)file_info.st_size);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
MessageBox::Show("Picture Failed");
}
curl_easy_cleanup(curl);
}
fclose(fd);
}
...
curl_global_cleanup();
I'm trying to send this string "ààà" via curl POST HTTP.
CURL *curl;
CURLcode res;
char* content = "value=ààà!";
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept:application/x-www-form-urlencoded");
headers = curl_slist_append(headers, "Content-Type:application/x-www-form-urlencoded");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:3000");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, content);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
curl_easy_cleanup(curl);
}
curl_global_cleanup();
I tried to send wchat_t* (using CURLOPT_POSTFIELDSIZE, wcslen(content))
instead of char*, I didn't solved.
I even tried to send using content-type:application/json but I get Unexpected end of JSON input .