vdr-plugin-scraper2vdr/lib/curl.c

177 lines
5.3 KiB
C

/*
* curl.c:
*
* See the README file for copyright information and how to reach the author.
*
*/
#include <curl/curl.h>
#include "common.h"
#include "config.h"
//***************************************************************************
// Callbacks
//***************************************************************************
static size_t WriteMemoryCallback(void* ptr, size_t size, size_t nmemb, void* data)
{
size_t realsize = size * nmemb;
struct MemoryStruct* mem = (struct MemoryStruct*)data;
if (mem->memory)
mem->memory = (char*)realloc(mem->memory, mem->size + realsize + 1);
else
mem->memory = (char*)malloc(mem->size + realsize + 1);
if (mem->memory)
{
memcpy (&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
static size_t WriteHeaderCallback(void* ptr, size_t size, size_t nmemb, void* data)
{
size_t realsize = size * nmemb;
struct MemoryStruct* mem = (struct MemoryStruct*)data;
char* p;
if (ptr)
{
// get filename
{
// Content-Disposition: attachment; filename="20140103_20140103_de_qy.zip"
const char* attribute = "Content-disposition: ";
if ((p = strcasestr((char*)ptr, attribute)))
{
if (p = strcasestr(p, "filename="))
{
p += strlen("filename=");
tell(4, "found filename at [%s]", p);
if (*p == '"')
p++;
sprintf(mem->name, "%s", p);
if ((p = strchr(mem->name, '\n')))
*p = 0;
if ((p = strchr(mem->name, '\r')))
*p = 0;
if ((p = strchr(mem->name, '"')))
*p = 0;
tell(4, "set name to '%s'", mem->name);
}
}
}
// since some sources update "ETag" an "Last-Modified:" without changing the contents
// we have to use "Content-Length:" to check for updates :(
{
const char* attribute = "Content-Length: ";
if ((p = strcasestr((char*)ptr, attribute)))
{
sprintf(mem->tag, "%s", p+strlen(attribute));
if ((p = strchr(mem->tag, '\n')))
*p = 0;
if ((p = strchr(mem->tag, '\r')))
*p = 0;
if ((p = strchr(mem->tag, '"')))
*p = 0;
}
}
}
return realsize;
}
//***************************************************************************
// Download File
//***************************************************************************
int downloadFile(const char* url, int& size, MemoryStruct* data, int timeout, const char* userAgent)
{
CURL* curl_handle;
long code;
CURLcode res = CURLE_OK;
size = 0;
// init curl
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
{
tell(0, "Error, something went wrong with curl_global_init()");
return fail;
}
curl_handle = curl_easy_init();
if (!curl_handle)
{
tell(0, "Error, unable to get handle from curl_easy_init()");
return fail;
}
if (EPG2VDRConfig.useproxy)
{
curl_easy_setopt(curl_handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_easy_setopt(curl_handle, CURLOPT_PROXY, EPG2VDRConfig.httpproxy); // Specify HTTP proxy
}
curl_easy_setopt(curl_handle, CURLOPT_URL, url); // Specify URL to get
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 0); // don't follow redirects
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); // Send all data to this function
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void*)data); // Pass our 'data' struct to the callback function
curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, WriteHeaderCallback); // Send header to this function
curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER, (void*)data); // Pass some header details to this struct
curl_easy_setopt(curl_handle, CURLOPT_MAXFILESIZE, 100*1024*1024); // Set maximum file size to get (bytes)
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1); // No progress meter
curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); // No signaling
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout); // Set timeout
curl_easy_setopt(curl_handle, CURLOPT_NOBODY, data->headerOnly ? 1 : 0); //
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, userAgent); // Some servers don't like requests
// that are made without a user-agent field
// perform http-get
if ((res = curl_easy_perform(curl_handle)) != 0)
{
data->clear();
tell(1, "Error, download failed; %s (%d)",
curl_easy_strerror(res), res);
curl_easy_cleanup(curl_handle); // Cleanup curl stuff
return fail;
}
curl_easy_getinfo(curl_handle, CURLINFO_HTTP_CODE, &code);
curl_easy_cleanup(curl_handle); // cleanup curl stuff
if (code == 404)
{
data->clear();
return fail;
}
size = data->size;
return success;
}