Update to current version in newpg module.
authorMarcus Brinkmann <mb@g10code.com>
Tue, 22 Jan 2002 16:29:12 +0000 (16:29 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Tue, 22 Jan 2002 16:29:12 +0000 (16:29 +0000)
23 files changed:
assuan/ChangeLog
assuan/Makefile.am
assuan/assuan-buffer.c
assuan/assuan-client.c
assuan/assuan-connect.c
assuan/assuan-defs.h
assuan/assuan-handler.c
assuan/assuan-inquire.c
assuan/assuan-listen.c
assuan/assuan-pipe-connect.c [new file with mode: 0644]
assuan/assuan-pipe-server.c
assuan/assuan-socket-connect.c [new file with mode: 0644]
assuan/assuan-socket-server.c [new file with mode: 0644]
assuan/assuan-util.c
assuan/assuan.h
jnlib/ChangeLog
jnlib/Makefile.am
jnlib/argparse.c
jnlib/libjnlib-config.h
jnlib/logging.c
jnlib/logging.h
jnlib/strlist.c [new file with mode: 0644]
jnlib/strlist.h [new file with mode: 0644]

index dbf5f43..76cd68e 100644 (file)
@@ -1,3 +1,69 @@
+2002-01-22  Marcus Brinkmann  <marcus@g10code.de>
+
+       * assuan-socket-connect.c (LOGERRORX): Reverse arguments to fputs.
+
+2002-01-21  Werner Koch  <wk@gnupg.org>
+
+       * assuan-connect.c: Move all except assuan_get_pid to...
+       * assuan-pipe-connect.c: this.
+       (assuan_pipe_disconnect): Removed.
+       (do_finish, do_deinit): New 
+       (assuan_pipe_connect): and set them into the context.
+       * assuan-socket-connect.c: New.
+       
+       * assuan-util.c (_assuan_log_sanitized_string): New.
+
+       * assuan-pipe-server.c (assuan_init_pipe_server): Factored most
+       code out to ...
+       (_assuan_new_context): new func.
+       (_assuan_release_context): New
+       * assuan-connect.c (assuan_pipe_connect): Use the new functions.
+
+2002-01-20  Werner Koch  <wk@gnupg.org>
+
+       * assuan.h: Added Invalid Option error code.
+
+       * assuan-handler.c (std_handler_option): New.
+       (std_cmd_tbl): Add OPTION as standard command.
+       (assuan_register_option_handler): New.
+       (dispatch_command): Use case insensitive matching as a fallback.
+       (my_strcasecmp): New.
+
+2002-01-19  Werner Koch  <wk@gnupg.org>
+
+       * assuan-buffer.c (_assuan_read_line): Add output logging.
+       (assuan_write_line): Ditto.
+       (_assuan_cookie_write_data): Ditto.
+       (_assuan_cookie_write_flush): Ditto.
+       * assuan-util.c (_assuan_log_print_buffer): New.
+       (assuan_set_log_stream): New.
+       (assuan_begin_confidential): New.
+       (assuan_end_confidential): New.
+
+       * assuan-defs.h: Add a few handler variables.
+       * assuan-pipe-server.c (assuan_deinit_pipe_server): Removed.
+       (deinit_pipe_server): New.
+       (assuan_deinit_server): New.  Changed all callers to use this.
+       * assuan-listen.c (assuan_accept): Use the accept handler.
+       * assuan-handler.c (process_request): Use the close Handler.
+       * assuan-socket-server.c: New.
+
+2002-01-14  Werner Koch  <wk@gnupg.org>
+
+       * assuan-client.c (_assuan_read_from_server): Skip spaces after
+       the keyword.
+
+2002-01-03  Werner Koch  <wk@gnupg.org>
+
+       * assuan-handler.c (assuan_set_okay_line): New.
+       (process_request): And use it here.
+
+2002-01-02  Werner Koch  <wk@gnupg.org>
+
+       * assuan-inquire.c (init_membuf,put_membuf,get_membuf): Apply a
+       hidden 0 behind the buffer so that the buffer can be used as a
+       string in certain contexts.
+
 2001-12-14  Marcus Brinkmann  <marcus@g10code.de>
 
        * assuan-connect.c (assuan_pipe_connect): New argument
      * You may find it source-copied in other packages.        *
      ***********************************************************       
        
- Copyright 2001 Free Software Foundation, Inc.
+ Copyright 2001, 2002 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
index bc14e8f..7508dce 100644 (file)
@@ -38,7 +38,10 @@ libassuan_a_SOURCES = \
        assuan-listen.c \
        assuan-connect.c \
        assuan-client.c \
-       assuan-pipe-server.c 
+       assuan-pipe-server.c \
+       assuan-socket-server.c \
+       assuan-pipe-connect.c \
+       assuan-socket-connect.c 
 
 
 assuan-errors.c : assuan.h
index 399d11d..bd08817 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <config.h>
 #include <stdlib.h>
+#include <string.h>
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
@@ -119,10 +120,17 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
     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, "%p <- [Error: %s]\n",
+                 ctx, strerror (errno)); 
+      return ASSUAN_Read_Error;
+    }
   if (!nread)
     {
       assert (ctx->inbound.eof);
+      if (ctx->log_fp)
+        fprintf (ctx->log_fp, "%p <- [EOF]\n", ctx); 
       return -1; 
     }
 
@@ -153,10 +161,23 @@ _assuan_read_line (ASSUAN_CONTEXT ctx)
             n--;
           line[n] = 0;
           ctx->inbound.linelen = n;
