mirror of
https://github.com/MindWorkAI/AI-Studio.git
synced 2026-10-05 13:49:41 +00:00
Build and Release / Determine run mode (push) Waiting to run
Build and Release / Read metadata (push) Blocked by required conditions
Build and Release / Sync Flatpak repo (push) Blocked by required conditions
Build and Release / Collect Flatpak artifacts (push) Blocked by required conditions
Build and Release / Verify (push) Waiting to run
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-pc-windows-msvc.exe, win-arm64, windows-latest, aarch64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-unknown-linux-gnu, linux-arm64, ubuntu-22.04-arm, aarch64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-apple-darwin, osx-x64, macos-latest, x86_64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-pc-windows-msvc.exe, win-x64, windows-latest, x86_64-pc-windows-msvc, nsis,updater, nsis) (push) Blocked by required conditions
Build and Release / Prepare & create release (push) Blocked by required conditions
Build and Release / Publish release (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-aarch64-apple-darwin, osx-arm64, macos-latest, aarch64-apple-darwin, dmg,app,updater, dmg) (push) Blocked by required conditions
Build and Release / Build app (${{ matrix.dotnet_runtime }}) (-x86_64-unknown-linux-gnu, linux-x64, ubuntu-22.04, x86_64-unknown-linux-gnu, appimage,updater, appimage) (push) Blocked by required conditions
105 lines
4.8 KiB
C#
105 lines
4.8 KiB
C#
using AIStudio.Settings.DataModel;
|
|
using AIStudio.Tools.Rust;
|
|
using AIStudio.Tools.Validation;
|
|
|
|
using MailKit;
|
|
|
|
using MimeKit;
|
|
|
|
namespace AIStudio.Tools.Mail;
|
|
|
|
/// <summary>
|
|
/// Decides which attachments of a mail count as such, and which of them get their text read.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Everything here works on the structure of a mail, so nothing of an attachment is fetched before
|
|
/// it is clear that its text is wanted. Read are documents alone, the same types a local folder
|
|
/// indexes. Whatever else a mail carries, e.g. images or archives, is known by its name only.
|
|
/// </remarks>
|
|
public static class MailAttachmentRules
|
|
{
|
|
private const string BASE64_ENCODING = "base64";
|
|
|
|
private const long BYTES_PER_MEGABYTE = 1024L * 1024L;
|
|
|
|
/// <summary>
|
|
/// Whether a part is the signature of a signed mail rather than something the sender attached.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// A signed mail carries its signature as a part of its own, which many programs mark as an
|
|
/// attachment. A reader never sees it as one, since a mail program shows a seal instead, and it
|
|
/// has no text to read.
|
|
/// </remarks>
|
|
/// <param name="contentType">The content type of the part.</param>
|
|
public static bool IsSignature(ContentType contentType) =>
|
|
contentType.IsMimeType("application", "pkcs7-signature")
|
|
|| contentType.IsMimeType("application", "x-pkcs7-signature")
|
|
|| contentType.IsMimeType("application", "pgp-signature");
|
|
|
|
/// <summary>
|
|
/// Up to which size the text of an attachment is read.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// A size beyond what the dialog allows, e.g. from a settings file written by hand, is brought
|
|
/// back into that range. Attachments are a cost of their own, and no value should open them up
|
|
/// without bounds.
|
|
/// </remarks>
|
|
/// <param name="mailbox">The mailbox.</param>
|
|
/// <returns>The size in megabytes, or null when the mailbox reads no attachments at all.</returns>
|
|
public static int? GetMaxSizeMegabytes(DataSourceMailbox mailbox) => mailbox.IndexAttachments
|
|
? Math.Clamp(mailbox.MaxAttachmentSizeMegabytes, DataSourceValidation.MIN_ATTACHMENT_SIZE_MEGABYTES, DataSourceValidation.MAX_ATTACHMENT_SIZE_MEGABYTES)
|
|
: null;
|
|
|
|
/// <summary>
|
|
/// The file type of an attachment, from its name or else from its content type.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Only ever used after checking it against the known document types, which is what keeps a
|
|
/// name of the sender's choosing from becoming part of a path.
|
|
/// </remarks>
|
|
/// <param name="part">The attachment.</param>
|
|
/// <returns>The extension in lower case and without a dot, or empty when there is none.</returns>
|
|
public static string GetExtension(BodyPartBasic part)
|
|
{
|
|
var extension = Path.GetExtension(MailTextNormalization.NormalizeHeaderValue(part.FileName)).TrimStart('.');
|
|
if (extension.Length is 0 && MimeTypes.TryGetExtension(part.ContentType.MimeType, out var contentTypeExtension))
|
|
extension = contentTypeExtension.TrimStart('.');
|
|
|
|
return extension.ToLowerInvariant();
|
|
}
|
|
|
|
/// <summary>
|
|
/// How large an attachment is once it is decoded, as far as the structure of the mail tells.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The server reports the size as the attachment travels, which with Base64 is a third more than
|
|
/// the file the user sees. The estimate errs a little to the large side, since it counts the line
|
|
/// breaks of the encoding as well.
|
|
/// </remarks>
|
|
/// <param name="part">The attachment.</param>
|
|
/// <returns>The estimated size in bytes.</returns>
|
|
public static long EstimateDecodedSize(BodyPartBasic part) => string.Equals(part.ContentTransferEncoding, BASE64_ENCODING, StringComparison.OrdinalIgnoreCase)
|
|
? part.Octets / 4L * 3L
|
|
: part.Octets;
|
|
|
|
/// <summary>
|
|
/// Why the text of an attachment is not read.
|
|
/// </summary>
|
|
/// <param name="part">The attachment.</param>
|
|
/// <param name="maxSizeMegabytes">Up to which size attachments are read, or null when none are, cf. GetMaxSizeMegabytes.</param>
|
|
/// <returns>The reason, or null when the text is to be read.</returns>
|
|
public static MailPartTextState? GetReasonToSkip(BodyPartBasic part, int? maxSizeMegabytes)
|
|
{
|
|
if (maxSizeMegabytes is not { } maxSize)
|
|
return MailPartTextState.ATTACHMENTS_DISABLED;
|
|
|
|
if (!FileTypes.IsAllowedExtension(GetExtension(part), FileTypes.DOCUMENT))
|
|
return MailPartTextState.UNSUPPORTED_TYPE;
|
|
|
|
// Beyond what can be fetched at all, an attachment is too large whatever the limit:
|
|
if (EstimateDecodedSize(part) > maxSize * BYTES_PER_MEGABYTE || part.Octets > MailAttachmentPieces.MAX_OCTETS)
|
|
return MailPartTextState.TOO_LARGE;
|
|
|
|
return null;
|
|
}
|
|
} |