Reading emails from gmail POP3 account using libCurl - c++

I'm currently working in a C++ project which has to be able to read emails from an gmail POP3 account just like the title says. Also is important to say that I need to download the attachments (is encode base64?) of the mail and its body.
The fact is that everyone recommend to use libCurl for this task, but the code sample on their web is not working.
I saw this example on Libcurl website:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl)
{
/* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");
/* This will only fetch the message with ID "1" of the given mailbox */
curl_easy_setopt(curl, CURLOPT_URL, "pop3s://user#pop.example.com/1");
/* 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);
}
return 0;
}
As you see, the code looks pretty easy for fetching email by email inside the inbox, but when i try to perform the operation with CURLcode curl_easy_perform(CURL *) the function doesn't return anything and the process 'dies' so i can't skip this line.
My code is the following one:
void MailServer::Open(char *username,char *password)
{
m_username = username; //username = example#gmail.com
m_password = password; //password = blabla123
curl = curl_easy_init();
curl_easy_setopt(curl,CURLOPT_USERNAME,username);
curl_easy_setopt(curl,CURLOPT_PASSWORD,password);
m_popsAccount = "pop3s://" + m_username +"/1";
curl_easy_setopt(curl, CURLOPT_URL, m_popsAccount.c_str());
res = curl_easy_perform(curl); //here does not return anything
}
I tried to find some 'clear' example on the web, but i really couldn't...
Someone could give me a hand with it? :)

I made it guys! Here's a good sample about how you can access a gmail acount and see what's inside. I'm currently working on parsing the information inside, because actually it only retrieves the amount of mails on inbox and its size.
If you change the url as "pops://pop.gmail.com:995/1" it will return the content of the messege and also including a base64 encoding for the attachments. Thanks Anyway... here is the code! :)
#pragma region Types
struct MemoryStruct {
char *memory;
size_t size;
};
#pragma endregion
void MailServer::Open(char *username,char *password)
{
m_username = username;
m_password = password;
struct MemoryStruct chunk;
chunk.memory = (char*) malloc(1); //crecerá según sea necesario con el realloc
chunk.size = 0; //no hay datos en este punto
//inicializacion
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
//login
curl_easy_setopt(curl,CURLOPT_USERNAME,username);
curl_easy_setopt(curl,CURLOPT_PASSWORD,password);
m_popsAccount = "pop3s://pop.gmail.com:995/";
curl_easy_setopt(curl, CURLOPT_URL, m_popsAccount.c_str());
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
//some servers needs this validation
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0");
res = curl_easy_perform(curl);
if(res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
else
{
/*
here is where you can work with the data inside the chunk...
*/
printf("%s\n",chunk.memory); //here is the information
printf("%lu bytes retrieved\n", (long)chunk.size);
}
//se libera la memoria si hay datos
if(chunk.memory)
free(chunk.memory);
/* always cleanup */
curl_global_cleanup();
}
size_t MailServer::WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}

Related

ByBit Api. Open Active Order. Return "empty param of timestamp". Libcurl c++

