1 /* version.c - version check
2 * Copyright (C) 2000 Werner Koch (dd9jn)
3 * Copyright (C) 2001 g10 Code GmbH
5 * This file is part of GPGME.
7 * GPGME is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * GPGME is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
33 #include "key.h" /* for key_cache_init */
36 static char *tmp_engine_version;
38 static const char *get_engine_info (void);
42 do_subsystem_inits (void)
48 _gpgme_sema_subsystem_init ();
49 _gpgme_key_cache_init ();
55 parse_version_number ( const char *s, int *number )
59 if ( *s == '0' && isdigit(s[1]) )
60 return NULL; /* leading zeros are not allowed */
61 for ( ; isdigit(*s); s++ ) {
66 return val < 0? NULL : s;
71 parse_version_string( const char *s, int *major, int *minor, int *micro )
73 s = parse_version_number ( s, major );
74 if ( !s || *s != '.' )
77 s = parse_version_number ( s, minor );
78 if ( !s || *s != '.' )
81 s = parse_version_number ( s, micro );
84 return s; /* patchlevel */
88 compare_versions ( const char *my_version, const char *req_version )
90 int my_major, my_minor, my_micro;
91 int rq_major, rq_minor, rq_micro;
92 const char *my_plvl, *rq_plvl;
97 my_plvl = parse_version_string ( my_version,
98 &my_major, &my_minor, &my_micro );
100 return NULL; /* very strange: our own version is bogus */
101 rq_plvl = parse_version_string( req_version,
102 &rq_major, &rq_minor, &rq_micro );
104 return NULL; /* req version string is invalid */
106 if ( my_major > rq_major
107 || (my_major == rq_major && my_minor > rq_minor)
108 || (my_major == rq_major && my_minor == rq_minor
109 && my_micro > rq_micro)
110 || (my_major == rq_major && my_minor == rq_minor
111 && my_micro == rq_micro
112 && strcmp( my_plvl, rq_plvl ) >= 0) ) {
120 * gpgme_check_version:
121 * @req_version: A string with a version
123 * Check that the the version of the library is at minimum the requested one
124 * and return the version string; return NULL if the condition is not
125 * met. If a NULL is passed to this function, no check is done and
126 * the version string is simply returned. It is a pretty good idea to
127 * run this function as soon as poossible, becuase it also intializes
128 * some subsystems. In a multithreaded environment if should be called
129 * before the first thread is created.
131 * Return value: The version string or NULL
134 gpgme_check_version ( const char *req_version )
136 do_subsystem_inits ();
137 return compare_versions ( VERSION, req_version );
142 * gpgme_get_engine_info:
144 * Return information about the underlying crypto engine. This is an
145 * XML string with various information. To get the version of the
146 * crypto engine it should be sufficient to grep for the first
147 * <literal>version</literal> tag and use it's content. A string is
148 * always returned even if the crypto engine is not installed; in this
149 * case a XML string with some error information is returned.
151 * Return value: A XML string with information about the crypto engine.
154 gpgme_get_engine_info ()
156 do_subsystem_inits ();
157 return get_engine_info ();
161 * gpgme_check_engine:
163 * Check whether the installed crypto engine matches the requirement of
166 * Return value: 0 or an error code.
169 gpgme_check_engine ()
171 const char *info = gpgme_get_engine_info ();
174 s = strstr (info, "<version>");
177 s2 = strchr (s, '<');
179 char *ver = xtrymalloc (s2 - s + 1);
181 return mk_error (Out_Of_Core);
182 memcpy (ver, s, s2-s);
184 s = compare_versions ( ver, NEED_GPG_VERSION );
190 return mk_error (Invalid_Engine);
196 version_line_handler ( GpgmeCtx c, char *line )
202 if ( c->out_of_core )
207 if ( memcmp (line, "gpg ", 4) )
209 if ( !(p = strpbrk (line, "0123456789")) )
211 len = strcspn (p, " \t\r\n()<>" );
213 tmp_engine_version = xtrystrdup (p);
219 get_engine_info (void)
221 static const char *engine_info =NULL;
224 const char *path = NULL;
226 /* FIXME: make sure that only one instance does run */
230 path = _gpgme_get_gpg_path ();
231 err = gpgme_new (&c);
234 err = _gpgme_gpg_new ( &c->gpg );
238 err = _gpgme_gpg_set_simple_line_handler ( c->gpg,
239 version_line_handler, c );
243 _gpgme_gpg_add_arg ( c->gpg, "--version" );
245 xfree (tmp_engine_version); tmp_engine_version = NULL;
246 err = _gpgme_gpg_spawn ( c->gpg, c );
250 if (tmp_engine_version) {
254 fmt = "<GnupgInfo>\n"
256 " <version>%s</version>\n"
260 /*(yes, I know that we allocating 2 extra bytes)*/
261 p = xtrymalloc ( strlen(fmt) + strlen(path)
262 + strlen (tmp_engine_version) + 1);
264 err = mk_error (Out_Of_Core);
267 sprintf (p, fmt, tmp_engine_version, path);
269 xfree (tmp_engine_version); tmp_engine_version = NULL;
272 err = mk_error (General_Error);
278 const char *errstr = gpgme_strerror (err);
281 fmt = "<GnupgInfo>\n"
283 " <error>%s</error>\n"
288 p = xtrymalloc ( strlen(fmt) + strlen(errstr) + strlen(path) + 1);
290 sprintf (p, fmt, errstr, path);
294 engine_info = "<GnupgInfo>\n"
295 " <error>Out of core</error>\n"