MAILClient.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * @file IMAPClient.h
  3. * @brief libcurl wrapper for IMAP operations
  4. *
  5. * @author Mohamed Amine Mzoughi <mohamed-amine.mzoughi@laposte.net>
  6. * @date 2017-01-02
  7. *
  8. * Updated by acetone in 2023 for QtEmailFetcher
  9. */
  10. #ifndef INCLUDE_MAILCLIENT_H_
  11. #define INCLUDE_MAILCLIENT_H_
  12. #define CLIENT_USERAGENT "mailclientcpp-agent/1.0"
  13. #include <algorithm>
  14. #include <cstddef> // std::size_t
  15. #include <cstdio> // snprintf
  16. #include <cstdlib>
  17. #include <cstring> // strerror, strlen, memcpy, strcpy
  18. #include <ctime>
  19. #include <curl/curl.h>
  20. #include <fstream>
  21. #include <functional>
  22. #include <iostream>
  23. #include <mutex>
  24. #include <stdarg.h> // va_start, etc...
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <sstream>
  28. #include <string>
  29. #include <memory> // std::unique_ptr
  30. #include "CurlHandle.h"
  31. class CMailClient
  32. {
  33. public:
  34. // Public definitions
  35. typedef std::function<int(void*, double, double, double, double)> ProgressFnCallback;
  36. typedef std::function<void(const std::string&)> LogFnCallback;
  37. // Progress Function Data Object - parameter void* of ProgressFnCallback references it
  38. struct ProgressFnStruct
  39. {
  40. ProgressFnStruct() : dLastRunTime(0), pCurl(nullptr), pOwner(nullptr) {}
  41. double dLastRunTime;
  42. CURL* pCurl;
  43. /* owner of the MailClient object. can be used in the body of the progress
  44. * function to send signals to the owner (e.g. to update a GUI's progress bar)
  45. */
  46. void* pOwner;
  47. };
  48. enum SettingsFlag
  49. {
  50. NO_FLAGS = 0x00,
  51. ENABLE_LOG = 0x01,
  52. VERIFY_PEER = 0x02,
  53. VERIFY_HOST = 0x04,
  54. ALL_FLAGS = 0xFF
  55. };
  56. //enum class SslTlsFlag : unsigned char
  57. // DO NOT combine them !
  58. enum SslTlsFlag
  59. {
  60. NO_SSLTLS = 0x00,
  61. ENABLE_TLS = 0x01,
  62. ENABLE_SSL = 0x02
  63. };
  64. /* Please provide your logger thread-safe routine, otherwise, you can turn off
  65. * error log messages printing by not using the flag ALL_FLAGS or ENABLE_LOG */
  66. explicit CMailClient(LogFnCallback oLogger);
  67. virtual ~CMailClient();
  68. // copy constructor and assignment operator are disabled
  69. CMailClient(const CMailClient& Copy) = delete;
  70. CMailClient& operator=(const CMailClient& Copy) = delete;
  71. // Setters - Getters (for unit tests)
  72. void SetProgressFnCallback(void* pOwner, const ProgressFnCallback& fnCallback);
  73. void SetProxy(const std::string& strProxy);
  74. inline void SetTimeout(const int& iTimeout) { m_iCurlTimeout = iTimeout; }
  75. inline void SetNoSignal(const bool& bNoSignal) { m_bNoSignal = bNoSignal; }
  76. inline auto GetProgressFnCallback() const
  77. {
  78. return m_fnProgressCallback.target<int(*)(void*,double,double,double,double)>();
  79. }
  80. inline void* GetProgressFnCallbackOwner() const { return m_ProgressStruct.pOwner; }
  81. inline const std::string& GetProxy() const { return m_strProxy; }
  82. inline int GetTimeout() const { return m_iCurlTimeout; }
  83. inline bool GetNoSignal() const { return m_bNoSignal; }
  84. inline const std::string& GetURL() const { return m_strURL; }
  85. inline const std::string& GetUsername() const { return m_strUserName; }
  86. inline const std::string& GetPassword() const { return m_strPassword; }
  87. inline unsigned char GetFlags() const { return m_eSettingsFlags; }
  88. inline SslTlsFlag GetSslTlsFlags() const { return m_eSslTlsFlags; }
  89. // Session
  90. bool InitSession(const std::string& strHost,
  91. const std::string& strLogin,
  92. const std::string& strPassword,
  93. const SettingsFlag& SettingsFlags = ALL_FLAGS,
  94. const SslTlsFlag& SslTlsFlags = NO_SSLTLS);
  95. virtual bool CleanupSession();
  96. const CURL* GetCurlPointer() const { return m_pCurlSession; }
  97. static const std::string& GetCertificateFile() { return s_strCertificationAuthorityFile; }
  98. static void SetCertificateFile(const std::string& strPath) { s_strCertificationAuthorityFile = strPath; }
  99. void SetSSLCertFile(const std::string& strPath) { m_strSSLCertFile = strPath; }
  100. const std::string& GetSSLCertFile() const { return m_strSSLCertFile; }
  101. void SetSSLKeyFile(const std::string& strPath) { m_strSSLKeyFile = strPath; }
  102. const std::string& GetSSLKeyFile() const { return m_strSSLKeyFile; }
  103. void SetSSLKeyPassword(const std::string& strPwd) { m_strSSLKeyPwd = strPwd; }
  104. const std::string& GetSSLKeyPwd() const { return m_strSSLKeyPwd; }
  105. inline unsigned char GetSettingsFlags() const { return m_eSettingsFlags; }
  106. #ifdef DEBUG_CURL
  107. static void SetCurlTraceLogDirectory(const std::string& strPath);
  108. #endif
  109. protected:
  110. virtual bool PrePerform() { return true; }
  111. /* common operations to SMTP, POP & IMAP are performed here */
  112. bool Perform();
  113. virtual bool PostPerform(CURLcode) { return true; }
  114. virtual inline void ParseURL(std::string&) { }
  115. // Curl callbacks
  116. static size_t WriteInStringCallback(void* ptr, size_t size, size_t nmemb, void* data);
  117. static size_t WriteToFileCallback(void* ptr, size_t size, size_t nmemb, void* data);
  118. static size_t ReadLineFromFileStreamCallback(void* ptr, size_t size, size_t nmemb, void* stream);
  119. static size_t ReadLineFromStringStreamCallback(void* ptr, size_t size, size_t nmemb, void* userp);
  120. static size_t ReadFromFileCallback(void* ptr, size_t size, size_t nmemb, void* stream);
  121. // Helper for error log printing
  122. static std::string StringFormat(const std::string strFormat, ...);
  123. #ifdef DEBUG_CURL
  124. static int DebugCallback(CURL* curl, curl_infotype curl_info_type, char* strace, size_t nSize, void* pFile);
  125. inline void StartCurlDebug();
  126. inline void EndCurlDebug();
  127. #endif
  128. std::string m_strUserName;
  129. std::string m_strPassword;
  130. std::string m_strURL;
  131. std::string m_strProxy;
  132. bool m_bNoSignal;
  133. /* Can be used in derived classes to perform file I/O or
  134. * or input string stream operations */
  135. std::string m_strLocalFile;
  136. std::fstream m_fLocalFile;
  137. std::istringstream m_ssString;
  138. // SSL
  139. static std::string s_strCertificationAuthorityFile;
  140. std::string m_strSSLCertFile;
  141. std::string m_strSSLKeyFile;
  142. std::string m_strSSLKeyPwd;
  143. mutable CURL* m_pCurlSession;
  144. struct curl_slist* m_pRecipientslist;
  145. int m_iCurlTimeout;
  146. SettingsFlag m_eSettingsFlags;
  147. SslTlsFlag m_eSslTlsFlags;
  148. // Progress function
  149. ProgressFnCallback m_fnProgressCallback;
  150. ProgressFnStruct m_ProgressStruct;
  151. bool m_bProgressCallbackSet;
  152. // Log printer callback
  153. LogFnCallback m_oLog;
  154. #ifdef DEBUG_CURL
  155. static std::string s_strCurlTraceLogDirectory;
  156. std::ofstream m_ofFileCurlTrace;
  157. #endif
  158. CurlHandle& m_curlHandle;
  159. };
  160. inline CMailClient::SettingsFlag operator|(CMailClient::SettingsFlag a, CMailClient::SettingsFlag b) {
  161. return static_cast<CMailClient::SettingsFlag>(static_cast<int>(a) | static_cast<int>(b));
  162. }
  163. // Logs messages
  164. #define LOG_ERROR_CURL_ALREADY_INIT_MSG "[MAILClient][Error] Curl session is already initialized ! " \
  165. "Use CleanupSession() to clean the present one."
  166. #define LOG_ERROR_EMPTY_HOST_MSG "[MAILClient][Error] Empty hostname."
  167. #define LOG_ERROR_CURL_NOT_INIT_MSG "[MAILClient][Error] Curl session is not initialized ! Use InitSession() before."
  168. #define LOG_WARNING_OBJECT_NOT_CLEANED "[MAILClient][Warning] Object was freed before calling CMailClient::CleanupSession()." \
  169. " The API session was cleaned though."
  170. #define LOG_ERROR_PREPERFORM_FAILED_MSG "[MAILClient][Error] PrePerform failed !"
  171. #define LOG_ERROR_POSTPERFORM_FAILED_MSG "[MAILClient][Error] PostPerform failed !"
  172. #define LOG_ERROR_CURL_PEFORM_FAILURE_FORMAT "[MAILClient][Error] Unable to perform a request (Error=%d | %s) !"
  173. #endif