+          if (ctx->log_fp)
+            {
+              fprintf (ctx->log_fp, "%p <- ", 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, "%p <- [Invalid line]\n", ctx);
   *line = 0;
   ctx->inbound.linelen = 0;
   return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
@@ -206,6 +227,17 @@ assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
     return ASSUAN_Invalid_Value;
 
   /* fixme: we should do some kind of line buffering */
+  if (ctx->log_fp)
+    {
+      fprintf (ctx->log_fp, "%p -> ", 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;
@@ -266,6 +298,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, "%p -> ", 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))
@@ -300,6 +343,17 @@ _assuan_cookie_write_flush (void *cookie)
   line += linelen;
   if (linelen)
     {
+      if (ctx->log_fp)
+        {
+          fprintf (ctx->log_fp, "%p -> ", 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))
index a555cf3..d56357d 100644 (file)
@@ -63,6 +63,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
     {
       *okay = 1;
       *off = 2;
+      while (line[*off] == ' ')
+        ++*off;
     }
   else if (linelen >= 3
            && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
@@ -70,6 +72,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
     {
       *okay = 0;
       *off = 3;
+      while (line[*off] == ' ')
+        ++*off;
     }  
   else if (linelen >= 7
            && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
@@ -79,6 +83,8 @@ _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
     {
       *okay = 3;
       *off = 7;
+      while (line[*off] == ' ')
+        ++*off;
     }
   else
     rc = ASSUAN_Invalid_Response;
index 613b54a..49d4aac 100644 (file)
 
 #include "assuan-defs.h"
 
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-#ifdef HAVE_JNLIB_LOGGING
-#include "../jnlib/logging.h"
-#define LOGERROR1(a,b)   log_error ((a), (b))
-#else
-#define LOGERROR1(a,b)   fprintf (stderr, (a), (b))
-#endif
-
-
-
-static int
-writen ( int fd, const char *buffer, size_t length )
+/* Disconnect and release the context CTX. */
+void
+assuan_disconnect (ASSUAN_CONTEXT ctx)
 {
-  while (length)
+  if (ctx)
     {
-      int nwritten = write (fd, buffer, length);
-      
-      if (nwritten < 0)
-        {
-          if (errno == EINTR)
-            continue;
-          return -1; /* write error */
-        }
-      length -= nwritten;
-      buffer += nwritten;
+      assuan_write_line (ctx, "BYE");
+      ctx->finish_handler (ctx);
+      ctx->deinit_handler (ctx);
+      ctx->deinit_handler = NULL;
+      _assuan_release_context (ctx);
     }
-  return 0;  /* okay */
-}
-
-
-
-/* Connect to a server over a pipe, creating the assuan context and
-   returning it in CTX.  The server filename is NAME, the argument
-   vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
-   descriptors not to close in the child.  */
-AssuanError
-assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[],
-                    int *fd_child_list)
-{
-  static int fixed_signals = 0;
-  AssuanError err;
-  int rp[2];
-  int wp[2];
-  int fd[2];
-
-  if (!ctx || !name || !argv || !argv[0])
-    return ASSUAN_Invalid_Value;
-
-  if (!fixed_signals)
-    { 
-      struct sigaction act;
-        
-      sigaction (SIGPIPE, NULL, &act);
-      if (act.sa_handler == SIG_DFL)
-       {
-         act.sa_handler = SIG_IGN;
-         sigemptyset (&act.sa_mask);
-         act.sa_flags = 0;
-         sigaction (SIGPIPE, &act, NULL);
-        }
-      fixed_signals = 1;
-      /* FIXME: This is not MT safe */
-    }
-
-  if (pipe (rp) < 0)
-    return ASSUAN_General_Error;
-
-  if (pipe (wp) < 0)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      return ASSUAN_General_Error;
-    }
-  
-  fd[0] = rp[0];  /* Our inbound is read end of read pipe.  */
-  fd[1] = wp[1];  /* Our outbound is write end of write pipe.  */
-
-  err = assuan_init_pipe_server (ctx, fd);  /* FIXME: Common code should be factored out.  */
-  if (err)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      return err;
-    }
-  (*ctx)->is_server = 0;
-
-  (*ctx)->pid = fork ();
-  if ((*ctx)->pid < 0)
-    {
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      assuan_deinit_pipe_server (*ctx);  /* FIXME: Common code should be factored out.  */
-      return ASSUAN_General_Error;
-    }
-
-  if ((*ctx)->pid == 0)
-    {
-      int i, n;
-      char errbuf[512];
-#ifdef HAVE_JNLIB_LOGGING
-      int log_fd = log_get_fd (); 
-#endif
-      /* close all files which will not be duped but keep stderr
-         and log_stream for now */
-      n = sysconf (_SC_OPEN_MAX);
-      if (n < 0)
-        n = MAX_OPEN_FDS;
-      for (i=0; i < n; i++)
-        {
-         int *fdp = fd_child_list;
-
-         if (fdp)
-           {
-             while (*fdp != -1 && *fdp != i)
-               fdp++;
-           }
-
-          if (!(fdp && *fdp != -1)
-             && i != fileno (stderr) 
-#ifdef HAVE_JNLIB_LOGGING
-              && i != log_fd
-#endif
-              && i != rp[1] && i != wp[0])
-            close(i);
-        }
-      errno = 0;
-
-      /* Dup handles and to stdin/stdout and exec */
-      if (rp[1] != STDOUT_FILENO)
-        {
-          if (dup2 (rp[1], STDOUT_FILENO) == -1)
-            {
-              LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
-              _exit (4);
-            }
-          close (rp[1]);
-        }
-      if (wp[0] != STDIN_FILENO)
-        {
-          if (dup2 (wp[0], STDIN_FILENO) == -1)
-            {
-              LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
-              _exit (4);
-            }
-          close (wp[0]);
-        }
-
-      execv (name, argv); 
-      /* oops - use the pipe to tell the parent about it */
-      snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n",
-                ASSUAN_Problem_Starting_Server, name, strerror (errno));
-      errbuf[sizeof(errbuf)-1] = 0;
-      writen (1, errbuf, strlen (errbuf));
-      _exit (4);
-    }
-
-  close (rp[1]);
-  close (wp[0]);
-
-  /* initial handshake */
-  {
-    int okay, off;
-
-    err = _assuan_read_from_server (*ctx, &okay, &off);
-    if (err)
-      {
-        LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
-      }
-    else if (okay != 1)
-      {
-        LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
-        err = ASSUAN_Connect_Failed;
-      }
-  }
-
-  if (err)
-    {
-      if ((*ctx)->pid != -1)
-        waitpid ((*ctx)->pid, NULL, 0);  /* FIXME Check return value.  */
-      assuan_deinit_pipe_server (*ctx);  /* FIXME: Common code should be factored out.  */
-    }
-
-  return err;
-}
-
-void
-assuan_pipe_disconnect (ASSUAN_CONTEXT ctx)
-{
-  assuan_write_line (ctx, "BYE");
-  close (ctx->inbound.fd);
-  close (ctx->outbound.fd);
-  waitpid (ctx->pid, NULL, 0);  /* FIXME Check return value.  */
-  assuan_deinit_pipe_server (ctx);
 }
 
 pid_t
@@ -242,5 +52,3 @@ assuan_get_pid (ASSUAN_CONTEXT ctx)
 {
   return ctx ? ctx->pid : -1;
 }