Please help!!!! Is there a working example of opening an order in C++
Constantly sending a request to open an order POST https://api.bybit.com/private/linear/order/create
{"api_key":"WTVpIZqOwx2LGYY3TB","order_type":"Market","qty":5,"side":"Buy","symbol":"MATICUSDT","time_in_force":"GoodTillCancel","timestamp":1652444871610,"sign":"433b79f452a6c43f3b507df4b5cee84314c7aae584546a889cde7d750ac2f4a6"}
I get an error
{"ret_code":10001,"ret_msg":"empty param of timestamp","ext_code":"","ext_info":"","result":null,"time_now":"1652444872.324646"
And no one can explain why
the code itself
int main(int, char **)
{
CURL *curl;
CURLcode res;
unsigned long long timestamp = chrono::duration_cast<chrono::milliseconds>(chrono::_V2::system_clock::now().time_since_epoch()).count();
string api_key = "WT***************3TB";
string secret_key = "Ik**************4vE";
string reqParam = "api_key=" + api_key + "&order_type=Market&qty=5&side=Buy&symbol=MATICUSDT&time_in_force=GoodTillCancel&timestamp=" + to_string(timestamp);
string sign = hmacEncode(reqParam, secret_key);
string json = "{\"api_key\":\"" + api_key + "\",\"side\"=\"Buy\",\"symbol\"=\"MATICUSDT\",\"order_type\":\"Market\",\"qty\":2,\"time_in_force\":\"GoodTillCancel\",\"timestamp\":" + to_string(timestamp) + " ,\"sign\":\"" + sign + "\"}";
cout << json << endl;
curl = curl_easy_init();
if (curl)
{
// set params
curl_easy_setopt(curl, CURLOPT_POST, 1); // post req
curl_easy_setopt(curl, CURLOPT_URL, "https://api.bybit.com/private/linear/order/create"); // url
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
// Header "Content-Type: application/json"
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
/* 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);
}
return 0;
}
https://github.com/alex290/bybitorder-api/blob/master/src/main.cpp
Everything solved the problem. Here is the working code
int main(int, char **)
{
CURL *curl;
CURLcode res;
unsigned long long timestamp = chrono::duration_cast<chrono::milliseconds>(chrono::_V2::system_clock::now().time_since_epoch()).count();
string api_key = "WT***************3TB";
string secret_key = "Ik**************4vE";
string reqParam = "api_key=" + api_key + "&close_on_trigger=false&order_type=Market&position_idx=0&qty=5&reduce_only=false&side=Buy&symbol=MATICUSDT&time_in_force=GoodTillCancel&timestamp=" + to_string(timestamp);
string sign = hmacEncode(reqParam, secret_key);
reqParam = reqParam + "&sign=" + sign;
string urlStr = "https://api.bybit.com/private/linear/order/create?" + reqParam;
cout << urlStr << endl;
curl = curl_easy_init();
if (curl)
{
// set params
curl_easy_setopt(curl, CURLOPT_POST, 1); // post req
curl_easy_setopt(curl, CURLOPT_URL, urlStr.c_str()); // url
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
// Header "Content-Type: application/json"
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
/* 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);
}
return 0;
}
I see some strange things. Your wrong JSON in the code:
"\"side\"=\"Buy\",\"symbol\"=\"MATICUSDT\"
It is not consistent with the dumped JSON
"side":"Buy","symbol":"MATICUSDT".
Your code has space after the timestamp, the dumped JSON has no spaces. And the parameter order is different.

C++: How can I Send binary data(protobuf data) using HTTP post request through a curl call

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

Listen to a push message?

I have to listen to a web service’s push message indefinitely. The web service I am listening to send soap response messages whenever there is an update in the content. After I received the message I have to parse it and store it in to structs. Following is my code.
CURL *curl;
CURLcode res;
const char *onlineWebServiceRequest = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"> <soap:Body> <GetCitiesByCountry xmlns=\"http://www.webserviceX.NET\"> <CountryName>Netherlands</CountryName> </GetCitiesByCountry> </soap:Body> </soap:Envelope>";
if(curl){
curl_easy_setopt(curl, CURLOPT_URL, "http://www.webservicex.net/globalweather.asmx/GetCitiesByCountry" );
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, onlineWebServiceRequest);
res = curl_easy_perform(curl);
// call some other method to parse the res
curl_easy_cleanup(curl);
}
Doubts:
Is it the right way to receive push messages? If yes.,
The above code does not check the connection status with web service. How can I check that?
If no, what are all the other option I have probably with open source?
Thanks in advance
You'd better off checking for errors.
To do that you have to enable CURLOPT_ERRORBUFFER option.
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
And add a buffer (it must be at least CURL_ERROR_SIZE bytes big).
char errbuf[CURL_ERROR_SIZE];
Additionally, you could set CURLOPT_FAILONERROR to true, to force curl to convert all response codes >= 300 to errors.
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
To get the actual output from the server you need to set a function to write the data (CURLOPT_WRITEFUNCTION) and a chunk of memory (CURLOPT_WRITEDATA).
A complete example adapted from [1] and [2]:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
CURL curl = curl_easy_init();
if(curl) {
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = (char *)malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
char errbuf[CURL_ERROR_SIZE];
/* specify URL to get */
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
/* send all data to this function */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
/* force curl to fail error when http code >= 300 */
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
/* provide a buffer to store errors in */
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
/* set the error buffer as empty before performing a request */
errbuf[0] = 0;
/* perform the request */
res = curl_easy_perform(curl);
/* if the request did not complete correctly, show the error
information. if no detailed error information was written to errbuf
show the more generic information from curl_easy_strerror instead.
*/
if(res != CURLE_OK) {
size_t len = strlen(errbuf);
fprintf(stderr, "\nlibcurl: (%d) ", res);
if(len)
fprintf(stderr, "%s%s", errbuf,
((errbuf[len - 1] != '\n') ? "\n" : ""));
else
fprintf(stderr, "%s\n", curl_easy_strerror(res));
}
else {
/*
* Now, our chunk.memory points to a memory block that is chunk.size
* bytes big and contains the remote file.
*
* Do something nice with it!
*/
printf("%lu bytes retrieved\n", (long)chunk.size);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl);
free(chunk.memory);
}
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return 0;
}

How do I kill the popup?

If you edit the following code to have valid certificate paths and a url that requires client certificates and then compile it with clang++ -lcurl curl.cpp on OS X (I'm using El Cap, but I think Mavericks or later behave the same way), and run the executable, you get a popup (shown below) from OS X asking if you want to allow the executable to use a private key in your keychain. This is annoying to users that know what's going on (internally curl on OS X uses the OS X security framework to load the client cert) but it's frightening for users who don't know what's happening because they think that the program is trying to access a private key in their keychain (as an aside this is an example of terrible UX from Apple as the popup message is a complete red herring).
The curl command line tool doesn't produce a popup, so either there is a lower level API I could use or it's because the executable is signed. The real program I'm trying to add this feature to is often distributed as source code so signing the executable isn't an ideal approach, as I can't distribute the signing keys or they'll be revoked. Does anyone know how I can prevent the popup programmatically?
#include <curl/curl.h>
#include <string>
using namespace std;
static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
string *responseData = (string *) userData;
responseData->append((const char *) buffer, size * nmemb);
return size * nmemb;
}
void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, "https://example.dev/v1/check.json");
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
*chunk = curl_slist_append(NULL, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
curl_easy_setopt(curl, CURLOPT_SSLCERT, "/path/to/client_cert.p12");
curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "P12");
curl_easy_setopt(curl, CURLOPT_SSLCERTPASSWD, "1234");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/ca.crt");
}
int main(){
CURL* curl = curl_easy_init();
struct curl_slist *chunk = NULL;
string responseData;
long responseCode;
string bodyJsonString = "{\"version\": 1}";
prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
if (responseCode != 200) {
fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
}
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
}
This is how I solved this problem (thanks to the Phusion folks for letting me tinker on this):
#include <curl/curl.h>
#include <string>
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
using namespace std;
const char* cert_label = "Name of the certificate as it appears in keychain access";
const char* domain = "https://example.dev/v1/check.json";
const char* ca_path = "/path/to/ca.crt";
const char* cert_path = "/path/to/client_cert.p12";
const char* cert_pw = "1234";
static OSStatus LookupKeychainItem(const char *label,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
if(kSecClassIdentity != NULL) {
CFTypeRef keys[4];
CFTypeRef values[4];
CFDictionaryRef query_dict;
CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
kCFStringEncodingUTF8);
/* Set up our search criteria and expected results: */
values[0] = kSecClassIdentity; /* we want a certificate and a key */
keys[0] = kSecClass;
values[1] = kCFBooleanTrue; /* we need a reference */
keys[1] = kSecReturnRef;
values[2] = kSecMatchLimitOne; /* one is enough, thanks */
keys[2] = kSecMatchLimit;
/* identity searches need a SecPolicyRef in order to work */
values[3] = SecPolicyCreateSSL(false, label_cf);
keys[3] = kSecMatchPolicy;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
(const void **)values, 4L,
&kCFCopyStringDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CFRelease(values[3]);
CFRelease(label_cf);
/* Do we have a match? */
status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key);
CFRelease(query_dict);
}
return status;
}
SecAccessRef createAccess()
{
SecAccessRef access=NULL;
if (SecAccessCreate(CFStringCreateWithCString(NULL, cert_label, kCFStringEncodingUTF8), NULL, &access)){
printf("SecAccessCreate failed\n");
return NULL;
}
return access;
}
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
const char *cPassword,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8 *)cPath, strlen(cPath), false);
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
cPassword, kCFStringEncodingUTF8) : NULL;
CFDataRef pkcs_data = NULL;
if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
NULL, NULL, &status)) {
SecAccessRef access = createAccess();
const void *cKeys[] = {kSecImportExportPassphrase,kSecImportExportAccess};
//kSecTrustSettingsKeyUseAny
const void *cValues[] = {password,access};
CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
2L, NULL, NULL);
CFArrayRef items = NULL;
/* Here we go: */
status = SecPKCS12Import(pkcs_data, options, &items);
if(items)
CFRelease(items);
CFRelease(options);
CFRelease(pkcs_data);
}
if(password)
CFRelease(password);
CFRelease(pkcs_url);
return status;
}
static size_t receiveResponseBytes(void *buffer, size_t size, size_t nmemb, void *userData) {
string *responseData = (string *) userData;
responseData->append((const char *) buffer, size * nmemb);
return size * nmemb;
}
void prepareCurlPOST(CURL *curl, string &bodyJsonString, string *responseData, struct curl_slist **chunk) {
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_URL, domain);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, bodyJsonString.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, bodyJsonString.length());
*chunk = curl_slist_append(NULL, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, *chunk);
curl_easy_setopt(curl, CURLOPT_SSLCERT, cert_label);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, receiveResponseBytes);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, responseData);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 180);
curl_easy_setopt(curl, CURLOPT_CAINFO, ca_path);
}
void killKey(){
SecIdentityRef id = NULL;
if (LookupKeychainItem(cert_label,&id) != errSecItemNotFound){
CFArrayRef itemList = CFArrayCreate(NULL, (const void **)&id, 1, NULL);
const void *keys2[] = { kSecClass, kSecMatchItemList, kSecMatchLimit };
const void *values2[] = { kSecClassIdentity, itemList, kSecMatchLimitAll };
CFDictionaryRef dict = CFDictionaryCreate(NULL, keys2, values2, 3, NULL, NULL);
OSStatus oserr = SecItemDelete(dict);
if (oserr) {
CFStringRef str = SecCopyErrorMessageString(oserr, NULL);
printf("Removing Passenger Cert from keychain failed: %s Please remove the private key from the certificate labeled %s in your keychain.", CFStringGetCStringPtr(str,kCFStringEncodingUTF8), cert_label);
CFRelease(str);
}
CFRelease(dict);
CFRelease(itemList);
}
}
void preAuthKey(){
SecIdentityRef id = NULL;
if(LookupKeychainItem(cert_label,&id) == errSecItemNotFound){
OSStatus status = SecKeychainSetUserInteractionAllowed(false);
if(status != errSecSuccess){
printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
}
CopyIdentityFromPKCS12File("/path/to/client_cert.p12","1234",&id);
status = SecKeychainSetUserInteractionAllowed(true);
if(status != errSecSuccess){
printf("%s\n",CFStringGetCStringPtr(SecCopyErrorMessageString(status,NULL),kCFStringEncodingUTF8));
}
}
}
int main(){
preAuthKey();
CURL* curl = curl_easy_init();
struct curl_slist *chunk = NULL;
string responseData;
long responseCode;
string bodyJsonString = "{\"version\": 1}";
prepareCurlPOST(curl, bodyJsonString, &responseData, &chunk);
fprintf(stderr,"%s\n",curl_easy_strerror(curl_easy_perform(curl)));
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
if (responseCode != 200) {
fprintf(stderr, "HTTP %d %s\n", (int) responseCode, responseData.c_str());
}
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
killKey();
}

