doc: Fix documentation of struct data types
[gpgme.git] / src / dirinfo.c
index ab15a59..8526d39 100644 (file)
@@ -1,5 +1,5 @@
 /* dirinfo.c - Get directory information
- * Copyright (C) 2009 g10 Code GmbH
+ * Copyright (C) 2009, 2013 g10 Code GmbH
  *
  * This file is part of GPGME.
  *
@@ -7,12 +7,12 @@
  * 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.
- * 
+ *
  * GPGME 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
  * Lesser General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 #include "priv-io.h"
 #include "debug.h"
 #include "sema.h"
+#include "sys-util.h"
 
 DEFINE_STATIC_LOCK (dirinfo_lock);
 
 /* Constants used internally to select the data.  */
-enum 
+enum
   {
     WANT_HOMEDIR,
-    WANT_AGENT_SOCKET
+    WANT_AGENT_SOCKET,
+    WANT_GPGCONF_NAME,
+    WANT_GPG_NAME,
+    WANT_GPGSM_NAME,
+    WANT_G13_NAME,
+    WANT_UISRV_SOCKET,
+    WANT_GPG_ONE_MODE
   };
 
 /* Values retrieved via gpgconf and cached here.  */
 static struct {
   int  valid;         /* Cached information is valid.  */
+  int  disable_gpgconf;
   char *homedir;
   char *agent_socket;
+  char *gpgconf_name;
+  char *gpg_name;
+  char *gpgsm_name;
+  char *g13_name;
+  char *uisrv_socket;
+  int  gpg_one_mode;  /* System is in gpg1 mode.  */
 } dirinfo;
 
 
+\f
+/* Helper function to be used only by gpgme_set_global_flag.  */
+void
+_gpgme_dirinfo_disable_gpgconf (void)
+{
+  dirinfo.disable_gpgconf = 1;
+}
+
+
 /* Parse the output of "gpgconf --list-dirs".  This function expects
-   that DIRINFO_LOCK is held by the caller.  */
+   that DIRINFO_LOCK is held by the caller.  If COMPONENTS is set, the
+   output of --list-components is expected. */
 static void
-parse_output (char *line)
+parse_output (char *line, int components)
 {
   char *value, *p;
 
@@ -58,6 +82,14 @@ parse_output (char *line)
   if (!value)
     return;
   *value++ = 0;
+  if (components)
+    {
+      /* Skip the second field.  */
+      value = strchr (value, ':');
+      if (!value)
+        return;
+      *value++ = 0;
+    }
   p = strchr (value, ':');
   if (p)
     *p = 0;
@@ -65,20 +97,46 @@ parse_output (char *line)
     return;
   if (!*value)
     return;
-  
-  if (!strcmp (line, "homedir") && !dirinfo.homedir)
-    dirinfo.homedir = strdup (value);
-  else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
-    dirinfo.agent_socket = strdup (value);
+
+  if (components)
+    {
+      if (!strcmp (line, "gpg") && !dirinfo.gpg_name)
+        dirinfo.gpg_name = strdup (value);
+      else if (!strcmp (line, "gpgsm") && !dirinfo.gpgsm_name)
+        dirinfo.gpgsm_name = strdup (value);
+      else if (!strcmp (line, "g13") && !dirinfo.g13_name)
+        dirinfo.g13_name = strdup (value);
+    }
+  else
+    {
+      if (!strcmp (line, "homedir") && !dirinfo.homedir)
+        {
+          const char name[] = "S.uiserver";
+
+          dirinfo.homedir = strdup (value);
+          if (dirinfo.homedir)
+            {
+              dirinfo.uisrv_socket = malloc (strlen (dirinfo
+                                                     .homedir)
+                                             + 1 + strlen (name) + 1);
+              if (dirinfo.uisrv_socket)
+                strcpy (stpcpy (stpcpy (dirinfo.uisrv_socket, dirinfo.homedir),
+                                DIRSEP_S), name);
+            }
+        }
+      else if (!strcmp (line, "agent-socket") && !dirinfo.agent_socket)
+        dirinfo.agent_socket = strdup (value);
+    }
 }
 
 
 /* Read the directory information from gpgconf.  This function expects
-   that DIRINFO_LOCK is held by the caller.  */
+   that DIRINFO_LOCK is held by the caller.  PGNAME is the name of the
+   gpgconf binary. If COMPONENTS is set, not the directories bit the
+   name of the componeNts are read. */
 static void
