/*****************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * $Id: lib500.c,v 1.9 2008-09-20 04:26:56 yangtse Exp $
 */

#include <string.h>
#ifndef	_MSC_VER
	#include <stdbool.h>
	#include <unistd.h>
#else	// _MSC_VER
	#include <stdio.h>
	#define bool unsigned int
	#define true 1
	#define false 0
	#define __bool_true_false_are_defined 1
	#define	usleep(x)	Sleep( (x) / 1000 )
	#define	snprintf	_snprintf
#endif	// _MSC_VER
#include <curl/curl.h>

#define numChannels 2

#define activeFtp false

#define DEFAULT_TIMEOUT_MILLISECS 250
#define MAX_TIMEOUT_MILLISECS 1000

#define URL "ftp://localhost/tmp"
#define USERPWD "user:secret"

struct upload {
  const char *path;
  const char *data;
  int repeat;
  int count;
};

static size_t CurlReadCallback( void *ptr, size_t size, size_t nmemb,
                                void *stream )
{
  struct upload *up = (struct upload *)stream;
  (void)size;
  (void)nmemb;

  /* we repeat sending the data until count repeat cycles are complete */
  if(up->count++ >= up->repeat)
    return 0;

  strcpy(ptr, up->data);
  return strlen(up->data);
}

