/**
  A Simple C program for uploading file to a server.
  On first attempt program uploads the file. If not success
  then it tries to resume the previous one.
*/

#include <stdlib.h>
#include <stdio.h>

#include <curl/curl.h>
#include <sys/stat.h>

#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif // WIN32

//Just change these two and run the program
#define LOCAL_FILENAME "/home/kumar/tests/curluploadtest.zip"
#define SERVER_FILENAME "ftp://test006:123098@203.113.132.156:56868/curluploadtest.zip"

//Sleep
#define TIME_DELAY_SECS 10


/* from ftp_upload example */
/* parse headers for Content-Length */
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  int r;
  unsigned long long len = 0;

  r = sscanf((char*)ptr, "Content-Length: %llu\n", &len);

  if (r)
    *((long *) stream) = len;

  return size * nmemb;
}

/* from ftp_upload example */
size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  return size * nmemb;
}

/* from ftp_upload example */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  FILE *f = (FILE*) stream;
  size_t n;

  if (ferror(f))
    return CURL_READFUNC_ABORT;

  n = fread(ptr, size, nmemb, f) * size;

  return n;
}

/* Sleep function for both win and linux */
void delay()
{
#ifdef WIN32
    Sleep(TIME_DELAY_SECS * 1000);
#else
    usleep(TIME_DELAY_SECS * 1000 * 1000);
#endif // win32
}

int main(int argc, char *argv[])
{

  CURL *curlhandle = NULL;

  curl_global_init(CURL_GLOBAL_ALL);
  curlhandle = curl_easy_init();

  curl_easy_setopt(curlhandle, CURLOPT_URL,
                   SERVER_FILENAME);

  curl_easy_setopt(curlhandle, CURLOPT_FTP_CREATE_MISSING_DIRS,
                          CURLFTP_CREATE_DIR_RETRY);

  curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);

  struct stat buf;

  stat(LOCAL_FILENAME, &buf);

  /*Even tried with this option but no effect*/
  //curl_easy_setopt(curlhandle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size);


  /*No of tries; just a big number so as to avoid infinite loop*/
  int ntries = 0;

  /*First try to resume, if file not in server then proceed for normal upload*/
  while(ntries < 10000000)
  {
        ++ntries;
        FILE *f = fopen(LOCAL_FILENAME, "rb");

        if(f == NULL) return 1;

        long resumeFrom = 0;

        curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION,
        getcontentlengthfunc);
        curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &resumeFrom);
        curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1L);
        curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1L);
        curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, discardfunc);
        CURLcode r = CURLE_GOT_NOTHING;
        r = curl_easy_perform(curlhandle);
        /*If we got some prob with server so lets wait for 10 secs*/
        if(r != CURLE_OK)
        {
            delay();
            continue;
        }
        if (r == CURLE_OK && (resumeFrom > 0))
        {
            curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 0L);
            curl_easy_setopt(curlhandle, CURLOPT_HEADER, 0L);

            fseek(f, resumeFrom, SEEK_SET);

            curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM, resumeFrom);
            curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L);
        }
        else
        {
            curl_easy_setopt(curlhandle, CURLOPT_APPEND, 0L);
        }

        curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);

        /* enable uploading */
        curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);

        curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);

        curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);

        r = curl_easy_perform(curlhandle); //fszie 6144037725, r frm 811543779

        fclose(f);

        if(r == CURLE_OK) break;
  }

  curl_easy_cleanup(curlhandle);
  curl_global_cleanup();

  return 1;
}
