/* t-gpgconf.c - Regression test. * Copyright (C) 2001, 2004, 2007 g10 Code GmbH * * This file is part of GPGME. * * GPGME is free software; you can redistribute it and/or modify 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. * * 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 . * SPDX-License-Identifier: LGPL-2.1-or-later */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #ifdef HAVE_W32_SYSTEM #include #endif #include #include "t-support.h" static char * spaces (char *str, int extra) { static char buf[80]; int len = str ? strlen (str) : 0; int n; #define TABSTOP 30 n = TABSTOP - len - extra; memset (buf, ' ', sizeof (buf)); if (n < 1 || n > (sizeof (buf) - 1)) { buf[0] = '\n'; n = TABSTOP + 1; } buf[n] = '\0'; return buf; } void dump_arg (int type, gpgme_conf_arg_t arg) { if (!arg) { printf ("(none)"); return; } while (arg) { switch (type) { case GPGME_CONF_STRING: case GPGME_CONF_PATHNAME: case GPGME_CONF_LDAP_SERVER: case GPGME_CONF_KEY_FPR: case GPGME_CONF_PUB_KEY: case GPGME_CONF_SEC_KEY: case GPGME_CONF_ALIAS_LIST: printf ("`%s'", arg->value.string); break; case GPGME_CONF_UINT32: printf ("%u", arg->value.uint32); break; case GPGME_CONF_INT32: printf ("%i", arg->value.int32); break; case GPGME_CONF_NONE: printf ("%i (times)", arg->value.count); break; default: printf ("(unknown type)"); } arg = arg->next; if (arg) printf (" "); } } void dump_opt (gpgme_conf_opt_t opt) { char level; char runtime = (opt->flags & GPGME_CONF_RUNTIME) ? 'r' : ' '; switch (opt->level) { case GPGME_CONF_BASIC: level = 'b'; break; case GPGME_CONF_ADVANCED: level = 'a'; break; case GPGME_CONF_EXPERT: level = 'e'; break; case GPGME_CONF_INVISIBLE: level = 'i'; break; case GPGME_CONF_INTERNAL: level = '#'; break; default: level = '?'; } if (opt->flags & GPGME_CONF_GROUP) { printf ("\n"); printf ("%c%c [%s]%s%s\n", level, runtime, opt->name, spaces (opt->name, 5), opt->description ? opt->description : ""); } else { if (opt->argname) { const char *more = (opt->flags & GPGME_CONF_LIST) ? "..." : ""; if (opt->flags & GPGME_CONF_OPTIONAL) { printf ("%c%c --%s [%s%s] %s", level, runtime, opt->name, opt->argname, more, spaces (opt->name, 9 + strlen (opt->argname) + strlen (more))); } else { printf ("%c%c --%s %s%s %s", level, runtime, opt->name, opt->argname, more, spaces (opt->name, 7 + strlen (opt->argname) + strlen (more))); } } else printf ("%c%c --%s%s", level, runtime, opt->name, spaces (opt->name, 5)); if (opt->description) printf ("%s", opt->description); printf ("\n"); if (opt->flags & GPGME_CONF_DEFAULT) { printf ("%s%s = ", spaces (NULL, 0), opt->argname ? opt->argname : "(default)"); dump_arg (opt->type, opt->default_value); printf ("\n"); } else if (opt->flags & GPGME_CONF_DEFAULT_DESC) printf ("%s%s = %s\n", spaces (NULL, 0), opt->argname ? opt->argname : "(default)", opt->default_description); if (opt->no_arg_value) { printf ("%sNo Arg Def = ", spaces (NULL, 0)); dump_arg (opt->type, opt->no_arg_value); printf ("\n"); } if (opt->value) { printf ("%sCurrent = ", spaces (NULL, 0)); dump_arg (opt->type, opt->value); printf ("\n"); } } #if 0 arg = comp->options; while (opt) { dump_opt (opt); opt = opt->next; } #endif } void dump_comp (gpgme_conf_comp_t comp) { gpgme_conf_opt_t opt; printf ("COMPONENT\n"); printf ("=========\n"); printf (" Name: %s\n", comp->name); if (comp->description) printf (" Desc: %s\n", comp->description); if (comp->program_name) printf (" Path: %s\n", comp->program_name); printf ("\n"); opt = comp->options; while (opt) { dump_opt (opt); opt = opt->next; } } int lookup (gpgme_conf_comp_t conf, const char *component, const char *option, gpgme_conf_comp_t *comp, gpgme_conf_opt_t *opt) { *comp = conf; while (*comp && strcmp ((*comp)->name, component)) *comp = (*comp)->next; if (*comp) { *opt = (*comp)->options; while (*opt && strcmp ((*opt)->name, option)) *opt = (*opt)->next; /* Allow for the option not to be there. */ if (*opt) return 1; /* Found. */ } return 0; /* Not found. */ } #include int main (void) { gpgme_ctx_t ctx; gpgme_error_t err; gpgme_conf_comp_t conf; gpgme_conf_comp_t comp; int first; int i, N = 10; init_gpgme (GPGME_PROTOCOL_GPGCONF); err = gpgme_new (&ctx); fail_if_err (err); { /* Let's check getting the agent-socket directory for different homedirs. */ char *result1 = NULL; char *result2 = NULL; err = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_GPGCONF, NULL, "/tmp/foo"); fail_if_err (err); err = gpgme_op_conf_dir (ctx, "agent-socket", &result1); fail_if_err (err); err = gpgme_ctx_set_engine_info (ctx, GPGME_PROTOCOL_GPGCONF, NULL, NULL); fail_if_err (err); err = gpgme_op_conf_dir (ctx, "agent-socket", &result2); fail_if_err (err); /* They have to be different. */ test (strcmp(result1, result2)); gpgme_free (result1); gpgme_free (result2); } err = gpgme_op_conf_load (ctx, &conf); fail_if_err (err); comp = conf; first = 1; while (comp) { if (!first) printf ("\n"); else first = 0; dump_comp (comp); comp = comp->next; } /* Now change something. */ fprintf (stderr, " dirmngr.verbose "); for (i = 0; i < N; i++) { unsigned int count = i % 4 + 1; /* counts must not be zero */ gpgme_conf_arg_t arg; gpgme_conf_opt_t opt; err = gpgme_conf_arg_new (&arg, GPGME_CONF_NONE, &count); fail_if_err (err); if (lookup (conf, "dirmngr", "verbose", &comp, &opt)) { /* Found. */ err = gpgme_conf_opt_change (opt, 0, arg); fail_if_err (err); err = gpgme_op_conf_save (ctx, comp); fail_if_err (err); } else { fprintf (stderr, "Skipping test, option dirmngr.verbose not found.\n"); break; } /* Reload config and verify that the value was updated. */ gpgme_conf_release (conf); err = gpgme_op_conf_load (ctx, &conf); fail_if_err (err); if (lookup (conf, "dirmngr", "verbose", &comp, &opt)) { /* Found. */ test (opt->alt_type == GPGME_CONF_NONE); test (opt->value); test ((unsigned long) opt->value->value.count == count); } fprintf (stderr, "."); fflush (stderr); } /* Now change something else. */ fprintf (stderr, " dirmngr.keyserver "); for (i = 0; i < N; i++) { const char *values[2] = { "hkp://foo.bar", "hkps://bar.foo" }; gpgme_conf_arg_t arg; gpgme_conf_opt_t opt; err = gpgme_conf_arg_new (&arg, GPGME_CONF_STRING, values[i%2]); fail_if_err (err); if (lookup (conf, "dirmngr", "keyserver", &comp, &opt)) { /* Found. */ test (opt->alt_type == GPGME_CONF_STRING); err = gpgme_conf_opt_change (opt, 0, arg); fail_if_err (err); err = gpgme_op_conf_save (ctx, comp); fail_if_err (err); } else { fprintf (stderr, "Skipping test, option dirmngr.keyserver not found.\n"); break; } /* Reload config and verify that the value was updated. */ gpgme_conf_release (conf); err = gpgme_op_conf_load (ctx, &conf); fail_if_err (err); if (lookup (conf, "dirmngr", "keyserver", &comp, &opt)) { /* Found. */ test (opt->alt_type == GPGME_CONF_STRING); test (opt->value); test (opt->value->value.string); test (strcmp (opt->value->value.string, values[i%2]) == 0); } fprintf (stderr, "."); fflush (stderr); } fprintf (stderr, "\n"); gpgme_conf_release (conf); gpgme_release (ctx); return 0; }