bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Bruno Haible <bruno@clisp.org>
To: bug-gnulib@gnu.org
Subject: login_tty: Ensure declaration in <utmp.h>
Date: Sat, 21 Jan 2023 21:19:45 +0100	[thread overview]
Message-ID: <2163753.nneeDZaL83@nimes> (raw)

The login_tty module does not provide the function's declaration in a
consistent way. The simple recipe

  Include:
  extern int login_tty (int);

breaks down as soon as Gnulib may want to override the login_tty function.
Which we'll want to do soon on Android.

What Gnulib should do is to provide the declaration in the same header file
as glibc, that is, in <utmp.h>. For this, it is irrelevant that <utmp.h>
is not standardized POSIX, and it is also irrelevant that BSD systems have
the declaration in <util.h> or <libutil.h>.

This patch does it. In particular, it adds a module 'utmp' (for <utmp.h>),
as well as utmp-tests and utmp-c++-tests.


2023-01-21  Bruno Haible  <bruno@clisp.org>

	login_tty: Ensure declaration in <utmp.h>.

	* tests/test-utmp-c++.cc: New file.
	* modules/utmp-c++-tests: New file.

	* tests/test-utmp.c: New file.
	* modules/utmp-tests: New file.

	* lib/login_tty.c: Include <utmp.h>.
	* m4/login_tty.m4: New file.
	(gl_FUNC_LOGIN_TTY): Moved here from m4/pty.m4. Set HAVE_LOGIN_TTY.
	* m4/pty.m4 (gl_FUNC_LOGIN_TTY): Moved to m4/login_tty.m4.
	* modules/login_tty (Files): Add m4/login_tty.m4.
	(Depends-on): Add utmp. Remove pty. Update condition.
	(configure.ac): Update condition. Invoke gl_UTMP_MODULE_INDICATOR
	instead of gl_PTY_MODULE_INDICATOR.
	(Include): List <utmp.h>.
	* doc/glibc-functions/login_tty.texi: Mark the include file diversity as
	fixed.
	* tests/test-login_tty.c: Include <utmp.h>. Don't declare login_tty
	here.

	* lib/utmp.in.h: New file.
	* m4/utmp_h.m4: New file.
	* modules/utmp: New file.
	* doc/glibc-headers/utmp.texi: New file.
	* doc/gnulib.texi (Glibc Header File Substitutes): Include it.

diff --git a/doc/glibc-functions/login_tty.texi b/doc/glibc-functions/login_tty.texi
index b1adf8cd0b..3e743b1527 100644
--- a/doc/glibc-functions/login_tty.texi
+++ b/doc/glibc-functions/login_tty.texi
@@ -23,6 +23,13 @@ Portability problems fixed by Gnulib:
 This function is missing on some platforms:
 Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.3, Android 5.1.
 @item
+This function is declared in @code{<utmp.h>} on glibc, Cygwin, Android,
+in @code{<util.h>} on macOS 11.1, NetBSD 5.0, OpenBSD 3.8,
+and in @code{<libutil.h>} on FreeBSD 13.0, Haiku.
+@c Also note that @code{<sys/types.h>} is
+@c a prerequisite of @code{<utmp.h>} on FreeBSD 8.0, OpenBSD 4.6 and
+@c of @code{<libutil.h>} on FreeBSD 8.0.
+@item
 This function requires linking with @code{-lutil} on some platforms:
 glibc 2.3.6, FreeBSD 13.0, NetBSD 5.0, OpenBSD 3.8.
 It is available without link options on other platforms:
@@ -34,11 +41,4 @@ Portability problems not fixed by Gnulib:
 @item
 This function is missing on some platforms:
 mingw, MSVC 14.
-@item
-This function is declared in @code{<utmp.h>} on glibc, Cygwin,
-in @code{<util.h>} on macOS 11.1, NetBSD 5.0, OpenBSD 3.8,
-and in @code{<libutil.h>} on FreeBSD 13.0, Haiku.
-Also note that @code{<sys/types.h>} is
-a prerequisite of @code{<utmp.h>} on FreeBSD 8.0, OpenBSD 4.6 and
-of @code{<libutil.h>} on FreeBSD 8.0.
 @end itemize
