Skip to content

Commit f602c34

Browse files
committed
Add option to only use known mail servers to SMTP, IMAP and POP3 blocks
Closes #908
1 parent 575021b commit f602c34

7 files changed

Lines changed: 139 additions & 4 deletions

File tree

RuriLib.Tests/Blocks/Requests/MailRequestBlocksTests.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
using ImapMethods = RuriLib.Blocks.Requests.Imap.Methods;
33
using Pop3Methods = RuriLib.Blocks.Requests.Pop3.Methods;
44
using RuriLib.Exceptions;
5+
using RuriLib.Functions.Imap;
6+
using RuriLib.Functions.Pop3;
7+
using RuriLib.Functions.Smtp;
58
using RuriLib.Logging;
69
using RuriLib.Models.Bots;
710
using RuriLib.Models.Configs;
811
using RuriLib.Models.Data;
912
using RuriLib.Models.Environment;
13+
using RuriLib.Providers.Emails;
1014
using SmtpMethods = RuriLib.Blocks.Requests.Smtp.Methods;
1115
using RuriLib.Tests.Utils.Mockup;
1216
using System.Collections.Generic;
@@ -123,6 +127,45 @@ public async Task SmtpSendMailAdvanced_WithoutClient_Throws()
123127
Assert.Equal("Connect the SMTP client first!", ex.Message);
124128
}
125129

130+
[Fact]
131+
public async Task SmtpAutoConnect_KnownServersOnly_DoesNotFallback()
132+
{
133+
var repository = new InMemoryEmailDomainRepository();
134+
repository.AddSmtp("test.local", "127.0.0.1", 1);
135+
var data = NewBotData(repository);
136+
137+
var ex = await Assert.ThrowsAsync<BlockExecutionException>(() =>
138+
SmtpMethods.SmtpAutoConnect(data, "test1@test.local", 250, SmtpAutoConnectMode.KnownServersOnly));
139+
140+
Assert.Equal("Exhausted the known SMTP servers from smtpdomains.dat, failed to connect!", ex.Message);
141+
}
142+
143+
[Fact]
144+
public async Task ImapAutoConnect_KnownServersOnly_DoesNotFallback()
145+
{
146+
var repository = new InMemoryEmailDomainRepository();
147+
repository.AddImap("test.local", "127.0.0.1", 1);
148+
var data = NewBotData(repository);
149+
150+
var ex = await Assert.ThrowsAsync<BlockExecutionException>(() =>
151+
ImapMethods.ImapAutoConnect(data, "test1@test.local", 250, ImapAutoConnectMode.KnownServersOnly));
152+
153+
Assert.Equal("Exhausted the known IMAP servers from imapdomains.dat, failed to connect!", ex.Message);
154+
}
155+
156+
[Fact]
157+
public async Task Pop3AutoConnect_KnownServersOnly_DoesNotFallback()
158+
{
159+
var repository = new InMemoryEmailDomainRepository();
160+
repository.AddPop3("test.local", "127.0.0.1", 1);
161+
var data = NewBotData(repository);
162+
163+
var ex = await Assert.ThrowsAsync<BlockExecutionException>(() =>
164+
Pop3Methods.Pop3AutoConnect(data, "test1@test.local", 250, Pop3AutoConnectMode.KnownServersOnly));
165+
166+
Assert.Equal("Exhausted the known POP3 servers from pop3domains.dat, failed to connect!", ex.Message);
167+
}
168+
126169
private static ProtocolLogger CreateLogger(string content)
127170
{
128171
var stream = new MemoryStream(Encoding.UTF8.GetBytes(content))
@@ -132,10 +175,11 @@ private static ProtocolLogger CreateLogger(string content)
132175
return new ProtocolLogger(stream);
133176
}
134177