How to check network connection with cURL

I have a linux based embedded system and take snapshots from an ip camera using cURL library.
My camera provides some CGI functions and one of them is for taking image snapshot.
After invoking dedicated CGI function camera sends taken picture as response successfully.
I save cameras response as a jpg file and everything works fine so far.
But when the network connection is broken my code produces a zero sized jpg file.
I removed zero sized images but it will be better not saving image in case of curl_easy_perform(curl) call returns error.
is it possible disabling saving in case of error in cURL?
const int maxNumberOfImages = 20;
CURL *curl;
CURLcode result;
FILE *CURLOPT_WRITEFUNCTION_FILE;
bool flag = true;
string url = "http://admin:1234#";//needs refactory
url.append(ip);
url.append(":80/snapshot.jpg");
DEBUG_PRINT(url);
char actionDate[20];
time_t now = time(NULL);
strftime(actionDate, 20, "%Y-%m-%d %H:%M:%S", localtime(&now));
char *directory = "/root/rootfs_frequent_rw/snapshots/";
string fileName = directory;
fileName.append(cam_name);
fileName.append("___");
fileName.append(actionDate);
fileName.append(".jpg");
createDirectoryIfNotExist(directory);
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
CURLOPT_WRITEFUNCTION_FILE = fopen(fileName.c_str(), "wb");
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEDATA, CURLOPT_WRITEFUNCTION_FILE);
result = curl_easy_perform(curl);
if(result != CURLE_OK){
DEBUG_PRINT("ERROR\n");
flag = false;
}
else
DEBUG_PRINT("SUCCESS\n");
curl_easy_cleanup(curl);
}
fclose(CURLOPT_WRITEFUNCTION_FILE);
cx based embedded system and taking snapshots from an ip camera. url_global_cleanup();
isFileEmpty(fileName.c_str()); //if file is zero sized delete it.
if(flag)
return ReturnValue::return_success;
return ReturnValue::return_operation_failed;
i solved the problem by using CURLOPT_WRITEFUNCTION option. After changing an example code (getinmemory) from cURL documentation i got the following code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = realloc(mem->memory, mem->size + realsize + 1);
if(mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
int main(void)
{
CURL *curl_handle;
CURLcode res;
FILE *pFile;
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://admin:1234#10.108.67.235:80/snapshot.jpg");
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 1L);
/* get it! */
res = curl_easy_perform(curl_handle);
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
}
else {
/*
* Now, our chunk.memory points to a memory block that is chunk.size
* bytes big and contains the remote file.
*
* Do something nice with it!
*/
printf("%lu bytes retrieved\n", (long)chunk.size);
pFile = fopen("test.jpg", "wb");
fwrite(chunk.memory, sizeof(char), (long)chunk.size, pFile);
fclose(pFile);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return 0;
}