summaryrefslogtreecommitdiffstats
path: root/fb-helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'fb-helper.c')
-rw-r--r--fb-helper.c429
1 files changed, 0 insertions, 429 deletions
diff --git a/fb-helper.c b/fb-helper.c
deleted file mode 100644
index 3dd6dbb..0000000
--- a/fb-helper.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Description: This is intended as a helper for fb only.
- *
- * Synopsis: ./fb-helper <action> <URL> <file>
- *
- * action can be:
- * d = download <URL>
- * u = upload <file> to <URL>
- *
- * Author: Florian "Bluewind" Pritz <flo@xssn.at>
- *
- * Licensed under GPLv3
- * (see COPYING for full license text)
- */
-
-#define _POSIX_C_SOURCE 2
-
-#include <stdio.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <libgen.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <curl/curl.h>
-#include <curl/easy.h>
-
-#define FORMAT_BYTES_BUFFER 16
-#define FORMAT_TIME_BUFFER 16
-#define SAMPLE_COUNT 15
-
-#define UNUSED __attribute__((unused))
-
-struct sample {
- size_t size;
- double time;
-};
-
-/* struct which holds the persistent data for progress_callback */
-struct progressData {
- struct timeval last;
- double ullast;
- int lastStringLength;
- struct sample samples[SAMPLE_COUNT];
- int current_sample;
-};
-
-struct options {
- int debug;
- char *url;
- char *file;
- char *apikeyfile;
-};
-
-/* load the contents of file fn into data */
-int load_file(const char *fn, char **data, size_t *data_size)
-{
- FILE *fp;
- size_t buf_size = 1024*1024; /* use 1MiB chunks */
-
- fp = fopen(fn, "rb");
- if (fp == NULL) {
- perror("load_file");
- return 1;
- }
-
- /* read the file in buf_size chunks and appened the data to *data */
- while (!feof(fp)) {
- char *tmp;
- tmp = realloc(*data, *data_size + buf_size);
- if (tmp == NULL) {
- perror("load_file");
- return 1;
- }
- *data = tmp;
-
- *data_size += fread(*data + *data_size, sizeof(char), buf_size, fp);
-
- if (ferror(fp)) {
- perror("load_file");
- return 1;
- }
- }
-
- fclose(fp);
-
- return 0;
-}
-
-void format_bytes(char *buf, int bufsize, double bytes)
-{
- double size = bytes;
- int suffix_pos = 0;
- static const char *suffix[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"};
- static const int suffix_count = sizeof(suffix) / sizeof(suffix[0]);
- static const double boundary = 2048.0;
-
- for(suffix_pos = 0; suffix_pos + 1 < suffix_count; suffix_pos++) {
- if(size <= boundary && size >= -boundary) {
- break;
- }
- size /= 1024.0;
- }
-
- // don't print decimals for bytes
- if (suffix_pos != 0)
- snprintf(buf, bufsize, "%.2f%s", size, suffix[suffix_pos]);
- else
- snprintf(buf, bufsize, "%.0f%s", size, suffix[suffix_pos]);
-}
-
-void format_time(char *buf, int bufsize, time_t time)
-{
- int seconds = 0;
- int minutes = 0;
- int hours = 0;
-
- seconds = time%60;
- minutes = (time/60)%60;
- hours = time/60/60;
-
- if (hours > 0) {
- snprintf(buf, bufsize, "%d:%02d:%02d", hours, minutes, seconds);
- } else {
- snprintf(buf, bufsize, "%02d:%02d", minutes, seconds);
- }
-}
-
-int progress_callback(
- void *cb_data,
- double UNUSED dltotal, double UNUSED dlnow,
- double ultotal, double ulnow
-){
- struct timeval now;
- struct progressData *data = (struct progressData *)cb_data;
- double timeSpent = 0;
- int printed = 0;
- char speed[FORMAT_BYTES_BUFFER];
- char total[FORMAT_BYTES_BUFFER];
- char eta[FORMAT_TIME_BUFFER];
- time_t time_remaining = 0;
-
- double ulspeed = 0.0;
- size_t sample_total = 0;
- double sample_time = 0.0;
-
- if (0 == ulnow)
- return 0;
-
- /* upload complete; clean up */
- if (ulnow >= ultotal) {
- fprintf(stderr, "%*s\r", data->lastStringLength + 1, "");
- return 0;
- }
-
- gettimeofday(&now, NULL);
-
- /* calculate time between this and the last call in seconds */
- timeSpent =
- (double)(now.tv_sec - data->last.tv_sec) +
- (double)(now.tv_usec - data->last.tv_usec) / 1E6;
-
- /* don't refresh too often, catch if time went backwards */
- if (timeSpent < 0.2 && timeSpent > -1.0)
- return 0;
-
- /* save a sample every time we update and average over all samples
- * to reduce jumpiness */
- data->samples[data->current_sample].size = ulnow - data->ullast;
- data->samples[data->current_sample].time = timeSpent;
-
- data->current_sample++;
- if (data->current_sample >= SAMPLE_COUNT) {
- data->current_sample = 0;
- }
-
- for (int i = 0; i < SAMPLE_COUNT; i++) {
- if (data->samples[i].size != 0) {
- sample_total += data->samples[i].size;
- sample_time += data->samples[i].time;
- }
- }
-
- ulspeed = sample_total / sample_time;
-
- if (ulspeed < 1) {
- snprintf(eta, sizeof(eta), "stalling");
- } else {
- time_remaining = (ultotal - ulnow) / ulspeed;
- format_time(eta, sizeof(eta), time_remaining);
- }
-
- format_bytes((char *)&total, sizeof(total), ulnow);
- format_bytes((char *)&speed, sizeof(speed), ulspeed);
-
- /* print the progress */
- printed = fprintf(stderr,
- "\r%s/s uploaded: %.1f%% = %s; ETA: %s",
- speed, /* upload speed */
- ulnow * 100.0 / ultotal, /* percent uploaded */
- total, /* total data uploaded */
- eta
- );
-
- /* pad the string if the last one was longer to remove left over characters */
- if (data->lastStringLength > printed)
- fprintf(stderr, "%*s", data->lastStringLength - printed, "");
-
- /* save current values for the next run */
- data->ullast = ulnow;
- data->last = now;
- data->lastStringLength = printed;
-
- return 0;
-}
-
-void display_help()
-{
- printf("Usage: fb-helper <options>\n");
- printf("\n");
- printf("Options:\n");
- printf(" -D Print debugging information\n");
- printf(" -h This help\n");
- printf(" -u <url> URL of pastebin or URL to download\n");
- printf(" -f <file> File to upload to URL\n");
- printf(" -F key=value Post key=value\n");
- printf(" -a <file> Path to API key file\n");
-}
-
-int main(int argc, char *argv[])
-{
- CURL *curl = NULL;
- CURLcode res;
-
- struct curl_httppost *formpost = NULL;
- struct curl_httppost *lastptr = NULL;
- struct curl_slist *headerlist = NULL;
- static const char buf[] = "Expect:";
-
- char *userAgent = "fb-client/"VERSION;
-
- struct progressData cb_data = {
- .last = {.tv_sec = 0, .tv_usec = 0},
- .ullast = 0.0,
- .lastStringLength = 0,
- .current_sample = 0
- };
-
- char *data = NULL;
-
- int ret = 0;
-
- int opt;
- struct options options = {
- .debug = 0,
- .file = NULL,
- .url = NULL,
- .apikeyfile = NULL
- };
-
- if (argc == 1) {
- display_help();
- exit(0);
- }
-
- while ((opt = getopt(argc, argv, "Du:f:F:m:a:h")) != -1) {
- switch (opt) {
- case 'D': options.debug = 1; break;
-
- case 'u': options.url = optarg; break;
-
- case 'f': options.file = optarg; break;
-
- case 'F':
- {
- char *save = NULL;
- char *key = strtok_r(optarg, "=", &save);
- char *value = strtok_r(save, "=", &save);
-
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, key,
- CURLFORM_PTRCONTENTS, value,
- CURLFORM_END);
- }
- break;
-
- case 'a': options.apikeyfile = optarg; break;
-
- case 'h':
- display_help();
- exit(0);
- break;
-
- default:
- fprintf(stderr, "Error: unknown option %c", opt);
- exit(1);
- }
- }
-
- /* initialize curl */
- if (curl_global_init(CURL_GLOBAL_ALL) != 0) {
- fprintf(stderr, "Error initializing curl");
- ret = 10;
- goto cleanup;
- }
-
- curl = curl_easy_init();
- if(!curl) {
- fprintf(stderr, "Error initializing curl");
- ret = 1;
- goto cleanup;
- }
-
- if (options.debug > 0) {
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- }
-
- if (options.apikeyfile) {
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "apikey",
- CURLFORM_FILECONTENT, options.apikeyfile,
- CURLFORM_END);
- } else {
- /* use .netrc settings for authentication if available */
- curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
- }
-
-
- /* if we have a file to upload, add it as a POST request */
- if (options.file) {
- struct stat statbuf;
-
- if(stat(options.file, &statbuf) == -1) {
- fprintf(stderr, "fb-helper: %s: ", options.file);
- perror(NULL);
- ret = 1;
- goto cleanup;
- }
-
- /* load files with 0 size (/proc files for example) into memory so we can
- * determine their real length */
- if (statbuf.st_size == 0) {
- size_t data_size = 0;
-
- if (load_file(options.file, &data, &data_size) != 0) {
- ret = 1;
- goto cleanup;
- }
-
- if (data_size == 0) {
- fprintf(stderr, "Error: skipping 0-byte file: \"%s\"\n", options.file);
- ret = 1;
- goto cleanup;
- }
-
- /* Fill in the file upload field */
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "file",
- CURLFORM_BUFFER, basename(options.file),
- CURLFORM_BUFFERPTR, data,
- CURLFORM_BUFFERLENGTH, (char *)data_size,
- CURLFORM_END);
- } else {
- /* Fill in the file upload field */
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "file",
- CURLFORM_FILE, options.file,
- CURLFORM_END);
- }
-
- if (isatty(fileno(stderr)) == 1) {
- /* display progress bar*/
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &cb_data);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback);
- }
- }
-
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
-
- /* initialize custom header list (stating that Expect: 100-continue is not
- wanted */
- headerlist = curl_slist_append(headerlist, buf);
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
-
- curl_easy_setopt(curl, CURLOPT_URL, options.url);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
-
- /* bail if the upload stalls for 30 seconds */
- curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
- curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 30L);
-
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
- curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
-
- curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
-
- /* save time for progress calculation */
- gettimeofday(&cb_data.last, NULL);
-
- /* run the request */
- res = curl_easy_perform(curl);
-
- /* handle curl errors */
- if (res != 0) {
- fprintf(stderr, "\n%s\n", curl_easy_strerror(res));
- ret = 1;
- goto cleanup;
- }
-
-cleanup:
- if (curl)
- curl_easy_cleanup(curl);
-
- if (formpost)
- curl_formfree(formpost);
-
- curl_slist_free_all (headerlist);
- curl_global_cleanup();
- free(data);
-
- return ret;
-}