diff --git a/AUTHORS b/AUTHORS index d554ac7c9..93f6ed4e6 100644 --- a/AUTHORS +++ b/AUTHORS @@ -125,8 +125,34 @@ GnuPG. The RPM specs file scripts/gnupg.spec has been contributed by several people. - Copyright 1998, 1999, 2000, 2001, 2002, 2004, - 2005 Free Software Foundation, Inc. + +Copyright +========= + +GnuPG is distributed under the GNU General Public License, version 2 +or later. A few files are under the Lesser General Public License, a +few other files carry the all permissive license note as found at the +bottom of this file. Certain files in keyserver/ allow one specific +exception: + + In addition, as a special exception, the Free Software Foundation + gives permission to link the code of the keyserver helper tools: + gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + project's "OpenSSL" library (or with modified versions of it that + use the same license as the "OpenSSL" library), and distribute the + linked executables. You must obey the GNU General Public License + in all respects for all of the code used other than "OpenSSL". If + you modify this file, you may extend this exception to your version + of the file, but you are not obligated to do so. If you do not + wish to do so, delete this exception statement from your version. + +Note that the gpgkeys_* binaries are currently installed under the +name gpg2keys_*. + +========= + + Copyright 1998, 1999, 2000, 2001, 2002, 2004, 2005, + 2006 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 diff --git a/ChangeLog b/ChangeLog index aa0a178da..3f58bc8a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2006-09-22 Werner Koch + + * AUTHORS: Add information about used licenses. + 2006-09-20 Werner Koch * Makefile.am (dist-hook): Removed distfiles cruft. diff --git a/common/ChangeLog b/common/ChangeLog index cde4c4b3d..1657ae0be 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,10 @@ +2006-09-22 Werner Koch + + * i18n.h: Changed license to an all permissive one. + + * ttyio.c (tty_get): We need to use readline too. Added two more + hooks. + 2006-09-21 Werner Koch * ttyio.c (tty_private_set_rl_hooks): New. diff --git a/common/common-defs.h b/common/common-defs.h index 0a6403a2c..96d0a1f32 100644 --- a/common/common-defs.h +++ b/common/common-defs.h @@ -23,9 +23,12 @@ #define GNUPG_COMMON_COMMON_DEFS_H /*-- ttyio.c --*/ -void tty_private_set_rl_hooks (void (*set_completer) (rl_completion_func_t*), +void tty_private_set_rl_hooks (void (*init_stream) (FILE *), + void (*set_completer) (rl_completion_func_t*), void (*inhibit_completion) (int), - void (*cleanup_after_signal) (void) ); + void (*cleanup_after_signal) (void), + char *(*readline_fun) (const char*), + void (*add_history_fun) (const char*)); diff --git a/common/i18n.h b/common/i18n.h index 0187ba265..6881a8a61 100644 --- a/common/i18n.h +++ b/common/i18n.h @@ -1,22 +1,14 @@ /* i18n.h * Copyright (C) 1998, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. */ #ifndef GNUPG_COMMON_I18N_H diff --git a/common/ttyio.c b/common/ttyio.c index 8b8f8835f..8f1e7b35c 100644 --- a/common/ttyio.c +++ b/common/ttyio.c @@ -81,7 +81,9 @@ static int no_terminal; static void (*my_rl_set_completer) (rl_completion_func_t *); static void (*my_rl_inhibit_completion) (int); static void (*my_rl_cleanup_after_signal) (void); - +static void (*my_rl_init_stream) (FILE *); +static char *(*my_rl_readline) (const char*); +static void (*my_rl_add_history) (const char*); /* This is a wrapper around ttyname so that we can use it even when @@ -174,6 +176,10 @@ init_ttyfp(void) exit(2); } #endif + + if (my_rl_init_stream) + my_rl_init_stream (ttyfp); + #ifdef HAVE_TCGETATTR atexit( cleanup ); #endif @@ -520,7 +526,39 @@ do_get( const char *prompt, int hidden ) char * tty_get( const char *prompt ) { - return do_get( prompt, 0 ); + if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history) + { + char *line; + char *buf; + + if (!initialized) + init_ttyfp(); + + last_prompt_len = 0; + + line = my_rl_readline (prompt?prompt:""); + + /* We need to copy it to memory controlled by our malloc + implementations; further we need to convert an EOF to our + convention. */ + buf = xmalloc(line? strlen(line)+1:2); + if (line) + { + strcpy (buf, line); + trim_spaces (buf); + if (strlen (buf) > 2 ) + my_rl_add_history (line); /* Note that we test BUF but add LINE. */ + free (line); + } + else + { + buf[0] = CONTROL_D; + buf[1] = 0; + } + return buf; + } + else + return do_get ( prompt, 0 ); } char * @@ -573,13 +611,19 @@ tty_get_answer_is_yes( const char *prompt ) /* Called by gnupg_rl_initialize to setup the reradline support. */ void -tty_private_set_rl_hooks (void (*set_completer) (rl_completion_func_t*), +tty_private_set_rl_hooks (void (*init_stream) (FILE *), + void (*set_completer) (rl_completion_func_t*), void (*inhibit_completion) (int), - void (*cleanup_after_signal) (void)) + void (*cleanup_after_signal) (void), + char *(*readline_fun) (const char*), + void (*add_history_fun) (const char*)) { + my_rl_init_stream = init_stream; my_rl_set_completer = set_completer; my_rl_inhibit_completion = inhibit_completion; my_rl_cleanup_after_signal = cleanup_after_signal; + my_rl_readline = readline_fun; + my_rl_add_history = add_history_fun; } diff --git a/keyserver/ChangeLog b/keyserver/ChangeLog index d58e1c8df..7a9851555 100644 --- a/keyserver/ChangeLog +++ b/keyserver/ChangeLog @@ -1,3 +1,25 @@ +2006-09-22 Werner Koch + + * gpgkeys_curl.c, gpgkeys_hkp.c, gpgkeys_ldap.c, curl-shim.c: + * curl-shim.h, ksutil.c, ksutil.h: Add special license exception + for OpenSSL. This helps to avoid license conflicts if OpenLDAP or + cURL is linked against OpenSSL and we would thus indirectly link + to OpenSSL. This is considered a bug fix and forgives all + possible violations, pertaining to this issue, possibly occured in + the past. + + * Makefile.am (gpg2keys_ldap_LDADD): For license reasons do not + link against common_libs. + (gpg2keys_curl_LDADD, gpg2keys_hkp_LDADD): Ditto. + * ksutil.c (ks_hextobyte, ks_toupper, ks_strcasecmp): New. + Identical to the ascii_foo versions from jnlib. + * gpgkeys_ldap.c: Include assert.h. + (main): Replace BUG by assert. + (build_attrs): Use ks_hextobyte and ks_strcasecmp. + + * gpgkeys_finger.c (get_key): Resolved signed/unisgned char + mismatch. + 2006-09-19 Werner Koch * no-libgcrypt.c: New. Taken from ../tools. diff --git a/keyserver/Makefile.am b/keyserver/Makefile.am index cb7ff8d50..1d2e40910 100644 --- a/keyserver/Makefile.am +++ b/keyserver/Makefile.am @@ -18,6 +18,10 @@ ## Process this file with automake to produce Makefile.in +# Note that we have renamed the resulting binaries to from gpgkeys_foo +# to gpg2keys_foo to allow for a non-conflicting installation of +# gnupg1 and gnupg2. Having the same names for the helpers would +# otherwise lead to trouble when to uninstall one of them. EXTRA_PROGRAMS = gpg2keys_ldap gpg2keys_hkp gpg2keys_finger gpg2keys_curl EXTRA_SCRIPTS = gpg2keys_mailto @@ -32,7 +36,7 @@ libexec_PROGRAMS = $(GPGKEYS_LDAP) $(GPGKEYS_HKP) $(GPGKEYS_FINGER) \ libexec_SCRIPTS = $(GPGKEYS_MAILTO) noinst_SCRIPTS = gpgkeys_test -common_libs = ../gl/libgnu.a ../common/libcommon.a ../jnlib/libjnlib.a +common_libs = ../gl/libgnu.a ../common/libcommon.a ../jnlib/libjnlib.a other_libs = $(LIBICONV) $(LIBINTL) $(CAPLIBS) gpg2keys_ldap_SOURCES = gpgkeys_ldap.c ksutil.c ksutil.h no-libgcrypt.c @@ -42,7 +46,7 @@ gpg2keys_curl_SOURCES = gpgkeys_curl.c ksutil.c ksutil.h no-libgcrypt.c gpg2keys_ldap_CPPFLAGS = $(LDAP_CPPFLAGS) $(AM_CPPFLAGS) -gpg2keys_ldap_LDADD = $(common_libs) $(LDAPLIBS) $(NETLIBS) \ +gpg2keys_ldap_LDADD = $(LDAPLIBS) $(NETLIBS) \ $(other_libs) $(W32LIBS) gpg2keys_finger_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) \ @@ -50,10 +54,10 @@ gpg2keys_finger_LDADD = $(common_libs) $(LIBGCRYPT_LIBS) \ if FAKE_CURL gpg2keys_curl_SOURCES += curl-shim.c curl-shim.h -gpg2keys_curl_LDADD = $(common_libs) $(NETLIBS) $(DNSLIBS) \ +gpg2keys_curl_LDADD = $(NETLIBS) $(DNSLIBS) \ $(other_libs) $(W32LIBS) gpg2keys_hkp_SOURCES += curl-shim.c curl-shim.h -gpg2keys_hkp_LDADD = $(common_libs) $(NETLIBS) $(DNSLIBS) \ +gpg2keys_hkp_LDADD = $(NETLIBS) $(DNSLIBS) \ $(other_libs) $(W32LIBS) else gpg2keys_curl_CPPFLAGS = $(LIBCURL_CPPFLAGS) $(AM_CPPFLAGS) diff --git a/keyserver/curl-shim.c b/keyserver/curl-shim.c index 12c7afa94..f9ab3be6c 100644 --- a/keyserver/curl-shim.c +++ b/keyserver/curl-shim.c @@ -19,6 +19,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #include diff --git a/keyserver/curl-shim.h b/keyserver/curl-shim.h index e942ec710..ad8e8e1d9 100644 --- a/keyserver/curl-shim.h +++ b/keyserver/curl-shim.h @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #ifndef _CURL_SHIM_H_ diff --git a/keyserver/gpgkeys_curl.c b/keyserver/gpgkeys_curl.c index 9e4b56729..192f9ba66 100644 --- a/keyserver/gpgkeys_curl.c +++ b/keyserver/gpgkeys_curl.c @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #include diff --git a/keyserver/gpgkeys_finger.c b/keyserver/gpgkeys_finger.c index b4f7b6a78..58082790f 100644 --- a/keyserver/gpgkeys_finger.c +++ b/keyserver/gpgkeys_finger.c @@ -325,13 +325,13 @@ get_key (char *getkey) if(gotit) { - print_nocr(output,line); - if (!strncmp(line,END,strlen(END))) + print_nocr(output, (const char*)line); + if (!strncmp((char*)line,END,strlen(END))) break; } - else if(!strncmp(line,BEGIN,strlen(BEGIN))) + else if(!strncmp((char*)line,BEGIN,strlen(BEGIN))) { - print_nocr(output,line); + print_nocr(output, (const char*)line); gotit=1; } } diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c index e6de3634c..1692a5033 100644 --- a/keyserver/gpgkeys_hkp.c +++ b/keyserver/gpgkeys_hkp.c @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #include diff --git a/keyserver/gpgkeys_ldap.c b/keyserver/gpgkeys_ldap.c index b56cca1cf..df4279ff7 100644 --- a/keyserver/gpgkeys_ldap.c +++ b/keyserver/gpgkeys_ldap.c @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #include @@ -29,6 +40,7 @@ #endif #include #include +#include #ifdef _WIN32 #include @@ -355,7 +367,7 @@ build_attrs(LDAPMod ***modlist,char *line) if((record=strsep(&line,":"))==NULL) return; - if(ascii_strcasecmp("pub",record)==0) + if(ks_strcasecmp("pub",record)==0) { char *tok; int disabled=0,revoked=0; @@ -461,7 +473,7 @@ build_attrs(LDAPMod ***modlist,char *line) make_one_attr(modlist,"pgpDisabled",disabled?"1":"0"); make_one_attr(modlist,"pgpRevoked",revoked?"1":"0"); } - else if(ascii_strcasecmp("sub",record)==0) + else if(ks_strcasecmp("sub",record)==0) { char *tok; @@ -499,7 +511,7 @@ build_attrs(LDAPMod ***modlist,char *line) /* Ignore the rest of the items for subkeys since the LDAP schema doesn't store them. */ } - else if(ascii_strcasecmp("uid",record)==0) + else if(ks_strcasecmp("uid",record)==0) { char *userid,*tok; @@ -520,7 +532,7 @@ build_attrs(LDAPMod ***modlist,char *line) while(*tok) if(tok[0]=='%' && tok[1] && tok[2]) { - if((userid[i]=hextobyte(&tok[1]))==-1) + if((userid[i]=ks_hextobyte(&tok[1]))==-1) userid[i]='?'; i++; @@ -536,7 +548,7 @@ build_attrs(LDAPMod ***modlist,char *line) make_one_attr(modlist,"pgpUserID",userid); } - else if(ascii_strcasecmp("sig",record)==0) + else if(ks_strcasecmp("sig",record)==0) { char *tok; @@ -2325,7 +2337,7 @@ main(int argc,char *argv[]) free(searchkey); } else - BUG(); + assert (!"bad action"); if(!failed) ret=KEYSERVER_OK; diff --git a/keyserver/ksutil.c b/keyserver/ksutil.c index 64912bb2d..18158fc81 100644 --- a/keyserver/ksutil.c +++ b/keyserver/ksutil.c @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #include @@ -538,3 +549,55 @@ curl_writer_finalize(struct curl_writer_ctx *ctx) ctx->flags.done=1; } } + + +int +ks_hextobyte (const char *s) +{ + int c; + + if ( *s >= '0' && *s <= '9' ) + c = 16 * (*s - '0'); + else if ( *s >= 'A' && *s <= 'F' ) + c = 16 * (10 + *s - 'A'); + else if ( *s >= 'a' && *s <= 'f' ) + c = 16 * (10 + *s - 'a'); + else + return -1; + s++; + if ( *s >= '0' && *s <= '9' ) + c += *s - '0'; + else if ( *s >= 'A' && *s <= 'F' ) + c += 10 + *s - 'A'; + else if ( *s >= 'a' && *s <= 'f' ) + c += 10 + *s - 'a'; + else + return -1; + return c; +} + + +/* Non localized version of toupper. */ +int +ks_toupper (int c) +{ + if (c >= 'a' && c <= 'z') + c &= ~0x20; + return c; +} + + +/* Non localized version of strcasecmp. */ +int +ks_strcasecmp (const char *a, const char *b) +{ + if (a == b) + return 0; + + for (; *a && *b; a++, b++) + { + if (*a != *b && ks_toupper (*a) != ks_toupper (*b)) + break; + } + return *a == *b? 0 : (ks_toupper (*a) - ks_toupper (*b)); +} diff --git a/keyserver/ksutil.h b/keyserver/ksutil.h index 16c1ebf88..154054407 100644 --- a/keyserver/ksutil.h +++ b/keyserver/ksutil.h @@ -1,14 +1,14 @@ /* ksutil.h * Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. * - * This file is part of GNUPG. + * This file is part of GnuPG. * - * GNUPG is free software; you can redistribute it and/or modify + * 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, + * 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. @@ -17,6 +17,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. + * + * In addition, as a special exception, the Free Software Foundation + * gives permission to link the code of the keyserver helper tools: + * gpgkeys_ldap, gpgkeys_curl and gpgkeys_hkp with the OpenSSL + * project's "OpenSSL" library (or with modified versions of it that + * use the same license as the "OpenSSL" library), and distribute the + * linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If + * you modify this file, you may extend this exception to your version + * of the file, but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. */ #ifndef _KSUTIL_H_ @@ -127,4 +138,9 @@ struct curl_writer_ctx size_t curl_writer(const void *ptr,size_t size,size_t nmemb,void *cw_ctx); void curl_writer_finalize(struct curl_writer_ctx *ctx); +int ks_hextobyte (const char *s); +int ks_toupper (int c); +int ks_strcasecmp (const char *a, const char *b); + + #endif /* !_KSUTIL_H_ */ diff --git a/tools/ChangeLog b/tools/ChangeLog index 7e400d708..e456ca34f 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2006-09-22 Werner Koch + + * no-libgcrypt.c: Changed license to a simple all permissive one. + 2006-09-20 Werner Koch * Makefile.am: Changes to allow parallel make runs. diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index 10e88f0e7..966ff162d 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -1,22 +1,14 @@ /* no-libgcrypt.c - Replacement functions for libgcrypt. * Copyright (C) 2003 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. + * This file is free software; as a special exception the author gives + * unlimited permission to copy and/or distribute it, with or without + * modifications, as long as this notice is preserved. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY, to the extent permitted by law; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. */ #include