diff --git a/doc/glibc-headers/utmp.texi b/doc/glibc-headers/utmp.texi
new file mode 100644
index 0000000000..d7d1091e14
--- /dev/null
+++ b/doc/glibc-headers/utmp.texi
@@ -0,0 +1,34 @@
+@node utmp.h
+@section @file{utmp.h}
+
+Defines functions for login and logout (to a tty session) and for examining the
+history of logins and logouts.
+
+Documentation:
+@itemize
+@item
+@ifinfo
+@ref{Manipulating the Database,,Manipulating the User Accounting Database,libc},
+@end ifinfo
+@ifnotinfo
+@url{https://www.gnu.org/software/libc/manual/html_node/Manipulating-the-Database.html},
+@end ifnotinfo
+@item
+@uref{https://www.kernel.org/doc/man-pages/online/pages/man5/utmp.5.html,,man utmp}.
+@end itemize
+
+Gnulib module: utmp
+
+Portability problems fixed by Gnulib:
+@itemize
+@item
+This header file is missing on some platforms:
+FreeBSD 13.0, mingw, MSVC 14.
+@item
+@code{<sys/types.h>} is a prerequisite of @code{<utmp.h>} on some platforms:
+FreeBSD 8.0, OpenBSD 7.2.
+@end itemize
+
+Portability problems not fixed by Gnulib:
+@itemize
+@end itemize
diff --git a/doc/gnulib.texi b/doc/gnulib.texi
index 7388fb0b45..e9a4ace67f 100644
--- a/doc/gnulib.texi
+++ b/doc/gnulib.texi
@@ -3845,6 +3845,7 @@ not worked around by Gnulib.
 * sys/random.h::
 * sysexits.h::
 * ttyent.h::
+* utmp.h::
 @end menu
 
 @include glibc-headers/a.out.texi
@@ -3883,6 +3884,7 @@ not worked around by Gnulib.
 @include glibc-headers/sys_random.texi
 @include glibc-headers/sysexits.texi
 @include glibc-headers/ttyent.texi
+@include glibc-headers/utmp.texi
 
 @node Glibc Function Substitutes
 @chapter Glibc Function Substitutes
diff --git a/lib/login_tty.c b/lib/login_tty.c
index fb20195b5f..4b291362a3 100644
--- a/lib/login_tty.c
+++ b/lib/login_tty.c
@@ -17,7 +17,8 @@
 
 #include <config.h>
 
-/* Currently no specification header.  */
+/* Specification.  */
+#include <utmp.h>
 
 #include <fcntl.h>
 #include <unistd.h>
diff --git a/lib/utmp.in.h b/lib/utmp.in.h
new file mode 100644
index 0000000000..58318e7ffb
--- /dev/null
+++ b/lib/utmp.in.h
@@ -0,0 +1,76 @@
+/* A GNU-like <utmp.h>.
+
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This file 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.
+
+   This file 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 <https://www.gnu.org/licenses/>.  */
+
+#if __GNUC__ >= 3
+@PRAGMA_SYSTEM_HEADER@
+#endif
+@PRAGMA_COLUMNS@
+
+#ifndef _@GUARD_PREFIX@_UTMP_H
+
+#include <sys/types.h>
+
+/* The include_next requires a split double-inclusion guard.  */
+#if @HAVE_UTMP_H@
+# @INCLUDE_NEXT@ @NEXT_UTMP_H@
+#endif
+
+#ifndef _@GUARD_PREFIX@_UTMP_H
+#define _@GUARD_PREFIX@_UTMP_H
+
+/* FreeBSD, NetBSD, OpenBSD, macOS, Minix, Haiku declare login_tty in
+   <util.h> or <libutil.h>, not in <utmp.h>.  */
+/* But in any case avoid namespace pollution on glibc systems.  */
+#if (@GNULIB_LOGIN_TTY@ || defined GNULIB_POSIXCHECK) && ! defined __GLIBC__
+# if HAVE_UTIL_H      /* macOS, NetBSD, OpenBSD, Minix */
+#  include <util.h>
+# elif HAVE_LIBUTIL_H /* FreeBSD, Haiku */
+#  include <libutil.h>
+# endif
+#endif
+
+/* The definitions of _GL_FUNCDECL_RPL etc. are copied here.  */
+
+/* The definition of _GL_WARN_ON_USE is copied here.  */
+
+
+#if @GNULIB_LOGIN_TTY@
+# if @REPLACE_LOGIN_TTY@
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef login_tty
+#   define login_tty rpl_login_tty
+#  endif
+_GL_FUNCDECL_RPL (login_tty, int, (int fd));
+_GL_CXXALIAS_RPL (login_tty, int, (int fd));
+# else
+#  if !@HAVE_LOGIN_TTY@
+_GL_FUNCDECL_SYS (login_tty, int, (int fd));
+#  endif
+_GL_CXXALIAS_SYS (login_tty, int, (int fd));
+# endif
+_GL_CXXALIASWARN (login_tty);
+#elif defined GNULIB_POSIXCHECK
+# undef login_tty
+# if HAVE_RAW_DECL_LOGIN_TTY
+_GL_WARN_ON_USE (login_tty, "login_tty is unportable - "
+                 "use gnulib module login_tty for portability");
+# endif
+#endif
+
+
+#endif /* _@GUARD_PREFIX@_UTMP_H */
+#endif /* _@GUARD_PREFIX@_UTMP_H */
diff --git a/m4/login_tty.m4 b/m4/login_tty.m4
new file mode 100644
index 0000000000..0d504050f1
--- /dev/null
+++ b/m4/login_tty.m4
@@ -0,0 +1,30 @@
+# login_tty.m4 serial 1
+dnl Copyright (C) 2010-2023 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_LOGIN_TTY],
+[
+  AC_REQUIRE([gl_PTY_LIB])
+
+  AC_CHECK_HEADERS_ONCE([utmp.h util.h libutil.h])
+  gl_saved_libs="$LIBS"
+  LIBS="$LIBS $PTY_LIB"
+  gl_CHECK_FUNCS_ANDROID([login_tty], [[
+    #include <sys/types.h>
+    #if HAVE_UTMP_H
+    # include <utmp.h>
+    #endif
+    #if HAVE_UTIL_H
+    # include <util.h>
+    #elif HAVE_LIBUTIL_H
+    # include <libutil.h>
+    #endif
+  ]])
+  LIBS="$gl_saved_LIBS"
+
+  if test $ac_cv_func_login_tty = no; then
+    HAVE_LOGIN_TTY=0
+  fi
+])
diff --git a/m4/pty.m4 b/m4/pty.m4
index f6b5bb3115..ccf2ba8b1b 100644
--- a/m4/pty.m4
+++ b/m4/pty.m4
@@ -1,4 +1,4 @@
-# pty.m4 serial 17
+# pty.m4 serial 18
 dnl Copyright (C) 2010-2023 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -149,24 +149,3 @@ AC_DEFUN([gl_FUNC_OPENPTY],
     gl_CHECK_FUNCS_ANDROID([posix_openpt], [[#include <stdlib.h>]])
   fi
 ])
-
-AC_DEFUN([gl_FUNC_LOGIN_TTY],
-[
-  AC_REQUIRE([gl_PTY_LIB])
-
-  AC_CHECK_HEADERS_ONCE([utmp.h util.h libutil.h])
-  gl_saved_libs="$LIBS"
-  LIBS="$LIBS $PTY_LIB"
-  gl_CHECK_FUNCS_ANDROID([login_tty], [[
-    #include <sys/types.h>
-    #if HAVE_UTMP_H
-    # include <utmp.h>
-    #endif
-    #if HAVE_UTIL_H
-    # include <util.h>
-    #elif HAVE_LIBUTIL_H
-    # include <libutil.h>
-    #endif
-  ]])
-  LIBS="$gl_saved_LIBS"
-])
diff --git a/m4/utmp_h.m4 b/m4/utmp_h.m4
new file mode 100644
index 0000000000..fff6dbdfe7
--- /dev/null
+++ b/m4/utmp_h.m4
@@ -0,0 +1,64 @@
+# Configure a GNU-like replacement for <utmp.h>.
+
+# Copyright (C) 2023 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+AC_DEFUN_ONCE([gl_UTMP_H],
+[
+  dnl Ensure to expand the default settings once only, before all statements
+  dnl that occur in other macros.
+  AC_REQUIRE([gl_UTMP_H_DEFAULTS])
+
+  gl_CHECK_NEXT_HEADERS([utmp.h])
+  if test $ac_cv_header_utmp_h = yes; then
+    HAVE_UTMP_H=1
+  else
+    HAVE_UTMP_H=0
+  fi
+  AC_SUBST([HAVE_UTMP_H])
+
+  dnl Check for declarations of anything we want to poison if the
+  dnl corresponding gnulib module is not in use, and which is not
+  dnl guaranteed by C89.
+  gl_WARN_ON_USE_PREPARE([[
+      #include <sys/types.h>
+      #include <utmp.h>
+    ]],
+    [login_tty])
+])
+
+# gl_UTMP_MODULE_INDICATOR([modulename])
+# sets the shell variable that indicates the presence of the given module
+# to a C preprocessor expression that will evaluate to 1.
+# This macro invocation must not occur in macros that are AC_REQUIREd.
+AC_DEFUN([gl_UTMP_MODULE_INDICATOR],
+[
+  dnl Ensure to expand the default settings once only.
+  gl_UTMP_H_REQUIRE_DEFAULTS
+  gl_MODULE_INDICATOR_SET_VARIABLE([$1])
+  dnl Define it also as a C macro, for the benefit of the unit tests.
+  gl_MODULE_INDICATOR_FOR_TESTS([$1])
+])
+
+# Initializes the default values for AC_SUBSTed shell variables.
+# This macro must not be AC_REQUIREd.  It must only be invoked, and only
+# outside of macros or in macros that are not AC_REQUIREd.
+AC_DEFUN([gl_UTMP_H_REQUIRE_DEFAULTS],
+[
+  m4_defun(GL_MODULE_INDICATOR_PREFIX[_UTMP_H_MODULE_INDICATOR_DEFAULTS], [
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOGIN_TTY])
+  ])
+  m4_require(GL_MODULE_INDICATOR_PREFIX[_UTMP_H_MODULE_INDICATOR_DEFAULTS])
+  AC_REQUIRE([gl_UTMP_H_DEFAULTS])
+])
+
+AC_DEFUN([gl_UTMP_H_DEFAULTS],
+[
+  dnl Assume proper GNU behavior unless another module says otherwise.
+  HAVE_LOGIN_TTY=1;             AC_SUBST([HAVE_LOGIN_TTY])
+  REPLACE_LOGIN_TTY=0;          AC_SUBST([REPLACE_LOGIN_TTY])
+])
diff --git a/modules/login_tty b/modules/login_tty
index aa46b7f8b0..7b09ec1bd2 100644
--- a/modules/login_tty
+++ b/modules/login_tty
@@ -4,17 +4,18 @@ standard input, standard output, standard error of the current process.
 
 Files:
 lib/login_tty.c