-
-
index ecabd38..7d55aab 100644 (file)
@@ -35,13 +35,18 @@ struct cmdtbl_s {
 struct assuan_context_s {
   AssuanError err_no;
   const char *err_str;
+  int os_errno;  /* last system error number used with certain error codes*/
 
+  int confidential;
   int is_server;  /* set if this is context belongs to a server */
   int in_inquire;
   char *hello_line;
+  char *okay_line; /* see assan_set_okay_line() */
   
   void *user_pointer;  /* for assuan_[gs]et_pointer () */
 
+  FILE *log_fp;
+
   struct {
     int fd;
     int eof;
@@ -68,7 +73,13 @@ struct assuan_context_s {
 
   int pipe_mode;  /* We are in pipe mode, i.e. we can handle just one
                      connection and must terminate then */
-  pid_t pid;   /* In pipe mode, the pid of the child server process.  */
+  pid_t pid;     /* In pipe mode, the pid of the child server process.  
+                     In socket mode, the pid of the server */
+  int listen_fd;  /* The fd we are listening on (used by socket servers) */
+
+  void (*deinit_handler)(ASSUAN_CONTEXT);  
+  int (*accept_handler)(ASSUAN_CONTEXT);
+  int (*finish_handler)(ASSUAN_CONTEXT);
 
   struct cmdtbl_s *cmdtbl;
   size_t cmdtbl_used; /* used entries */
@@ -77,6 +88,7 @@ struct assuan_context_s {
   void (*bye_notify_fnc)(ASSUAN_CONTEXT);
   void (*reset_notify_fnc)(ASSUAN_CONTEXT);
   void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
+  int  (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*);
   void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
   void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
 
@@ -84,9 +96,12 @@ struct assuan_context_s {
   int input_fd;   /* set by INPUT command */
   int output_fd;  /* set by OUTPUT command */
 
+};
 
 
-};
+/*-- assuan-pipe-server.c --*/
+int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
+void _assuan_release_context (ASSUAN_CONTEXT ctx);
 
 
 /*-- assuan-handler.c --*/
@@ -114,6 +129,9 @@ void  _assuan_free (void *p);
 
 #define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
 
+void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t  length);
+void _assuan_log_sanitized_string (const char *string);
+
 
 #endif /*ASSUAN_DEFS_H*/
 
index a82bd53..1c8aded 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "assuan-defs.h"
 
+#define spacep(p)  (*(p) == ' ' || *(p) == '\t')
 #define digitp(a) ((a) >= '0' && (a) <= '9')
 
 
@@ -48,6 +49,53 @@ std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
     ctx->cancel_notify_fnc (ctx);
   return set_error (ctx, Not_Implemented, NULL); 
 }
+
+static int
+std_handler_option (ASSUAN_CONTEXT ctx, char *line)
+{
+  char *key, *value, *p;
+
+  for (key=line; spacep (key); key++)
+    ;
+  if (!*key)
+    return set_error (ctx, Syntax_Error, "argument required");
+  if (*key == '=')
+    return set_error (ctx, Syntax_Error, "no option name given");
+  for (value=key; *value && !spacep (value) && *value != '='; value++)
+    ;
+  if (*value)
+    {
+      if (spacep (value))
+        *value++ = 0; /* terminate key */
+      for (; spacep (value); value++)
+        ;
+      if (*value == '=')
+        {
+          *value++ = 0; /* terminate key */
+          for (; spacep (value); value++)
+            ;
+          if (!*value)
+            return set_error (ctx, Syntax_Error, "option argument expected");
+        }
+      if (*value)
+        {
+          for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
+            ;
+          if (p > value)
+            *++p = 0; /* strip trailing spaces */
+        }
+    }
+
+  if (*key == '-' && key[1] == '-' && key[2])
+    key += 2; /* the double dashes are optional */
+  if (*key == '-')
+    return set_error (ctx, Syntax_Error,
+                      "option should not begin with one dash");
+
+  if (ctx->option_handler_fnc)
+    return ctx->option_handler_fnc (ctx, key, value);
+  return 0;
+}
   
 static int
 std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
@@ -147,6 +195,7 @@ static struct {
 } std_cmd_table[] = {
   { "NOP",    ASSUAN_CMD_NOP,    std_handler_nop, 1 },
   { "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
+  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
   { "BYE",    ASSUAN_CMD_BYE,    std_handler_bye, 1 },
   { "AUTH",   ASSUAN_CMD_AUTH,   std_handler_auth, 1 },
   { "RESET",  ASSUAN_CMD_RESET,  std_handler_reset, 1 },
@@ -154,6 +203,7 @@ static struct {
 
   { "INPUT",  ASSUAN_CMD_INPUT,  std_handler_input },
   { "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
+  { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
   { NULL }
 };
 
@@ -263,6 +313,17 @@ assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
 }
 
 int
+assuan_register_option_handler (ASSUAN_CONTEXT ctx,
+                               int (*fnc)(ASSUAN_CONTEXT,
+                                          const char*, const char*))
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  ctx->option_handler_fnc = fnc;
+  return 0;
+}
+
+int
 assuan_register_input_notify (ASSUAN_CONTEXT ctx,
                               void (*fnc)(ASSUAN_CONTEXT, const char *))
 {
@@ -312,6 +373,20 @@ handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
   return set_error (ctx, Not_Implemented, NULL);
 }
 
+/* like ascii_strcasecmp but assume that B is already uppercase */
+static int
+my_strcasecmp (const char *a, const char *b)
+{
+    if (a == b)
+        return 0;
+
+    for (; *a && *b; a++, b++)
+      {
+       if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
+           break;
+      }
+    return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
+}
 
 /* Parse the line, break out the command, find it in the command
    table, remove leading and white spaces from the arguments, all the
@@ -339,8 +414,18 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
   shift = p - line;
 
   for (i=0; (s=ctx->cmdtbl[i].name); i++)
-    if (!strcmp (line, s))
-      break;
+    {
+      if (!strcmp (line, s))
+        break;
+    }
+  if (!s)
+    { /* and try case insensitive */
+      for (i=0; (s=ctx->cmdtbl[i].name); i++)
+        {
+          if (!my_strcasecmp (line, s))
+            break;
+        }
+    }
   if (!s)
     return set_error (ctx, Unknown_Command, NULL);
   line += shift;
@@ -382,17 +467,18 @@ process_request (ASSUAN_CONTEXT ctx)
   /* Error handling */
   if (!rc)
     {
-      rc = assuan_write_line (ctx, "OK");
+      rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
     }
   else if (rc == -1)
     { /* No error checking because the peer may have already disconnect */ 
       assuan_write_line (ctx, "OK closing connection");
+      ctx->finish_handler (ctx);
     }
   else 
     {
       char errline[256];
 
-      if (rc < 100)
+        if (rc < 100)
         sprintf (errline, "ERR %d server fault (%.50s)",
                  ASSUAN_Server_Fault, assuan_strerror (rc));
       else
@@ -405,6 +491,12 @@ process_request (ASSUAN_CONTEXT ctx)
       rc = assuan_write_line (ctx, errline);
     }
 
+  ctx->confidential = 0;
+  if (ctx->okay_line)
+    {
+      xfree (ctx->okay_line);
+      ctx->okay_line = NULL;
+    }
   return rc;
 }
 
@@ -522,6 +614,35 @@ assuan_get_data_fp (ASSUAN_CONTEXT ctx)
 }
 
 
+/* Set the text used for the next OK reponse.  This string is
+   automatically reset to NULL after the next command. */
+AssuanError
+assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
+{
+  if (!ctx)
+    return ASSUAN_Invalid_Value;
+  if (!line)
+    {
+      xfree (ctx->okay_line);
+      ctx->okay_line = NULL;
+    }
+  else
+    {
+      /* FIXME: we need to use gcry_is_secure() to test whether
+         we should allocate the entire line in secure memory */
+      char *buf = xtrymalloc (3+strlen(line)+1);
+      if (!buf)
+        return ASSUAN_Out_Of_Core;
+      strcpy (buf, "OK ");
+      strcpy (buf+3, line);
+      xfree (ctx->okay_line);
+      ctx->okay_line = buf;
+    }
+  return 0;
+}
+
+
+
 void
 assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
 {
index 8fec77e..933091e 100644 (file)
@@ -1,5 +1,5 @@
 /* assuan-inquire.c - handle inquire stuff
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -56,7 +56,8 @@ init_membuf (struct membuf *mb, int initiallen, size_t maxlen)
   mb->out_of_core = 0;
   mb->too_large = 0;
   mb->maxlen = maxlen;
-  mb->buf = xtrymalloc (initiallen);
+  /* we need to allocate one byte more for get_membuf */
+  mb->buf = xtrymalloc (initiallen+1);
   if (!mb->buf)
       mb->out_of_core = 1;
 }
@@ -78,7 +79,8 @@ put_membuf (struct membuf *mb, const void *buf, size_t len)
       char *p;
       
       mb->size += len + 1024;
-      p = xtryrealloc (mb->buf, mb->size);
+      /* we need to allocate one byte more for get_membuf */
+      p = xtryrealloc (mb->buf, mb->size+1);
       if (!p)
         {
           mb->out_of_core = 1;
@@ -102,6 +104,7 @@ get_membuf (struct membuf *mb, size_t *len)
       return NULL;
     }
 
+  mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
   p = mb->buf;
   *len = mb->len;
   mb->buf = NULL;
index 57fe4b6..db63ad2 100644 (file)
@@ -69,15 +69,13 @@ assuan_accept (ASSUAN_CONTEXT ctx)
   if (!ctx)
     return ASSUAN_Invalid_Value;
 
-  /* fixme: cancel existing connection */
   if (ctx->pipe_mode > 1)
     return -1; /* second invocation for pipemode -> terminate */
+  ctx->finish_handler (ctx);
 
-  if (!ctx->pipe_mode)
-    {
-
-      /* fixme: wait for request */
-    }
+  rc = ctx->accept_handler (ctx);
+  if (rc)
+    return rc;
 
   /* send the hello */
   rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
diff --git a/assuan/assuan-pipe-connect.c b/assuan/assuan-pipe-connect.c
new file mode 100644 (file)
index 0000000..ccfc1f0
--- /dev/null
@@ -0,0 +1,269 @@
+/* assuan-pipe-connect.c - Establish a pipe connection (client) 
+ *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * GnuPG 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "assuan-defs.h"
+
+#ifdef _POSIX_OPEN_MAX
+#define MAX_OPEN_FDS _POSIX_OPEN_MAX
+#else
+#define MAX_OPEN_FDS 20
+#endif
+
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#define LOGERROR1(a,b)   log_error ((a), (b))
+#else
+#define LOGERROR1(a,b)   fprintf (stderr, (a), (b))
+#endif
+
+
+
+static int
+writen ( int fd, const char *buffer, size_t length )
+{
+  while (length)
+    {
+      int nwritten = write (fd, buffer, length);
+      
+      if (nwritten < 0)
+        {
+          if (errno == EINTR)
+            continue;
+          return -1; /* write error */
+        }
+      length -= nwritten;
+      buffer += nwritten;
+    }
+  return 0;  /* okay */
+}
+
+
+static int
+do_finish (ASSUAN_CONTEXT ctx)
+{
+  if (ctx->inbound.fd != -1)
+    {
+      close (ctx->inbound.fd);
+      ctx->inbound.fd = -1;
+    }
+  if (ctx->outbound.fd != -1)
+    {
+      close (ctx->outbound.fd);
+      ctx->outbound.fd = -1;
+    }
+  if (ctx->pid != -1)
+    {
+      waitpid (ctx->pid, NULL, 0);  /* FIXME Check return value.  */
+      ctx->pid = -1;
+    }
+  return 0;
+}
+
+static void
+do_deinit (ASSUAN_CONTEXT ctx)
+{
+  do_finish (ctx);
+}
+
+
+
+/* Connect to a server over a pipe, creating the assuan context and
+   returning it in CTX.  The server filename is NAME, the argument
+   vector in ARGV.  FD_CHILD_LIST is a -1 terminated list of file
+   descriptors not to close in the child.  */
+AssuanError
+assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[],
+                    int *fd_child_list)
+{
+  static int fixed_signals = 0;
+  AssuanError err;
+  int rp[2];
+  int wp[2];
+
+  if (!ctx || !name || !argv || !argv[0])
+    return ASSUAN_Invalid_Value;
+
+  if (!fixed_signals)
+    { 
+      struct sigaction act;
+        
+      sigaction (SIGPIPE, NULL, &act);
+      if (act.sa_handler == SIG_DFL)
+       {
+         act.sa_handler = SIG_IGN;
+         sigemptyset (&act.sa_mask);
+         act.sa_flags = 0;
+         sigaction (SIGPIPE, &act, NULL);
+        }
+      fixed_signals = 1;
+      /* FIXME: This is not MT safe */
+    }
+
+  if (pipe (rp) < 0)
+    return ASSUAN_General_Error;
+
+  if (pipe (wp) < 0)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      return ASSUAN_General_Error;
+    }
+  
+  err = _assuan_new_context (ctx);
+  if (err)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      return err;
+    }
+  (*ctx)->pipe_mode = 1;
+  (*ctx)->inbound.fd  = rp[0];  /* Our inbound is read end of read pipe. */
+  (*ctx)->outbound.fd = wp[1];  /* Our outbound is write end of write pipe. */
+  (*ctx)->deinit_handler = do_deinit;
+  (*ctx)->finish_handler = do_finish;
+
+  (*ctx)->pid = fork ();
+  if ((*ctx)->pid < 0)
+    {
+      close (rp[0]);
+      close (rp[1]);
+      close (wp[0]);
+      close (wp[1]);
+      _assuan_release_context (*ctx); 
+      return ASSUAN_General_Error;
+    }
+
+  if ((*ctx)->pid == 0)
+    {
+      int i, n;
+      char errbuf[512];
+#ifdef HAVE_JNLIB_LOGGING
+      int log_fd = log_get_fd (); 
+#endif
+      /* close all files which will not be duped but keep stderr
+         and log_stream for now */
+      n = sysconf (_SC_OPEN_MAX);
+      if (n < 0)
+        n = MAX_OPEN_FDS;
+      for (i=0; i < n; i++)
+        {
+         int *fdp = fd_child_list;
+
+         if (fdp)
+           {
+             while (*fdp != -1 && *fdp != i)
+               fdp++;
+           }
+
+          if (!(fdp && *fdp != -1)
+             && i != fileno (stderr) 
+#ifdef HAVE_JNLIB_LOGGING
+              && i != log_fd
+#endif
+              && i != rp[1] && i != wp[0])
+            close(i);
+        }
+      errno = 0;
+
+      /* Dup handles and to stdin/stdout and exec */
+      if (rp[1] != STDOUT_FILENO)
+        {
+          if (dup2 (rp[1], STDOUT_FILENO) == -1)
+            {
+              LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
+              _exit (4);
+            }
+          close (rp[1]);
+        }
+      if (wp[0] != STDIN_FILENO)
+        {
+          if (dup2 (wp[0], STDIN_FILENO) == -1)
+            {
+              LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
+              _exit (4);
+            }
+          close (wp[0]);
+        }
+
+      execv (name, argv); 
+      /* oops - use the pipe to tell the parent about it */
+      snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n",
+                ASSUAN_Problem_Starting_Server, name, strerror (errno));
+      errbuf[sizeof(errbuf)-1] = 0;
+      writen (1, errbuf, strlen (errbuf));
+      _exit (4);
+    }
+
+  close (rp[1]);
+  close (wp[0]);
+
+  /* initial handshake */
+  {
+    int okay, off;
+
+    err = _assuan_read_from_server (*ctx, &okay, &off);
+    if (err)
+      {
+        LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
+      }
+    else if (okay != 1)
+      {
+        LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
+        err = ASSUAN_Connect_Failed;
+      }
+  }
+
+  if (err)
+    {
+      assuan_disconnect (*ctx);
+      *ctx = NULL;
+    }
+
+  return err;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
index 2a9b829..d15f54f 100644 (file)
 
 #include "assuan-defs.h"
 