-read_gpgconf_dirs (void) 
+read_gpgconf_dirs (const char *pgmname, int components)
 {
-  const char *pgmname;
   char linebuf[1024] = {0};
   int linelen = 0;
   char * argv[3];
@@ -89,12 +147,8 @@ read_gpgconf_dirs (void)
   int nread;
   char *mark = NULL;
 
-  pgmname = _gpgme_get_gpgconf_path ();
-  if (!pgmname)
-    return;  /* No way.  */
-
   argv[0] = (char *)pgmname;
-  argv[1] = "--list-dirs";
+  argv[1] = components? "--list-components" : "--list-dirs";
   argv[2] = NULL;
 
   if (_gpgme_io_pipe (rp, 1) < 0)
@@ -102,7 +156,7 @@ read_gpgconf_dirs (void)
 
   cfd[0].fd = rp[1];
 
-  status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL);
+  status = _gpgme_io_spawn (pgmname, argv, 0, cfd, NULL, NULL, NULL);
   if (status < 0)
     {
       _gpgme_io_close (rp[0]);
@@ -112,8 +166,8 @@ read_gpgconf_dirs (void)
 
   do
     {
-      nread = _gpgme_io_read (rp[0], 
-                              linebuf + linelen, 
+      nread = _gpgme_io_read (rp[0],
+                              linebuf + linelen,
                               sizeof linebuf - linelen - 1);
       if (nread > 0)
        {
@@ -132,7 +186,7 @@ read_gpgconf_dirs (void)
               else
                 mark[0] = '\0';
 
-              parse_output (line);
+              parse_output (line, components);
            }
 
           nused = lastmark? (lastmark + 1 - linebuf) : 0;
@@ -141,20 +195,48 @@ read_gpgconf_dirs (void)
        }
     }
   while (nread > 0 && linelen < sizeof linebuf - 1);
-  
+
   _gpgme_io_close (rp[0]);
 }
 
 
 static const char *
-get_gpgconf_dir (int what)
+get_gpgconf_item (int what)
 {
   const char *result = NULL;
 
   LOCK (dirinfo_lock);
   if (!dirinfo.valid)
     {
-      read_gpgconf_dirs ();
+      char *pgmname;
+
+      pgmname = dirinfo.disable_gpgconf? NULL : _gpgme_get_gpgconf_path ();
+      if (pgmname && access (pgmname, F_OK))
+        {
+          _gpgme_debug (DEBUG_INIT,
+                        "gpgme-dinfo: gpgconf='%s' [not installed]\n", pgmname);
+          free (pgmname);
+          pgmname = NULL; /* Not available.  */
+        }
+      else
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: gpgconf='%s'\n",
+                      pgmname? pgmname : "[null]");
+      if (!pgmname)
+        {
+          /* Probably gpgconf is not installed.  Assume we are using
+             GnuPG-1.  */
+          dirinfo.gpg_one_mode = 1;
+          pgmname = _gpgme_get_gpg_path ();
+          if (pgmname)
+            dirinfo.gpg_name = pgmname;
+        }
+      else
+        {
+          dirinfo.gpg_one_mode = 0;
+          read_gpgconf_dirs (pgmname, 0);
+          read_gpgconf_dirs (pgmname, 1);
+          dirinfo.gpgconf_name = pgmname;
+        }
       /* Even if the reading of the directories failed (e.g. due to an
          too old version gpgconf or no gpgconf at all), we need to
          mark the entries as valid so that we won't try over and over
@@ -162,11 +244,35 @@ get_gpgconf_dir (int what)
          the read values later because they are practically statically
          allocated.  */
       dirinfo.valid = 1;
+      if (dirinfo.gpg_name)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     gpg='%s'\n",
+                      dirinfo.gpg_name);
+      if (dirinfo.g13_name)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:     g13='%s'\n",
+                      dirinfo.g13_name);
+      if (dirinfo.gpgsm_name)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   gpgsm='%s'\n",
+                      dirinfo.gpgsm_name);
+      if (dirinfo.homedir)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo: homedir='%s'\n",
+                      dirinfo.homedir);
+      if (dirinfo.agent_socket)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   agent='%s'\n",
+                      dirinfo.agent_socket);
+      if (dirinfo.uisrv_socket)
+        _gpgme_debug (DEBUG_INIT, "gpgme-dinfo:   uisrv='%s'\n",
+                      dirinfo.uisrv_socket);
     }
   switch (what)
     {
     case WANT_HOMEDIR: result = dirinfo.homedir; break;
     case WANT_AGENT_SOCKET: result = dirinfo.agent_socket; break;
+    case WANT_GPGCONF_NAME: result = dirinfo.gpgconf_name; break;
+    case WANT_GPG_NAME:   result = dirinfo.gpg_name; break;
+    case WANT_GPGSM_NAME: result = dirinfo.gpgsm_name; break;
+    case WANT_G13_NAME:   result = dirinfo.g13_name; break;
+    case WANT_UISRV_SOCKET:  result = dirinfo.uisrv_socket; break;
+    case WANT_GPG_ONE_MODE: result = dirinfo.gpg_one_mode? "1":NULL; break;
     }
   UNLOCK (dirinfo_lock);
   return result;
