diff options
Diffstat (limited to 'contrib/sendmail/libsm/uxtext_unquote.c')
-rw-r--r-- | contrib/sendmail/libsm/uxtext_unquote.c | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/contrib/sendmail/libsm/uxtext_unquote.c b/contrib/sendmail/libsm/uxtext_unquote.c new file mode 100644 index 000000000000..67e77c306048 --- /dev/null +++ b/contrib/sendmail/libsm/uxtext_unquote.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2020 Proofpoint, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> +#include <sm/sendmail.h> + +/* +** based on +** https://github.com/aox/encodings/utf.cpp +** see license.txt included below. +*/ + +#if USE_EAI +#include <ctype.h> +#define SM_ISDIGIT(c) (isascii(c) && isdigit(c)) + +#include <sm/assert.h> + +/* for prototype */ +#include <sm/ixlen.h> + +# if 0 +/* +** RFC 6533: +** +** In the ABNF below, all productions not defined in this document are +** defined in Appendix B of [RFC5234], in Section 4 of [RFC3629], or in +** [RFC3464]. +** +** utf-8-type-addr = "utf-8;" utf-8-enc-addr +** utf-8-address = Mailbox ; Mailbox as defined in [RFC6531]. +** utf-8-enc-addr = utf-8-addr-xtext / +** utf-8-addr-unitext / +** utf-8-address +** utf-8-addr-xtext = 1*(QCHAR / EmbeddedUnicodeChar) +** ; 7bit form of utf-8-addr-unitext. +** ; Safe for use in the ORCPT [RFC3461] +** ; parameter even when SMTPUTF8 SMTP +** ; extension is not advertised. +** utf-8-addr-unitext = 1*(QUCHAR / EmbeddedUnicodeChar) +** ; MUST follow utf-8-address ABNF when +** ; dequoted. +** ; Safe for using in the ORCPT [RFC3461] +** ; parameter when SMTPUTF8 SMTP extension +** ; is also advertised. +** QCHAR = %x21-2a / %x2c-3c / %x3e-5b / %x5d-7e +** ; ASCII printable characters except +** ; CTLs, SP, '\', '+', '='. +** QUCHAR = QCHAR / UTF8-2 / UTF8-3 / UTF8-4 +** ; ASCII printable characters except +** ; CTLs, SP, '\', '+' and '=', plus +** ; other Unicode characters encoded in UTF-8 +** EmbeddedUnicodeChar = %x5C.78 "{" HEXPOINT "}" +** ; starts with "\x" +** HEXPOINT = ( ( "0"/"1" ) %x31-39 ) / "10" / "20" / +** "2B" / "3D" / "7F" / ; all xtext-specials +** "5C" / (HEXDIG8 HEXDIG) / ; 2-digit forms +** ( NZHEXDIG 2(HEXDIG) ) / ; 3-digit forms +** ( NZDHEXDIG 3(HEXDIG) ) / ; 4-digit forms excluding +** ( "D" %x30-37 2(HEXDIG) ) / ; ... surrogate +** ( NZHEXDIG 4(HEXDIG) ) / ; 5-digit forms +** ( "10" 4*HEXDIG ) ; 6-digit forms +** ; represents either "\" or a Unicode code point outside +** ; the ASCII repertoire +** HEXDIG8 = %x38-39 / "A" / "B" / "C" / "D" / "E" / "F" +** ; HEXDIG excluding 0-7 +** NZHEXDIG = %x31-39 / "A" / "B" / "C" / "D" / "E" / "F" +** ; HEXDIG excluding "0" +** NZDHEXDIG = %x31-39 / "A" / "B" / "C" / "E" / "F" +** ; HEXDIG excluding "0" and "D" +*/ +# endif /* 0 */ + +/* +** UXTEXT_UNQUOTE -- "unquote" a utf-8-addr-unitext +** +** Parameters: +** quoted -- original string [x] +** unquoted -- "decoded" string [x] (buffer provided by caller) +** if NULL this is basically a syntax check. +** olen -- length of unquoted (must be > 0) +** +** Returns: +** >0: length of "decoded" string +** <0: error +*/ + +int +uxtext_unquote(quoted, unquoted, olen) + const char *quoted; + char *unquoted; + int olen; +{ + const unsigned char *cp; + int ch, len; + +#define APPCH(ch) do \ + { \ + if (len >= olen) \ + return 0 - olen; \ + if (NULL != unquoted) \ + unquoted[len] = (char) (ch); \ + len++; \ + } while (0) + + SM_REQUIRE(olen > 0); + SM_REQUIRE(NULL != quoted); + len = 0; + for (cp = (const unsigned char *) quoted; (ch = *cp) != 0; cp++) + { + if (ch == '\\' && cp[1] == 'x' && cp[2] == '{') + { + int uc = 0; + + cp += 2; + while ((ch = *++cp) != '}') + { + if (SM_ISDIGIT(ch)) + uc = (uc << 4) + (ch - '0'); + else if (ch >= 'a' && ch <= 'f') + uc = (uc << 4) + (ch - 'a' + 10); + else if (ch >= 'A' && ch <= 'F') + uc = (uc << 4) + (ch - 'A' + 10); + else + return 0 - len; + if (uc > 0x10ffff) + return 0 - len; + } + + if (uc < 0x80) + APPCH(uc); + else if (uc < 0x800) + { + APPCH(0xc0 | ((char) (uc >> 6))); + APPCH(0x80 | ((char) (uc & 0x3f))); + } + else if (uc < 0x10000) + { + APPCH(0xe0 | ((char) (uc >> 12))); + APPCH(0x80 | ((char) (uc >> 6) & 0x3f)); + APPCH(0x80 | ((char) (uc & 0x3f))); + } + else if (uc < 0x200000) + { + APPCH(0xf0 | ((char) (uc >> 18))); + APPCH(0x80 | ((char) (uc >> 12) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 6) & 0x3f)); + APPCH(0x80 | ((char) (uc & 0x3f))); + } + else if (uc < 0x4000000) + { + APPCH(0xf8 | ((char) (uc >> 24))); + APPCH(0x80 | ((char) (uc >> 18) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 12) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 6) & 0x3f)); + APPCH(0x80 | ((char) (uc & 0x3f))); + } + else + { + APPCH(0xfc | ((char) (uc >> 30))); + APPCH(0x80 | ((char) (uc >> 24) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 18) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 12) & 0x3f)); + APPCH(0x80 | ((char) (uc >> 6) & 0x3f)); + APPCH(0x80 | ((char) (uc & 0x3f))); + } + } + else + APPCH(ch); + } + APPCH('\0'); + return len; +} + +# if 0 +aox/doc/readme/license.txt + +Copyright (c) 2003-2014, Archiveopteryx and its contributors. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written +agreement is hereby granted, provided that the above copyright notice +and this paragraph and the following two paragraphs appear in all +copies. + +IN NO EVENT SHALL ORYX BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, +ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF +ORYX HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +ORYX SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" +BASIS, AND ORYX HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, +UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +# endif /* 0 */ +#endif /* USE_EAI */ |