135-
private static BotData NewBotData()
178+
private static BotData NewBotData(IEmailDomainRepository? emailDomains = null)
136179
=> new(
137180
new BotProviders(null!)
138181
{
182+
EmailDomains = emailDomains ?? new InMemoryEmailDomainRepository(),
139183
ProxySettings = new MockedProxySettingsProvider(),
140184
Security = new MockedSecurityProvider()
141185
},

RuriLib/Blocks/Requests/Imap/Methods.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ public static class Methods
3737
/// Connects to an IMAP server by automatically detecting the host and port.
3838
/// </summary>
3939
[Block("Connects to an IMAP server by automatically detecting the host and port")]
40-
public static async Task ImapAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
40+
public static async Task ImapAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000,
41+
[BlockParam("Mode", "Choose whether to use only the known entries from imapdomains.dat or all discovery strategies.")]
42+
ImapAutoConnectMode mode = ImapAutoConnectMode.Full)
4143
{
4244
data.Logger.LogHeader();
4345

@@ -71,6 +73,11 @@ public static async Task ImapAutoConnect(BotData data, string email, int timeout
7173
}
7274
}
7375

76+
if (mode == ImapAutoConnectMode.KnownServersOnly)
77+
{
78+
throw new BlockExecutionException("Exhausted the known IMAP servers from imapdomains.dat, failed to connect!");
79+
}
80+
7481
// Thunderbird autoconfig
7582
candidates.Clear();
7683
var thunderbirdUrl = $"https://live.mozillamessaging.com/autoconfig/v1.1/{domain}";
@@ -217,6 +224,13 @@ public static async Task ImapAutoConnect(BotData data, string email, int timeout
217224
throw new BlockExecutionException("Exhausted all possibilities, failed to connect!");
218225
}
219226