@@ -177,13 +283,76 @@ get_gpgconf_dir (int what)
 const char *
 _gpgme_get_default_homedir (void)
 {
-  return get_gpgconf_dir (WANT_HOMEDIR);
+  return get_gpgconf_item (WANT_HOMEDIR);
 }
 
 /* Return the default gpg-agent socket name.  Returns NULL if not known.  */
 const char *
 _gpgme_get_default_agent_socket (void)
 {
-  return get_gpgconf_dir (WANT_AGENT_SOCKET);
+  return get_gpgconf_item (WANT_AGENT_SOCKET);
+}
+
+/* Return the default gpg file name.  Returns NULL if not known.  */
+const char *
+_gpgme_get_default_gpg_name (void)
+{
+  return get_gpgconf_item (WANT_GPG_NAME);
 }
 
+/* Return the default gpgsm file name.  Returns NULL if not known.  */
+const char *
+_gpgme_get_default_gpgsm_name (void)
+{
+  return get_gpgconf_item (WANT_GPGSM_NAME);
+}
+
+/* Return the default g13 file name.  Returns NULL if not known.  */
+const char *
+_gpgme_get_default_g13_name (void)
+{
+  return get_gpgconf_item (WANT_G13_NAME);
+}
+
+/* Return the default gpgconf file name.  Returns NULL if not known.  */
+const char *
+_gpgme_get_default_gpgconf_name (void)
+{
+  return get_gpgconf_item (WANT_GPGCONF_NAME);
+}
+
+/* Return the default UI-server socket name.  Returns NULL if not
+   known.  */
+const char *
+_gpgme_get_default_uisrv_socket (void)
+{
+  return get_gpgconf_item (WANT_UISRV_SOCKET);
+}
+
+/* Return true if we are in GnuPG-1 mode - ie. no gpgconf and agent
+   being optional.  */
+int
+_gpgme_in_gpg_one_mode (void)
+{
+  return !!get_gpgconf_item (WANT_GPG_ONE_MODE);
+}
+
+
+
+/* Helper function to return the basename of the passed filename.  */
+const char *
+_gpgme_get_basename (const char *name)
+{
+  const char *s;
+
+  if (!name || !*name)
+    return name;
+  for (s = name + strlen (name) -1; s >= name; s--)
+    if (*s == '/'
+#ifdef HAVE_W32_SYSTEM
+        || *s == '\\' || *s == ':'
+#endif
+        )
+      return s+1;
+  return name;
+}