+static void
+deinit_pipe_server (ASSUAN_CONTEXT ctx)
+{
+  /* nothing to do for this simple server */
+}
+
+static int
+accept_connection (ASSUAN_CONTEXT ctx)
+{
+  /* This is a NOP for a pipe server */
+  return 0;
+}
 
+static int
+finish_connection (ASSUAN_CONTEXT ctx)
+{
+  /* This is a NOP for a pipe server */
+  return 0;
+}
+
+
+/* Create a new context.  Note that the handlers are set up for a pipe
+   server/client - this wau we don't need extra dummy functions */
 int
-assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
+_assuan_new_context (ASSUAN_CONTEXT *r_ctx)
 {
   ASSUAN_CONTEXT ctx;
   int rc;
@@ -35,14 +57,17 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
   ctx = xtrycalloc (1, sizeof *ctx);
   if (!ctx)
     return ASSUAN_Out_Of_Core;
-  ctx->is_server = 1;
   ctx->input_fd = -1;
   ctx->output_fd = -1;
 
-  ctx->inbound.fd = filedes[0];
-  ctx->outbound.fd = filedes[1];
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
 
-  ctx->pipe_mode = 1;
+  ctx->listen_fd = -1;
+  /* use the pipe server handler as a default */
+  ctx->deinit_handler = deinit_pipe_server;
+  ctx->accept_handler = accept_connection;
+  ctx->finish_handler = finish_connection;
 
   rc = _assuan_register_std_commands (ctx);
   if (rc)
@@ -52,22 +77,47 @@ assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
   return rc;
 }
 
+
+
+int
+assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
+{
+  int rc;
+
+  rc = _assuan_new_context (r_ctx);
+  if (!rc)
+    {
+      ASSUAN_CONTEXT ctx = *r_ctx;
+
+      ctx->is_server = 1;
+      ctx->inbound.fd = filedes[0];
+      ctx->outbound.fd = filedes[1];
+      ctx->pipe_mode = 1;
+    }
+  return rc;
+}
+
+
 void
-assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx)
+_assuan_release_context (ASSUAN_CONTEXT ctx)
 {
   if (ctx)
     {
       xfree (ctx->hello_line);
+      xfree (ctx->okay_line);
       xfree (ctx);
     }
 }
 
