How to convert curl command with -F option to libcurl - c++

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;
}

Related

I cannot send an email using curl and c++

im trying to send an email with curl and c++ just like this example but when i execute the program:
#include <iostream>
#include <curl/curl.h>
int main()
{
int a;
char errbuf[CURL_ERROR_SIZE] = {0};
CURL *curl = curl_easy_init();
CURLcode res;
struct upload_status upload_ctx = { 0 };
if(curl)
{
curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "");
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, "");
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(curl, CURLOPT_CAINFO, "D:\\MinGW\\cacert.pem");
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
}
check_errors(res, errbuf);
return 0;
}
i get this error:
curl_easy_perform() failed: Failed sending data to the peer
libcurl: (55) MAIL failed: 530
I deleted most of the code because i couldn't post the question but the rest is in the example.
The problem i had in my code was that i thought that by using:
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "myemail#example.com"); i was specifyng the username, which was in fact, an error.
To specify the username libcurl has another option:
curl_easy_setopt(curl, CURLOPT_USERNAME, "myemail#example.com");

C++ send zip file using google email with curl

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.

cUrl Problems with uploading files

Using cUrl ( windows ) and was trying to get an upload function to work. However, it just doesnt seem to work. Getting error ERROR_FILE_NOT_PROVIDED from anonfiles
Here is the API = https://anonfiles.com/docs/api
Here is my code:
std::string UploadPicture()
{
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.anonfiles.com/upload");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "cache-control: no-cache");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "file=test.ini");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return readBuffer;
}
return "Failed";
}
Any help is welcome. I have tried many other ways as well, but didnt manage to get it right.

How to define metadata with libcurl?

I do following command with curl (the command line tool) to upload a file to google drive:
curl --request POST \
'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart' \
--header 'Authorization: Bearer "..."' \
-F "metadata={name : 'backup.zip'};type=application/json;charset=UTF-8" \
-F "#backup.zip;type=application/zip"
The following programm with libcurl could only use the URL, the header and upload the file using formdata:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
struct curl_slist *chunk= NULL;
chunk= curl_slist_append(chunk, "Authorization: Bearer \"...\"");
curl_slist_append(chunk, "Accept: application/json");
curl_slist_append(chunk, "Content-Type: application/json");
curl_mimepart *part= NULL;
curl_mime_type(part, "application/octet-stream");
struct curl_httppost* formpost = NULL;
struct curl_httppost* lastptr = NULL;
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_FILE, "main.c",
CURLFORM_END);
/* Perform the request, res will get the return code */
//curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/drive/v3/files");
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, part);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
How can I specify the -F "metadata={name : 'backup.zip'};type=application/json;charset=UTF-8" in libcurl?
I tried it with CURLFORM_COPYNAME but this doesn't work.
You are setting the HTTP request's top-level Content-Type header to application/json, which is wrong. It needs to be multipart/related instead, per Google's documentation: Send a multipart upload request.
The command-line you showed is inserting a MIME part of type application/json into the POST form data, but you are not doing the same thing in your code.
Also, you should not be using CURLOPT_MIMEPOST and CURLOPT_HTTPPOST together. Use ONE or the OTHER, not BOTH. CURLOPT_HTTPPOST is deprecated, replaced by CURLOPT_MIMEPOST. And you are not even passing the correct input value to CURLOPT_MIMEPOST anyway. It expects a curl_mime*, not a curl_mimepart*.
Try something more like this instead:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
/* set custom HTTP headers */
struct curl_slist *header = NULL;
// uncomment this if you are not using libcurl 7.61.0 or later...
//
// header = curl_slist_append(header, "Authorization: Bearer \"...\"");
//
header = curl_slist_append(header, "Content-Type: multipart/related");
header = curl_slist_append(header, "Accept: application/json");
/* set MIME post content */
curl_mime *mime = curl_mime_init(curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_name(part, "metadata");
curl_mime_type(part, "application/json;charset=UTF-8");
curl_mime_data(part, "{\"name\" : \"backup.zip\"}", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(mime);
curl_mime_type(part, "application/zip");
curl_mime_filedata(part, "backup.zip");
/* Perform the request, res will get the return code */
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
// comment this out if you are not using libcurl 7.61.0 or later...
//
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "...");
//
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(header);
curl_mime_free(mime);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Or maybe this (I'm not sure the correct way to specify the HTTP Content-Type when using a MIME body - documentation and examples are very limited on this topic, most of the examples I found are for SMTP, not HTTP):
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
/* set custom HTTP headers */
struct curl_slist *header = NULL;
// uncomment this if you are not using libcurl 7.61.0 or later...
//
// header = curl_slist_append(header, "Authorization: Bearer \"...\"");
//
header = curl_slist_append(header, "Accept: application/json");
/* set MIME post content */
curl_mime *mime = curl_mime_init(curl);
curl_mime *rel = curl_mime_init(curl);
curl_mimepart *part = curl_mime_addpart(rel);
curl_mime_name(part, "metadata");
curl_mime_type(part, "application/json;charset=UTF-8");
curl_mime_data(part, "{\"name\" : \"backup.zip\"}", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(rel);
curl_mime_type(part, "application/zip");
curl_mime_filedata(part, "backup.zip");
part = curl_mime_addpart(mime);
curl_mime_type(part, "multipart/related");
curl_mime_subparts(part, rel);
/* Perform the request, res will get the return code */
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
// comment this out if you are not using libcurl 7.61.0 or later...
//
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "...");
//
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(header);
curl_mime_free(mime);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}

Uploading a picture to a Password Protected Directory using libcurl and C++

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();