tests: Add test for the ssh key export.
[gnupg.git] / common / mbox-util.c
index 332f62f..c1f05b8 100644 (file)
@@ -5,27 +5,21 @@
  * This file is part of GnuPG.
  *
  * This file is free software; you can redistribute it and/or modify
- * it under the terms of either
- *
- *   - the GNU Lesser General Public License as published by the Free
- *     Software Foundation; either version 3 of the License, or (at
- *     your option) any later version.
- *
- * or
- *
- *   - the GNU General Public License as published by the Free
- *     Software Foundation; either version 2 of the License, or (at
- *     your option) any later version.
- *
- * or both in parallel, as here.
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
  *
  * This file is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/* NB: GPGME uses the same code to reflect our idea on how to extract
+ * a mail address from a user id.
  */
 
 #include <config.h>
@@ -50,6 +44,47 @@ string_count_chr (const char *string, int c)
   return count;
 }
 
+static int
+mem_count_chr (const void *buffer, int c, size_t length)
+{
+  const char *s = buffer;
+  int count;
+
+  for (count=0; length; length--, s++)
+    if (*s == c)
+      count++;
+  return count;
+}
+
+
+/* This is a case-sensitive version of our memistr.  I wonder why no
+   standard function memstr exists but I better do not use the name
+   memstr to avoid future conflicts.  */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+  const unsigned char *buf = buffer;
+  const unsigned char *t = (const unsigned char *)buf;
+  const unsigned char *s = (const unsigned char *)sub;
+  size_t n = buflen;
+
+  for ( ; n ; t++, n-- )
+    {
+      if (*t == *s)
+        {
+          for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+            ;
+          if (!*s)
+            return (const char*)buf;
+          t = (const unsigned char *)buf;
+          s = (const unsigned char *)sub ;
+          n = buflen;
+       }
+    }
+  return NULL;
+}
+
+
 
 static int
 string_has_ctrl_or_space (const char *string)
@@ -74,58 +109,73 @@ has_dotdot_after_at (const char *string)
 }
 
 
-/* Check whether the string has characters not valid in an RFC-822
-   address.  To cope with OpenPGP we ignore non-ascii characters
-   so that for example umlauts are legal in an email address.  An
-   OpenPGP user ID must be utf-8 encoded but there is no strict
-   requirement for RFC-822.  Thus to avoid IDNA encoding we put the
-   address verbatim as utf-8 into the user ID under the assumption
-   that mail programs handle IDNA at a lower level and take OpenPGP
-   user IDs as utf-8.  Note that we can't do an utf-8 encoding
-   checking here because in keygen.c this function is called with the
-   native encoding and native to utf-8 encoding is only done  later.  */
+/* Check whether BUFFER has characters not valid in an RFC-822
+   address.  LENGTH gives the length of BUFFER.
+
+   To cope with OpenPGP we ignore non-ascii characters so that for
+   example umlauts are legal in an email address.  An OpenPGP user ID
+   must be utf-8 encoded but there is no strict requirement for
+   RFC-822.  Thus to avoid IDNA encoding we put the address verbatim
+   as utf-8 into the user ID under the assumption that mail programs
+   handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
+   Note that we can't do an utf-8 encoding checking here because in
+   keygen.c this function is called with the native encoding and
+   native to utf-8 encoding is only done later.  */
 int
-has_invalid_email_chars (const char *s)
+has_invalid_email_chars (const void *buffer, size_t length)
 {
+  const unsigned char *s = buffer;
   int at_seen=0;
   const char *valid_chars=
     "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
 
-  for ( ; *s; s++ )
+  for ( ; length && *s; length--, s++ )
     {
-      if ( (*s & 0x80) )
+      if ((*s & 0x80))
         continue; /* We only care about ASCII.  */
-      if ( *s == '@' )
+      if (*s == '@')
         at_seen=1;
-      else if ( !at_seen && !(strchr (valid_chars, *s)
-                              || strchr ("!#$%&'*+/=?^`{|}~", *s)))
+      else if (!at_seen && !(strchr (valid_chars, *s)
+                             || strchr ("!#$%&'*+/=?^`{|}~", *s)))
         return 1;
-      else if ( at_seen && !strchr( valid_chars, *s ) )
+      else if (at_seen && !strchr (valid_chars, *s))
         return 1;
     }
   return 0;
 }
 
 
+/* Same as is_valid_mailbox (see below) but operates on non-nul
+   terminated buffer.  */
+int
+is_valid_mailbox_mem (const void *name_arg, size_t namelen)
+{
+  const char *name = name_arg;
+
+  return !( !name
+            || !namelen
+            || has_invalid_email_chars (name, namelen)
+            || mem_count_chr (name, '@', namelen) != 1
+            || *name == '@'
+            || name[namelen-1] == '@'
+            || name[namelen-1] == '.'
+            || my_memstr (name, namelen, ".."));
+}
+
+
 /* Check whether NAME represents a valid mailbox according to
    RFC822. Returns true if so. */
 int
 is_valid_mailbox (const char *name)
 {
-  return !( !name
-            || !*name
-            || has_invalid_email_chars (name)
-            || string_count_chr (name,'@') != 1
-            || *name == '@'
-            || name[strlen(name)-1] == '@'
-            || name[strlen(name)-1] == '.'
-            || strstr (name, "..") );
+  return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
 }
 
 
 /* Return the mailbox (local-part@domain) form a standard user id.
-   Caller must free the result.  Returns NULL if no valid mailbox was
-   found (or we are out of memory). */
+   All plain ASCII characters in the result are converted to
+   lowercase.  Caller must free the result.  Returns NULL if no valid
+   mailbox was found (or we are out of memory). */
 char *
 mailbox_from_userid (const char *userid)
 {
@@ -176,7 +226,7 @@ mailbox_from_userid (const char *userid)
   else
     errno = EINVAL;
 
-  return result;
+  return result? ascii_strlwr (result): NULL;
 }