-
-
-
-
-
-
-
-
-
+void
+assuan_deinit_server (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      /* We use this function pointer to avoid linking other server
+         when not needed but still allow for a generic deinit function */
+      ctx->deinit_handler (ctx);
+      ctx->deinit_handler = NULL;
+      _assuan_release_context (ctx);
+    }
+}
diff --git a/assuan/assuan-socket-connect.c b/assuan/assuan-socket-connect.c
new file mode 100644 (file)
index 0000000..6602b82
--- /dev/null
@@ -0,0 +1,150 @@
+/* assuan-socket-connect.c - Assuan socket based client
+ *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * GnuPG 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "assuan-defs.h"
+
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#define LOGERROR(a)      log_error ((a))
+#define LOGERROR1(a,b)   log_error ((a), (b))
+#define LOGERROR2(a,b,c) log_error ((a), (b), (c))
+#define LOGERRORX(a)     log_printf ((a))
+#else
+#define LOGERROR(a)      fprintf (stderr, (a))
+#define LOGERROR1(a,b)   fprintf (stderr, (a), (b))
+#define LOGERROR2(a,b,c) fprintf (stderr, (a), (b), (c))
+#define LOGERRORX(a)     fputs ((a), stderror)
+#endif
+
+
+
+static int
+do_finish (ASSUAN_CONTEXT ctx)
+{
+  if (ctx->inbound.fd != -1)
+    {
+      close (ctx->inbound.fd);
+    }
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+  return 0;
+}
+
+static void
+do_deinit (ASSUAN_CONTEXT ctx)
+{
+  do_finish (ctx);
+}
+
+
+
+/* Make a connection to the Unix domain socket NAME and return a new
+   Assuan context in CTX.  SERVER_PID is currently not used but may
+   becode handy in future. */
+AssuanError
+assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
+                       const char *name, pid_t server_pid)
+{
+  AssuanError err;
+  ASSUAN_CONTEXT ctx;
+  int fd;
+  struct sockaddr_un srvr_addr;
+  size_t len;
+
+  if (!r_ctx || !name)
+    return ASSUAN_Invalid_Value;
+  *r_ctx = NULL;
+
+  /* we require that the name starts with a slash, so that we can
+     alter reuse this function for other socket types */
+  if (*name != '/')
+    return ASSUAN_Invalid_Value;
+  if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
+    return ASSUAN_Invalid_Value;
+
+  err = _assuan_new_context (&ctx); 
+  if (err)
+      return err;
+  ctx->pid = server_pid; /* save it in case we need it later */
+  ctx->deinit_handler = do_deinit;
+  ctx->finish_handler = do_finish;
+
+  fd = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (fd == -1)
+    {
+      LOGERROR1 ("can't create socket: %s\n", strerror (errno));
+      _assuan_release_context (ctx);
+      return ASSUAN_General_Error;
+    }
+    
+  memset (&srvr_addr, 0, sizeof srvr_addr );
+  srvr_addr.sun_family = AF_UNIX;
+  strcpy (srvr_addr.sun_path, name);
+  len = (offsetof (struct sockaddr_un, sun_path)
+         + strlen (srvr_addr.sun_path) + 1);
+    
+  if (connect (fd, (struct sockaddr*)&srvr_addr, len) == -1)
+    {
+      LOGERROR2 ("can't connect to `%s': %s\n", name, strerror (errno));
+      _assuan_release_context (ctx);
+      close (fd );
+      return ASSUAN_Connect_Failed;
+    }
+
+  ctx->inbound.fd = fd;
+  ctx->outbound.fd = fd;
+
+  /* initial handshake */
+  {
+    int okay, off;
+
+    err = _assuan_read_from_server (ctx, &okay, &off);
+    if (err)
+      {
+        LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
+      }
+    else if (okay != 1)
+      {
+        LOGERROR ("can't connect server: `");
+        _assuan_log_sanitized_string (ctx->inbound.line);
+        LOGERRORX ("'\n");
+        err = ASSUAN_Connect_Failed;
+      }
+  }
+
+  if (err)
+    {
+      assuan_disconnect (ctx); 
+    }
+  else
+    *r_ctx = ctx;
+  return 0;
+}
+
+
diff --git a/assuan/assuan-socket-server.c b/assuan/assuan-socket-server.c
new file mode 100644 (file)
index 0000000..6ad6455
--- /dev/null
@@ -0,0 +1,121 @@
+/* assuan-socket-server.c - Assuan socket based server
+ *     Copyright (C) 2002 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * GnuPG 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "assuan-defs.h"
+
+static int
+accept_connection (ASSUAN_CONTEXT ctx)
+{
+  int fd;
+  struct sockaddr_un clnt_addr;
+  size_t len = sizeof clnt_addr;
+
+  fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
+  if (fd == -1)
+    {
+      ctx->os_errno = errno;
+      return ASSUAN_Accept_Failed;
+    }
+
+  ctx->inbound.fd = fd;
+  ctx->inbound.eof = 0;
+  ctx->inbound.linelen = 0;
+  ctx->inbound.attic.linelen = 0;
+  ctx->inbound.attic.pending = 0;
+
+  ctx->outbound.fd = fd;
+  ctx->outbound.data.linelen = 0;
+  ctx->outbound.data.error = 0;
+  
+  ctx->confidential = 0;
+
+  return 0;
+}
+
+static int
+finish_connection (ASSUAN_CONTEXT ctx)
+{
+  if (ctx->inbound.fd != -1)
+    {
+      close (ctx->inbound.fd);
+    }
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+  return 0;
+}
+
+
+static void
+deinit_socket_server (ASSUAN_CONTEXT ctx)
+{
+  finish_connection (ctx);
+}
+
+
+
+/* Initialize a server for the socket LISTEN_FD which has already be
+   put into listen mode */
+int
+assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd)
+{
+  ASSUAN_CONTEXT ctx;
+  int rc;
+
+  *r_ctx = NULL;
+  ctx = xtrycalloc (1, sizeof *ctx);
+  if (!ctx)
+    return ASSUAN_Out_Of_Core;
+  ctx->is_server = 1;
+  ctx->input_fd = -1;
+  ctx->output_fd = -1;
+
+  ctx->inbound.fd = -1;
+  ctx->outbound.fd = -1;
+
+  ctx->listen_fd = listen_fd;
+  ctx->deinit_handler = deinit_socket_server;
+  ctx->accept_handler = accept_connection;
+  ctx->finish_handler = finish_connection;
+
+  rc = _assuan_register_std_commands (ctx);
+  if (rc)
+    xfree (ctx);
+  else
+    *r_ctx = ctx;
+  return rc;
+}
+
+
+
+
+
+
+
+
+
+
index 3eeee9a..4153ef8 100644 (file)
 
 #include "assuan-defs.h"
 
+#ifdef HAVE_JNLIB_LOGGING
+#include "../jnlib/logging.h"
+#endif
+
 
 static void *(*alloc_func)(size_t n) = malloc;
 static void *(*realloc_func)(void *p, size_t n) = realloc;
@@ -96,3 +100,97 @@ assuan_get_pointer (ASSUAN_CONTEXT ctx)
   return ctx? ctx->user_pointer : NULL;
 }
 
