#include <stdio.h>
#include <stdlib.h>
#include <curl/curl.h>
/* parse headers for Content-Length */ 
size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
  int r;
  long len = 0;
 
  /* _snscanf() is Win32 specific */ 
  r = _snscanf((const char*)ptr, size * nmemb, "Content-Length: %ld\n", &len);
 
  if (r) /* Microsoft: we don't read the specs */ 
    *((long *) stream) = len;
 
  return size * nmemb;
}
 
/* discard downloaded data */ 
size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream) {
  return size * nmemb;
}
 
/* read data to upload */ 
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;
}

static
void dump(const char *text,
          FILE *stream, unsigned char *ptr, size_t size,
          bool nohex)
{
  size_t i;
  size_t c;
 
  unsigned int width=0x10;
 
  if(nohex)
    /* without the hex output, we can fit more on screen */ 
    width = 0x40;
 
  fprintf(stream, "%s, %10.10ld bytes (0x%8.8lx)\n",
          text, (long)size, (long)size);
 
  fflush(stream);
}
 
static
int my_trace(CURL *handle, curl_infotype type,
             unsigned char *data, size_t size,
             void *userp)
{
  const char *text;
 
  (void)userp;
  (void)handle; /* prevent compiler warning */ 
 
  switch (type) {
  case CURLINFO_TEXT:
    fprintf(stderr, "== Info: %s", data);
  default: /* in case a new one is introduced to shock us */ 
    return 0;
 
  case CURLINFO_HEADER_OUT:
    text = "=> Send header";
    break;
  case CURLINFO_HEADER_IN:
    text = "<= Recv header";
    break;
  }
 
  dump(text, stderr, data, size, TRUE);
  return 0;
}
CURLcode  Multi_Run(CURLM* multi_handle, CURL*curl)
{
	 int still_running =1;
	 curl_multi_perform(multi_handle, &still_running);
 
	

	  while(still_running) {
		struct timeval timeout;
		int rc; /* select() return code */ 
 
		fd_set fdread;
		fd_set fdwrite;
		fd_set fdexcep;
		int maxfd = -1;
 
		long curl_timeo = -1;
 
		FD_ZERO(&fdread);
		FD_ZERO(&fdwrite);
		FD_ZERO(&fdexcep);
 
		/* set a suitable timeout to play around with */ 
		timeout.tv_sec = 1;
		timeout.tv_usec = 0;
 
		curl_multi_timeout(multi_handle, &curl_timeo);
		if(curl_timeo >= 0) {
		  timeout.tv_sec = curl_timeo / 1000;
		  if(timeout.tv_sec > 1)
			timeout.tv_sec = 1;
		  else
			timeout.tv_usec = (curl_timeo % 1000) * 1000;
		}
 
		/* get file descriptors from the transfers */ 
		curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
 
		/* In a real-world program you OF COURSE check the return code of the
		   function calls.  On success, the value of maxfd is guaranteed to be
		   greater or equal than -1.  We call select(maxfd + 1, ...), specially in
		   case of (maxfd == -1), we call select(0, ...), which is basically equal
		   to sleep. */ 
 
		rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
 
		switch(rc) {
		case -1:
		  /* select error */ 
		  break;
		case 0:
		default:
		  /* timeout or readable/writable sockets */ 
		  curl_multi_perform(multi_handle, &still_running);
		  break;
		}
	  }
	  int msgs_left; /* how many messages are left */ 

   CURLMsg *msg = curl_multi_info_read(multi_handle, &msgs_left); /* for picking up messages with the transfer status */ 
   while (msg) {
    if (msg->msg == CURLMSG_DONE) {
 
		return msg->data.result;
	}
	msg = curl_multi_info_read(multi_handle, &msgs_left);
  }
}

