Various changes.
[gnupg.git] / assuan / assuan-buffer.c
index eec4876..da6b201 100644 (file)
 
 #include <config.h>
 #include <stdlib.h>
+#include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <assert.h>
-
 #include "assuan-defs.h"
 
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#endif
+
+
+static const char *
+my_log_prefix (void)
+{
+#ifdef HAVE_JNLIB_LOGGING
+  return log_get_prefix (NULL);
+#else
+  return "";
+#endif
+}
+
 
 static int
 writen ( int fd, const char *buffer, size_t length )
 {
   while (length)
     {
-      int nwritten = write (fd, buffer, length);
+      int nwritten = _assuan_write_wrapper?
+        _assuan_write_wrapper (fd, buffer, length):
+        write (fd, buffer, length);
       
       if (nwritten < 0)
         {
@@ -58,7 +75,10 @@ readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
   *r_nread = 0;
   while (nleft > 0)
     {
-      int n = read (fd, buf, nleft);
+      int n = _assuan_read_wrapper?
+        _assuan_read_wrapper (fd, buf, nleft):
+        read (fd, buf, nleft);
+
       if (n < 0)
         {
           if (errno == EINTR)
@@ -89,50 +109,70 @@ int
 _assuan_read_line (ASSUAN_CONTEXT ctx)
 {
   char *line = ctx->inbound.line;
-  int n, nread;
+  int n, nread, atticlen;
   int rc;
-  
+
   if (ctx->inbound.eof)
     return -1;
 
-  if (ctx->inbound.attic.linelen)
+  atticlen = ctx->inbound.attic.linelen;
+  if (atticlen)
     {
-      memcpy (line, ctx->inbound.attic.line, ctx->inbound.attic.linelen);
-      nread = ctx->inbound.attic.linelen;
+      memcpy (line, ctx->inbound.attic.line, atticlen);
       ctx->inbound.attic.linelen = 0;
-      for (n=0; n < nread && line[n] != '\n'; n++)
+      for (n=0; n < atticlen && line[n] != '\n'; n++)
         ;
-      if (n < nread)
-        rc = 0; /* found another line in the attic */
+      if (n < atticlen)
+       {
+         rc = 0; /* found another line in the attic */
+         nread = atticlen;
+         atticlen = 0;
+       }
       else
         { /* read the rest */
-          n = nread;
-          assert (n < LINELENGTH);
-          rc = readline (ctx->inbound.fd, line + n, LINELENGTH - n,
-                         &nread, &ctx->inbound.eof);
+          assert (atticlen < LINELENGTH);
+          rc = readline (ctx->inbound.fd, line + atticlen,
+                        LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
         }
     }
   else
     rc = readline (ctx->inbound.fd, line, LINELENGTH,
                    &nread, &ctx->inbound.eof);
   if (rc)
-    return ASSUAN_Read_Error;
+    {
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
+                 my_log_prefix (), ctx, strerror (errno)); 
+      return ASSUAN_Read_Error;
+    }
   if (!nread)
     {
       assert (ctx->inbound.eof);
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx); 
       return -1; 
     }
 
+  ctx->inbound.attic.pending = 0;
+  nread += atticlen;
   for (n=0; n < nread; n++)
     {
       if (line[n] == '\n')
         {
           if (n+1 < nread)
             {
+              char *s, *d;
+              int i;
+
               n++;
               /* we have to copy the rest because the handlers are
                  allowed to modify the passed buffer */
-              memcpy (ctx->inbound.attic.line, line+n, nread-n);
+              for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
+                {
+                  if (*s=='\n')
+                    ctx->inbound.attic.pending = 1;
+                  *d++ = *s++;
+                }
               ctx->inbound.attic.linelen = nread-n;
               n--;
             }
@@ -140,24 +180,83 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
             n--;
           line[n] = 0;
           ctx->inbound.linelen = n;
+          if (ctx->log_fp)
+            {
+              fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx); 
+              if (ctx->confidential)
+                fputs ("[Confidential data not shown]", ctx->log_fp);
+              else
+                _assuan_log_print_buffer (ctx->log_fp, 
+                                          ctx->inbound.line,
+                                          ctx->inbound.linelen);
+              putc ('\n', ctx->log_fp);
+            }
           return 0;
         }
     }
 
+  if (ctx->log_fp)
+    fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
   *line = 0;
   ctx->inbound.linelen = 0;
   return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
 }
 
 
+/* Read the next line from the client or server and return a pointer
+   to a buffer with holding that line.  linelen returns the length of
+   the line.  This buffer is valid until another read operation is
+   done on this buffer.  The caller is allowed to modify this buffer.
+   He should only use the buffer if the function returns without an
+   error.
+
+   Returns: 0 on success or an assuan error code
+   See also: assuan_pending_line().
+*/
+AssuanError
+assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
+{
+  AssuanError err;
 
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
 
-int 
-_assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
+  err = _assuan_read_line (ctx);
+  *line = ctx->inbound.line;
+  *linelen = ctx->inbound.linelen;
+  return err;
+}
+
+
+/* Return true when a full line is pending for a read, without the need
+   for actual IO */
+int
+assuan_pending_line (ASSUAN_CONTEXT ctx)
+{
+  return ctx && ctx->inbound.attic.pending;
+}
+
+
+AssuanError 
+assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
 {
   int rc;
+  
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
 
   /* fixme: we should do some kind of line buffering */
+  if (ctx->log_fp)
+    {
+      fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+      if (ctx->confidential)
+        fputs ("[Confidential data not shown]", ctx->log_fp);
+      else
+        _assuan_log_print_buffer (ctx->log_fp, 
+                                  line, strlen (line));
+      putc ('\n', ctx->log_fp);
+    }
+
   rc = writen (ctx->outbound.fd, line, strlen(line));
   if (rc)
     rc = ASSUAN_Write_Error;
@@ -218,6 +317,17 @@ _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
       
       if (linelen >= LINELENGTH-2-2)
         {
+          if (ctx->log_fp)
+            {
+              fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+              if (ctx->confidential)
+                fputs ("[Confidential data not shown]", ctx->log_fp);
+              else 
+                _assuan_log_print_buffer (ctx->log_fp, 
+                                          ctx->outbound.data.line,
+                                          linelen);
+              putc ('\n', ctx->log_fp);
+            }
           *line++ = '\n';
           linelen++;
           if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
@@ -252,6 +362,17 @@ _assuan_cookie_write_flush (void *cookie)
   line += linelen;
   if (linelen)
     {
+      if (ctx->log_fp)
+        {
+          fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx); 
+          if (ctx->confidential)
+            fputs ("[Confidential data not shown]", ctx->log_fp);
+          else
+            _assuan_log_print_buffer (ctx->log_fp, 
+                                      ctx->outbound.data.line,
+                                      linelen);
+          putc ('\n', ctx->log_fp);
+            }
       *line++ = '\n';
       linelen++;
       if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
@@ -297,7 +418,7 @@ assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
       if (ctx->outbound.data.error)
         return ctx->outbound.data.error;
       if (!ctx->is_server)
-        return _assuan_write_line (ctx, "END");
+        return assuan_write_line (ctx, "END");
     }
   else
     {