+
+void
+assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp)
+{
+  if (ctx)
+    {
+      if (ctx->log_fp)
+        fflush (ctx->log_fp);
+      ctx->log_fp = fp;
+    }
+}
+
+
+void
+assuan_begin_confidential (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 1;
+    }
+}
+
+void
+assuan_end_confidential (ASSUAN_CONTEXT ctx)
+{
+  if (ctx)
+    {
+      ctx->confidential = 0;
+    }
+}
+
+void
+_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
+{
+  const unsigned char *s;
+  int n;
+
+  for (n=length,s=buffer; n; n--, s++)
+    {
+      if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
+        break;
+    }
+  s = buffer;
+  if (!n && *s != '[')
+    fwrite (buffer, length, 1, fp);
+  else
+    {
+      putc ('[', fp);
+      for (n=0; n < length; n++, s++)
+          fprintf (fp, " %02x", *s);
+      putc (' ', fp);
+      putc (']', fp);
+    }
+}
+
+
+/* print a user supplied string after filtering out potential bad
+   characters*/
+void
+_assuan_log_sanitized_string (const char *string)
+{
+  const unsigned char *s = string;
+#ifdef HAVE_JNLIB_LOGGING
+  FILE *fp = log_get_stream ();
+#else
+  FILE *fp = stderr;
+#endif
+
+  for (; *s; s++)
+    {
+      if (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
+        {
+          putc ('\\', fp);
+          if (*s == '\n')
+            putc ('n', fp);
+          else if (*s == '\r')
+            putc ('r', fp);
+          else if (*s == '\f')
+            putc ('f', fp);
+          else if (*s == '\v')
+            putc ('v', fp);
+          else if (*s == '\b')
+            putc ('b', fp);
+          else if (!*s)
+            putc ('0', fp);
+          else
+            fprintf (fp, "x%02x", *s );
+       }
+      else
+        putc (*s, fp);
+    }
+}
+
+
index cddc98c..5971d81 100644 (file)
@@ -1,5 +1,5 @@
 /* assuan.c - Definitions for the Assuna protocol
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -47,6 +47,7 @@ typedef enum {
   ASSUAN_No_Data_Callback = 12,
   ASSUAN_No_Inquire_Callback = 13,
   ASSUAN_Connect_Failed = 14,
+  ASSUAN_Accept_Failed = 15,
 
   /* error codes above 99 are meant as status codes */
   ASSUAN_Not_Implemented = 100,
@@ -69,6 +70,9 @@ typedef enum {
   ASSUAN_Invalid_Data = 117,
   ASSUAN_Unexpected_Command = 118,
   ASSUAN_Too_Much_Data = 119,
+  ASSUAN_Inquire_Unknown = 120,
+  ASSUAN_Inquire_Error = 121,
+  ASSUAN_Invalid_Option = 122,
 
   ASSUAN_Bad_Certificate = 201,
   ASSUAN_Bad_Certificate_Path = 202,
@@ -83,6 +87,7 @@ typedef enum {
   ASSUAN_Cert_Revoked = 301,
   ASSUAN_No_CRL_For_Cert = 302,
   ASSUAN_CRL_Too_Old = 303,
+  ASSUAN_Not_Trusted = 304,
 
 } AssuanError;
 
@@ -93,6 +98,7 @@ typedef enum {
   ASSUAN_CMD_BYE,
   ASSUAN_CMD_AUTH,
   ASSUAN_CMD_RESET,
+  ASSUAN_CMD_OPTION,
   ASSUAN_CMD_DATA,
   ASSUAN_CMD_END,
   ASSUAN_CMD_INPUT,
@@ -120,6 +126,11 @@ int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
                                   void (*fnc)(ASSUAN_CONTEXT, const char *));
 int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
                                   void (*fnc)(ASSUAN_CONTEXT, const char *));
+
+int assuan_register_option_handler (ASSUAN_CONTEXT ctx,
+                                    int (*fnc)(ASSUAN_CONTEXT,
+                                               const char*, const char*));
+
 int assuan_process (ASSUAN_CONTEXT ctx);
 int assuan_process_next (ASSUAN_CONTEXT ctx);
 int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
@@ -127,6 +138,7 @@ int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
 
 
 FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
+AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line);
 void assuan_write_status (ASSUAN_CONTEXT ctx,
                           const char *keyword, const char *text);
 
@@ -142,13 +154,21 @@ AssuanError assuan_close_output_fd (ASSUAN_CONTEXT ctx);
 
 /*-- assuan-pipe-server.c --*/
 int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]);
-void assuan_deinit_pipe_server (ASSUAN_CONTEXT ctx);
+void assuan_deinit_server (ASSUAN_CONTEXT ctx);
 
+/*-- assuan-socket-server.c --*/
+int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd);
 
-/*-- assuan-connect.c --*/
+
+/*-- assuan-pipe-connect.c --*/
 AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
                                  char *const argv[], int *fd_child_list);
-void assuan_pipe_disconnect (ASSUAN_CONTEXT ctx);
+/*-- assuan-socket-connect.c --*/
+AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name,
+                                   pid_t server_pid);
+
+/*-- assuan-connect.c --*/
+void assuan_disconnect (ASSUAN_CONTEXT ctx);
 pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
 
 /*-- assuan-client.c --*/
@@ -178,10 +198,13 @@ AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
 void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
                                void *(*new_realloc_func)(void *p, size_t n),
                                void (*new_free_func)(void*) );
+void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp);
 int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
 void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer);
 void *assuan_get_pointer (ASSUAN_CONTEXT ctx);
 
+void assuan_begin_confidential (ASSUAN_CONTEXT ctx);
+void assuan_end_confidential (ASSUAN_CONTEXT ctx);
 
 /*-- assuan-errors.c (built) --*/
 const char *assuan_strerror (AssuanError err);
index 1d750bf..b5f723c 100644 (file)
@@ -5,6 +5,22 @@
        unconditionally.
        Reported by Jose Carlos Garcia Sogo <jsogo@debian.org>.
 
+2002-01-19  Werner Koch  <wk@gnupg.org>
+
+       * logging.c (log_get_stream): New.
+
+2001-12-05  Werner Koch  <wk@gnupg.org>
+
+       * logging.c (log_set_prefix): New.
+       (do_logv): Include prefix and pid only if enabled. Print time only
+       when explicitly enabled.
+       (log_logv): New.  
+       * logging.h: Include log_logv() only when requested.
+
+2001-11-06  Werner Koch  <wk@gnupg.org>
+
+       * strlist.c, strlist.h: New. Taken from pgnupg/util/strgutil.c
+
 2001-08-30  Werner Koch  <wk@gnupg.org>
 
        * logging.c (log_printf): Don't pass NULL instead of arg_ptr.
index 1049f3c..515a49a 100644 (file)
@@ -26,11 +26,14 @@ noinst_LIBRARIES = libjnlib.a
 
 
 #libjnlib_a_LDFLAGS =
-libjnlib_a_SOURCES = libjnlib-config.h        \
-                    xmalloc.c xmalloc.h       \
-                    stringhelp.c stringhelp.h \
-                    argparse.c argparse.h     \
-                    logging.c logging.h       \
-                    types.h mischelp.h
-
+libjnlib_a_SOURCES = \
+       libjnlib-config.h \
+       stringhelp.c stringhelp.h \
+       strlist.c strlist.h \
+       argparse.c argparse.h \
+       logging.c logging.h  \
+       dotlock.c dotlock.h  \
+       types.h mischelp.h
+
+#                   xmalloc.c xmalloc.h       
 
