/*****************************************************************************
 *                                  _   _ ____  _
 *  Project                     ___| | | |  _ \| |
 *                             / __| | | | |_) | |
 *                            | (__| |_| |  _ <| |___
 *                             \___|\___/|_| \_\_____|
 *
 * $Id: lib525.c,v 1.13 2006-10-27 01:58:59 yangtse Exp $
 */

#include "curl.h"

/* read data to upload */
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
  FILE *f = stream;
  size_t n;

  if (ferror(f))
    return CURL_READFUNC_ABORT;

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

  return n;
}


#define MAIN_LOOP_HANG_TIMEOUT     300 * 1000
#define MULTI_PERFORM_HANG_TIMEOUT 120 * 1000

int main(int argc, char* argv[])
{
  int res = 0;
  CURL *curl;
  FILE *hd_src ;
  int running;
  char done=FALSE;
  CURLM *m;
  char ml_timedout = FALSE;
  char mp_timedout = FALSE;

  /* get the file size of the local file */
/*
  hd = open(arg2, O_RDONLY) ;
  fstat(hd, &file_info);
  close(hd) ;
*/
  /* get a FILE * of the same file, could also be made with
     fdopen() from the previous descriptor, but hey this is just
     an example! */
  hd_src = fopen("text.txt", "rb");
  if (hd_src == NULL) {
    fprintf(stderr, "could not open file text.txt\n");
    return -1;
  }

  if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
    fprintf(stderr, "curl_global_init() failed\n");
    fclose(hd_src);
    return -1;
  }

  if ((curl = curl_easy_init()) == NULL) {
    fprintf(stderr, "curl_easy_init() failed\n");
    fclose(hd_src);
    curl_global_cleanup();
    return -1;
  }

  /* enable uploading */
  curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;

  /* specify target */
  curl_easy_setopt(curl,CURLOPT_URL, "ftp://localhost/lib525.txt");

  /* go verbose */
  curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);

  /* use active FTP */
  curl_easy_setopt(curl, CURLOPT_FTPPORT, "-");

  /* now specify which file to upload */
  curl_easy_setopt(curl, CURLOPT_READDATA, hd_src);

  /* NOTE: if you want this code to work on Windows with libcurl as a DLL, you
     MUST also provide a read callback with CURLOPT_READFUNCTION. Failing to
     do so will give you a crash since a DLL may not use the variable's memory
     when passed in to it from an app like this. */
  curl_easy_setopt(curl, CURLOPT_READFUNCTION, readfunc);

  /* Set the size of the file to upload (optional).  If you give a *_LARGE
     option you MUST make sure that the type of the passed-in argument is a
     curl_off_t. If you use CURLOPT_INFILESIZE (without _LARGE) you must
     make sure that to pass in a type 'long' argument. */
/*  curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
                    (curl_off_t)file_info.st_size);
*/

  if ((m = curl_multi_init()) == NULL) {
    fprintf(stderr, "curl_multi_init() failed\n");
    curl_easy_cleanup(curl);
    curl_global_cleanup();
    fclose(hd_src);
    return -1;
  }

  if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) {
    fprintf(stderr, "curl_multi_add_handle() failed, "
            "with code %d\n", res);
    curl_multi_cleanup(m);
    curl_easy_cleanup(curl);
    curl_global_cleanup();
    fclose(hd_src);
    return -1;
  }

  res = CURLM_CALL_MULTI_PERFORM;
  while (!done) {
    fd_set rd, wr, exc;
    int max_fd;
    struct timeval interval;

    interval.tv_sec = 1;
    interval.tv_usec = 0;

    while (res == CURLM_CALL_MULTI_PERFORM) {
      res = (int)curl_multi_perform(m, &running);
      if (running <= 0) {
        done = TRUE;
        break;
      }
    }
    if (done)
      break;

    if (res != CURLM_OK) {
      fprintf(stderr, "not okay???\n");
      break;
    }

    FD_ZERO(&rd);
    FD_ZERO(&wr);
    FD_ZERO(&exc);
    max_fd = 0;

    if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) {
      fprintf(stderr, "unexpected failured of fdset.\n");
      res = 189;
      break;
    }

    if (select(max_fd+1, &rd, &wr, &exc, &interval) == -1) {
      fprintf(stderr, "bad select??\n");
      res = 195;
      break;
    }

    res = CURLM_CALL_MULTI_PERFORM;
  }

#ifdef LIB529
  /* test 529 */
  curl_multi_remove_handle(m, curl);
  curl_multi_cleanup(m);
  curl_easy_cleanup(curl);
#else
  /* test 525 */
  curl_multi_remove_handle(m, curl);
  curl_easy_cleanup(curl);
  curl_multi_cleanup(m);
#endif

  fclose(hd_src); /* close the local file */

  curl_global_cleanup();
  return res;
}

