namespace AIStudio.Assistants.BeyondFactsLab; /// /// Prepares the mail with which a person sends a shared session to the research team of the BeyondFacts Lab. /// /// /// The lab writes no mail itself: a mailto link opens the mail program of the person with the address, the subject, /// and a short text, and the person attaches the exported file and sends it, from their own address. The link holds /// nothing of the session, since mail programs accept only short links; the runtime opens it outside the app. /// public static class BflShareMail { private static string TB(string fallbackEN) => Tools.PluginSystem.I18N.I.T(fallbackEN, typeof(BflShareMail).Namespace, nameof(BflShareMail)); /// /// The address of the research team. /// /// /// A placeholder until the research team names its address; it is replaced before the release which brings the /// lab, as the lab is a prototype until then. /// public const string RECIPIENT = "xxx@xxx.xxx"; /// /// The longest link the lab hands to a mail program. Some programs on Windows refuse longer ones. /// public const int MAX_URI_LENGTH = 1_800; /// /// The line break of a mailto link, which RFC 6068 demands as CR LF. /// private const string LINE_BREAK = "\r\n"; /// /// Gets the subject of the mail, in the language of the app. /// /// /// The mail speaks to the research team, not to the person, so neither the subject nor the text addresses anybody: /// the form of address the person chose for the lab does not fit the research team. /// public static string Subject => TB("A shared session of the BeyondFacts Lab"); /// /// Gets the text of the mail, in the language of the app. /// public static string Body => TB(""" Hello, attached is a session of the BeyondFacts Lab, which I share for the research on the lab. Before I exported it, AI Studio removed the personal details it recognized. Kind regards """); /// /// Creates the link which opens the mail to the research team. /// public static string CreateUri() => CreateUri(RECIPIENT, Subject, Body); /// /// Creates a mailto link, with everything encoded as RFC 6068 demands. /// /// /// A link longer than MAX_URI_LENGTH loses the end of its text, at a word, so that no mail program refuses it. /// /// The address. /// The subject. /// The text, with line breaks of any kind. /// The link. public static string CreateUri(string recipient, string subject, string body) { var at = recipient.LastIndexOf('@'); var address = at < 0 ? Uri.EscapeDataString(recipient) : $"{Uri.EscapeDataString(recipient[..at])}@{Uri.EscapeDataString(recipient[(at + 1)..])}"; var prefix = $"mailto:{address}?subject={Uri.EscapeDataString(subject.ReplaceLineEndings(" "))}"; var text = body.Trim().ReplaceLineEndings("\n"); var uri = Compose(prefix, text); while (uri.Length > MAX_URI_LENGTH && text.Length > 0) { var cut = text.LastIndexOfAny([' ', '\n']); text = cut > 0 ? text[..cut].TrimEnd() : string.Empty; uri = Compose(prefix, text); } return uri; } /// /// Puts the link together from its beginning and its text. /// /// The link up to its subject. /// The text, with LF line breaks. private static string Compose(string prefix, string text) => text.Length is 0 ? prefix : $"{prefix}&body={Uri.EscapeDataString(text.Replace("\n", LINE_BREAK))}"; }