227+
/// <summary>
228+
/// Connects to an IMAP server by automatically detecting the host and port.
229+
/// </summary>
230+
/// <remarks>Backwards-compatible overload without the mode flag.</remarks>
231+
public static Task ImapAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
232+
=> ImapAutoConnect(data, email, timeoutMilliseconds, ImapAutoConnectMode.Full);
233+
220234
private static async Task<bool> TryConnect(BotData data, ImapClient client, string domain, HostEntry entry)
221235
{
222236
data.Logger.Log($"Trying {entry.Host} on port {entry.Port}...", LogColors.DarkOrchid);

RuriLib/Blocks/Requests/Pop3/Methods.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ public static class Methods
3434
/// Connects to a POP3 server by automatically detecting the host and port.
3535
/// </summary>
3636
[Block("Connects to a POP3 server by automatically detecting the host and port")]
37-
public static async Task Pop3AutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
37+
public static async Task Pop3AutoConnect(BotData data, string email, int timeoutMilliseconds = 60000,
38+
[BlockParam("Mode", "Choose whether to use only the known entries from pop3domains.dat or all discovery strategies.")]
39+
Pop3AutoConnectMode mode = Pop3AutoConnectMode.Full)
3840
{
3941
data.Logger.LogHeader();
4042

@@ -68,6 +70,11 @@ public static async Task Pop3AutoConnect(BotData data, string email, int timeout
6870
}
6971
}
7072

73+
if (mode == Pop3AutoConnectMode.KnownServersOnly)
74+
{
75+
throw new BlockExecutionException("Exhausted the known POP3 servers from pop3domains.dat, failed to connect!");
76+
}
77+
7178
// Thunderbird autoconfig
7279
candidates.Clear();
7380
var thunderbirdUrl = $"https://live.mozillamessaging.com/autoconfig/v1.1/{domain}";
@@ -214,6 +221,13 @@ public static async Task Pop3AutoConnect(BotData data, string email, int timeout
214221
throw new BlockExecutionException("Exhausted all possibilities, failed to connect!");
215222
}
216223

224+
/// <summary>
225+
/// Connects to a POP3 server by automatically detecting the host and port.
226+
/// </summary>
227+
/// <remarks>Backwards-compatible overload without the mode flag.</remarks>
228+
public static Task Pop3AutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
229+
=> Pop3AutoConnect(data, email, timeoutMilliseconds, Pop3AutoConnectMode.Full);
230+
217231
private static async Task<bool> TryConnect(BotData data, Pop3Client client, string domain, HostEntry entry)
218232
{
219233
data.Logger.Log($"Trying {entry.Host} on port {entry.Port}...", LogColors.Mantis);

RuriLib/Blocks/Requests/Smtp/Methods.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public static class Methods
3636
/// Connects to a SMTP server by automatically detecting the host and port.
3737
/// </summary>
3838
[Block("Connects to a SMTP server by automatically detecting the host and port")]
39-
public static async Task SmtpAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
39+
public static async Task SmtpAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000,
40+
[BlockParam("Mode", "Choose whether to use only the known entries from smtpdomains.dat or all discovery strategies.")]
41+
SmtpAutoConnectMode mode = SmtpAutoConnectMode.Full)
4042
{
4143
data.Logger.LogHeader();
4244

@@ -69,6 +71,11 @@ public static async Task SmtpAutoConnect(BotData data, string email, int timeout
6971
}
7072
}
7173

74+
if (mode == SmtpAutoConnectMode.KnownServersOnly)
75+
{
76+
throw new BlockExecutionException("Exhausted the known SMTP servers from smtpdomains.dat, failed to connect!");
77+
}
78+
7279
// Thunderbird autoconfig
7380
candidates.Clear();
7481
var thunderbirdUrl = $"https://live.mozillamessaging.com/autoconfig/v1.1/{domain}";
@@ -218,6 +225,13 @@ public static async Task SmtpAutoConnect(BotData data, string email, int timeout
218225
throw new BlockExecutionException("Exhausted all possibilities, failed to connect!");
219226
}
220227

228+
/// <summary>
229+
/// Connects to a SMTP server by automatically detecting the host and port.
230+
/// </summary>
231+
/// <remarks>Backwards-compatible overload without the mode flag.</remarks>
232+
public static Task SmtpAutoConnect(BotData data, string email, int timeoutMilliseconds = 60000)
233+
=> SmtpAutoConnect(data, email, timeoutMilliseconds, SmtpAutoConnectMode.Full);
234+
221235
private static async Task<bool> TryConnect(BotData data, SmtpClient client, string domain, HostEntry entry)
222236
{
223237
data.Logger.Log($"Trying {entry.Host} on port {entry.Port}...", LogColors.LightBrown);
@@ -230,6 +244,7 @@ private static async Task<bool> TryConnect(BotData data, SmtpClient client, stri
230244
if (!client.Capabilities.HasFlag(SmtpCapabilities.Authentication))
231245
{
232246
data.Logger.Log($"Server doesn't support authentication, trying another one...");
247+
await client.DisconnectAsync(true, data.CancellationToken).ConfigureAwait(false);
233248
return false;
234249
}
235250

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace RuriLib.Functions.Imap;
2+
3+
/// <summary>
4+
/// Controls how IMAP auto-connect discovers candidate servers.
5+
/// </summary>
6+
public enum ImapAutoConnectMode
7+
{
8+
/// <summary>
9+
/// Try known servers first, then fall back to all discovery strategies.
10+
/// </summary>
11+
Full,
12+
/// <summary>
13+
/// Only try the servers already known in <c>imapdomains.dat</c>.
14+
/// </summary>
15+
KnownServersOnly
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace RuriLib.Functions.Pop3;
2+
3+
/// <summary>
4+
/// Controls how POP3 auto-connect discovers candidate servers.
5+
/// </summary>
6+
public enum Pop3AutoConnectMode
7+
{
8+
/// <summary>
9+
/// Try known servers first, then fall back to all discovery strategies.
10+
/// </summary>
11+
Full,
12+
/// <summary>
13+
/// Only try the servers already known in <c>pop3domains.dat</c>.
14+
/// </summary>
15+
KnownServersOnly
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace RuriLib.Functions.Smtp;
2+
3+
/// <summary>
4+
/// Controls how SMTP auto-connect discovers candidate servers.
5+
/// </summary>
6+
public enum SmtpAutoConnectMode
7+
{
8+
/// <summary>
9+
/// Try known servers first, then fall back to all discovery strategies.
10+
/// </summary>
11+
Full,
12+
/// <summary>
13+
/// Only try the servers already known in <c>smtpdomains.dat</c>.
14+
/// </summary>
15+
KnownServersOnly
16+
}

0 commit comments

Comments
 (0)