int main(void)
{
	CURL *curl;
	CURLcode res;
	curl_global_init(CURL_GLOBAL_ALL);

	curl = curl_easy_init();
	if(curl) {

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////
		//testCWD
		//curl_easy_setopt(curl, CURLOPT_URL, "ftp://labuser:tester@10.192.16.122:21//Users/labuser/bugs/dir1/");
		//curl_easy_setopt(curl, CURLOPT_VERBOSE,1L);
		//curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD,CURLFTPMETHOD_SINGLECWD);
		//curl_easy_setopt(curl, CURLOPT_URL, "ftp://VAIDYA-PC%5Cftpuser:P%40$$w0rd@vaidya-pc:25/testdelete/");
		//res = curl_easy_perform(curl);

		//curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "cwd \/Users");
		//res = curl_easy_perform(curl);
		///* always cleanup */ 
		//curl_easy_cleanup(curl);
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////
		//test ftps connection
		/* init a multi stack */ 
		CURLM *multi_handle = curl_multi_init();

		// How curl changes directories using CWD:
		curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_SINGLECWD);

		// setup curl callbacks
		//curl_easy_setopt(curl, CURLOPT_FTP_RESPONSE_TIMEOUT, timeout);
 
		curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
 
		curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, discardfunc);
 
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, readfunc);

		// NOTE: -- These two calls are obsolete in 7.10.8.  
		// You can still compile, however, the library won't use them.  
		// Here is the link that explains the unsupport; http://curl.haxx.se/mail/lib-2003-10/0100.html
		//curl_easy_setopt(handle, CURLOPT_PASSWDFUNCTION, theContext.CurlPasswdCallback);
		//curl_easy_setopt(curl, CURLOPT_PASSWDDATA, &theContext);


		// Daniel Stenberg: The signal is used for stopping slow DNS name
		// resolves, nothing else. (Doesn't work in Win32 and is not
		// thread safe in *nix).
		curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
	//	curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, theContext.theCurlErrorBuffer);

		// Set the use of extended (IPv6 compliant) semantics for PORT/PASV:
		curl_easy_setopt(curl, CURLOPT_FTP_USE_EPSV, 1); 
		curl_easy_setopt(curl, CURLOPT_FTP_USE_EPRT, 1); 

		// curl global cache is not thread-safe
		curl_easy_setopt(curl, CURLOPT_DNS_USE_GLOBAL_CACHE, (long)0);
	 
		// [gc 7/28/03] We need to re-think this for next release. The verbose flag adds all
		// kinds of debug info which can be a serious performance hit (eg. host name lookups, etc).
		// For now I've commented out most areas using verbose in curl that were slow, but we should
		// use a different mechanism for logging, not debug callbacks...
		curl_easy_setopt(curl, CURLOPT_VERBOSE, (long)1);
	
	
		// if 'port' is zero, curl will automatically use the default (21) port.
		curl_easy_setopt(curl, CURLOPT_PORT, (long)25);


		//////////////////////////// SSL related initialization:

		//if( theContext.mUseFTPS )
		{
			//ASSERT( !theContext.mCACertFilePath.empty() );	// Must be set by now!
			//if( !theContext.mCACertFilePath.empty() )
			//{
			//	curl_easy_setopt( curl, CURLOPT_CAINFO, theContext.mCACertFilePath.c_str() );
			//}
			curl_easy_setopt( curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
			curl_easy_setopt( curl, CURLOPT_FTPSSLAUTH, CURLFTPAUTH_DEFAULT );	// "CURLFTPAUTH_DEFAULT", "CURLFTPAUTH_SSL", "CURLFTPAUTH_TLS"
			curl_easy_setopt( curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT  );	// "CURL_SSLVERSION_DEFAULT", "CURL_SSLVERSION_TLSv1", "CURL_SSLVERSION_SSLv2", "CURL_SSLVERSION_SSLv3"
			curl_easy_setopt( curl, CURLOPT_FTP_SSL_CCC, CURLFTPSSL_CCC_NONE );	// "CURLFTPSSL_CCC_NONE", "CURLFTPSSL_CCC_PASSIVE", "CURLFTPSSL_CCC_ACTIVE"
			curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 );
			curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 0 );
			curl_easy_setopt( curl, CURLOPT_CERTINFO, (long)1 );
		}

	
	curl_easy_setopt(curl, CURLOPT_URL, "ftp://VAIDYA-PC%5Cftpuser:P%40$$w0rd@vaidya-pc:25/testdelete/");

	// Clear any quoted operations
	curl_easy_setopt(curl, CURLOPT_POSTQUOTE, NULL);
	curl_easy_setopt(curl, CURLOPT_QUOTE, NULL);
	curl_easy_setopt(curl, CURLOPT_PREQUOTE, NULL);

	// disable data channel by default
	curl_easy_setopt(curl, CURLOPT_NOBODY, (long)1);

	// Default to download
	curl_easy_setopt(curl, CURLOPT_UPLOAD, (long)0);

	// Clear any custom requests
	curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);

	// Don't do filetime checks by default
	curl_easy_setopt(curl, CURLOPT_FILETIME, NULL);

	// set timeout based on channel properties.
	//curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)theContext.getOperationTimeout());
	curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) 0);

	// Default to directory lists using LIST
	curl_easy_setopt(curl, CURLOPT_FTPLISTONLY, 0);

	// Set the transfer type
	curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1); 

	// Set thePasvSetting based on Get/SetProperties.  Default to PASV.
	curl_easy_setopt(curl, CURLOPT_FTPPORT, NULL);
	
	// enable progress callbacks 
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, (long)0);

	curl_multi_add_handle(multi_handle,curl);

	CURLcode ret = Multi_Run(multi_handle,curl);
	curl_multi_remove_handle(multi_handle,curl); 
		curl_multi_cleanup(multi_handle);
		curl_easy_cleanup(curl);
		curl_global_cleanup(); 
	}
}