int main(void)
{
  const char *userPassword = USERPWD;
  CURLM* curlMulti = curl_multi_init();
  CURL *curlEasy[numChannels];
  int i;
  int running_handles;
  CURLMcode multiResult;
  bool result = true;
  int indx=0;
  char urlbuffer[256];
  long timeout;
  int fdMax;
  fd_set fdRead, fdWrite, fdException;

  struct upload updata[]= {
    {"file01", "mooo", 12, 0},
    {"file02", "more than the 1234456789", 10, 0},
    {"file03", "mooo123", 1, 0},
    {"file04", "more than the 1234456789 ABC", 4, 0},
    {"file05", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 17, 0},
    {"file06", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 123, 0},
    {"file07", "more than the 1234456789 ABC", 116, 0},
    {"file08", "mooo123 mooo123 mooo123asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 1, 0},
    {"file09", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 33, 0},
    {"file10", "mooosaysthecowanddisappears!mooosaysthecowanddisappears!mooosaysthecowanddisappears", 200, 0},
    {"file11", "mooo", 1, 0},
    {"file12", "more than the 1234456789", 134, 0},
    {"file13", "mooo123", 6, 0},
    {"file14", "more than the 1234456789 ABC", 99, 0},
    {"file15", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 112, 0},
    {"file16", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 210, 0},
    {"file17", "more than the 1234456789 ABC", 170, 0},
    {"file18", "mooo123 mooo123 mooo123", 200, 0},
    {"file19", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 12, 0},
    {"file20", "mooosaysthecowanddisappears!mooosaysthecowanddisappears!mooosaysthecowanddisappears", 23, 0},
    {"file21", "mooo", 34, 0},
    {"file22", "more than the 1234456789", 45, 0},
    {"file23", "mooo123", 56, 0},
    {"file24", "more than the 1234456789 ABC", 67, 0},
    {"file25", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 78, 0},
    {"file26", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 389, 0},
    {"file27", "more than the 1234456789 ABC", 90, 0},
    {"file28", "mooo123 mooo123 mooo123", 100, 0},
    {"file29", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 750, 0},
    {"file30", "mooosaysthecowanddisappears!mooosaysthecowanddisappears!mooosaysthecowanddisappears", 10, 0},
    {"file31", "mooo", 1, 0},
    {"file32", "more than the 1234456789", 400, 0},
    {"file33", "mooo123", 500, 0},
    {"file34", "more than the 1234456789 ABC", 315, 0},
    {"file35", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 102, 0},
    {"file36", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 123, 0},
    {"file37", "more than the 1234456789 ABC", 450, 0},
    {"file38", "mooo123 mooo123 mooo123", 145, 0},
    {"file39", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 223, 0},
    {"file40", "mooosaysthecowanddisappears!mooosaysthecowanddisappears!mooosaysthecowanddisappears", 10, 0},
    {"file41", "mooo", 1, 0},
    {"file42", "more than the 1234456789", 400, 0},
    {"file43", "mooo123", 500, 0},
    {"file44", "more than the 1234456789 ABC", 75, 0},
    {"file45", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 102, 0},
    {"file46", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 123, 0},
    {"file47", "more than the 1234456789 ABC", 50, 0},
    {"file48", "mooo123 mooo123 mooo123", 45, 0},
    {"file49", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 123, 0},
    {"file50", "mooosaysthecowanddisappears!mooosaysthecowanddisappears!mooosaysthecowanddisappears", 23, 0},
    {"file51", "mooo", 34, 0},
    {"file52", "more than the 1234456789", 245, 0},
    {"file53", "mooo123", 56, 0},
    {"file54", "more than the 1234456789 ABC", 67, 0},
    {"file55", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 78, 0},
    {"file56", "more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC more than the 1234456789 ABC", 89, 0},
    {"file57", "more than the 1234456789 ABC", 590, 0},
    {"file58", "mooo123 mooo123 mooo123", 100, 0},
    {"file59", "asd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafkasd fhsdah fhjasdjkfjhasd jfd hjsdasfjhdsfhjsdaas djjhsdajhf hjsd fj jhsdajsld jhsdh jhasd fjasd jh  jhsd jhsda jadfj kjhsd jh jsdslafk", 250, 0},
    {NULL, NULL, 0, 0} /* end of list */
  };

  for(i = 0; i < numChannels; i++ ) {
    CURL* easy = curl_easy_init();

    snprintf(urlbuffer, sizeof(urlbuffer), "%s/%s", URL, updata[indx].path);

    printf("WE USE URL(%d) %s\n", indx, urlbuffer);

    curl_easy_setopt( easy, CURLOPT_UPLOAD, 1 );
    curl_easy_setopt( easy, CURLOPT_NOSIGNAL, 1 );
    curl_easy_setopt( easy, CURLOPT_NOPROGRESS, 1);
    curl_easy_setopt( easy, CURLOPT_VERBOSE, 1 );
    curl_easy_setopt( easy, CURLOPT_FTP_USE_EPRT, 0  /* use PORT instead */ );
    curl_easy_setopt( easy, CURLOPT_FTP_USE_EPSV, 0  /* use PASV instead */ );
    curl_easy_setopt( easy, CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_MULTICWD );
    curl_easy_setopt( easy, CURLOPT_FTP_CREATE_MISSING_DIRS , 1 );
    curl_easy_setopt( easy, CURLOPT_SSH_AUTH_TYPES , CURLSSH_AUTH_PASSWORD );
    curl_easy_setopt( easy, CURLOPT_USERPWD , userPassword);
    curl_easy_setopt( easy, CURLOPT_FTPPORT , activeFtp ? "-" : 0 );
    curl_easy_setopt( easy, CURLOPT_URL , urlbuffer );
    curl_easy_setopt( easy, CURLOPT_READFUNCTION , CurlReadCallback );
    curl_easy_setopt( easy, CURLOPT_READDATA , &updata[indx] );
    curl_multi_add_handle( curlMulti, easy );

    indx++;

    curlEasy[ i ] = easy;
  }

  while( result ) {
    int num_messages;
    CURLMsg* curlMsg;

    /* call curl_multi_perform, as long as it wants to be called: */
    while( ( multiResult = curl_multi_perform( curlMulti, &running_handles ) )
           == CURLM_CALL_MULTI_PERFORM );

    /* now process waiting easy handle messages: */
    curlMsg = curl_multi_info_read( curlMulti, &num_messages );
    while( curlMsg ) {
      if( curlMsg->msg == CURLMSG_DONE )
      {
        CURL* easy = curlMsg->easy_handle;
        CURLcode easyResult = curlMsg->data.result;
        curl_multi_remove_handle( curlMulti, easy );
        if( ( easyResult != CURLE_URL_MALFORMAT ) && ( easyResult != CURLE_OK ) )
        {
          /* serious error occured. */
          result = false;
          break;
        }

        /* prepare and resurrect easy handle for next transfer: */
        if( updata[indx].path )
        {
          snprintf(urlbuffer, sizeof(urlbuffer), "%s/%s", URL,
                   updata[indx].path);

          printf("WE USE URL(%d) %s\n", indx, urlbuffer);

          curl_easy_setopt( easy, CURLOPT_URL , urlbuffer );
          curl_easy_setopt( easy, CURLOPT_READFUNCTION, CurlReadCallback);
          curl_easy_setopt( easy, CURLOPT_READDATA, &updata[indx]);
          curl_multi_add_handle( curlMulti, easy );
          indx++;
          running_handles++;
        }
      }
      curlMsg = curl_multi_info_read( curlMulti, &num_messages );
    }

    if( !running_handles )
      break;

    /* get curl timeout setting: */
    curl_multi_timeout( curlMulti, &timeout );
    if( timeout < 0 )
      timeout = DEFAULT_TIMEOUT_MILLISECS;
    if( timeout > MAX_TIMEOUT_MILLISECS )
      timeout = MAX_TIMEOUT_MILLISECS;

    /* check socket action: */
    FD_ZERO( &fdRead );
    FD_ZERO( &fdWrite );
    FD_ZERO( &fdException );
    curl_multi_fdset( curlMulti, &fdRead, &fdWrite, &fdException, &fdMax );
    if( fdMax != -1 ) {
      /* socket stuff to do: */
      struct timeval tv;
      int select_result;

      tv.tv_sec = timeout/1000;
      tv.tv_usec = (timeout%1000) * 1000;
      select_result = select( fdMax + 1, &fdRead, &fdWrite, &fdException, &tv );
      if( select_result < 0 )
      {
        result = false;
        break;
      }
    }
    else
    {
      usleep( DEFAULT_TIMEOUT_MILLISECS * 1000 );
    }


  }

  /* clean-up libcurl easy handles: */
  for(i = 0; i < numChannels; i++ )
  {
    curl_multi_remove_handle( curlMulti, curlEasy[ i ] );
    curl_easy_cleanup( curlEasy[ i ] );
  }

  /* clean-up libcurl multi handle: */
  curl_multi_cleanup( curlMulti );

  return( result );
}

