react-native-email-imap-smtp 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/package.json +1 -1
  2. package/react-native.config.js +1 -2
  3. package/windows/EmailImapSmtp/EmailImapSmtp.def +3 -0
  4. package/windows/EmailImapSmtp/EmailImapSmtp.vcxproj +159 -0
  5. package/windows/EmailImapSmtp/EmailImapSmtp.vcxproj.filters +74 -0
  6. package/windows/EmailImapSmtp/EmailImapSmtpModule.h +494 -0
  7. package/windows/{ImapProtocol.cpp → EmailImapSmtp/ImapProtocol.cpp} +1 -0
  8. package/windows/EmailImapSmtp/PropertySheet.props +28 -0
  9. package/windows/EmailImapSmtp/ReactPackageProvider.cpp +20 -0
  10. package/windows/EmailImapSmtp/ReactPackageProvider.h +22 -0
  11. package/windows/EmailImapSmtp/ReactPackageProvider.idl +13 -0
  12. package/windows/{SmtpProtocol.cpp → EmailImapSmtp/SmtpProtocol.cpp} +1 -0
  13. package/windows/{TlsSocket.cpp → EmailImapSmtp/TlsSocket.cpp} +139 -15
  14. package/windows/{TlsSocket.h → EmailImapSmtp/TlsSocket.h} +3 -3
  15. package/windows/EmailImapSmtp/pch.cpp +5 -0
  16. package/windows/EmailImapSmtp/pch.h +39 -0
  17. package/windows/EmailImapSmtp.sln +30 -0
  18. package/windows/ExperimentalFeatures.props +15 -0
  19. package/windows/EmailImapSmtpModule.h +0 -139
  20. /package/windows/{EmailImapSmtp.cpp → EmailImapSmtp/EmailImapSmtp.cpp} +0 -0
  21. /package/windows/{EmailImapSmtp.h → EmailImapSmtp/EmailImapSmtp.h} +0 -0
  22. /package/windows/{EmailImapSmtpModule.cpp → EmailImapSmtp/EmailImapSmtpModule.cpp} +0 -0
  23. /package/windows/{EmailImapSmtpPackage.cpp → EmailImapSmtp/EmailImapSmtpPackage.cpp} +0 -0
  24. /package/windows/{EmailImapSmtpPackage.h → EmailImapSmtp/EmailImapSmtpPackage.h} +0 -0
  25. /package/windows/{ImapProtocol.h → EmailImapSmtp/ImapProtocol.h} +0 -0
  26. /package/windows/{ProtocolDefs.h → EmailImapSmtp/ProtocolDefs.h} +0 -0
  27. /package/windows/{SmtpProtocol.h → EmailImapSmtp/SmtpProtocol.h} +0 -0
@@ -2,8 +2,132 @@
2
2
  // TlsSocket.cpp — WinSock2 TCP + Schannel TLS implementation
3
3
  // ============================================================
4
4
 
5
+ #include "pch.h"
5
6
  #include "TlsSocket.h"
6
7
 
