<commit_before>﻿# FTP client for C++
[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT)


## About
This is a simple FTP client for C++. It wraps libcurl for FTP requests and meant to be a portable
and easy-to-use API to perform FTP related operations.

Compilation has been tested with:
- GCC 5.4.0 (GNU/Linux Ubuntu 16.04 LTS)
- Microsoft Visual Studio 2015 (Windows 10)

Underlying libraries:
- [libcurl](http://curl.haxx.se/libcurl/)

## Usage
Create an object and provide to its constructor a callable object (for log printing) having this signature :

```cpp
void(const std::string&)
```

Later, you can disable log printing by avoiding the flag CFTPClient::SettingsFlag::ENABLE_LOG when initializing a session.

```cpp
#include "FTPClient.h"

CFTPClient FTPClient([](const std::string&){ std::cout << strLogMsg << std::endl; });
```

Before performing one or more requests, a session must be initialized with server parameters.

```cpp
FTPClient.InitSession("ftp://127.0.0.1", 21, "username", "password");
```

You can also set parameters such as the time out (in seconds), the HTTP proxy server etc... before sending
your request.

To create and remove a remote empty directory :

```cpp
/* creates a directory "bookmarks" under ftp://127.0.0.1:21/documents/ */
FTPClient.CreateDir("/document/bookmarks");

/* removes the "empty" directory "bookmarks" created above
 * the directory must be empty, otherwise the method will fail */
FTPClient.RemoveDir("/document/bookmarks");
```

To download a file :

```cpp
/* download ftp://127.0.0.1:21/info.txt to "C:\downloaded_info.txt" */
FTPClient.DownloadFile("C:\\downloaded_info.txt", "info.txt");
```

To download a whole directory with the wildcard '*' :

```cpp
/* download all the elements of ftp://127.0.0.1:21/pictures/ to WildcardTest/ */
FTPClient.DownloadWildcard("/home/amine/WildcardTest", "pictures/*");
```

To upload and remove a file :

```cpp
/* upload C:\test_upload.txt to  ftp://127.0.0.1:21/upload/documents/test_upload.txt */
/* if /upload/documents/ doesn't exist, you can set the third parameter bCreateDir to true
to create missing directories */
FTPClient.UploadFile("C:\\test_upload.txt", "/upload/documents/test_upload.txt");

/* remove the above uploaded file */
FTPClient.RemoveFile("/upload/documents/test_upload.txt");
```

To list a remote directory:

```cpp
std::string strList;

/* list root directory
 * a third parameter can be set to false to request a detailed list */

FTPClient.List("/", strList);
```

To request a remote file's size and mtime:

```cpp
/* create a helper object to receive file's info */
CFTPClient::FileInfo ResFileInfo = { 0, 0.0 };

/* requests ftp://127.0.0.1:21/info.txt file size and mtime */
FTPClient.Info("info.txt", ResFileInfo));

/* if the operation succeeds, true will be returned. */

cout << ResFileInfo.dFileSize << endl; // file size of "/info.txt"
cout << ResFileInfo.tFileMTime << endl; // file mtime (epoch) of "/info.txt"
```

Always check that the methods above return true, otherwise, that means that  the request wasn't properly
executed.

Finally cleanup can be done automatically if the object goes out of scope. If the log printing is enabled,
a warning message will be printed. Or you can cleanup manually by calling CleanupSession() :

```cpp
FTPClient.CleanupSession();
```

After cleaning the session, if you want to reuse the object, you need to re-initialize it with the
proper method.

## Callback to a Progress Function

A pointer to a callback progress meter function or a callable object (lambda, functor etc...), which should match the prototype shown below, can be passed.

```cpp
int ProgCallback(void* ptr, double dTotalToDownload, double dNowDownloaded, double dTotalToUpload, double dNowUploaded);
```

This function gets called by libcurl instead of its internal equivalent with a frequent interval. While data is being transferred it will be called very frequently, and during slow periods like when nothing is being transferred it can slow down to about one call per second.

Returning a non-zero value from this callback will cause libcurl to abort the transfer.

The unit tests "TestDownloadFile" and "TestUploadAndRemoveFile" demonstrate how to use a progress function to display a progress bar on console when downloading or uploading a file.

## Thread Safety

A mutex is used to increment/decrement atomically the count of CFTPClient objects.

`curl_global_init` is called when the count of CFTPClient objects equals to zero (when instanciating the first object).
`curl_global_cleanup` is called when the count of CFTPClient objects become zero (when all CFTPClient objects are destroyed).

Do not share CFTPClient objects across threads as this would mean accessing libcurl handles from multiple threads
at the same time which is not allowed.

The method SetNoSignal can be used to skip all signal handling. This is important in multi-threaded applications as DNS<commit_msg>Updated thread safety section.<commit_after>﻿# FTP client for C++
[![MIT license](https://img.shields.io/badge/license-MIT-blue.svg)](http://opensource.org/licenses/MIT)


## About
This is a simple FTP client for C++. It wraps libcurl for FTP requests and meant to be a portable
and easy-to-use API to perform FTP related operations.

Compilation has been tested with:
- GCC 4.8.5 (Centos 7)
- GCC 5.4.0 (GNU/Linux Ubuntu 16.04 LTS)
- Microsoft Visual Studio 2015 (Windows 10)

Underlying libraries:
- [libcurl](http://curl.haxx.se/libcurl/)

## Usage
Create an object and provide to its constructor a callable object (for log printing) having this signature :

```cpp
void(const std::string&)
```

Later, you can disable log printing by avoiding the flag CFTPClient::SettingsFlag::ENABLE_LOG when initializing a session.

```cpp
#include "FTPClient.h"

CFTPClient FTPClient([](const std::string& strLogMsg){ std::cout << strLogMsg << std::endl; });
```

Before performing one or more requests, a session must be initialized with server parameters.

```cpp
FTPClient.InitSession("ftp://127.0.0.1", 21, "username", "password");
```

You can also set parameters such as the time out (in seconds), the HTTP proxy server etc... before sending
your request.

To create and remove a remote empty directory :

```cpp
/* creates a directory "bookmarks" under ftp://127.0.0.1:21/documents/ */
FTPClient.CreateDir("/document/bookmarks");

/* removes the "empty" directory "bookmarks" created above
 * the directory must be empty, otherwise the method will fail */
FTPClient.RemoveDir("/document/bookmarks");
```

To download a file :

```cpp
/* download ftp://127.0.0.1:21/info.txt to "C:\downloaded_info.txt" */
FTPClient.DownloadFile("C:\\downloaded_info.txt", "info.txt");
```

To download a whole directory with the wildcard '*' :

```cpp
/* download all the elements of ftp://127.0.0.1:21/pictures/ to WildcardTest/ */
FTPClient.DownloadWildcard("/home/amine/WildcardTest", "pictures/*");
```

To upload and remove a file :

```cpp
/* upload C:\test_upload.txt to  ftp://127.0.0.1:21/upload/documents/test_upload.txt */
/* if /upload/documents/ doesn't exist, you can set the third parameter bCreateDir to true
to create missing directories */
FTPClient.UploadFile("C:\\test_upload.txt", "/upload/documents/test_upload.txt");

/* remove the above uploaded file */
FTPClient.RemoveFile("/upload/documents/test_upload.txt");
```

To list a remote directory:

```cpp
std::string strList;

/* list root directory
 * a third parameter can be set to false to request a detailed list */

FTPClient.List("/", strList);
```

To request a remote file's size and mtime:

```cpp
/* create a helper object to receive file's info */
CFTPClient::FileInfo ResFileInfo = { 0, 0.0 };

/* requests ftp://127.0.0.1:21/info.txt file size and mtime */
FTPClient.Info("info.txt", ResFileInfo));

/* if the operation succeeds, true will be returned. */

cout << ResFileInfo.dFileSize << endl; // file size of "/info.txt"
cout << ResFileInfo.tFileMTime << endl; // file mtime (epoch) of "/info.txt"
```

Always check that the methods above return true, otherwise, that means that  the request wasn't properly
executed.

Finally cleanup can be done automatically if the object goes out of scope. If the log printing is enabled,
a warning message will be printed. Or you can cleanup manually by calling CleanupSession() :

```cpp
FTPClient.CleanupSession();
```

After cleaning the session, if you want to reuse the object, you need to re-initialize it with the
proper method.

## Callback to a Progress Function

A pointer to a callback progress meter function or a callable object (lambda, functor etc...), which should match the prototype shown below, can be passed.

```cpp
int ProgCallback(void* ptr, double dTotalToDownload, double dNowDownloaded, double dTotalToUpload, double dNowUploaded);
```

This function gets called by libcurl instead of its internal equivalent with a frequent interval. While data is being transferred it will be called very frequently, and during slow periods like when nothing is being transferred it can slow down to about one call per second.

Returning a non-zero value from this callback will cause libcurl to abort the transfer.

The unit tests "TestDownloadFile" and "TestUploadAndRemoveFile" demonstrate how to use a progress function to display a progress bar on console when downloading or uploading a file.

## Thread Safety

If you are using other libraries that make use of libcurl, please take a look at this issue (https://github.com/embeddedmz/ftpclient-cpp/issues/4). In short, remove from this project libcurl's global initialization/clean-up code, and manually call these functions, at your program startup/shutdown (or let your 3rd party library handle this).

Do not share CFTPClient objects across threads as this would mean accessing libcurl handles from multiple threads
at the same time which is not allowed.

The method SetNoSignal can be used to skip all signal handling. This is important in multi-threaded applications as DNS
{'fraction_non_alphanumeric': 0.10421021200358316, 'fraction_numerical': 0.013337314621279983, 'mean_word_length': 4.520879120879121, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 3, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 12, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1235586', 'n_tokens_mistral': 3007, 'n_tokens_neox': 2806, 'n_words': 1229}