Skip to content

gsauthof/imapdl

Repository files navigation

C++ License Build Status Code Coverage

IMAP4v1 Download Client

2014, Georg Sauthoff mail@georg.so

This repository contains a IMAP4v1 client for fetching messages from an IMAP server and storing them in a local maildir directory. It is also able to delete them on the server if they are successfully transferred.

Besides the actual client, the repository may be of interest as a base for other IMAP clients/servers because it includes Ragel based parsers for the client and server side of the IMAP protocol. For such use cases it is recommended to include this repository as Git submodule.

(last change to this readme file: 2017-04-29)

Features

  • Maildir support - client makes sure to fsync at the right times to minimize data loss in the case of power failure
  • SSL (i.e. TLS) enabled by default
  • In case the connection is interrupted during a fetch operation, the UIDs of completely fetched messages are written to a journal and expunged on next program start before the remaining messages are fetched. Useful, when e.g. retrieving a large mailbox over an unreliable mobile network (think: UMTS when travelling in a high speed train).
  • display From/Subject/Date headers during fetching (when INFO severity level is turned on)
  • Workarounds for some IMAP server bugs (deviations from the RFC)
  • Uses the UIDPLUS extension if available - thus, excluding side effects with concurrently established server connections when purging messages
  • Plain tilde expansion in local mailbox paths
  • Configuration via JSON run control file
  • Written in C++ with some C++11 features
  • Asynchronous IO using Boost ASIO
  • Robust IMAP protocol parser implemented in Ragel
  • Before commands are send to the server they are locally parsed with a Ragel grammar that implements the server side of the IMAP spec - thus, the client verifies that it doesn't violate RFC3501 in any obvious way.
  • High test coverage with unittests

Design Choices

  • Use sane and secure defaults (e.g. TLS encryption and certificate validation are enabled by default).
  • Don't send commands to the server that are expected to fail (e.g. the LOGIN command when it is disabled or the UID expunge command when the server has no UIDPLUS extension).
  • Verify commands before sending them to the server.
  • Use asynchronous IO without threads.
  • Use state machines where it makes the code more robust, compact, easier to reason about etc.
  • Support IPv4 and IPv6.
  • Use layering where it reduces complexity (e.g. in the download client the differenes between the Boost ASIO TCP and SSL APIs are abstracted away by a layer, on top of that are the IMAP parsers layered, etc.)
  • Give SASL support a low priority, because IMAP over TLS generally makes SASL redundant (cf. SASL notes section).
  • Make it portable (e.g. via using open standards like ISO C++, POSIX, portable tools like CMake, Ragel and portable libraries like Boost).

Compile

This project includes some Git submodules, thus, make sure that they are correctly updated after git clone (i.e. verify that the subdirectories libbuffer, libixxx and cmake/ragel are there. Perhaps you have to adjust the submodule URLs, in case you don't have your Github ssh account correctly setup.

Out-of-source builds are recommended, thus, do something like this:

$ git clone git@github.com:gsauthof/imap.git
$ cd imap
$ git submodule update --init
$ mkdir build
$ cd build
$ cmake ..
$ make imapdl ut

If can also use an alternative build generator with cmake, of course, e.g.:

$ cmake -G Ninja ..
$ ninja-build imapdl ut

In case you have Boost installed in a custom location you can do something like:

$ BOOST_ROOT=/home/juser/local/boost-1.55 cmake -G Ninja ..

For setting some CMake variables:

$ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=true -G Ninja ..

Or supply a custom cache initialization file via cmake -C.

Meson

Alternatively, this project can be built with Meson. The Meson build configuration is located in meson.build. The Meson build system is younger than CMake, it has more useful defaults, a saner syntax and some nice features.

Example:

$ meson --buildtype=release build
$ cd build
$ ninja-build imapdl

Dependencies

Basic usage

On the first run, imapdl generates a run controle file template under:

$HOME/.config/imapdl/rc.json

You can copy the 'example' section and rename it to 'default' for the default account. For multiple accounts you can use a section name of your choice and supply --account somename to the imapdl command line.

The default cipher list for SSL is somewhat progressive (i.e. it basically only include forward secrecy providing TLSv1.2 ciphers). You can use a more relaxed list via setting cipher_preset to 2 or 3 (higher means more relaxed) - or you can configure your own cipher list.

For verifying the authenticity of the certificate provided by the server you can either specify

Tested platforms

  • Linux (Fedora 19/20 x86_64)

IMAP Servers

  • Dovecot (1.2.9)
  • Cyrus (Cyrus IMAP v2.3.13)
  • Google GMail (Gimap)

Licence

GPLv3+

Appendix

Example Subdirectory

A collection of small example programs for testing some related features:

  • length.rl - lexing a token based on the preceding length value
  • client.cc - exploring ASIO features, simple example ASIO client, also used for unittesting replay feature
  • server.cc - exploring ASIO features, also used for replaying IMAP sessions in unittests
  • replay.cc - for dumping serialized network sessions
  • hash.cc - implement sha256sum using the Botan C++ library

SASL Notes

When securing the connection with TLS, SASL doesn't increase your security. On the other hand, on unsecured connections SASL only protects your password somewhat (depending on the used method) but it doesn't help against man-in-the-middle attacks or eavesdropping on the content of your mails. SASL is perhaps of interest for certain methods, e.g. to support Kerberos authentication with IMAP servers, but I haven't come across such setups, yet.

Links