8
+ // Manual SSPI/Schannel declarations for UWP compat (SDK excludes these)
9
+ #pragma comment(lib, "ws2_32.lib")
10
+ #pragma comment(lib, "crypt32.lib")
11
+ #pragma comment(lib, "secur32.lib")
12
+
13
+ #ifndef SCHANNEL_CRED_VERSION
14
+ #define SECURITY_STATUS int
15
+ #define SEC_E_OK 0
16
+ #define SEC_I_CONTINUE_NEEDED 0x00090312L
17
+ #define SEC_E_INCOMPLETE_MESSAGE 0x80090318L
18
+ #define SECPKG_ATTR_STREAM_SIZES 0x00000004
19
+ #define SECPKG_CRED_OUTBOUND 2
20
+ #define SCHANNEL_CRED_VERSION 4
21
+ #define SP_PROT_TLS1_2 0x00000800
22
+ #define SCH_CRED_MANUAL_CRED_VALIDATION 0x00000008
23
+ #define SCH_CRED_NO_SYSTEM_MAPPER 0x00000002
24
+ #define SCH_CRED_NO_SERVERNAME_CHECK 0x00000004
25
+ #define SECBUFFER_VERSION 0
26
+ #define SECBUFFER_EMPTY 0
27
+ #define SECBUFFER_DATA 1
28
+ #define SECBUFFER_TOKEN 2
29
+ #define SECBUFFER_STREAM_HEADER 5
30
+ #define SECBUFFER_STREAM_TRAILER 6
31
+ #define SECBUFFER_EXTRA 9
32
+ #define SECBUFFER_MISSING 11
33
+ #define ISC_REQ_SEQUENCE_DETECT 0x00000008
34
+ #define ISC_REQ_REPLAY_DETECT 0x00000004
35
+ #define ISC_REQ_CONFIDENTIALITY 0x00000010
36
+ #define ISC_REQ_ALLOCATE_MEMORY 0x00000100
37
+ #define ISC_REQ_STREAM 0x00008000
38
+ #define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000
39
+
40
+ typedef struct _SecHandle {
41
+ ULONG_PTR dwLower;
42
+ ULONG_PTR dwUpper;
43
+ } SecHandle;
44
+ typedef SecHandle CredHandle;
45
+ typedef SecHandle CtxtHandle;
46
+
47
+ typedef struct _SecBuffer {
48
+ unsigned long cbBuffer;
49
+ unsigned long BufferType;
50
+ void* pvBuffer;
51
+ } SecBuffer;
52
+
53
+ typedef struct _SecBufferDesc {
54
+ unsigned long ulVersion;
55
+ unsigned long cBuffers;
56
+ SecBuffer* pBuffers;
57
+ } SecBufferDesc;
58
+
59
+ typedef struct _SCHANNEL_CRED {
60
+ DWORD dwVersion;
61
+ DWORD cCreds;
62
+ void* paCred;
63
+ void* hRootStore;
64
+ DWORD cMappers;
65
+ void* aphMappers;
66
+ DWORD cSupportedAlgs;
67
+ void* paSupportedAlgs;
68
+ DWORD dwFlags;
69
+ DWORD dwCredFormat;
70
+ DWORD grbitEnabledProtocols;
71
+ DWORD dwMinimumCipherStrength;
72
+ DWORD dwMaximumCipherStrength;
73
+ } SCHANNEL_CRED;
74
+
75
+ typedef struct _SecPkgContext_StreamSizes {
76
+ unsigned long cbHeader;
77
+ unsigned long cbTrailer;
78
+ unsigned long cbMaximumMessage;
79
+ unsigned long cBuffers;
80
+ unsigned long cbBlockSize;
81
+ unsigned long cbMaxTrailer;
82
+ } SecPkgContext_StreamSizes;
83
+
84
+ typedef struct _SecPkgContext_Sizes {
85
+ unsigned long cbMaxToken;
86
+ unsigned long cbMaxSignature;
87
+ unsigned long cbBlockSize;
88
+ unsigned long cbMaxTrailer;
89
+ } SecPkgContext_Sizes;
90
+
91
+ typedef struct _TimeStamp {
92
+ LONG LowPart;
93
+ LONG HighPart;
94
+ } TimeStamp;
95
+
96
+ #ifndef SEC_ENTRY
97
+ #define SEC_ENTRY
98
+ #endif
99
+ extern "C" {
100
+ int SEC_ENTRY AcquireCredentialsHandleW(LPWSTR, LPWSTR, unsigned long, void*, void*, void*, void*, CredHandle*, TimeStamp*);
101
+ int SEC_ENTRY AcquireCredentialsHandleA(LPSTR, LPSTR, unsigned long, void*, void*, void*, void*, CredHandle*, TimeStamp*);
102
+ int SEC_ENTRY InitializeSecurityContextA(CredHandle*, void*, LPSTR, unsigned long, unsigned long, unsigned long, SecBufferDesc*, unsigned long, CtxtHandle*, SecBufferDesc*, unsigned long*, TimeStamp*);
103
+ int SEC_ENTRY InitializeSecurityContextW(CredHandle*, void*, LPWSTR, unsigned long, unsigned long, unsigned long, SecBufferDesc*, unsigned long, CtxtHandle*, SecBufferDesc*, unsigned long*, TimeStamp*);
104
+ int SEC_ENTRY DeleteSecurityContext(CtxtHandle*);
105
+ int SEC_ENTRY FreeCredentialsHandle(CredHandle*);
106
+ int SEC_ENTRY FreeContextBuffer(void*);
107
+ int SEC_ENTRY EncryptMessage(CtxtHandle*, unsigned long, SecBufferDesc*, unsigned long);
108
+ int SEC_ENTRY DecryptMessage(CtxtHandle*, SecBufferDesc*, unsigned long, void*);
109
+ int SEC_ENTRY QueryContextAttributesW(CtxtHandle*, unsigned long, void*);
110
+ int SEC_ENTRY QueryContextAttributesA(CtxtHandle*, unsigned long, void*);
111
+ }
112
+
113
+ #define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
114
+ #define UNISP_NAME UNISP_NAME_A
115
+ #define AcquireCredentialsHandle AcquireCredentialsHandleA
116
+ #define QueryContextAttributes QueryContextAttributesA
117
+
118
+ #endif // SCHANNEL_CRED_VERSION
119
+
120
+ // Cast helpers: uint8_t[] members -> typed references for SSPI API calls
121
+ #ifdef SCHANNEL_CRED_VERSION
122
+ #define credHandle (*reinterpret_cast<CredHandle*>(m_credHandle))
123
+ #define ctxtHandle (*reinterpret_cast<CtxtHandle*>(m_ctxtHandle))
124
+ #define streamSizes (*reinterpret_cast<SecPkgContext_StreamSizes*>(m_streamSizes))
125
+ #else
126
+ #define credHandle m_credHandle
127
+ #define ctxtHandle m_ctxtHandle
128
+ #define streamSizes m_streamSizes
129
+ #endif
130
+
7
131
  #include <sstream>