index ba63558..0e353e4 100644 (file)
@@ -900,7 +900,7 @@ strusage( int level )
     switch( level ) {
       case 11: p = "foo"; break;
       case 13: p = "0.0"; break;
-      case 14: p = "Copyright (C) 2000 Free Software Foundation, Inc."; break;
+      case 14: p = "Copyright (C) 2001 Free Software Foundation, Inc."; break;
       case 15: p =
 "This program comes with ABSOLUTELY NO WARRANTY.\n"
 "This is free software, and you are welcome to redistribute it\n"
index de8e6a4..ec31d35 100644 (file)
 #ifndef LIBJNLIB_CONFIG_H
 #define LIBJNLIB_CONFIG_H
 
-#include "xmalloc.h"
+#include <gcrypt.h> /* gcry_malloc & Cie. */
 #include "logging.h"
 
-
-
 #ifdef USE_SIMPLE_GETTEXT
   int set_gettext_file( const char *filename );
   const char *gettext( const char *msgid );
 #endif /* !USE_SIMPLE_GETTEXT */
 
 
-#define jnlib_xmalloc(a)    xmalloc( (a) )
-#define jnlib_xcalloc(a,b)  xcalloc( (a), (b) )
-#define jnlib_xrealloc(a,n) xrealloc( (a), (n) )
-#define jnlib_xstrdup(a)    xstrdup( (a) )
-#define jnlib_free(a)      free( (a) )
+#define jnlib_xmalloc(a)    gcry_xmalloc( (a) )
+#define jnlib_xcalloc(a,b)  gcry_xcalloc( (a), (b) )
+#define jnlib_xrealloc(a,n) gcry_xrealloc( (a), (n) )
+#define jnlib_xstrdup(a)    gcry_xstrdup( (a) )
+#define jnlib_free(a)      gcry_free( (a) )
 
 #define jnlib_log_debug    log_debug
 #define jnlib_log_info    log_info
@@ -73,3 +71,5 @@
 
 #endif /*LIBJNUTIL_CONFIG_H*/
 
+
+
index 69b94b1..2e0d53a 100644 (file)
 #include <stdarg.h>
 #include <errno.h>
 #include <time.h>
+#include <sys/types.h>
+#include <unistd.h>
 #ifdef __MINGW32__
   #include <io.h>
 #endif
 
+#define JNLIB_NEED_LOG_LOGV 1
 #include "libjnlib-config.h"
 #include "logging.h"
 
-enum my_log_levels {
-    MY_LOG_BEGIN,  /* only print the timestamp if configured */
-    MY_LOG_CONT,
-    MY_LOG_INFO,
-    MY_LOG_WARN,
-    MY_LOG_ERROR,
-    MY_LOG_FATAL,
-    MY_LOG_BUG,
-    MY_LOG_DEBUG
-};
 
 static FILE *logstream;
-static int use_time;
+static char prefix_buffer[80];
+static int with_time;
+static int with_prefix;
+static int with_pid;
+
 static int missing_lf;
 static int errorcount;
 
@@ -95,61 +92,93 @@ log_set_file( const char *name )
     if( logstream && logstream != stderr )
        fclose( logstream );
     logstream = fp;
-    use_time = fp != stderr;
     missing_lf = 0;
 }
 
 
+void
+log_set_prefix (const char *text, unsigned int flags)
+{
+  if (text)
+    {
+      strncpy (prefix_buffer, text, sizeof (prefix_buffer)-1);
+      prefix_buffer[sizeof (prefix_buffer)-1] = 0;
+    }
+  
+  with_prefix = (flags & 1);
+  with_time = (flags & 2);
+  with_pid  = (flags & 4);
+}
+
 int
 log_get_fd()
 {
     return fileno(logstream?logstream:stderr);
 }
 
-static void
-do_logv( int level, const char *fmt, va_list arg_ptr )
+FILE *
+log_get_stream ()
 {
-    if( !logstream )
-       logstream = stderr;
-
-    if( missing_lf && level != MY_LOG_CONT )
-       putc('\n', logstream );
-    missing_lf = 0;
+    return logstream?logstream:stderr;
+}
 
-    if( use_time && level != MY_LOG_CONT ) {
-       /* Note this does not work for multiple line logging as we would
-        * need to print to a buffer first */
-       struct tm *tp;
-       time_t atime = time(NULL);
 
-       tp = localtime( &atime );
-       fprintf( logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
-                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
-                        tp->tm_hour, tp->tm_min, tp->tm_sec );
+static void
+do_logv( int level, const char *fmt, va_list arg_ptr )
+{
+  if (!logstream)
+    logstream = stderr;
+
+  if (missing_lf && level != JNLIB_LOG_CONT)
+    putc('\n', logstream );
+  missing_lf = 0;
+
+  if (level != JNLIB_LOG_CONT)
+    { /* Note this does not work for multiple line logging as we would
+       * need to print to a buffer first */
+      if (with_time)
+        {
+          struct tm *tp;
+          time_t atime = time (NULL);
+          
+          tp = localtime (&atime);
+          fprintf (logstream, "%04d-%02d-%02d %02d:%02d:%02d ",
+                   1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+                   tp->tm_hour, tp->tm_min, tp->tm_sec );
+        }
+      if (with_prefix)
+        fputs (prefix_buffer, logstream);
+      if (with_pid)
+        fprintf (logstream, "[%u]", (unsigned int)getpid ());
+      if (!with_time)
+        putc (':', logstream);
+      putc (' ', logstream);
     }
 
-    switch ( level ) {
-      case MY_LOG_BEGIN: break;
-      case MY_LOG_CONT: break;
-      case MY_LOG_INFO: break;
-      case MY_LOG_WARN: break;
-      case MY_LOG_ERROR: break;
-      case MY_LOG_FATAL: fputs("Fatal: ",logstream ); break;
-      case MY_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
-      case MY_LOG_DEBUG: fputs("DBG: ", logstream ); break;
-      default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
+  switch (level)
+    {
+    case JNLIB_LOG_BEGIN: break;
+    case JNLIB_LOG_CONT: break;
+    case JNLIB_LOG_INFO: break;
+    case JNLIB_LOG_WARN: break;
+    case JNLIB_LOG_ERROR: break;
+    case JNLIB_LOG_FATAL: fputs("Fatal: ",logstream ); break;
+    case JNLIB_LOG_BUG: fputs("Ohhhh jeeee: ", logstream); break;
+    case JNLIB_LOG_DEBUG: fputs("DBG: ", logstream ); break;
+    default: fprintf(logstream,"[Unknown log level %d]: ", level ); break;
     }
 
-    if( fmt ) {
-       vfprintf(logstream,fmt,arg_ptr) ;
-       if( *fmt && fmt[strlen(fmt)-1] != '\n' )
-           missing_lf = 1;
+  if (fmt)
+    {
+      vfprintf(logstream,fmt,arg_ptr) ;
+      if (*fmt && fmt[strlen(fmt)-1] != '\n')
+        missing_lf = 1;
     }
 
-    if( level == MY_LOG_FATAL )
-       exit(2);
-    if( level == MY_LOG_BUG )
-       abort();
+  if (level == JNLIB_LOG_FATAL)
+    exit(2);
+  if (level == JNLIB_LOG_BUG)
+    abort();
 }
 
 static void
@@ -163,6 +192,11 @@ do_log( int level, const char *fmt, ... )
 }
 
 
+void
+log_logv (int level, const char *fmt, va_list arg_ptr)
+{
+  do_logv (level, fmt, arg_ptr);
+}
 
 void
 log_info( const char *fmt, ... )
@@ -170,7 +204,7 @@ log_info( const char *fmt, ... )
     va_list arg_ptr ;
 
     va_start( arg_ptr, fmt ) ;
-    do_logv( MY_LOG_INFO, fmt, arg_ptr );
+    do_logv( JNLIB_LOG_INFO, fmt, arg_ptr );
     va_end(arg_ptr);
 }
 
@@ -180,7 +214,7 @@ log_error( const char *fmt, ... )
     va_list arg_ptr ;
 
     va_start( arg_ptr, fmt ) ;
-    do_logv( MY_LOG_ERROR, fmt, arg_ptr );
+    do_logv( JNLIB_LOG_ERROR, fmt, arg_ptr );
     va_end(arg_ptr);
     /* protect against counter overflow */
     if( errorcount < 30000 )
@@ -194,7 +228,7 @@ log_fatal( const char *fmt, ... )
     va_list arg_ptr ;
 
     va_start( arg_ptr, fmt ) ;
-    do_logv( MY_LOG_FATAL, fmt, arg_ptr );
+    do_logv( JNLIB_LOG_FATAL, fmt, arg_ptr );
     va_end(arg_ptr);
     abort(); /* never called, bugs it makes the compiler happy */
 }
@@ -205,7 +239,7 @@ log_bug( const char *fmt, ... )
     va_list arg_ptr ;
 
     va_start( arg_ptr, fmt ) ;
-    do_logv( MY_LOG_BUG, fmt, arg_ptr );
+    do_logv( JNLIB_LOG_BUG, fmt, arg_ptr );
     va_end(arg_ptr);
     abort(); /* never called, but it makes the compiler happy */
 }
