From 97adf68f6e1de2941a6563bd0c3447c45fdbe17a Mon Sep 17 00:00:00 2001 From: Karl Gustav Sterneberg <kg@roxen.com> Date: Thu, 3 May 2018 11:36:17 +0200 Subject: [PATCH] MIME: Setter for message boundary prefix. --- lib/modules/MIME.pmod/module.pmod | 53 ++++++++++++++++++++++++++++++- src/modules/MIME/testsuite.in | 12 +++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/modules/MIME.pmod/module.pmod b/lib/modules/MIME.pmod/module.pmod index c1efe16705..f3ee29c940 100644 --- a/lib/modules/MIME.pmod/module.pmod +++ b/lib/modules/MIME.pmod/module.pmod @@ -176,15 +176,66 @@ protected int(0..1) has_prefix(string|object s, string prefix) #endif +private string boundary_prefix; + +//! Set a message boundary prefix. The @[MIME.generate_boundary()] will use this +//! prefix when creating a boundary string. +//! +//! @throws +//! An error is thrown if @[boundary_prefix] doesn't adhere to @rfc{1521@}. +//! +//! @seealso +//! @[MIME.generate_boundary()], @[MIME.get_boundary_prefix()] +//! +//! @param boundary_prefix +//! This must adhere to @rfc{1521@} and can not be longer than 56 characters. +void set_boundary_prefix(string(8bit) boundary_prefix) +{ + // 5 upto 14 chars is randomly added to the boundary so the prefix must not + // risking overflowing the max-length of 70 chars + if (boundary_prefix && (sizeof(boundary_prefix) + 14) > 70) { + error("Too long boundary prefix. The boundary prefix can not be longer " + "than 56 characters.\n"); + } + + sscanf(boundary_prefix, "%*s%[^0-9a-zA-Z'()+_,./:=?-]", string illegal); + + if (illegal && sizeof(illegal)) { + error("An illegal character (%q) was found in the boundary prefix.\n", + illegal); + } + + this::boundary_prefix = boundary_prefix; +} + +//! Returns the @tt{boundary_prefix@} set via @[set_boundary_prefix()]. +//! +//! @seealso +//! @[MIME.set_boundary_prefix()], @[MIME.Message.setboundary()] +string(8bit) get_boundary_prefix() +{ + return boundary_prefix; +} + //! This function will create a string that can be used as a separator string -//! for multipart messages. The generated string is guaranteed not to appear +//! for multipart messages. If a boundary prefix has been set +//! using @[MIME.set_boundary_prefix()], the generated string will be prefixed +//! with the boundary prefix. +//! +//! The generated string is guaranteed not to appear //! in @tt{base64@}, @tt{quoted-printable@}, or @tt{x-uue@} encoded data. //! It is also unlikely to appear in normal text. This function is used by //! the cast method of the @tt{Message@} class if no boundary string is //! specified. //! +//! @seealso +//! @[MIME.set_boundary_prefix()] +//! string generate_boundary( ) { + if (boundary_prefix) { + return boundary_prefix + random( 1000000000 ); + } return "'ThIs-RaNdOm-StRiNg-/=_."+random( 1000000000 )+":"; } diff --git a/src/modules/MIME/testsuite.in b/src/modules/MIME/testsuite.in index f9b0173f43..204c087927 100644 --- a/src/modules/MIME/testsuite.in +++ b/src/modules/MIME/testsuite.in @@ -139,4 +139,16 @@ test_eq([[MIME.Message("MIME-Version: 1.0\r\n\r\nfoo\r\n")->getencoded()]], "foo test_equal([[MIME.Message((string)MIME.Message("foo\r\n", (["mImE-veRsion":"1.0"])))->headers]], (["mime-version":"1.0","content-length":"5"])) + +test_any([[ + string pf_in = "My-Pr3f1x(.0/9)"; + MIME.set_boundary_prefix(pf_in); + string pf_out = MIME.get_boundary_prefix(); + string boundary = MIME.generate_boundary(); + int nm = sscanf(boundary, pf_out + "=_.%d:", int n); + return pf_in == pf_out && + boundary[0..sizeof(pf_out)-1] == pf_out && + nm == 1 && n <= 1000000000; +]], 1) + END_MARKER -- GitLab