+m4/login_tty.m4
 m4/pty.m4
 
 Depends-on:
-pty
+utmp
 sys_ioctl
-open            [test $ac_cv_func_login_tty = no]
+open            [test $HAVE_LOGIN_TTY = 0]
 
 configure.ac:
 gl_FUNC_LOGIN_TTY
-gl_CONDITIONAL([GL_COND_OBJ_LOGIN_TTY], [test $ac_cv_func_login_tty = no])
-gl_PTY_MODULE_INDICATOR([login_tty])
+gl_CONDITIONAL([GL_COND_OBJ_LOGIN_TTY], [test $HAVE_LOGIN_TTY = 0])
+gl_UTMP_MODULE_INDICATOR([login_tty])
 
 Makefile.am:
 if GL_COND_OBJ_LOGIN_TTY
@@ -22,7 +23,7 @@ lib_SOURCES += login_tty.c
 endif
 
 Include:
-extern int login_tty (int);
+<utmp.h>
 
 Link:
 $(PTY_LIB)
diff --git a/modules/utmp b/modules/utmp
new file mode 100644
index 0000000000..3a02f01364
--- /dev/null
+++ b/modules/utmp
@@ -0,0 +1,49 @@
+Description:
+A GNU-like <utmp.h>.
+
+Files:
+lib/utmp.in.h
+m4/utmp_h.m4
+
+Depends-on:
+gen-header
+include_next
+snippet/c++defs
+snippet/warn-on-use
+
+configure.ac:
+gl_UTMP_H
+gl_UTMP_H_REQUIRE_DEFAULTS
+AC_PROG_MKDIR_P
+
+Makefile.am:
+BUILT_SOURCES += utmp.h
+
+# We need the following in order to create <utmp.h> when the system
+# doesn't have one that works with the given compiler.
+utmp.h: utmp.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(WARN_ON_USE_H)
+@NMD@	$(AM_V_GEN)$(MKDIR_P) '%reldir%'
+	$(gl_V_at)$(SED_HEADER_STDOUT) \
+	      -e 's|@''GUARD_PREFIX''@|${gl_include_guard_prefix}|g' \
+	      -e 's/@''HAVE_UTMP_H''@/$(HAVE_UTMP_H)/g' \
+	      -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+	      -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+	      -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \
+	      -e 's|@''NEXT_UTMP_H''@|$(NEXT_UTMP_H)|g' \
+	      -e 's/@''GNULIB_LOGIN_TTY''@/$(GNULIB_LOGIN_TTY)/g' \
+	      -e 's|@''HAVE_LOGIN_TTY''@|$(HAVE_LOGIN_TTY)|g' \
+	      -e 's|@''REPLACE_LOGIN_TTY''@|$(REPLACE_LOGIN_TTY)|g' \
+	      -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \
+	      -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \
+	      $(srcdir)/utmp.in.h > $@-t
+	$(AM_V_at)mv $@-t $@
+MOSTLYCLEANFILES += utmp.h utmp.h-t
+
+Include:
+<utmp.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/modules/utmp-c++-tests b/modules/utmp-c++-tests
new file mode 100644
index 0000000000..814dfc36db
--- /dev/null
+++ b/modules/utmp-c++-tests
@@ -0,0 +1,19 @@
+Files:
+tests/test-utmp-c++.cc
+tests/signature.h
+
+Status:
+c++-test
+
+Depends-on:
+ansi-c++-opt
+
+configure.ac:
+
+Makefile.am:
+if ANSICXX
+TESTS += test-utmp-c++
+check_PROGRAMS += test-utmp-c++
+test_utmp_c___SOURCES = test-utmp-c++.cc
+test_utmp_c___LDADD = $(LDADD) $(PTY_LIB)
+endif
diff --git a/modules/utmp-tests b/modules/utmp-tests
new file mode 100644
index 0000000000..4fa3d62aa8
--- /dev/null
+++ b/modules/utmp-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-utmp.c
+
+Depends-on:
+utmp-c++-tests
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-utmp
+check_PROGRAMS += test-utmp
diff --git a/tests/test-login_tty.c b/tests/test-login_tty.c
index 294b46d63c..0aa693147a 100644
--- a/tests/test-login_tty.c
+++ b/tests/test-login_tty.c
@@ -17,7 +17,7 @@
 #include <config.h>
 
 /* Specification.  */