@@ -216,7 +250,7 @@ log_debug( const char *fmt, ... )
     va_list arg_ptr ;
 
     va_start( arg_ptr, fmt ) ;
-    do_logv( MY_LOG_DEBUG, fmt, arg_ptr );
+    do_logv( JNLIB_LOG_DEBUG, fmt, arg_ptr );
     va_end(arg_ptr);
 }
 
@@ -227,16 +261,35 @@ log_printf (const char *fmt, ...)
   va_list arg_ptr;
 
   va_start (arg_ptr, fmt);
-  do_logv (fmt ? MY_LOG_CONT : MY_LOG_BEGIN, fmt, arg_ptr);
+  do_logv (fmt ? JNLIB_LOG_CONT : JNLIB_LOG_BEGIN, fmt, arg_ptr);
   va_end (arg_ptr);
 }
 
+/* Print a hexdump of BUFFER.  With TEXT of NULL print just the raw
+   dump, with TEXT just an empty string, print a trailing linefeed,
+   otherwise print an entire debug line. */
+void
+log_printhex (const char *text, const void *buffer, size_t length)
+{
+  if (text && *text)
+    log_debug ("%s ", text);
+  if (length)
+    {
+      const unsigned char *p = buffer;
+      log_printf ("%02X", *p);
+      for (length--, p++; length--; p++)
+        log_printf (" %02X", *p);
+    }
+  if (text)
+    log_printf ("\n");
+}
+
 
 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
 void
 bug_at( const char *file, int line, const char *func )
 {
-    do_log( MY_LOG_BUG,
+    do_log( JNLIB_LOG_BUG,
             ("... this is a bug (%s:%d:%s)\n"), file, line, func );
     abort(); /* never called, but it makes the compiler happy */
 }
@@ -244,7 +297,7 @@ bug_at( const char *file, int line, const char *func )
 void
 bug_at( const char *file, int line )
 {
-    do_log( MY_LOG_BUG,
+    do_log( JNLIB_LOG_BUG,
             _("you found a bug ... (%s:%d)\n"), file, line);
     abort(); /* never called, but it makes the compiler happy */
 }
index 83158f0..7b7b8c8 100644 (file)
 #include <stdio.h>
 #include "mischelp.h"
 
+
 int  log_get_errorcount (int clear);
 void log_set_file( const char *name );
+void log_set_prefix (const char *text, unsigned int flags);
 int  log_get_fd(void);
+FILE *log_get_stream (void);
 
 #ifdef JNLIB_GCC_M_FUNCTION
   void bug_at( const char *file, int line, const char *func ) JNLIB_GCC_A_NR;
@@ -36,12 +39,36 @@ int  log_get_fd(void);
 # define BUG() bug_at( __FILE__ , __LINE__ )
 #endif
 
+/* To avoid mandatory inclusion of stdarg and other stuff, do it only
+   if explicitly requested to do so. */
+#ifdef JNLIB_NEED_LOG_LOGV
+#include <stdarg.h>
+enum jnlib_log_levels {
+    JNLIB_LOG_BEGIN,
+    JNLIB_LOG_CONT,
+    JNLIB_LOG_INFO,
+    JNLIB_LOG_WARN,
+    JNLIB_LOG_ERROR,
+    JNLIB_LOG_FATAL,
+    JNLIB_LOG_BUG,
+    JNLIB_LOG_DEBUG
+};
+void log_logv (int level, const char *fmt, va_list arg_ptr);
+#endif /*JNLIB_NEED_LOG_LOGV*/
+
+
 void log_bug( const char *fmt, ... )   JNLIB_GCC_A_NR_PRINTF(1,2);
 void log_fatal( const char *fmt, ... ) JNLIB_GCC_A_NR_PRINTF(1,2);
 void log_error( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
 void log_info( const char *fmt, ... )  JNLIB_GCC_A_PRINTF(1,2);
 void log_debug( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
 void log_printf( const char *fmt, ... ) JNLIB_GCC_A_PRINTF(1,2);
+void log_printhex (const char *text, const void *buffer, size_t length);
 
 
 #endif /*LIBJNLIB_LOGGING_H*/
+
+
+
+
+
diff --git a/jnlib/strlist.c b/jnlib/strlist.c
new file mode 100644 (file)
index 0000000..7cbaf5e
--- /dev/null
@@ -0,0 +1,133 @@
+/* strlist.c -  string helpers
+ *     Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * GnuPG 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "libjnlib-config.h"
+#include "strlist.h"
+
+
+void
+free_strlist( STRLIST sl )
+{
+    STRLIST sl2;
+
+    for(; sl; sl = sl2 ) {
+       sl2 = sl->next;
+       jnlib_free(sl);
+    }
+}
+
+
+STRLIST
+add_to_strlist( STRLIST *list, const char *string )
+{
+    STRLIST sl;
+
+    sl = jnlib_xmalloc( sizeof *sl + strlen(string));
+    sl->flags = 0;
+    strcpy(sl->d, string);
+    sl->next = *list;
+    *list = sl;
+    return sl;
+}
+
+#if 0
+/****************
+ * same as add_to_strlist() but if is_utf8 is *not* set a conversion
+ * to UTF8 is done
+ */
+STRLIST
+add_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
+{
+    STRLIST sl;
+
+    if( is_utf8 )
+       sl = add_to_strlist( list, string );
+    else {
+       char *p = native_to_utf8( string );
+       sl = add_to_strlist( list, p );
+       m_free( p );
+    }
+    return sl;
+}
+#endif
+
+STRLIST
+append_to_strlist( STRLIST *list, const char *string )
+{
+    STRLIST r, sl;
+
+    sl = jnlib_xmalloc( sizeof *sl + strlen(string));
+    sl->flags = 0;
+    strcpy(sl->d, string);
+    sl->next = NULL;
+    if( !*list )
+       *list = sl;
+    else {
+       for( r = *list; r->next; r = r->next )
+           ;
+       r->next = sl;
+    }
+    return sl;
+}
+
+#if 0
+STRLIST
+append_to_strlist2( STRLIST *list, const char *string, int is_utf8 )
+{
+    STRLIST sl;
+
+    if( is_utf8 )
+       sl = append_to_strlist( list, string );
+    else {
+       char *p = native_to_utf8( string );
+       sl = append_to_strlist( list, p );
+       m_free( p );
+    }
+    return sl;
+}
+#endif
+
+STRLIST
+strlist_prev( STRLIST head, STRLIST node )
+{
+    STRLIST n;
+
+    for(n=NULL; head && head != node; head = head->next )
+       n = head;
+    return n;
+}
+
+STRLIST
+strlist_last( STRLIST node )
+{
+    if( node )
+       for( ; node->next ; node = node->next )
+           ;
+    return node;
+}
+
+
+
diff --git a/jnlib/strlist.h b/jnlib/strlist.h
new file mode 100644 (file)
index 0000000..53c0bc7
--- /dev/null
@@ -0,0 +1,43 @@
+/* strlist.h
+ *     Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of 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.
+ *
+ * GnuPG 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#ifndef LIBJNLIB_STRLIST_H
+#define LIBJNLIB_STRLIST_H
+
+struct string_list {
+  struct string_list *next;
+  unsigned int flags;
+  char d[1];
+};
+typedef struct string_list *STRLIST;
+
+
+void    free_strlist( STRLIST sl );
+STRLIST add_to_strlist( STRLIST *list, const char *string );
+STRLIST add_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
+STRLIST append_to_strlist( STRLIST *list, const char *string );
+STRLIST append_to_strlist2( STRLIST *list, const char *string, int is_utf8 );
+STRLIST strlist_prev( STRLIST head, STRLIST node );
+STRLIST strlist_last( STRLIST node );
+
+#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+
+
+#endif /*LIBJNLIB_STRLIST_H*/