8
132
  #include <cstring>
9
133
  #include <chrono>
@@ -249,11 +373,11 @@ bool TlsSocket::connect(const std::string& host, int port, int timeoutMs, bool c
249
373
 
250
374
  void TlsSocket::disconnectInternal() {
251
375
  if (m_hasCtxtHandle) {
252
- DeleteSecurityContext(&m_ctxtHandle);
376
+ DeleteSecurityContext(&ctxtHandle);
253
377
  m_hasCtxtHandle = false;
254
378
  }
255
379
  if (m_hasCredHandle) {
256
- FreeCredentialsHandle(&m_credHandle);
380
+ FreeCredentialsHandle(&credHandle);
257
381
  m_hasCredHandle = false;
258
382
  }
259
383
  if (m_socket != INVALID_SOCKET) {
@@ -298,7 +422,7 @@ bool TlsSocket::initializeSchannel() {
298
422
  &schannelCred,
299
423
  nullptr,
300
424
  nullptr,
301
- &m_credHandle,
425
+ &credHandle,
302
426
  &expiry
303
427
  );
304
428
 
@@ -337,7 +461,7 @@ bool TlsSocket::performClientHandshake() {
337
461
  TimeStamp expiry;
338
462
 
339
463
  status = InitializeSecurityContextW(
340
- &m_credHandle,
464
+ &credHandle,
341
465
  nullptr,
342
466
  const_cast<wchar_t*>(wServerName.c_str()),
343
467
  flags,
@@ -345,7 +469,7 @@ bool TlsSocket::performClientHandshake() {
345
469
  0,
346
470
  nullptr,
347
471
  0,
348
- &m_ctxtHandle,
472
+ &ctxtHandle,
349
473
  &outDesc,
350
474
  &outFlags,
351
475
  &expiry
@@ -404,8 +528,8 @@ bool TlsSocket::performClientHandshake() {
404
528
  outBuffers[0].BufferType = SECBUFFER_TOKEN;
405
529
 
406
530
  status = InitializeSecurityContextW(
407
- &m_credHandle,
408
- &m_ctxtHandle,
531
+ &credHandle,
532
+ &ctxtHandle,
409
533
  const_cast<wchar_t*>(wServerName.c_str()),
410
534
  flags,
411
535
  0,
@@ -477,7 +601,7 @@ bool TlsSocket::performClientHandshake() {
477
601
  }
478
602
 
479
603
  if (status == SEC_E_OK) {
480
- QueryContextAttributes(&m_ctxtHandle, SECPKG_ATTR_STREAM_SIZES, &m_streamSizes);
604
+ QueryContextAttributes(&ctxtHandle, SECPKG_ATTR_STREAM_SIZES, &streamSizes);
481
605
  m_hasCtxtHandle = true;
482
606
  // Save any extra (unconsumed) data to m_receiveBuffer so the caller
483
607
  // can read it (e.g. IMAP greeting piggybacked on the handshake).
@@ -505,22 +629,22 @@ bool TlsSocket::performClientHandshake() {
505
629
  bool TlsSocket::encryptMessage(const std::string& plaintext, std::vector<char>& ciphertext) {
506
630
  if (!m_hasCtxtHandle) return false;
507
631
 
508
- int needed = m_streamSizes.cbHeader + static_cast<int>(plaintext.size()) + m_streamSizes.cbTrailer;
632
+ int needed = streamSizes.cbHeader + static_cast<int>(plaintext.size()) + streamSizes.cbTrailer;
509
633
  std::vector<char> msg(needed);
510
634
 
511
635
  SecBuffer buffers[4];
512
- buffers[0].cbBuffer = m_streamSizes.cbHeader;
636
+ buffers[0].cbBuffer = streamSizes.cbHeader;
513
637
  buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
514
638
  buffers[0].pvBuffer = msg.data();
515
639
 
516
640
  buffers[1].cbBuffer = static_cast<unsigned long>(plaintext.size());
517
641
  buffers[1].BufferType = SECBUFFER_DATA;
518
- buffers[1].pvBuffer = msg.data() + m_streamSizes.cbHeader;
642
+ buffers[1].pvBuffer = msg.data() + streamSizes.cbHeader;
519
643
  memcpy(buffers[1].pvBuffer, plaintext.data(), plaintext.size());
520
644
 
521
- buffers[2].cbBuffer = m_streamSizes.cbTrailer;
645
+ buffers[2].cbBuffer = streamSizes.cbTrailer;
522
646
  buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
523
- buffers[2].pvBuffer = msg.data() + m_streamSizes.cbHeader + plaintext.size();
647
+ buffers[2].pvBuffer = msg.data() + streamSizes.cbHeader + plaintext.size();
524
648
 
525
649
  buffers[3].cbBuffer = 0;
526
650
  buffers[3].BufferType = SECBUFFER_EMPTY;
@@ -530,7 +654,7 @@ bool TlsSocket::encryptMessage(const std::string& plaintext, std::vector<char>&
530
654
  desc.cBuffers = 4;
531
655
  desc.pBuffers = buffers;
532
656
 
533
- SECURITY_STATUS status = EncryptMessage(&m_ctxtHandle, 0, &desc, 0);
657
+ SECURITY_STATUS status = EncryptMessage(&ctxtHandle, 0, &desc, 0);
534
658
  if (status != SEC_E_OK) return false;
535
659
 
536
660
  int totalSize = buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer;
@@ -563,7 +687,7 @@ int TlsSocket::decryptMessage(std::vector<char>& buffer, std::vector<char>& plai
563
687
  desc.cBuffers = 4;
564
688
  desc.pBuffers = buffers;
565
689
 
566
- SECURITY_STATUS status = DecryptMessage(&m_ctxtHandle, &desc, 0, nullptr);
690
+ SECURITY_STATUS status = DecryptMessage(&ctxtHandle, &desc, 0, nullptr);
567
691
  if (status == SEC_E_INCOMPLETE_MESSAGE) {
568
692
  // need more data
569
693
  return 0; // need more data
@@ -58,13 +58,13 @@ public:
58
58
  private:
59
59
  SOCKET m_socket = INVALID_SOCKET;
60
60
  bool m_tls = false;
61
- CredHandle m_credHandle{};
62
- CtxtHandle m_ctxtHandle{};
61
+ uint8_t m_credHandle[16];
62
+ uint8_t m_ctxtHandle[16];
63
63
  bool m_hasCredHandle = false;
64
64
  bool m_hasCtxtHandle = false;
65
65
  std::string m_serverName;
66
66
  bool m_checkCertificate = true;
67
- SecPkgContext_StreamSizes m_streamSizes{};
67
+ uint8_t m_streamSizes[24];
68
68
 
69
69
  std::mutex m_mutex;
70
70
  int m_lastError = 0; // stores WSAGetLastError() on failure
@@ -0,0 +1,5 @@
1
+ // ============================================================
2
+ // pch.cpp — Precompiled Header Implementation
3
+ // ============================================================
4
+
5
+ #include "pch.h"
@@ -0,0 +1,39 @@
1
+ // ============================================================
2
+ // pch.h — Precompiled Header
3
+ // ============================================================
4
+
5
+ #pragma once
6
+
7
+ #define NOMINMAX
8
+ #define WIN32_LEAN_AND_MEAN
9
+ #define SECURITY_WIN32
10
+
11
+ #include <windows.h>
12
+ #include <winsock2.h>
13
+ #include <ws2tcpip.h>
14
+ #include <winrt/Microsoft.ReactNative.h>
15
+ #include <winrt/Windows.Foundation.h>
16
+ #include <winrt/Windows.Foundation.Collections.h>
17
+
18
+ #include <string>
19
+ #include <vector>
20
+ #include <map>
21
+ #include <memory>
22
+ #include <mutex>
23
+ #include <thread>
24
+ #include <atomic>
25
+ #include <condition_variable>
26
+ #include <functional>
27
+ #include <optional>
28
+ #include <variant>
29
+ #include <set>
30
+ #include <regex>
31
+ #include <sstream>
32
+ #include <cctype>
33
+ #include <algorithm>
34
+ #include <chrono>
35
+ #include <cstring>
36
+ #include <cstdint>
37
+ #include <ctime>
38
+ #include <iomanip>
39
+ #include <cstdlib>
@@ -0,0 +1,30 @@
1
+ Microsoft Visual Studio Solution File, Format Version 12.00
2
+ # Visual Studio Version 17
3
+ VisualStudioVersion = 17.0.31903.59
4
+ MinimumVisualStudioVersion = 10.0.40219.1
5
+ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmailImapSmtp", "EmailImapSmtp\EmailImapSmtp.vcxproj", "{A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}"
6
+ EndProject
7
+ Global
8
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
9
+ Debug|x64 = Debug|x64
10
+ Debug|x86 = Debug|x86
11
+ Debug|ARM64 = Debug|ARM64
12
+ Release|x64 = Release|x64
13
+ Release|x86 = Release|x86
14
+ Release|ARM64 = Release|ARM64
15
+ EndGlobalSection
16
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
17
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|x64.ActiveCfg = Debug|x64
18
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|x64.Build.0 = Debug|x64
19
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|x86.ActiveCfg = Debug|x86
20
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|x86.Build.0 = Debug|x86
21
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|ARM64.ActiveCfg = Debug|ARM64
22
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Debug|ARM64.Build.0 = Debug|ARM64
23
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|x64.ActiveCfg = Release|x64
24
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|x64.Build.0 = Release|x64
25
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|x86.ActiveCfg = Release|x86
26
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|x86.Build.0 = Release|x86
27
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|ARM64.ActiveCfg = Release|ARM64
28
+ {A3B8E7F1-2C4D-5E6F-8A9B-0C1D2E3F4A5B}.Release|ARM64.Build.0 = Release|ARM64
29
+ EndGlobalSection
30
+ EndGlobal
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3
+ <PropertyGroup Label="ReactNativeWindowsExperimentalFeatures">
4
+ <!-- 不使用 Hermes -->
5
+ <UseHermes>false</UseHermes>
6
+ <!-- 不使用 WinUI 3 -->
7
+ <UseWinUI3>false</UseWinUI3>
8
+ <!-- 不使用实验性 NuGet -->
9
+ <UseExperimentalNuget>true</UseExperimentalNuget>
10
+ <RnwNewArch>true</RnwNewArch>
11
+ <RunCodegenWindows>false</RunCodegenWindows>
12
+ <!-- 不使用 Folly (不再需要) -->
13
+ <UseFolly>false</UseFolly>
14
+ </PropertyGroup>
15
+ </Project>
@@ -1,139 +0,0 @@
1
- // ============================================================
2
- // EmailImapSmtpModule.h — Windows TurboModule 实现
3
- // 通过 JSON 字符串与 JS 层通信,内部调用协议层 C++ 代码
4
- // ============================================================
5
-
6
- #pragma once
7
-
8
- #include <string>
9
- #include <unordered_map>
10
- #include <memory>
11
- #include <mutex>
12
-
13
- #include "winrt/Microsoft.ReactNative.h"
14
- #include "NativeModules.h"
15
-
16
- #include "ImapProtocol.h"
17
- #include "SmtpProtocol.h"
18
-
19
- namespace winrt::EmailImapSmtp {
20
-
21
- struct SessionState {
22
- std::unique_ptr<emailimap::ImapClient> imapClient;
23
- std::unique_ptr<emailimap::SmtpClient> smtpClient;
24
- bool imapConnected = false;
25
- bool smtpConnected = false;
26
- };
27
-
28
- REACT_MODULE(EmailImapSmtpModule);
29
- struct EmailImapSmtpModule {
30
- // ─── Session 管理 ─────────────────────────────────────
31
- std::unordered_map<std::string, std::shared_ptr<SessionState>> m_sessions;
32
- std::mutex m_mutex;
33
- int m_nextId = 1;
34
-
35
- std::string createSession() {
36
- auto state = std::make_shared<SessionState>();
37
- state->imapClient = std::make_unique<emailimap::ImapClient>();
38
- state->smtpClient = std::make_unique<emailimap::SmtpClient>();
39
- std::string id = "sess_" + std::to_string(m_nextId++);
40
- std::lock_guard<std::mutex> lock(m_mutex);
41
- m_sessions[id] = state;
42
- return id;
43
- }
44
-
45
- std::shared_ptr<SessionState> getSession(const std::string& id) {
46
- std::lock_guard<std::mutex> lock(m_mutex);
47
- auto it = m_sessions.find(id);
48
- if (it == m_sessions.end()) return nullptr;
49
- return it->second;
50
- }
51
-
52
- void removeSession(const std::string& id) {
53
- std::lock_guard<std::mutex> lock(m_mutex);
54
- m_sessions.erase(id);
55
- }
56
-
57
- // ─── IMAP 连接 ────────────────────────────────────────
58
-
59
- REACT_METHOD(imapConnect);
60
- std::string imapConnect(const std::string& configJson) noexcept {
61
- try {
62
- auto config = emailimap::ConnectionConfig{};
63
- // TODO: parse configJson → config
64
- // 使用 JSON 库(如 nlohmann/json)解析
65
-
66
- auto sessionId = createSession();
67
- auto session = getSession(sessionId);
68
- std::string error;
69
- if (session->imapClient->connect(config, error)) {
70
- session->imapConnected = true;
71
- return "{\"success\":true,\"sessionId\":\"" + sessionId + "\"}";
72
- }
73
- removeSession(sessionId);
74
- return "{\"success\":false,\"error\":\"" + escapeJson(error) + "\"}";
75
- } catch (const std::exception& e) {
76
- return "{\"success\":false,\"error\":\"" + escapeJson(e.what()) + "\"}";
77
- }
78
- }
79
-
80
- REACT_METHOD(imapDisconnect);
81
- void imapDisconnect(const std::string& sessionId) noexcept {
82
- auto session = getSession(sessionId);
83
- if (session && session->imapConnected) {
84
- session->imapClient->disconnect();
85
- session->imapConnected = false;
86
- }
87
- removeSession(sessionId);
88
- }
89
-
90
- // ─── SMTP ──────────────────────────────────────────────
91
-
92
- REACT_METHOD(smtpConnect);
93
- std::string smtpConnect(const std::string& configJson) noexcept {
94
- try {
95
- auto config = emailimap::SmtpConnectionConfig{};
96
- // TODO: parse configJson → config
97
-
98
- auto sessionId = createSession();
99
- auto session = getSession(sessionId);
100
- std::string error;
101
- if (session->smtpClient->connect(config, error)) {
102
- session->smtpConnected = true;
103
- return "{\"success\":true,\"sessionId\":\"" + sessionId + "\"}";
104
- }
105
- removeSession(sessionId);
106
- return "{\"success\":false,\"error\":\"" + escapeJson(error) + "\"}";
107
- } catch (const std::exception& e) {
108
- return "{\"success\":false,\"error\":\"" + escapeJson(e.what()) + "\"}";
109
- }
110
- }
111
-
112
- REACT_METHOD(smtpDisconnect);
113
- void smtpDisconnect(const std::string& sessionId) noexcept {
114
- auto session = getSession(sessionId);
115
- if (session && session->smtpConnected) {
116
- session->smtpClient->disconnect();
117
- session->smtpConnected = false;
118
- }
119
- removeSession(sessionId);
120
- }
121
-
122
- private:
123
- static std::string escapeJson(const std::string& s) {
124
- std::string result;
125
- for (char c : s) {
126
- switch (c) {
127
- case '"': result += "\\\""; break;
128
- case '\\': result += "\\\\"; break;
129
- case '\n': result += "\\n"; break;
130
- case '\r': result += "\\r"; break;
131
- case '\t': result += "\\t"; break;
132
- default: result += c;
133
- }
134
- }
135
- return result;
136
- }
137
- };
138
-
139
- } // namespace winrt::EmailImapSmtp