-extern int login_tty (int);
+#include <utmp.h>
 
 #include <errno.h>
 #include <pty.h>
diff --git a/tests/test-utmp-c++.cc b/tests/test-utmp-c++.cc
new file mode 100644
index 0000000000..76a2a88aa8
--- /dev/null
+++ b/tests/test-utmp-c++.cc
@@ -0,0 +1,35 @@
+/* Test of <utmp.h> substitute in C++ mode.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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 3 of the License, or
+   (at your option) any later version.
+
+   This program 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, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023.  */
+
+#define GNULIB_NAMESPACE gnulib
+#include <config.h>
+
+#include <utmp.h>
+
+#include "signature.h"
+
+
+#if GNULIB_TEST_LOGIN_TTY
+SIGNATURE_CHECK (GNULIB_NAMESPACE::login_tty, int, (int));
+#endif
+
+
+int
+main ()
+{
+}
diff --git a/tests/test-utmp.c b/tests/test-utmp.c
new file mode 100644
index 0000000000..04c598e57e
--- /dev/null
+++ b/tests/test-utmp.c
@@ -0,0 +1,27 @@
+/* Test of <utmp.h> substitute.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+
+   This program 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 3 of the License, or
+   (at your option) any later version.
+
+   This program 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, see <https://www.gnu.org/licenses/>.  */
+
+/* Written by Bruno Haible <bruno@clisp.org>, 2023.  */
+
+#include <config.h>
+
+#include <utmp.h>
+
+int
+main (void)
+{
+  return 0;
+}





                 reply	other threads:[~2023-01-21 20:20 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2163753.nneeDZaL83@nimes \
    --to=bruno@clisp.org \
    --cc=bug-gnulib@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).