* gpg.sgml: Clarify that --charset applies to informational strings and
[gnupg.git] / sm / base64.c
index 4d16209..07f546e 100644 (file)
@@ -1,5 +1,5 @@
 /* base64.c 
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -49,12 +49,13 @@ struct reader_cb_parm_s {
 
   int autodetect; /* try to detect the input encoding */
   int assume_pem; /* assume input encoding is PEM */
-  int assume_base64; /* assume inpout is base64 encoded */
+  int assume_base64; /* assume input is base64 encoded */
 
   int identified;
   int is_pem;
   int is_base64;
   int stop_seen;
+  int might_be_smime;
 
   struct {
     int idx;
@@ -121,6 +122,31 @@ static unsigned char asctobin[256] = {
 };
 
 
+static int
+has_only_base64 (const unsigned char *line, int linelen)
+{
+  if (linelen < 20)
+    return 0;
+  for (; linelen; line++, linelen--)
+    {
+      if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
+          break;
+      if ( !strchr (bintoasc, *line) )
+        return 0;
+    }
+  return 1;  /* yes */
+}
+
+static int
+is_empty_line (const unsigned char *line, int linelen)
+{
+  if (linelen >= 2 && *line == '\r' && line[1] == '\n')
+    return 1;
+  if (linelen >= 1 && *line == '\n')
+    return 1;
+  return 0;
+}
+
 
 static int
 base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
@@ -152,7 +178,7 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
           if (c == '\n')
             {
               parm->have_lf = 1;
-              /* FIXME: we need to skip overlong lines while detecting
+              /* Fixme: we need to skip overlong lines while detecting
                  the dashed lines */
               break;
             }
@@ -197,6 +223,31 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
           parm->is_pem = 1;
           parm->linelen = parm->readpos = 0;
         }
+      else if ( parm->have_lf && parm->line_counter == 1
+                && parm->linelen >= 13
+                && !ascii_memcasecmp (parm->line, "Content-Type:", 13))
+        { /* might be a S/MIME body */
+          parm->might_be_smime = 1;
+          parm->linelen = parm->readpos = 0;
+          goto next;
+        }
+      else if (parm->might_be_smime == 1
+               && is_empty_line (parm->line, parm->linelen))
+        {
+          parm->might_be_smime = 2;
+          parm->linelen = parm->readpos = 0;
+          goto next;
+        }
+      else if (parm->might_be_smime == 2)
+        {
+          parm->might_be_smime = 0;
+          if ( !has_only_base64 (parm->line, parm->linelen))
+            {
+              parm->linelen = parm->readpos = 0;
+              goto next;
+            }
+          parm->is_pem = 1;
+        }
       else
         {
           parm->linelen = parm->readpos = 0;
@@ -431,7 +482,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
       fputs (parm->pem_name, fp);
       fputs ("-----\n", fp);
     }
-  return ferror (fp)? GNUPG_Write_Error : 0;
+  return ferror (fp)? gpg_error (gpg_err_code_from_errno (errno)) : 0;
 }
 
 
@@ -453,13 +504,13 @@ gpgsm_create_reader (Base64Context *ctx,
   *r_reader = NULL;
   *ctx = xtrycalloc (1, sizeof **ctx);
   if (!*ctx)
-    return seterr (Out_Of_Core);
+    return OUT_OF_CORE (errno);
 
   r = ksba_reader_new ();
   if (!r)
     {
       xfree (*ctx); *ctx = NULL;
-      return seterr (Out_Of_Core);
+      return gpg_error (GPG_ERR_ENOMEM);
     }
 
   (*ctx)->u.rparm.fp = fp;
@@ -518,20 +569,21 @@ gpgsm_create_writer (Base64Context *ctx,
   *r_writer = NULL;
   *ctx = xtrycalloc (1, sizeof **ctx);
   if (!*ctx)
-    return seterr (Out_Of_Core);
+    return OUT_OF_CORE (errno);
 
   w = ksba_writer_new ();
   if (!w)
     {
       xfree (*ctx); *ctx = NULL;
-      return seterr (Out_Of_Core);
+      return gpg_error (GPG_ERR_ENOMEM);
     }
 
   if (ctrl->create_pem || ctrl->create_base64)
     {
       (*ctx)->u.wparm.fp = fp;
       if (ctrl->create_pem)
-        (*ctx)->u.wparm.pem_name = "CMS OBJECT"; /* fixme */
+        (*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
+                                                 : "CMS OBJECT";
       rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
     }
   else
@@ -555,7 +607,7 @@ gpgsm_finish_writer (Base64Context ctx)
   struct writer_cb_parm_s *parm;
   
   if (!ctx)
-    return GNUPG_Invalid_Value;
+    return gpg_error (GPG_ERR_INV_VALUE);
   parm = &ctx->u.wparm;
   if (parm->did_finish)
     return 0; /* already done */