cvs-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Cvs-cvs] ccvs ./ChangeLog ./Makefile.in ./aclocal.m4 ./c...


From: Derek Robert Price
Subject: [Cvs-cvs] ccvs ./ChangeLog ./Makefile.in ./aclocal.m4 ./c...
Date: Mon, 24 Apr 2006 18:50:29 +0000

CVSROOT:        /cvsroot/cvs
Module name:    ccvs
Branch:         
Changes by:     Derek Robert Price <address@hidden>     06/04/24 18:50:27

Modified files:
        .              : ChangeLog Makefile.in aclocal.m4 config.h.in 
                         configure configure.in 
        contrib        : Makefile.in 
        contrib/pam    : Makefile.in 
        diff           : Makefile.in 
        doc            : ChangeLog Makefile.in RCSFILES cvs.1 
                         cvs.texinfo cvsclient.texi stamp-1 stamp-vti 
                         version-client.texi version.texi 
        doc/i18n       : Makefile.in 
        doc/i18n/pt_BR : Makefile.in 
        lib            : ChangeLog Makefile.am Makefile.gnulib 
                         Makefile.in wait.h 
        m4             : ChangeLog gnulib-cache.m4 gnulib-comp.m4 
        maint-aux      : Makefile.in 
        man            : Makefile.in 
        src            : ChangeLog Makefile.am Makefile.in add.c admin.c 
                         annotate.c buffer.c buffer.h checkin.c 
                         checkout.c classify.c client.c client.h 
                         commit.c create_adm.c cvs.h diff.c edit.c 
                         edit.h entries.c fileattr.c filesubr.c 
                         find_names.c hash.c hash.h history.c ignore.c 
                         import.c lock.c log.c logmsg.c ls.c main.c 
                         mkmodules.c modules.c no_diff.c parseinfo.c 
                         parseinfo.h patch.c rcs.c rcs.h rcscmds.c 
                         recurse.c release.c remove.c repos.c root.c 
                         root.h run.c sanity.config.sh.in sanity.sh 
                         server.c server.h status.c subr.c subr.h tag.c 
                         update.c vers_ts.c watch.c wrapper.c zlib.c 
        tools          : Makefile.in 
        vms            : Makefile.in 
        windows-NT     : Makefile.in config.h config.h.in stamp-chi 
        windows-NT/SCC : Makefile.in 
Added files:
        .              : GPG-TODO 
        lib            : base64.c base64.h 
        m4             : base64.m4 uint32_t.m4 
        src            : base.c base.h classify.h diff.h difflib.c 
                         difflib.h entries.h filesubr.h gpg.c gpg.h 
                         ignore.h logmsg.h no_diff.h recurse.h repos.h 
                         run.h sign.c sign.h verify.c verify.h vers_ts.h 
                         wrapper.h 

Log message:
        Merge changes from signed-commits4.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/ChangeLog.diff?tr1=1.1291&tr2=1.1292&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/GPG-TODO.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/Makefile.in.diff?tr1=1.186&tr2=1.187&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/aclocal.m4.diff?tr1=1.152&tr2=1.153&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/config.h.in.diff?tr1=1.196&tr2=1.197&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/configure.diff?tr1=1.442&tr2=1.443&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/configure.in.diff?tr1=1.363&tr2=1.364&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/contrib/Makefile.in.diff?tr1=1.125&tr2=1.126&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/contrib/pam/Makefile.in.diff?tr1=1.46&tr2=1.47&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/diff/Makefile.in.diff?tr1=1.94&tr2=1.95&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/ChangeLog.diff?tr1=1.953&tr2=1.954&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/Makefile.in.diff?tr1=1.141&tr2=1.142&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/RCSFILES.diff?tr1=1.16&tr2=1.17&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/cvs.1.diff?tr1=1.42&tr2=1.43&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/cvs.texinfo.diff?tr1=1.679&tr2=1.680&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/cvsclient.texi.diff?tr1=1.143&tr2=1.144&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/stamp-1.diff?tr1=1.84&tr2=1.85&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/stamp-vti.diff?tr1=1.180&tr2=1.181&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/version-client.texi.diff?tr1=1.84&tr2=1.85&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/version.texi.diff?tr1=1.181&tr2=1.182&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/i18n/Makefile.in.diff?tr1=1.29&tr2=1.30&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/doc/i18n/pt_BR/Makefile.in.diff?tr1=1.30&tr2=1.31&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/ChangeLog.diff?tr1=1.503&tr2=1.504&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/Makefile.am.diff?tr1=1.108&tr2=1.109&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/Makefile.gnulib.diff?tr1=1.70&tr2=1.71&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/Makefile.in.diff?tr1=1.206&tr2=1.207&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/base64.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/base64.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/lib/wait.h.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/m4/ChangeLog.diff?tr1=1.163&tr2=1.164&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/m4/base64.m4.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/m4/gnulib-cache.m4.diff?tr1=1.6&tr2=1.7&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/m4/gnulib-comp.m4.diff?tr1=1.14&tr2=1.15&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/m4/uint32_t.m4.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/maint-aux/Makefile.in.diff?tr1=1.27&tr2=1.28&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/man/Makefile.in.diff?tr1=1.96&tr2=1.97&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/ChangeLog.diff?tr1=1.3375&tr2=1.3376&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/Makefile.am.diff?tr1=1.47&tr2=1.48&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/Makefile.in.diff?tr1=1.167&tr2=1.168&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/add.c.diff?tr1=1.121&tr2=1.122&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/admin.c.diff?tr1=1.112&tr2=1.113&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/annotate.c.diff?tr1=1.21&tr2=1.22&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/base.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/base.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/buffer.c.diff?tr1=1.70&tr2=1.71&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/buffer.h.diff?tr1=1.27&tr2=1.28&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/checkin.c.diff?tr1=1.56&tr2=1.57&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/checkout.c.diff?tr1=1.145&tr2=1.146&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/classify.c.diff?tr1=1.37&tr2=1.38&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/classify.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/client.c.diff?tr1=1.445&tr2=1.446&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/client.h.diff?tr1=1.61&tr2=1.62&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/commit.c.diff?tr1=1.258&tr2=1.259&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/create_adm.c.diff?tr1=1.52&tr2=1.53&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/cvs.h.diff?tr1=1.346&tr2=1.347&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/diff.c.diff?tr1=1.116&tr2=1.117&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/diff.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/difflib.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/difflib.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/edit.c.diff?tr1=1.91&tr2=1.92&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/edit.h.diff?tr1=1.12&tr2=1.13&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/entries.c.diff?tr1=1.66&tr2=1.67&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/entries.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/fileattr.c.diff?tr1=1.36&tr2=1.37&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/filesubr.c.diff?tr1=1.106&tr2=1.107&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/filesubr.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/find_names.c.diff?tr1=1.43&tr2=1.44&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/gpg.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/gpg.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/hash.c.diff?tr1=1.48&tr2=1.49&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/hash.h.diff?tr1=1.21&tr2=1.22&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/history.c.diff?tr1=1.96&tr2=1.97&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/ignore.c.diff?tr1=1.56&tr2=1.57&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/ignore.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/import.c.diff?tr1=1.175&tr2=1.176&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/lock.c.diff?tr1=1.118&tr2=1.119&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/log.c.diff?tr1=1.103&tr2=1.104&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/logmsg.c.diff?tr1=1.100&tr2=1.101&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/logmsg.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/ls.c.diff?tr1=1.18&tr2=1.19&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/main.c.diff?tr1=1.265&tr2=1.266&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/mkmodules.c.diff?tr1=1.96&tr2=1.97&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/modules.c.diff?tr1=1.98&tr2=1.99&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/no_diff.c.diff?tr1=1.38&tr2=1.39&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/no_diff.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/parseinfo.c.diff?tr1=1.85&tr2=1.86&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/parseinfo.h.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/patch.c.diff?tr1=1.106&tr2=1.107&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/rcs.c.diff?tr1=1.361&tr2=1.362&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/rcs.h.diff?tr1=1.83&tr2=1.84&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/rcscmds.c.diff?tr1=1.72&tr2=1.73&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/recurse.c.diff?tr1=1.115&tr2=1.116&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/recurse.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/release.c.diff?tr1=1.71&tr2=1.72&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/remove.c.diff?tr1=1.63&tr2=1.64&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/repos.c.diff?tr1=1.41&tr2=1.42&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/repos.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/root.c.diff?tr1=1.124&tr2=1.125&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/root.h.diff?tr1=1.23&tr2=1.24&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/run.c.diff?tr1=1.62&tr2=1.63&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/run.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/sanity.config.sh.in.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/sanity.sh.diff?tr1=1.1125&tr2=1.1126&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/server.c.diff?tr1=1.458&tr2=1.459&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/server.h.diff?tr1=1.45&tr2=1.46&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/sign.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/sign.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/status.c.diff?tr1=1.68&tr2=1.69&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/subr.c.diff?tr1=1.148&tr2=1.149&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/subr.h.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/tag.c.diff?tr1=1.144&tr2=1.145&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/update.c.diff?tr1=1.260&tr2=1.261&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/verify.c.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/verify.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/vers_ts.c.diff?tr1=1.65&tr2=1.66&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/vers_ts.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/watch.c.diff?tr1=1.45&tr2=1.46&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/wrapper.c.diff?tr1=1.47&tr2=1.48&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/wrapper.h.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/src/zlib.c.diff?tr1=1.33&tr2=1.34&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/tools/Makefile.in.diff?tr1=1.86&tr2=1.87&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/vms/Makefile.in.diff?tr1=1.89&tr2=1.90&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/windows-NT/Makefile.in.diff?tr1=1.118&tr2=1.119&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/windows-NT/config.h.diff?tr1=1.178&tr2=1.179&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/windows-NT/config.h.in.diff?tr1=1.106&tr2=1.107&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/windows-NT/stamp-chi.diff?tr1=1.92&tr2=1.93&r1=text&r2=text
http://cvs.savannah.gnu.org/viewcvs/cvs/ccvs/windows-NT/SCC/Makefile.in.diff?tr1=1.80&tr2=1.81&r1=text&r2=text

Patches:
Index: ccvs/ChangeLog
diff -u ccvs/ChangeLog:1.1291 ccvs/ChangeLog:1.1292
--- ccvs/ChangeLog:1.1291       Fri Apr 14 15:48:56 2006
+++ ccvs/ChangeLog      Mon Apr 24 18:50:24 2006
@@ -1,3 +1,83 @@
+2006-04-12  Derek Price  <address@hidden>
+
+       * m4/error.m4, m4/time_r.m4: Update from GNULIB.
+
+2006-01-20  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2006-01-18  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+       * configure.in: Define $DEFAULT_VERIFY_TEMPLATE for Makefiles.
+
+2006-01-13  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2006-01-11  Derek Price  <address@hidden>
+
+       * configure.in: Define DEFAULT_VERIFY_TEMPLATE as documented.
+
+       * GPG-TODO: Note progress.
+
+2006-01-10  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2006-01-04  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2006-01-03  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2006-01-01  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2005-12-31  Derek Price  <address@hidden>
+
+       * configure.in: Define DEFAULT_VERIFY_TEMPLATE.
+
+2005-12-30  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2005-12-27  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2005-11-10  Derek Price  <address@hidden>
+
+       * GPG-TODO: Note progress.
+
+2005-11-07  Derek Price  <address@hidden>
+
+       * GPG-TODO: Keep up to date.  Mark EOL delay unneeded due to GPG
+       --textmode option.
+
+2005-10-28  Derek Price  <address@hidden>
+
+       * configure.in: Verify that `$GPG --version' works.  Print a warning
+       when it doesn't.
+
+2005-10-27  Derek Price  <address@hidden>
+
+       * GPG-TODO: Update status.
+
+2005-10-16  Derek Price  <address@hidden>
+
+       * configure.in: Define DEFAULT_SIGN_TEMPLATE & DEFAULT_SIGN_TEXTMODE
+       here.  Don't define GPG_PROGRAM.
+
+2005-10-11  Derek Price  <address@hidden>
+
+       * GPG-TODO: New file.
+       * configure.in: Search for gpg.
+
 2006-04-14  Derek Price  <address@hidden>
 
        * maint-aux/gnulib-update: Update code to construct file list.
Index: ccvs/Makefile.in
diff -u ccvs/Makefile.in:1.186 ccvs/Makefile.in:1.187
--- ccvs/Makefile.in:1.186      Wed Apr 12 19:55:26 2006
+++ ccvs/Makefile.in    Mon Apr 24 18:50:24 2006
@@ -68,8 +68,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -181,6 +181,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -196,6 +197,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/aclocal.m4
diff -u ccvs/aclocal.m4:1.152 ccvs/aclocal.m4:1.153
--- ccvs/aclocal.m4:1.152       Wed Apr 12 19:55:26 2006
+++ ccvs/aclocal.m4     Mon Apr 24 18:50:24 2006
@@ -925,6 +925,7 @@
 m4_include([m4/allocsa.m4])
 m4_include([m4/asx_version_compare.m4])
 m4_include([m4/atexit.m4])
+m4_include([m4/base64.m4])
 m4_include([m4/bison.m4])
 m4_include([m4/canon-host.m4])
 m4_include([m4/canonicalize.m4])
Index: ccvs/config.h.in
diff -u ccvs/config.h.in:1.196 ccvs/config.h.in:1.197
--- ccvs/config.h.in:1.196      Wed Apr 12 19:55:26 2006
+++ ccvs/config.h.in    Mon Apr 24 18:50:24 2006
@@ -47,6 +47,25 @@
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
+/* Define to a command line template that will write an OpenPGP signature for
+   the file `%s' to its standard out. `%t' is substituted at run time with an
+   option which flags files as text files, when necessary, and the empty
+   string, otherwise. `%a' is substituted with a list of arguments provided by
+   the user. */
+#undef DEFAULT_SIGN_TEMPLATE
+
+/* Define to the option string that the OpenPGP program used in the
+   DEFAULT_SIGN_TEMPLATE would like to see for text files (substituted at run
+   time in place of `%t' in the DEFAULT_SIGN_TEMPLATE). */
+#undef DEFAULT_SIGN_TEXTMODE
+
+/* Define to a command line template that will read an OpenPGP signature from
+   the file `%s' and use it to verify the integrity of the file `%d'. `%t' is
+   substituted at run time with an option which flags files as text files,
+   when necessary, and the empty string, otherwise. `%a' is substituted with a
+   list of arguments provided by the user. */
+#undef DEFAULT_VERIFY_TEMPLATE
+
 /* Define if there is a member named d_ino in the struct describing directory
    headers. */
 #undef D_INO_IN_DIRENT
@@ -551,6 +570,11 @@
 /* Define to 1 if you have the `openat' function. */
 #undef HAVE_OPENAT
 
+/* Define if an OpenPGP capable program is available (and, assumedly, usable
+   command line templates are in the DEFAULT_SIGN_TEMPLATE and
+   DEFAULT_VERIFY_TEMPLATE macros). */
+#undef HAVE_OPENPGP
+
 /* Define to 1 if you have the <OS.h> header file. */
 #undef HAVE_OS_H
 
Index: ccvs/configure
diff -u ccvs/configure:1.442 ccvs/configure:1.443
--- ccvs/configure:1.442        Wed Apr 19 16:49:32 2006
+++ ccvs/configure      Mon Apr 24 18:50:24 2006
@@ -327,7 +327,7 @@
 
 gl_header_list=
 gl_func_list=
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME 
PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix 
program_transform_name bindir sbindir libexecdir datadir sysconfdir 
sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir 
build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS 
INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL 
AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP 
INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar 
am__untar ac_prefix_program MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT 
RANLIB ac_ct_RANLIB CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR 
am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE 
am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP LN_S PERL CSH MKTEMP SENDMAIL 
PR ROFF PS2PDF TEXI2DVI MAKE_TARGETS_IN_VPATH_TRUE MAKE_TARGETS_IN_VPATH_FALSE 
LIBOBJS GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE ALLOCA ALLOCA_H SYS_SOCKET_H 
STDBOOL_H HAVE__BOOL FNMATCH_H YACC YFLAGS LIB_CLOCK_GETTIME GETOPT_H GLOB_H 
LIB_NANOSLEEP HAVE_LONG_64BIT HAVE_LONG_LONG_64BIT STDINT_H UNISTD_H EOVERFLOW 
MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE build build_cpu 
build_vendor build_os host host_cpu host_vendor host_os INTL_MACOSX_LIBS 
LIBICONV LTLIBICONV INTLLIBS LIBINTL LTLIBINTL POSUB cvs_client_objects KRB4 
ZLIB_SUBDIRS ZLIB_CPPFLAGS ZLIB_LIBS with_default_rsh RSH_DFLT EDITOR LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME 
PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix 
program_transform_name bindir sbindir libexecdir datadir sysconfdir 
sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir 
build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS 
INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL 
AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP 
INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar 
am__untar ac_prefix_program MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT 
RANLIB ac_ct_RANLIB CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR 
am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE 
am__fastdepCC_TRUE am__fastdepCC_FALSE CPP EGREP LN_S PERL CSH MKTEMP SENDMAIL 
PR GPG DEFAULT_VERIFY_TEMPLATE ROFF PS2PDF TEXI2DVI MAKE_TARGETS_IN_VPATH_TRUE 
MAKE_TARGETS_IN_VPATH_FALSE LIBOBJS GL_COND_LIBTOOL_TRUE GL_COND_LIBTOOL_FALSE 
ALLOCA ALLOCA_H SYS_SOCKET_H STDBOOL_H HAVE__BOOL FNMATCH_H YACC YFLAGS 
LIB_CLOCK_GETTIME GETOPT_H GLOB_H LIB_NANOSLEEP HAVE_LONG_64BIT 
HAVE_LONG_LONG_64BIT STDINT_H UNISTD_H EOVERFLOW MKINSTALLDIRS USE_NLS MSGFMT 
GMSGFMT XGETTEXT MSGMERGE build build_cpu build_vendor build_os host host_cpu 
host_vendor host_os INTL_MACOSX_LIBS LIBICONV LTLIBICONV INTLLIBS LIBINTL 
LTLIBINTL POSUB cvs_client_objects KRB4 ZLIB_SUBDIRS ZLIB_CPPFLAGS ZLIB_LIBS 
with_default_rsh RSH_DFLT EDITOR LTLIBOBJS'
 ac_subst_files='MKTEMP_SH_FUNCTION'
 
 # Initialize some variables set by options.
@@ -5751,6 +5751,81 @@
 _ACEOF
 
 fi
+# For src/gpg.c
+# Extract the first word of "gpg", so it can be a program name with args.
+set dummy gpg; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_GPG+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  case $GPG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GPG="$GPG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+  for ac_exec_ext in '' $ac_executable_extensions; do
+  if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_GPG="$as_dir/$ac_word$ac_exec_ext"
+    echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+done
+
+  test -z "$ac_cv_path_GPG" && ac_cv_path_GPG="gpg"
+  ;;
+esac
+fi
+GPG=$ac_cv_path_GPG
+
+if test -n "$GPG"; then
+  echo "$as_me:$LINENO: result: $GPG" >&5
+echo "${ECHO_T}$GPG" >&6
+else
+  echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test x"$GPG" != xgpg; then
+  # The GPG on at least one of my FreeBSD 4.11 test systems fails to run
+  # because libintl is missing.
+  if $GPG --version >/dev/null 2>&1; then :; else
+    # GPG is broken.  Pretend it isn't there.
+    { echo "$as_me:$LINENO: WARNING: GPG is installed as \`$GPG', but is 
broken.  Ignoring it." >&5
+echo "$as_me: WARNING: GPG is installed as \`$GPG', but is broken.  Ignoring 
it." >&2;}
+    GPG=gpg
+  fi
+fi
+if test x"$GPG" != xgpg; then
+
+cat >>confdefs.h <<\_ACEOF
+#define HAVE_OPENPGP 1
+_ACEOF
+
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_SIGN_TEMPLATE "$GPG --detach-sign --output - %t %a -- %s"
+_ACEOF
+
+
+cat >>confdefs.h <<\_ACEOF
+#define DEFAULT_SIGN_TEXTMODE "--textmode"
+_ACEOF
+
+DEFAULT_VERIFY_TEMPLATE="$GPG --verify %t %a -- %S %s"
+
+
+cat >>confdefs.h <<_ACEOF
+#define DEFAULT_VERIFY_TEMPLATE "$DEFAULT_VERIFY_TEMPLATE"
+_ACEOF
+
 
 missing_dir=`cd $ac_aux_dir && pwd`
 
glocs="$PATH:/usr/local/bin:/usr/contrib/bin:/usr/gnu/bin:/local/bin:/local/gnu/bin:/gnu/bin"
@@ -8757,6 +8832,77 @@
 
   fi
 
+echo "$as_me:$LINENO: checking for inline" >&5
+echo $ECHO_N "checking for inline... $ECHO_C" >&6
+if test "${ac_cv_c_inline+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_c_inline=no
+for ac_kw in inline __inline__ __inline; do
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#ifndef __cplusplus
+typedef int foo_t;
+static $ac_kw foo_t static_foo () {return 0; }
+$ac_kw foo_t foo () {return 0; }
+#endif
+
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  ac_cv_c_inline=$ac_kw; break
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
+echo "${ECHO_T}$ac_cv_c_inline" >&6
+
+
+case $ac_cv_c_inline in
+  inline | yes) ;;
+  *)
+    case $ac_cv_c_inline in
+      no) ac_val=;;
+      *) ac_val=$ac_cv_c_inline;;
+    esac
+    cat >>confdefs.h <<_ACEOF
+#ifndef __cplusplus
+#define inline $ac_val
+#endif
+_ACEOF
+    ;;
+esac
+
 echo "$as_me:$LINENO: checking for C/C++ restrict keyword" >&5
 echo $ECHO_N "checking for C/C++ restrict keyword... $ECHO_C" >&6
 if test "${gl_cv_c_restrict+set}" = set; then
@@ -9275,77 +9421,6 @@
   fi
 
 
-echo "$as_me:$LINENO: checking for inline" >&5
-echo $ECHO_N "checking for inline... $ECHO_C" >&6
-if test "${ac_cv_c_inline+set}" = set; then
-  echo $ECHO_N "(cached) $ECHO_C" >&6
-else
-  ac_cv_c_inline=no
-for ac_kw in inline __inline__ __inline; do
-  cat >conftest.$ac_ext <<_ACEOF
-/* confdefs.h.  */
-_ACEOF
-cat confdefs.h >>conftest.$ac_ext
-cat >>conftest.$ac_ext <<_ACEOF
-/* end confdefs.h.  */
-#ifndef __cplusplus
-typedef int foo_t;
-static $ac_kw foo_t static_foo () {return 0; }
-$ac_kw foo_t foo () {return 0; }
-#endif
-
-_ACEOF
-rm -f conftest.$ac_objext
-if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
-  (eval $ac_compile) 2>conftest.er1
-  ac_status=$?
-  grep -v '^ *+' conftest.er1 >conftest.err
-  rm -f conftest.er1
-  cat conftest.err >&5
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); } &&
-        { ac_try='test -z "$ac_c_werror_flag"
-                        || test ! -s conftest.err'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; } &&
-        { ac_try='test -s conftest.$ac_objext'
-  { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
-  (eval $ac_try) 2>&5
-  ac_status=$?
-  echo "$as_me:$LINENO: \$? = $ac_status" >&5
-  (exit $ac_status); }; }; then
-  ac_cv_c_inline=$ac_kw; break
-else
-  echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-fi
-rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
-done
-
-fi
-echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5
-echo "${ECHO_T}$ac_cv_c_inline" >&6
-
-
-case $ac_cv_c_inline in
-  inline | yes) ;;
-  *)
-    case $ac_cv_c_inline in
-      no) ac_val=;;
-      *) ac_val=$ac_cv_c_inline;;
-    esac
-    cat >>confdefs.h <<_ACEOF
-#ifndef __cplusplus
-#define inline $ac_val
-#endif
-_ACEOF
-    ;;
-esac
-
 
 
 
@@ -17454,6 +17529,12 @@
 
 
 
+
+
+
+
+
+
   case $LIBOBJS in
     "canon-host.$ac_objext"   | \
   *" canon-host.$ac_objext"   | \
@@ -45721,6 +45802,8 @@
 s,@MKTEMP@,$MKTEMP,;t t
 s,@SENDMAIL@,$SENDMAIL,;t t
 s,@PR@,$PR,;t t
+s,@GPG@,$GPG,;t t
+s,@DEFAULT_VERIFY_TEMPLATE@,$DEFAULT_VERIFY_TEMPLATE,;t t
 s,@ROFF@,$ROFF,;t t
 s,@PS2PDF@,$PS2PDF,;t t
 s,@TEXI2DVI@,$TEXI2DVI,;t t
Index: ccvs/configure.in
diff -u ccvs/configure.in:1.363 ccvs/configure.in:1.364
--- ccvs/configure.in:1.363     Mon Apr 10 22:07:02 2006
+++ ccvs/configure.in   Mon Apr 24 18:50:24 2006
@@ -101,6 +101,49 @@
 if test x"$PR" != xno; then
        AC_DEFINE_UNQUOTED([PR_PROGRAM], ["$PR"], [Path to the pr utility])
 fi
+# For src/gpg.c
+AC_PATH_PROG(GPG, gpg, gpg)
+if test x"$GPG" != xgpg; then
+  # The GPG on at least one of my FreeBSD 4.11 test systems fails to run
+  # because libintl is missing.
+  if $GPG --version >/dev/null 2>&1; then :; else
+    # GPG is broken.  Pretend it isn't there.
+    AC_MSG_WARN([GPG is installed as \`$GPG', but is broken.  Ignoring it.])
+    GPG=gpg
+  fi
+fi
+if test x"$GPG" != xgpg; then
+  AC_DEFINE([HAVE_OPENPGP], [1],
+           [Define if an OpenPGP capable program is available (and, assumedly,
+            usable command line templates are in the DEFAULT_SIGN_TEMPLATE and
+            DEFAULT_VERIFY_TEMPLATE macros).])
+fi
+dnl These are defined by configure so that if the above is ever expanded to
+dnl look for OpenPGP capable programs other than `gpg', the default templates
+dnl can also be detected and substituted here.
+AC_DEFINE_UNQUOTED([DEFAULT_SIGN_TEMPLATE],
+                  ["$GPG --detach-sign --output - %t %a -- %s"],
+                  [Define to a command line template that will write an
+                   OpenPGP signature for the file `%s' to its standard out.
+                   `%t' is substituted at run time with an option which flags
+                   files as text files, when necessary, and the empty string,
+                   otherwise.  `%a' is substituted with a list of arguments
+                   provided by the user.])
+AC_DEFINE([DEFAULT_SIGN_TEXTMODE], ["--textmode"],
+         [Define to the option string that the OpenPGP program used in the
+          DEFAULT_SIGN_TEMPLATE would like to see for text files (substituted
+          at run time in place of `%t' in the DEFAULT_SIGN_TEMPLATE).])
+DEFAULT_VERIFY_TEMPLATE="$GPG --verify %t %a -- %S %s"
+AC_SUBST([DEFAULT_VERIFY_TEMPLATE])
+AC_DEFINE_UNQUOTED([DEFAULT_VERIFY_TEMPLATE],
+                  ["$DEFAULT_VERIFY_TEMPLATE"],
+                  [Define to a command line template that will read an
+                   OpenPGP signature from the file `%s' and use it to verify
+                   the integrity of the file `%d'.  `%t' is substituted at run
+                   time with an option which flags files as text files, when
+                   necessary, and the empty string, otherwise.  `%a' is
+                   substituted with a list of arguments provided by the
+                   user.])
 
 dnl FIXME This is truly gross.
 missing_dir=`cd $ac_aux_dir && pwd`
Index: ccvs/contrib/Makefile.in
diff -u ccvs/contrib/Makefile.in:1.125 ccvs/contrib/Makefile.in:1.126
--- ccvs/contrib/Makefile.in:1.125      Wed Apr 12 19:55:26 2006
+++ ccvs/contrib/Makefile.in    Mon Apr 24 18:50:24 2006
@@ -70,8 +70,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -183,6 +183,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -198,6 +199,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/contrib/pam/Makefile.in
diff -u ccvs/contrib/pam/Makefile.in:1.46 ccvs/contrib/pam/Makefile.in:1.47
--- ccvs/contrib/pam/Makefile.in:1.46   Wed Apr 12 19:55:26 2006
+++ ccvs/contrib/pam/Makefile.in        Mon Apr 24 18:50:24 2006
@@ -57,8 +57,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -149,6 +149,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -164,6 +165,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/diff/Makefile.in
diff -u ccvs/diff/Makefile.in:1.94 ccvs/diff/Makefile.in:1.95
--- ccvs/diff/Makefile.in:1.94  Wed Apr 12 19:55:27 2006
+++ ccvs/diff/Makefile.in       Mon Apr 24 18:50:24 2006
@@ -46,8 +46,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -158,6 +158,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -173,6 +174,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/doc/ChangeLog
diff -u ccvs/doc/ChangeLog:1.953 ccvs/doc/ChangeLog:1.954
--- ccvs/doc/ChangeLog:1.953    Wed Apr  5 14:45:28 2006
+++ ccvs/doc/ChangeLog  Mon Apr 24 18:50:24 2006
@@ -1,3 +1,42 @@
+2006-01-20  Derek Price  <address@hidden>
+
+       * cvsclient.text (Requests): Document Base-diff response.
+       (Responses): Document Base-diff response.
+
+2006-01-17  Derek Price  <address@hidden>
+
+       * RCSFILES: s/signatures/openpgp-signatures/.
+
+2006-01-16  Derek Price  <address@hidden>
+
+       * cvsclient.text (Responses): Document OpenPGP-signature response.
+
+2006-01-11  Derek Price  <address@hidden>
+
+       * cvs.texinfo (The connection method, Global options): Note new
+       --verify and --verify-template configuration options.  Note
+       --textmode.
+
+2005-12-12  Derek Price  <address@hidden>
+
+       * cvsclient.texi (Responses): Add new Base-* & Temp-checkout responses.
+
+2005-10-16  Derek Price  <address@hidden>
+
+       * RCSFILES: Note new openpgp-signatures newphrase.
+
+2005-10-15  Derek Price  <address@hidden>
+
+       * cvs.texinfo (commit options): Move OpenPGP stuff...
+       (Global options): ...here.  Add index entries.
+       (The connection method): Add index entries.
+
+2005-10-11  Derek Price  <address@hidden>
+
+       * cvs.texinfo (The connection method, commit options): Describe new
+       OpenPGP signature related options.
+       * cvsclient.texi (Requests): Describe Signature request.
+
 2006-04-05  Derek Price  <address@hidden>
 
        [patch #4992]
Index: ccvs/doc/Makefile.in
diff -u ccvs/doc/Makefile.in:1.141 ccvs/doc/Makefile.in:1.142
--- ccvs/doc/Makefile.in:1.141  Wed Apr 12 19:55:27 2006
+++ ccvs/doc/Makefile.in        Mon Apr 24 18:50:24 2006
@@ -64,8 +64,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -179,6 +179,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -194,6 +195,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/doc/RCSFILES
diff -u ccvs/doc/RCSFILES:1.16 ccvs/doc/RCSFILES:1.17
--- ccvs/doc/RCSFILES:1.16      Fri Feb 25 17:54:32 2005
+++ ccvs/doc/RCSFILES   Mon Apr 24 18:50:24 2006
@@ -115,10 +115,11 @@
 in the delta nodes should include `README'; CVS will not operate
 properly if this is not done.
 
-Newphrases are also used to implement the 'commitid' feature. The
-following new keyword is defined:
+Newphrases are also used to implement the 'commitid' & OpenPGP signature
+features. The following new keywords are defined for these purposes:
 
    commitid
+   openpgp-signatures
 
 The rules regarding keyword expansion are not documented along with
 the rest of the RCS file format; they are documented in the co(1)
Index: ccvs/doc/cvs.1
diff -u ccvs/doc/cvs.1:1.42 ccvs/doc/cvs.1:1.43
--- ccvs/doc/cvs.1:1.42 Wed Apr  5 14:19:28 2006
+++ ccvs/doc/cvs.1      Mon Apr 24 18:50:25 2006
@@ -481,6 +481,105 @@
 compress returned data.  This option only has an effect when passed to
 the \fBcvs\fR client.
 .SP
+.IX "OpenPGP Signatures"
+.IX "Commit Signatures"
+.IP "" 0
+\fB-g\fR
+.IP "" 2
+.IP "" 0
+\fB--sign\fR
+.IP "" 2
+.IP "" 0
+\fB--no-sign\fR
+.IP "" 2
+Force OpenPGP signatures on or off.  \fB-g\fR & \fB--sign\fR will cause the
+commit to abort if the server does not support OpenPGP signatures.  Without one
+of these options, CVS will autonegotiate signing, attempting to sign commits
+when the server supports it.  Overrides the \fBsign\fR and \fBno-sign\fR
+method options.
+.SP
+.IP "" 0
+\fB--sign-template \fItemplate\fB\fR
+.IP "" 2
+Use \fItemplate\fR as the command line template to generate OpenPGP signatures.
+Format strings in this template are substituted before the commit is run:
+.SP
+.IP "" 2
+\fB%t\fR
+.IP "" 4
+Substitute in the textmode flag (defaults to \fB--textmode\fR) when a
+signature is being generated for a text file.
+.SP
+.IP "" 2
+\fB%a\fR
+.IP "" 4
+Substitute in any \fIarg\fRs set via the \fB--sign-arg\fR option or the
+CVSROOT sign-arg method option.
+.SP
+.IP "" 2
+\fB%s\fR
+.IP "" 4
+Substitute the name of the file to generate a signature for.
+.SP
+This template should send the generated signature to its standard output.
+Overrides the \fBsign-template\fR method option and defaults to something like
+\fB/usr/bin/gpg --detach-sign --output - %t %a %s\fR.
+.SP
+.IP "" 0
+\fB--textmode\fR
+.IP "" 2
+The value passed to both in place of %t in both the OpenPGP signature
+and the OpenPGP verification command line templates.  Defaults to
+\fB--textmode\fR.
+.SP
+.IP "" 0
+\fB--verify\fR
+.IP "" 2
+.IP "" 0
+\fB--no-verify\fR
+.IP "" 2
+Force OpenPGP signature verification on checkout off, or set the failure mode.
+With a failure mode of \fBwarn\fR, the user will be warned of invalid
+signatures but the checkout will be allowed.  With a failure mode of
+\fBfatal\fR, the checkout will be aborted when the first corrupt file is
+received.  If the server does not support OpenPGP signatures, a failure mode
+of \fBfatal\fR will disallow the entire checkout.  Overrides the \fBverify\fR
+and \fBno-verify\fR method options (see node `The connection method\(aq in the 
CVS manual).
+.SP
+.IP "" 0
+\fB--verify-template=\fItemplate\fB\fR
+.IP "" 2
+Use \fItemplate\fR as the command line template to verify OpenPGP signatures.
+Format strings in this template are substituted before the command is run:
+.SP
+.IP "" 2
+\fB%t\fR
+.IP "" 4
+Substitute in the textmode flag (defaults to \fB--textmode\fR) when a
+signature is being verified for a text file.
+.SP
+.IP "" 2
+\fB%a\fR
+.IP "" 4
+Substitute in any \fIarg\fRs set via the \fB--verify-arg\fR option or the
+CVSROOT \fBverify-arg\fR method option.
+.SP
+.IP "" 2
+\fB%S\fR
+.IP "" 4
+Substitute the name of the file containing the signature.
+.SP
+.IP "" 2
+\fB%s\fR
+.IP "" 4
+Substitute the name of the signed file.
+.SP
+This template should exit with an exit code of zero if the signature is valid
+for the signed file and a non-zero exit code otherwise.  Overrides the
+\fBverify-template\fR method option see node `The connection method\(aq in the 
CVS manual and
+defaults to something like
+\fB/usr/bin/gpg --detach-sign --output - %t %a %S %s\fR.
+.SP
 .SH "Common options"
 .SS "Common command options"
 .IX "Common options"
@@ -1467,8 +1566,8 @@
 .IX "commit (subcommand)"
 .SP
 .IP "\(bu" 2
-Synopsis: commit [-lRf] [-m \(aqlog_message\(aq |
--F file] [-r revision] [files\&...]
+Synopsis: commit [-fglnR] [-m \(aqlog_message\(aq | -F file] [-r revision]
+                [files\&...]
 .IP "\(bu" 2
 Requires: working directory, repository.
 .IP "\(bu" 2
Index: ccvs/doc/cvs.texinfo
diff -u ccvs/doc/cvs.texinfo:1.679 ccvs/doc/cvs.texinfo:1.680
--- ccvs/doc/cvs.texinfo:1.679  Wed Apr  5 14:19:28 2006
+++ ccvs/doc/cvs.texinfo        Mon Apr 24 18:50:25 2006
@@ -2323,6 +2323,79 @@
 
 This method option first appeared in @sc{cvs} version 1.12.11 and is valid only
 as a modifcation to the @code{ext} connection method.
+
address@hidden OpenPGP Signatures
address@hidden Commit Signatures
address@hidden sign
address@hidden no-sign
+Force OpenPGP signatures on or off.  @samp{sign} will cause the commit to abort
+if the server does not support OpenPGP signatures.  Without one of these
+options, CVS will autonegotiate signing, attempting to sign commits when the
+server supports it.  May be overridden by the @samp{--sign} and 
@samp{--no-sign}
+global options (@pxref{Global options}).
+
address@hidden address@hidden
+Use @var{template} as the command line template to generate OpenPGP signatures.
+Format strings in this template are substituted before the command is run:
+
address@hidden @code
address@hidden %t
+Substitute in the textmode flag (defaults to @samp{--textmode}) when a
+signature is being generated for a text file.
+
address@hidden %a
+Substitute in any @var{arg}s set via the @samp{--sign-arg} option or the
+CVSROOT sign-arg method option.
+
address@hidden %s
+Substitute the name of the file to generate a signature for.
address@hidden table
+
+This template should send the generated signature to its standard output.
+IS overridden by the @samp{--sign-template} global command line option
address@hidden options} and defaults to
address@hidden/usr/bin/gpg --detach-sign --output - %t %a %s}.
+
address@hidden textmode
+The value passed to both in place of %t in both the OpenPGP signature
+and the OpenPGP verification command line templates.  Defaults to
address@hidden
+
address@hidden verify
address@hidden no-verify
+Force OpenPGP signature verification on checkout off, or set the failure mode.
+With a failure mode of @samp{warn}, the user will be warned of invalid
+signatures but the checkout will be allowed.  With a failure mode of
address@hidden, the checkout will be aborted when the first corrupt file is
+received.  If the server does not support OpenPGP signatures, a failure mode
+of @samp{fatal} will disallow the entire checkout.  May be overridden by the
address@hidden and @samp{--no-verify} global options (@pxref{Global options}).
+
address@hidden address@hidden
+Use @var{template} as the command line template to verify OpenPGP signatures.
+Format strings in this template are substituted before the command is run:
+
address@hidden @code
address@hidden %t
+Substitute in the textmode flag (defaults to @samp{--textmode}) when a
+signature is being verified for a text file.
+
address@hidden %a
+Substitute in any @var{arg}s set via the @samp{--verify-arg} option or the
+CVSROOT verify-arg method option.
+
address@hidden %S
+Substitute the name of the file containing the signature.
+
address@hidden %s
+Substitute the name of the signed file.
address@hidden table
+
+This template should exit with an exit code of zero if the signature is valid
+for the signed file and a non-zero exit code otherwise.  This method option is
+overridden by the @samp{--verify-template} global command line option
address@hidden options} and defaults to something like
address@hidden/usr/bin/gpg --detach-sign --output - %t %a %S %s}.
 @end table
 
 As a further example, to combine both the @code{CVS_RSH} and @code{CVS_SERVER}
@@ -8523,6 +8596,79 @@
 server will use the closest level allowed by the server administrator to
 compress returned data.  This option only has an effect when passed to
 the @sc{cvs} client.
+
address@hidden OpenPGP Signatures
address@hidden Commit Signatures
address@hidden -g
address@hidden --sign
address@hidden --no-sign
+Force OpenPGP signatures on or off.  @samp{-g} & @samp{--sign} will cause the
+commit to abort if the server does not support OpenPGP signatures.  Without one
+of these options, CVS will autonegotiate signing, attempting to sign commits
+when the server supports it.  Overrides the @samp{sign} and @samp{no-sign}
+method options.
+
address@hidden --sign-template @var{template}
+Use @var{template} as the command line template to generate OpenPGP signatures.
+Format strings in this template are substituted before the commit is run:
+
address@hidden @code
address@hidden %t
+Substitute in the textmode flag (defaults to @samp{--textmode}) when a
+signature is being generated for a text file.
+
address@hidden %a
+Substitute in any @var{arg}s set via the @samp{--sign-arg} option or the
+CVSROOT sign-arg method option.
+
address@hidden %s
+Substitute the name of the file to generate a signature for.
address@hidden table
+
+This template should send the generated signature to its standard output.
+Overrides the @samp{sign-template} method option and defaults to something like
address@hidden/usr/bin/gpg --detach-sign --output - %t %a %s}.
+
address@hidden --textmode
+The value passed to both in place of %t in both the OpenPGP signature
+and the OpenPGP verification command line templates.  Defaults to
address@hidden
+
address@hidden --verify
address@hidden --no-verify
+Force OpenPGP signature verification on checkout off, or set the failure mode.
+With a failure mode of @samp{warn}, the user will be warned of invalid
+signatures but the checkout will be allowed.  With a failure mode of
address@hidden, the checkout will be aborted when the first corrupt file is
+received.  If the server does not support OpenPGP signatures, a failure mode
+of @samp{fatal} will disallow the entire checkout.  Overrides the @samp{verify}
+and @samp{no-verify} method options (@pxref{The connection method}).
+
address@hidden address@hidden
+Use @var{template} as the command line template to verify OpenPGP signatures.
+Format strings in this template are substituted before the command is run:
+
address@hidden @code
address@hidden %t
+Substitute in the textmode flag (defaults to @samp{--textmode}) when a
+signature is being verified for a text file.
+
address@hidden %a
+Substitute in any @var{arg}s set via the @samp{--verify-arg} option or the
+CVSROOT @samp{verify-arg} method option.
+
address@hidden %S
+Substitute the name of the file containing the signature.
+
address@hidden %s
+Substitute the name of the signed file.
address@hidden table
+
+This template should exit with an exit code of zero if the signature is valid
+for the signed file and a non-zero exit code otherwise.  Overrides the
address@hidden method option @pxref{The connection method} and
+defaults to something like
address@hidden/usr/bin/gpg --detach-sign --output - %t %a %S %s}.
 @end table
 
 @c - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -9523,8 +9669,8 @@
 
 @itemize @bullet
 @item
-Synopsis: commit [-lRf] [-m 'log_message' |
--F file] [-r revision] address@hidden
+Synopsis: commit [-fglnR] [-m 'log_message' | -F file] [-r revision]
+                address@hidden
 @item
 Requires: working directory, repository.
 @item
Index: ccvs/doc/cvsclient.texi
diff -u ccvs/doc/cvsclient.texi:1.143 ccvs/doc/cvsclient.texi:1.144
--- ccvs/doc/cvsclient.texi:1.143       Fri Dec  9 17:54:55 2005
+++ ccvs/doc/cvsclient.texi     Mon Apr 24 18:50:25 2006
@@ -840,6 +840,17 @@
 This request should affect the @code{import} request, and may optionally
 affect the @code{ci} request or other relevant requests if any.
 
address@hidden Signature \n
+Response expected: no.  Additional data: signature transmission.
+Send the server the OpenPGP signature for the next Modified request.
+The OpenPGP signature should be
address@hidden://www.ietf.org/rfc/rfc2440.txt, RFC 2440} compliant.
+
address@hidden Base-diff \n
+Response expected: no.  Additional data: none.
+This is a dummy response intended to let the client know that the contents of
+files do not need to be sent prior to  @code{diff} requests.
+
 @item Modified @var{filename} \n
 Response expected: no.  Additional data: mode, \n, file transmission.
 Send the server a copy of one locally modified file.  @var{filename} is
@@ -1866,6 +1877,89 @@
 
 @item ok \n
 The command completed successfully.
+
address@hidden table
+
+The following responses are all optional, but if one is implemented, then all
+should be.  Servers may make this assumption.
+
address@hidden @code
address@hidden OpenPGP-signature \n
+Additional data: signature transmission.
+
+Send the client an OpenPGP signature to be used with the next
address@hidden, @code{Temp-checkout}, or @code{Base-signatures} response.
+The OpenPGP signature should be
address@hidden://www.ietf.org/rfc/rfc2440.txt, RFC 2440} compliant.
+
+Any number of signatures may be sent before any of these responses, and all
+signatures received will be considered to apply to the subsequent response.
+
address@hidden Base-checkout @var{pathname} \n
+Additional data: @var{RCS keyword options}. \n, @var{previous revision}. \n
address@hidden revision}. \n @var{mode}, \n, file transmission.
+
+Checkout a base file preliminary to a @code{Base-copy} or @code{Base-merge}
+response.  If @var{previous revision} is not empty, it should specify the
+previous base revision of this file, as determined by the entry for the file
+sent to the server.  The file transmission will then be an RCS diff, as for the
address@hidden response, but against the previous base file.
+
address@hidden Temp-checkout @var{pathname} \n
+This response is identical to @code{Base-checkout}, except the new file should
+be checked out as a temp file rather than stored with the other base files,
+to avoid overwriting earlier base checkouts.
+
address@hidden Base-copy @var{pathname} \n
+Additional data: @var{revision}. \n @var{flags} \n
+
+Copy a previously transmitted base file for @var{revision}, or the previously
+transmitted temp file when @var{revision} is not specified, over the
+file specified by @var{pathname}.  @var{flags} is two characters.  The
+first, for error checking purposes, is @samp{y} if @var{pathname} is expected
+to exist, @samp{n} if @var{pathname} is not expected to exist, and
address@hidden if @var{pathname} might exist.  The second character must be 
@samp{y}
+if the new @var{pathanme} should be writable and @samp{n}, otherwise.  When
+a temp file is used, it may be deleted and forgotten afterwards.
+
address@hidden Base-merge @var{pathname} \n
+Additional data: @var{rev1} \n @var{rev2} \n
+
+Merge the differences between @var{rev1} & @var{rev2} of @var{pathname} into
address@hidden  If one temp file was received via @code{Temp-checkout}, then
+use it in place of the base file for @var{rev1}.  If two temp files were
+received, then use the first in place of the base file for @var{rev1} and the
+second in place of the base file for @var{rev2}.  Temp files may be deleted
+and forgotten after the merge is complete.
+
address@hidden Base-entry @var{pathname} \n
+Additional data: New Entries line, \n
+
+Use new entry for @var{pathname}.  Any base files for revisions of
address@hidden other than the one specified in the new entries line may now be
+deleted.
+
address@hidden Base-merged @var{pathname} \n
+Additional data: New Entries line, \n
+
+Use new entry for @var{pathname}.  Any base files for revisions of
address@hidden other than the one specified in the new entries line may now be
+deleted.
+
address@hidden Base-diff @var{pathname} \n
+Additional data: @var{file-type-1} \n @var{rev1} \n @var{label1} \n
address@hidden \n @var{rev2} \n @var{label2} \n
+
+Perform a diff between two files.  @var{file-type-1} may be @samp{TEMP} or
address@hidden  @var{file-type-2} may be @samp{TEMP}, @samp{DEVNULL}, or
address@hidden  If either file type is @samp{TEMP}, then it is expected that
+the server sent a file in a previous @code{Temp-checkout} request.  Temp files
+are processed in order - if both file types are @samp{TEMP}, then the first
+received by the client must be used as file 1 and the second received by the
+client must be used as file 2.  If either file type is @samp{DEVNULL}, perform
+the diff against an empty file.  If @var{file-type-2} is @samp{WORKFILE}, then
+use the local file specified by @var{pathname} as file 2.
+
 @end table
 
 @node Text tags
Index: ccvs/doc/i18n/Makefile.in
diff -u ccvs/doc/i18n/Makefile.in:1.29 ccvs/doc/i18n/Makefile.in:1.30
--- ccvs/doc/i18n/Makefile.in:1.29      Wed Apr 12 19:55:27 2006
+++ ccvs/doc/i18n/Makefile.in   Mon Apr 24 18:50:25 2006
@@ -56,8 +56,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -157,6 +157,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -172,6 +173,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/doc/i18n/pt_BR/Makefile.in
diff -u ccvs/doc/i18n/pt_BR/Makefile.in:1.30 
ccvs/doc/i18n/pt_BR/Makefile.in:1.31
--- ccvs/doc/i18n/pt_BR/Makefile.in:1.30        Wed Apr 12 19:55:27 2006
+++ ccvs/doc/i18n/pt_BR/Makefile.in     Mon Apr 24 18:50:25 2006
@@ -56,8 +56,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -148,6 +148,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -163,6 +164,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/doc/stamp-1
diff -u ccvs/doc/stamp-1:1.84 ccvs/doc/stamp-1:1.85
--- ccvs/doc/stamp-1:1.84       Thu Apr 13 15:32:41 2006
+++ ccvs/doc/stamp-1    Mon Apr 24 18:50:25 2006
@@ -1,4 +1,4 @@
address@hidden UPDATED 1 February 2006
address@hidden UPDATED-MONTH February 2006
address@hidden UPDATED 13 April 2006
address@hidden UPDATED-MONTH April 2006
 @set EDITION 1.12.13.1
 @set VERSION 1.12.13.1
Index: ccvs/doc/stamp-vti
diff -u ccvs/doc/stamp-vti:1.180 ccvs/doc/stamp-vti:1.181
--- ccvs/doc/stamp-vti:1.180    Thu Apr 13 15:32:41 2006
+++ ccvs/doc/stamp-vti  Mon Apr 24 18:50:25 2006
@@ -1,4 +1,4 @@
address@hidden UPDATED 5 April 2006
address@hidden UPDATED 13 April 2006
 @set UPDATED-MONTH April 2006
 @set EDITION 1.12.13.1
 @set VERSION 1.12.13.1
Index: ccvs/doc/version-client.texi
diff -u ccvs/doc/version-client.texi:1.84 ccvs/doc/version-client.texi:1.85
--- ccvs/doc/version-client.texi:1.84   Thu Apr 13 15:32:41 2006
+++ ccvs/doc/version-client.texi        Mon Apr 24 18:50:25 2006
@@ -1,4 +1,4 @@
address@hidden UPDATED 1 February 2006
address@hidden UPDATED-MONTH February 2006
address@hidden UPDATED 13 April 2006
address@hidden UPDATED-MONTH April 2006
 @set EDITION 1.12.13.1
 @set VERSION 1.12.13.1
Index: ccvs/doc/version.texi
diff -u ccvs/doc/version.texi:1.181 ccvs/doc/version.texi:1.182
--- ccvs/doc/version.texi:1.181 Thu Apr 13 15:32:41 2006
+++ ccvs/doc/version.texi       Mon Apr 24 18:50:25 2006
@@ -1,4 +1,4 @@
address@hidden UPDATED 5 April 2006
address@hidden UPDATED 13 April 2006
 @set UPDATED-MONTH April 2006
 @set EDITION 1.12.13.1
 @set VERSION 1.12.13.1
Index: ccvs/lib/ChangeLog
diff -u ccvs/lib/ChangeLog:1.503 ccvs/lib/ChangeLog:1.504
--- ccvs/lib/ChangeLog:1.503    Wed Apr 19 16:49:15 2006
+++ ccvs/lib/ChangeLog  Mon Apr 24 18:50:25 2006
@@ -1,3 +1,18 @@
+2006-04-12  Derek Price  <address@hidden>
+
+       * Makefile.am: Backout previous change introduced by gnulib-tool.
+       Remove now automatic inclusion of time_r.
+       * Makefile.gnulib: Regenerated by gnulib-update.
+
+2005-10-27  Derek Price  <address@hidden>
+
+       * Makefile.am (libcvs_SOURCES): Add base64.[ch].
+       * base64.c, base64.h: New files from GNULIB.
+
+2005-10-19  Derek Price  <address@hidden>
+
+       * wait.h: #include "xtime.h" for FreeBSD 4.11.
+
 2006-04-19  Derek Price  <address@hidden>
 
        * inttypes.h: Update from GNULIB.
Index: ccvs/lib/Makefile.am
diff -u ccvs/lib/Makefile.am:1.108 ccvs/lib/Makefile.am:1.109
--- ccvs/lib/Makefile.am:1.108  Wed Apr 12 18:06:30 2006
+++ ccvs/lib/Makefile.am        Mon Apr 24 18:50:25 2006
@@ -80,6 +80,12 @@
 
 ## end   gnulib module allocsa
 
+## begin gnulib module base64
+
+libcvs_a_SOURCES += base64.h base64.c
+
+## end   gnulib module base64
+
 ## begin gnulib module cycle-check
 
 libcvs_a_SOURCES += cycle-check.c cycle-check.h dev-ino.h
Index: ccvs/lib/Makefile.gnulib
diff -u ccvs/lib/Makefile.gnulib:1.70 ccvs/lib/Makefile.gnulib:1.71
--- ccvs/lib/Makefile.gnulib:1.70       Fri Apr 14 15:22:28 2006
+++ ccvs/lib/Makefile.gnulib    Mon Apr 24 18:50:25 2006
@@ -8,7 +8,7 @@
 # the same distribution terms as the rest of that program.
 #
 # Generated by gnulib-tool.
-# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --aux-dir=build-aux --macro-prefix=gl allocsa atexit canon-host 
canonicalize closeout dirname dup2 error exit exitfail extensions fnmatch 
fnmatch-posix ftruncate getdate gethostname getline getlogin_r getndelim2 
getnline getopt getpagesize getpass-gnu gettext gettime gettimeofday glob 
inttypes lstat malloc md5 memmove minmax mkdir mkstemp mktime nanosleep 
pagealign_alloc pathmax quotearg readlink realloc regex rename restrict 
save-cwd setenv stat-macros stdbool stdint strcase strdup strerror strftime 
strstr strtoul strtoumax time_r timespec tzset unlocked-io vasnprintf vasprintf 
xalloc-die xgethostname xreadlink xsize yesno
+# Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib 
--m4-base=m4 --aux-dir=build-aux --macro-prefix=gl allocsa atexit base64 
canon-host canonicalize closeout dirname dup2 error exit exitfail extensions 
fnmatch fnmatch-posix ftruncate getdate gethostname getline getlogin_r 
getndelim2 getnline getopt getpagesize getpass-gnu gettext gettime gettimeofday 
glob inttypes lstat malloc md5 memmove minmax mkdir mkstemp mktime nanosleep 
pagealign_alloc pathmax quotearg readlink realloc regex rename restrict 
save-cwd setenv stat-macros stdbool stdint strcase strdup strerror strftime 
strstr strtoul strtoumax time_r timespec tzset unlocked-io vasnprintf vasprintf 
xalloc-die xgethostname xreadlink xsize yesno
 
 AUTOMAKE_OPTIONS = 1.5 gnits no-dependencies
 
@@ -52,6 +52,12 @@
 
 ## end   gnulib module allocsa
 
+## begin gnulib module base64
+
+libgnu_a_SOURCES += base64.h base64.c
+
+## end   gnulib module base64
+
 ## begin gnulib module cycle-check
 
 libgnu_a_SOURCES += cycle-check.c cycle-check.h dev-ino.h
Index: ccvs/lib/Makefile.in
diff -u ccvs/lib/Makefile.in:1.206 ccvs/lib/Makefile.in:1.207
--- ccvs/lib/Makefile.in:1.206  Wed Apr 12 19:54:01 2006
+++ ccvs/lib/Makefile.in        Mon Apr 24 18:50:25 2006
@@ -89,8 +89,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -167,9 +167,9 @@
 libcvs_a_AR = $(AR) $(ARFLAGS)
 libcvs_a_DEPENDENCIES = @LIBOBJS@ @ALLOCA@
 am_libcvs_a_OBJECTS = sighandle.$(OBJEXT) allocsa.$(OBJEXT) \
-       cycle-check.$(OBJEXT) basename.$(OBJEXT) stripslash.$(OBJEXT) \
-       getnline.$(OBJEXT) strnlen1.$(OBJEXT) xalloc-die.$(OBJEXT) \
-       xgethostname.$(OBJEXT)
+       base64.$(OBJEXT) cycle-check.$(OBJEXT) basename.$(OBJEXT) \
+       stripslash.$(OBJEXT) getnline.$(OBJEXT) strnlen1.$(OBJEXT) \
+       xalloc-die.$(OBJEXT) xgethostname.$(OBJEXT)
 libcvs_a_OBJECTS = $(am_libcvs_a_OBJECTS)
 am_getdate_OBJECTS = getdate-error.$(OBJEXT) getdate-getdate.$(OBJEXT) \
        getdate-progname.$(OBJEXT)
@@ -209,6 +209,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -224,6 +225,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
@@ -334,12 +336,13 @@
 # with the diff library (perhaps to have the caller, CVS, do the
 # matching?)
 libcvs_a_SOURCES = sighandle.c system.h wait.h xselect.h xtime.h \
-       allocsa.h allocsa.c cycle-check.c cycle-check.h dev-ino.h \
-       basename.c stripslash.c error.h exit.h getaddrinfo.h \
-       getnline.h getnline.c gettext.h mbchar.h mbuiter.h minmax.h \
-       setenv.h size_max.h strcase.h strnlen1.h strnlen1.c strstr.h \
-       printf-args.h printf-parse.h vasnprintf.h vasprintf.h verify.h \
-       xalloc-die.c xgethostname.h xgethostname.c xsize.h
+       allocsa.h allocsa.c base64.h base64.c cycle-check.c \
+       cycle-check.h dev-ino.h basename.c stripslash.c error.h exit.h \
+       getaddrinfo.h getnline.h getnline.c gettext.h mbchar.h \
+       mbuiter.h minmax.h setenv.h size_max.h strcase.h strnlen1.h \
+       strnlen1.c strstr.h printf-args.h printf-parse.h vasnprintf.h \
+       vasprintf.h verify.h xalloc-die.c xgethostname.h \
+       xgethostname.c xsize.h
 libcvs_a_LIBADD = @LIBOBJS@ @ALLOCA@
 BUILT_SOURCES = $(ALLOCA_H) $(FNMATCH_H) getdate.c $(GETOPT_H) \
        $(GLOB_H) $(STDBOOL_H) $(STDINT_H)
@@ -507,6 +510,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
Index: ccvs/lib/wait.h
diff -u ccvs/lib/wait.h:1.5 ccvs/lib/wait.h:1.6
--- ccvs/lib/wait.h:1.5 Thu Jan 23 21:04:51 2003
+++ ccvs/lib/wait.h     Mon Apr 24 18:50:25 2006
@@ -12,12 +12,16 @@
    GNU General Public License for more details.  */
 
 #ifdef HAVE_SYS_WAIT_H
-#include <sys/types.h>         /* For pid_t. */
-#ifdef HAVE_SYS_RESOURCE_H
-#include <sys/resource.h>      /* for rusage */
-#endif
-#include <sys/wait.h>
+# include <sys/types.h>                /* For pid_t. */
+# ifdef HAVE_SYS_RESOURCE_H
+#  include "xtime.h"           /* FreeBSD 4.11, at least, needs struct timeval
+                                * defined before including <sys/resource.h>
+                                */
+#  include <sys/resource.h>    /* for rusage */
+# endif
+# include <sys/wait.h>
 #endif
+
 #ifndef WIFSTOPPED
 #define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
 #endif
Index: ccvs/m4/ChangeLog
diff -u ccvs/m4/ChangeLog:1.163 ccvs/m4/ChangeLog:1.164
--- ccvs/m4/ChangeLog:1.163     Wed Apr 19 16:49:25 2006
+++ ccvs/m4/ChangeLog   Mon Apr 24 18:50:25 2006
@@ -1,3 +1,7 @@
+2005-10-27  Derek Price  <address@hidden>
+
+       * base64.m4: New file from GNULIB.
+
 2006-04-19  Derek Price  <address@hidden>
 
        * full-header-path.m4, longdouble.m4: Update from GNULIB.
Index: ccvs/m4/gnulib-cache.m4
diff -u ccvs/m4/gnulib-cache.m4:1.6 ccvs/m4/gnulib-cache.m4:1.7
--- ccvs/m4/gnulib-cache.m4:1.6 Wed Apr 12 19:51:23 2006
+++ ccvs/m4/gnulib-cache.m4     Mon Apr 24 18:50:25 2006
@@ -14,10 +14,10 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 
--aux-dir=build-aux --macro-prefix=gl allocsa atexit canon-host canonicalize 
closeout dirname dup2 error exit exitfail extensions fnmatch fnmatch-posix 
ftruncate getdate gethostname getline getlogin_r getndelim2 getnline getopt 
getpagesize getpass-gnu gettext gettime gettimeofday glob inttypes lstat malloc 
md5 memmove minmax mkdir mkstemp mktime nanosleep pagealign_alloc pathmax 
quotearg readlink realloc regex rename restrict save-cwd setenv stat-macros 
stdbool stdint strcase strdup strerror strftime strstr strtoul strtoumax time_r 
timespec tzset unlocked-io vasnprintf vasprintf xalloc-die xgethostname 
xreadlink xsize yesno
+#   gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 
--aux-dir=build-aux --macro-prefix=gl allocsa atexit base64 canon-host 
canonicalize closeout dirname dup2 error exit exitfail extensions fnmatch 
fnmatch-posix ftruncate getdate gethostname getline getlogin_r getndelim2 
getnline getopt getpagesize getpass-gnu gettext gettime gettimeofday glob 
inttypes lstat malloc md5 memmove minmax mkdir mkstemp mktime nanosleep 
pagealign_alloc pathmax quotearg readlink realloc regex rename restrict 
save-cwd setenv stat-macros stdbool stdint strcase strdup strerror strftime 
strstr strtoul strtoumax time_r timespec tzset unlocked-io vasnprintf vasprintf 
xalloc-die xgethostname xreadlink xsize yesno
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
-gl_MODULES([allocsa atexit canon-host canonicalize closeout dirname dup2 error 
exit exitfail extensions fnmatch fnmatch-posix ftruncate getdate gethostname 
getline getlogin_r getndelim2 getnline getopt getpagesize getpass-gnu gettext 
gettime gettimeofday glob inttypes lstat malloc md5 memmove minmax mkdir 
mkstemp mktime nanosleep pagealign_alloc pathmax quotearg readlink realloc 
regex rename restrict save-cwd setenv stat-macros stdbool stdint strcase strdup 
strerror strftime strstr strtoul strtoumax time_r timespec tzset unlocked-io 
vasnprintf vasprintf xalloc-die xgethostname xreadlink xsize yesno])
+gl_MODULES([allocsa atexit base64 canon-host canonicalize closeout dirname 
dup2 error exit exitfail extensions fnmatch fnmatch-posix ftruncate getdate 
gethostname getline getlogin_r getndelim2 getnline getopt getpagesize 
getpass-gnu gettext gettime gettimeofday glob inttypes lstat malloc md5 memmove 
minmax mkdir mkstemp mktime nanosleep pagealign_alloc pathmax quotearg readlink 
realloc regex rename restrict save-cwd setenv stat-macros stdbool stdint 
strcase strdup strerror strftime strstr strtoul strtoumax time_r timespec tzset 
unlocked-io vasnprintf vasprintf xalloc-die xgethostname xreadlink xsize yesno])
 gl_AVOID([])
 gl_SOURCE_BASE([lib])
 gl_M4_BASE([m4])
Index: ccvs/m4/gnulib-comp.m4
diff -u ccvs/m4/gnulib-comp.m4:1.14 ccvs/m4/gnulib-comp.m4:1.15
--- ccvs/m4/gnulib-comp.m4:1.14 Wed Apr 12 19:51:23 2006
+++ ccvs/m4/gnulib-comp.m4      Mon Apr 24 18:50:25 2006
@@ -31,6 +31,7 @@
   gl_FUNC_ALLOCA
   gl_ALLOCSA
   gl_FUNC_ATEXIT
+  gl_FUNC_BASE64
   gl_CANON_HOST
   AC_FUNC_CANONICALIZE_FILE_NAME
   gl_FUNC_CHDIR_LONG
@@ -138,6 +139,8 @@
   lib/asnprintf.c
   lib/asprintf.c
   lib/atexit.c
+  lib/base64.c
+  lib/base64.h
   lib/basename.c
   lib/canon-host.c
   lib/canon-host.h
@@ -304,6 +307,7 @@
   m4/alloca.m4
   m4/allocsa.m4
   m4/atexit.m4
+  m4/base64.m4
   m4/bison.m4
   m4/canon-host.m4
   m4/canonicalize.m4
Index: ccvs/maint-aux/Makefile.in
diff -u ccvs/maint-aux/Makefile.in:1.27 ccvs/maint-aux/Makefile.in:1.28
--- ccvs/maint-aux/Makefile.in:1.27     Fri Apr 14 15:15:15 2006
+++ ccvs/maint-aux/Makefile.in  Mon Apr 24 18:50:25 2006
@@ -59,8 +59,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -151,6 +151,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -166,6 +167,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/man/Makefile.in
diff -u ccvs/man/Makefile.in:1.96 ccvs/man/Makefile.in:1.97
--- ccvs/man/Makefile.in:1.96   Wed Apr 12 19:55:27 2006
+++ ccvs/man/Makefile.in        Mon Apr 24 18:50:25 2006
@@ -61,8 +61,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -158,6 +158,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -173,6 +174,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/src/ChangeLog
diff -u ccvs/src/ChangeLog:1.3375 ccvs/src/ChangeLog:1.3376
--- ccvs/src/ChangeLog:1.3375   Thu Apr 20 20:32:27 2006
+++ ccvs/src/ChangeLog  Mon Apr 24 18:50:25 2006
@@ -1,3 +1,931 @@
+2006-04-13  Derek Price  <address@hidden>
+
+       * diff.c (diff_fileproc): Correct for Version_TS error when calling
+       make_file_label.
+
+2006-04-12  Derek Price  <address@hidden>
+
+       * lock.c: #include "repos.h" for proto.
+
+2006-03-24  Derek Price  <address@hidden>
+
+       * verify.c: #include <getopt.h>.
+       (verify_usage): Correct usage.
+       (verify): Use declared int type for getopt return - char may be
+       unsigned on some systems.
+
+2006-03-13  Derek Price  <address@hidden>
+
+       Handle OpenPGP version 4 signatures.
+       * gpg.c (struct openpgp_signature_subpacket): New struct.
+       (parse_signature_subpacket): New function.
+       (parse_signature): Process version 4 signatures.
+
+2006-01-27  Derek Price  <address@hidden>
+
+       * verify.c: #include "wait.h" from GNULIB.
+
+2006-01-26  Derek Price  <address@hidden>
+
+       * verify.c: s/VERIFY_NEVER/VERIFY_OFF/.
+
+2006-01-20  Derek Price  <address@hidden>
+
+       * diff.h: New file.
+
+       * base.c (base_diff): Handle client/server mode.
+       * client.c (base_copy): Expand header comment.
+       (client_base_diff, handle_base_diff): New function.
+       (responses): Add Base-diff.
+       * diff.c (diff_mark_errors): Export.
+       (empty_files): s/int/bool/.
+       (diff_fileproc): Reduce verbosity.  Avoid passing `-' as part of a
+       revision number.  Pass time stamp to make_file_label when available.
+       (get_diff_info): New function.
+       * entries.c: Add traces.
+       * rcs.c (make_file_label), rcs.h: Accept time stamp as an argument.
+       * server.c (requests): Add Base-diff.
+       (iserver_base_checkout): Always send temp files.
+       (server_base_diff): Add new function.
+       * server.h (server_base_diff): New proto.
+       * vers_ts.c (time_stamp_server): Use a time stamp that won't match
+       ts_rcs when the server is running without file contents.
+
+       * sanity.sh: Update to compensate.
+       
+2006-01-19  Derek Price  <address@hidden>
+
+       * diff.c (have_rev1_label, have_rev2_label): Make boolean.
+       (diff_file_nodiff): Accept a tag for Name keywords.
+       (diff_fileproc): Factor some functionality to...
+       * base.c (base_diff), base.h: ...this new function.
+       
+       * rcs.c (RCS_cmp_file), rcs.h: Accept a tag for Name keywords. 
+       * checkin.c, import.c, no_diff.c, update.c: Update all callers.
+
+       * diff.c (diff_file_nodiff): Remove proto and move function before
+       first invocation.  Return found revisions in args rather than globals.
+       (diff_fileproc): Remove unused variables.  Use new diff_file_nodiff
+       API.  Check for temp_checkout errors.
+
+       * diff.c (enum diff_file): Add DIFF_CLIENT.
+       (diff): Send no content when possible.
+       (diff_fileproc): Consolidate complex handling into a single call to
+       diff_exec.
+       (diff_file_nodiff): Punt when only the client knows if there are true
+       differences.
+       * rcs.h (RCS_output_diff_options): Add prototype.
+       * rcscmds.c (RCS_exec_rcsdiff): Remove this unused function.
+       (RCS_output_diff_options): Handle add & remove cases.
+
+       * sanity.sh: Accomodate the above changes.
+
+2006-01-18  Derek Price  <address@hidden>
+
+       * sanity.sh: Create $HOME/.gnupg to work around a problem with at least
+       GnuPG 1.2.6 on an AMD64 running a Linux 2.6.9.
+       (import-101): Expect signed imports.
+
+       * client.c (update_entries): Improve error messages.
+       (client_write_sigfile): Cache signature when needed.  Update all
+       callers.
+       (client_base_checkout): Used cached signature for checkout
+       verification.
+       * cvs.h (CVS_VERIFY_TEMPLATE_ENV): New macro.
+       * import.c (add_rcs_file): Add with signature when needed.
+       * main.c (main): Standardize parsing of OpenPGP env var content.
+       Parse $CVS_VERIFY_TEMPLATE.
+       * sanity.config.sh.in: Add DEFAULT_VERIFY_TEMPLATE and quote other
+       var content.
+       * sign.c (get_sign_commits, have_sigfile, get_signature): Use global
+       server_active.  Update all references.
+       * verify.c (get_verify_commits_fatal): New function.
+       (iverify_signature): Replace with...
+       (verify_signature): ...this.  Improve error messages.  Accept fatal as
+       an argument.  Update all references.
+       
+       * sanity.sh: Update to compensate.
+       
+2006-01-17  Derek Price  <address@hidden>
+
+       * rcs.c (RCS_has_openpgp_signatures): Suppress error on some systems.
+
+2006-01-16  Derek Price  <address@hidden>
+
+       * client.c (handle_openpgp_signatures): Rename to...
+       (handle_openpgp_signature): ...this and handle OpenPGP-signature
+       responses as documented.
+       (client_write_sigfile): Ditto on the response handling.
+       (responses): Rename OpenPGP-signatures to OpenPGP-signature.  Handle
+       new function name.
+       * rcs.c (iRCS_get_openpgp_signatures): New function factored from...
+       (RCS_get_openpgp_signatures): ...here.  Change API to return sigs
+       after base 64 decoding.
+       (RCS_has_openpgp_signatures): New function.
+       * rcs.h (RCS_get_openpgp_signatures): Update proto.
+       (RCS_has_openpgp_signatures): New proto.
+       * server.c (server_send_signatures): Handle raw signatures and match
+       response documentation.
+       (server_base_signatures): Use RCS_has_openpgp_signatures.
+       * verify.c (verify_fileproc): Handle raw signatures.
+       * vers_ts.c (Version_TS): Save RCSNode in input finfo.
+       
+2006-01-14  Derek Price  <address@hidden>
+
+       * cvs.h [CVS_VERIFY_CHECKOUTS_ENV, CVS_SIGN_COMMITS_ENV]: New macros.
+       * main.c (main): Process $CVS_VERIFY_CHECKOUTS & $CVS_SIGN_COMMITS.
+       * sanity.sh: Turn off GPG in remote mode eith base files disabled.
+
+2006-01-13  Derek Price  <address@hidden>
+
+       * client.c (update_entries): Don't require signatures for `cvs export'.
+
+       * client.c (update_entries): Warn/exit when unsigned file contents are
+       received from the server.
+       * verify.c (get_verify_checkouts_fatal): New function.
+       * verify.h (get_verify_checkouts_fatal): New proto.
+       * sanity.sh (client): Skip tests incompatible with OpenPGP signatures.
+       (openpgp2): New tests.
+
+       * parseinfo.c (parse_config): Avoid a core dump.
+       * sanity.sh (openpgp): Add a few tests for commit signature
+       verification.
+
+2006-01-12  Derek Price  <address@hidden>
+
+       * gpg.c (read_signature): Rename to...
+       (next_signature): ...this to avoid conflicts with sign.c.
+       * gpg.h: Ditto.
+       * cvs.h (trace): Move decl...
+       * server.h (trace): ...here.
+       * main.c (trace): Move global...
+       * server.c (trace): ...here.
+       (serve_signature): s/read_signature/next_signature/.
+       * sign.c (get_signature): Verify signature when configured to.
+       * verify.c (iget_verify_checkouts, get_verify_checkouts): Use global
+       server_support.
+       (verify_state_to_string): New function.
+       (iget_verify_commits): Allow tracing of state.
+       (iverify_signature): Handle sig in a buffer.
+       (verify_signature): New function.
+       (verify_fileproc): Use new iverify_signature API.
+       * verify.h (get_verify_checkouts): Update proto.
+       (get_verify_commits, verify_signature): New protos.
+
+       * sanity.sh (writeproxy-0): Accept `sign' requests.
+
+       * gpg.h: #include "parseinfo.h" for struct config.
+       (openpgp_textmode, set_openpgp_textmode, get_openpgp_textmode): Move
+       global, functions from...
+       * sign.c (sign_textmode, set_sign_textmode, get_sign_textmode):
+       ...here.
+       * gpg.h (set_openpgp_textmode, get_openpgp_textmode): New protos...
+       * sign.h (set_sign_textmode, get_sign_textmode): ...here.
+       * main.c (main): Rename `textmode' to `openpgp-textmode'.
+       (config): Move global to...
+       * parseinfo.c (config): ...here.
+       (parse_config): Handle Verify* keys.
+       * parseinfo.h: Use stricter include formatting.
+       (config): Declare extern.
+       * root.c (new_cvsroot_t, free_cvsroot_t, parse_cvsroot), root.h
+       (cvsroot_t): Rename sign_textmode as above.
+       * verify.c: Stop using "cvs.h".  Add protos for a few functions and
+       globals still in main.c.
+       (verify_commits): New static global.
+       (iget_verify_checkouts): Reformat slightly for readability.
+       (iget_verify_commits, get_verify_commits): New functions.
+       (get_verify_template, get_verify_args): Process config keys.
+       * verify.h (verify_state): Force VERIFY_DEFAULT to 0 so that no
+       initialization is necessary for structs initialized with xcalloc().
+
+       * cvs.h: Move some protos into...
+       * repos.h: ...this new file.
+       * add.c, admin.c, checkout.c, client.c, commit.c, edit.c, fileattr.c,
+       history.c, logmsg.c, rcs.c, recurse.c, server.c, tag.c, update.c:
+       #include "repos.h".
+       * create_adm.c, repos.c: Ditto, and use stricter include formatting.
+
+2006-01-11  Derek Price  <address@hidden>
+
+       * main.c (opt_usage): Clarify --verify usage.
+       (main): Accept `--no-textmode'.
+       * root.c (new_cvsroot_t): Default sign/verify options to NULL.
+       (parse_cvsroot_t): Handle multiple textmode options and no-textmode.
+       * sign.c (get_sign_template): Return default when method option is
+       NULL.
+       (get_sign_textmode): Ditto, but return NULL when an option is set to
+       the empty string.
+       * verify.c (get_verify_template): Return default when method option is
+       NULL.
+       (iverify_signature): Use documented template format strings.
+
+2006-01-10  Derek Price  <address@hidden>
+
+       * sign.c (sign_usage): Add usage for `-r'.
+
+       * admin.c: Use "wrapper.h".
+       * client.c (client_base_signatures): Allow removal of signature files.
+       (handle_base_signature): Support new clear argument for
+       client_base_signatures.
+       (handle_base_clear_signature): New file.
+       (responses): Add Base-clear-signatures.
+       * gpg.c (parse_signature): Preserve raw signature.
+       * gpg.h (struct openpgp_signature): Add storage for raw signature.
+       * log.c (log_version): Display only low 32 bits of key IDs to users,
+       mimicing GnuPG.
+       * rcs.c: Use stricter include formatting.
+       (RCS_add_openpgp_signature): Use xalloc_die for memory errors.
+       (RCS_delete_openpgp_signatures): New function.
+       * rcs.h (RCS_delete_openpgp_signatures): Add proto.
+       * server.c (server_base_signatures): Send clear when there are no
+       signatures.
+       * sign.c (struct sign_args): Caller data for sign_fileproc.
+       (sign_fileproc, sign): Handle key deletion.
+       * verify.c (verify_fileproc): Match warning messages in local and
+       client/server mode.  Don't treat lack of signatures as an error.
+       * vers_ts.c (Version_TS), vers_ts.h (Version_TS): Make args const.
+
+       * sanity.sh (openpgp): Add signature deletion tests.
+
+       * client.c (send_fileproc): Compare files to base revision when
+       available.
+       (send_files): Accept FORCE_SIGNATURE flag.
+       * client.h: Define FORCE_SIGNATURE.
+       * sign.c (sign_check_fileproc): New function to verify files are
+       unmodified before wasting bandwidth.
+       (sign, sign_fileproc): Accept -d flag.
+
+       * no_diff.h, wrapper.h: New files with decls from...
+       * cvs.h: ...here.  Some decls moved to...
+       * filesubr.h, vers_ts.h: ...here.
+       * add.c, checkin.c, checkout.c, classify.c, commit.c, diff.c,
+       ignore.c, import.c, log.c, ls.c, no_diff.c, recurse.c, remove.c,
+       server.c, status.c, subr.c, update.c, watch.c, wrapper.c: Use stricter
+       include formatting.
+
+2006-01-09  Derek Price  <address@hidden>
+
+       * client.c (start_server): Suppress advertising OpenPGP-signatures
+       response when base support suppressed.
+       * rcs.c (RCS_get_openpgp_signatures): Support returning length for
+       convenience.  Fully parse archives when necessary.
+       (RCS_checkin): Don't sign dead revisions.
+       * rcs.h (RCS_get_openpgp_signatures): Add len to API.
+       * server.c (serve_wrapper_sendme_rcs_options): Remove extra semicolon.
+       (server_send_signatures): Use cached signature len.
+       (server_base_signatures): Check for option support before sending.
+       * subr.c (force_write_file): New function factored from...
+       (write_file): ...here.
+       * subr.h (force_write_file): New proto.
+       * verify.c (verify_fileproc): Handle local mode.
+       (verify_signature): Remove function.
+       * verify.h (verify_signature): Remove proto.
+
+       * sanity.sh: Support --no-bases.  s/--noredirect/--no-redirect/g, for
+       consistency.  Replace `test -z "$CVSNOBASES"' with boolean $bases.
+       (import): Don't expect signature on dead revision.
+       (openpgp): Skip without GPG and when bases are suppressed in remote
+       mode.
+
+       * sanity.sh (errmsg4-1): Increase verbosity to preserve warning being
+       tested.
+
+2006-01-06  Derek Price  <address@hidden>
+
+       * add.c, admin.c, annotate.c, base.c, buffer.c, checkin.c, checkout.c,
+       classify.c, client.c, client.h, commit.c, cvs.h, diff.c, edit.c,
+       edit.h, entries.c, fileattr.c, find_names.c, history.c, ignore.c,
+       import.c, lock.c, log.c, logmsg.c, ls.c, main.c, mkmodules.c,
+       modules.c, patch.c, rcs.c, recurse.c, release.c, remove.c, sanity.sh,
+       server.c, server.h, sign.c, status.c, tag.c, update.c, verify.c,
+       watch.c: Update copyright notices.
+
+       * client.c, client.h, commit.c, log.c, mkmodules.c, patch.c, server.c,
+       status.c: Use stricter include formatting.
+       (update_entries): Generalize sig_cache handling.
+       (client_write_sigfile): New function factored from...
+       (client_base_checkout): ...here.
+       (client_base_signatures, handle_base_signatures): New functions.
+       (responses): Add Base-signatures.
+       (struct send_data, send_files): Remove sign flag.
+       (send_fileproc): Compensate.  Send signatures for sign command.
+       * client.h [SEND_SIGNATURES]: Remove.
+       * commit.c (check_direntproc): Compensate.
+       * main.c (cmd): Add `sign' command.  
+       * rcs.c (RCS_add_openpgp_signature): New function.
+       * server.c (server_write_sigfile): New function factored from...
+       (serve_modified): ...here.
+       (serve_unchanged): Write signatures.
+       (requests): Add `sign' request.
+       (serve_sign, server_base_signatures): New functions.
+       * server.h (server_write_sigfile): Add proto.
+       * sign.c (sign_fileproc, sign): New functions.
+       (sign_usage): Add.
+
+       * sanity.sh (verify): Rename to...
+       (openpgp): ...this and add sign test.
+
+       * add.c, admin.c, annotate.c, base.c, buffer.c, checkin.c, checkout.c,
+       classify.c, diff.c, edit.c, edit.h, entries.c, fileattr.c,
+       find_names.c, history.c, ignore.c, import.c, lock.c, logmsg.c, ls.c,
+       modules.c, recurse.c, release.c, remove.c, tag.c, update.c, verify.c,
+       watch.c: Use stricter include formatting.
+       * cvs.h: Move decls to...
+       * classify.h, ignore.h, logmsg.h, recurse.h: ...these new files.
+
+2006-01-03  Derek Price  <address@hidden>
+
+       * verify.c (verify): Accept -p option.
+       (verify_fileproc): Send signature to stdout with -p.
+       * sanity.sh (verify): Test `cvs verify -p'.
+
+2006-01-01  Derek Price  <address@hidden>
+
+       * client.c (sig_cache): New static global.
+       (update_entries): Save signatures to CVS/Base after a commit.
+       (send_signature): Cache signatures after sending them to the server.
+       Accept full file name as an argument.  Update all callers.
+       * sanity.sh: Set GPG trust for test key.
+       (verify): New test.
+       * subr.c (write_file), subr.h: New function.
+       * verify.c (iverify_signature): New function factored from...
+       (verify_signature): ...here.
+
+       * sign.c (read_signature): Remove bin argument.  Update caller.
+
+       * base.c (translate_exists): Suppress GCC warning.
+
+2005-12-31  Derek Price  <address@hidden>
+
+       * verify.c, verify.h: New files.
+       * Makefile.am (cvs_SOURCES): Add new files.
+       * main.c: Include "verify.h".
+       (opt_usage): Add --verify* args.
+       (main): Process same.
+       * root.c (new_cvsroot_t): Default verify method options.
+       (parse_cvsroot): Process same.
+       * root.h (cvsroot_t): Add verify method options.
+       * sign.c (get_sign_textmode), sign.h (get_sign_textmode): Export.
+
+2005-12-30  Derek Price  <address@hidden>
+
+       * client.c (handle_openpgp_signatures): Clarify error message.
+
+       * rcs.c (RCS_get_openpgp_signatures): Remove erroneous comment.
+
+       * gpg.c (read_u8, read_u16, read_u32): Declare inline.
+       (read_u64): New function.
+       (read_signature): Expand header comment block.
+       (parse_signature): Parse up to key ID.
+       (struct openpgp_signature): Move decl to...
+       gpg.h (struct openpgp_signature): ...here.
+       (parse_signature): New proto.
+       * log.c: Include "base64.h" & "gpg.h".
+       (log_version): Print signature information when available.
+       * sanity.sh: Accept new signature info in log messages.
+
+       * gpg.c (write_part, parse_header, read_signature, parse_signature):
+       Use uint8_t rather than unsigned char.
+
+       * gpg.c (read_u8, read_u16, read_u32): Use <stdint.h> uintN_t types for
+       output rather than potentially variable bit length types.
+       (write_part, parse_header, read_signature, parse_signature): Carry
+       through above <stdint.h> change to callers.
+
+       * gpg.c: Minor comment fixes.
+
+       * gpg.c: Include <stdint.h>.
+       (parse_header): New function factored from...
+       (read_signature): ...here.
+       (struct openpgp_signature): New decl.
+       (parse_signature): New function.
+
+2005-12-27  Derek Price  <address@hidden>
+
+       * gpg.c (read_u32): New function.
+       (read_signature): Handle new style CTB packets.
+
+2005-12-13  Derek Price  <address@hidden>
+
+       * base.c (ibase_copy, base_merge): Remove signature files when using
+       temp files or SUPPRESS_BASES.
+
+       Send signature files to client with base files.
+       * base.c (base_checkout): Comment where the signature verification
+       will take place.
+       (ibase_copy): Suppress warning.
+       (base_remove): Add header comment.  Remove signature files with bases.
+       * client.c: Include base64.h.
+       (handle_openpgp_signatures): New function.
+       (client_base_checkout): Remove ugly comment.  Save stored signatures to
+       a file.
+       (responses): Add OpenPGP-signatures.
+       * rcs.c (RCS_get_openpgp_signatures): New function.
+       * rcs.h: Add proto for same.
+       * sanity.sh (basica): Force remove directory when done.
+       * server.c: Reorder headers for consistency.
+       (server_send_signatures): New function.
+       (ibase_server_checkout): Use new function to send signatures.
+
+2005-12-12  Derek Price  <address@hidden>
+
+       Simplify protocol slightly.
+       * add.c (add), update.c (join_file): Use temp files rather than base
+       files for resurrection and additions via join.
+       * base.c (temp_checkout): Export function.
+       (ibase_copy): Factor from...
+       (base_copy): ...here.
+       (temp_copy): New function.
+       * base.h (temp_checkout, temp_copy): New functions.
+       * client.c (client_base_copy): Work with temp files when necessary.
+       
+2005-12-10  Derek Price  <address@hidden>
+
+       * sanity.sh: Minor corrections for nobase testing.
+
+2005-12-09  Derek Price  <address@hidden>
+
+       * sanity.sh: Minor corrections for nobase testing.
+       (modes): Unset CVSUMASK when done.
+
+2005-12-08  Derek Price  <address@hidden>
+
+       * Makefile.am (maintainercheck-local, nobaseremotecheck,
+       nobaselocalcheck, nobaseproxycheck): New targets.
+       (check-local): Add nobaseremotecheck.
+       * base.c (base_copy, base_merge): Remove files when bases are
+       suppressed.
+       * checkin.c (Checkin): Don't create bases when suppressed.
+       * client.c (handle_base_checkout, handle_temp_checkout,
+       handle_base_copy, handle_base_merge, handle_base_entry,
+       handle_base_merged): Abort if these responses are received when the
+       client has requested the server not send them.
+       (client_base_copy): Force removal of temp files in noexec mode.
+       (start_server): Avoid sending Base-* and Temp-checkout as part of
+       valid_responses when the user has suppressed these.
+       * cvs.h (NOBASES_ENV): New macro.
+       (suppress_bases): New global.
+       * main.c (bases): Ditto.
+       (opt_usage, short_options, main): Add & process -B.
+       * update.c (join_file): Prefer Register to the potentially ambiguous
+       RegisterMerge when the merge actually only added a file.  Use
+       RCS_cmp_file to test if the file == its base when a base file is not
+       available.
+
+       * sanity.sh: Add processing for -B and -q options.
+       (unedit-without-baserev): Remove accidental commit.
+       
+       * base.c (base_checkout): Don't checkout base files when NOEXEC.
+       (temp_checkout): New function.
+       (base_copy): This function can't rely on the client to validate changes
+       in local mode.  Avoid copying when NOEXEC.
+       (base_merge): Use temp files when joining and in noexec mode to avoid
+       overwriting base files.  Suppress merging messages when REALLY_QUIET.
+       (translate_exists, validate_change): Move from...
+       * client.c: ...here.
+       (handle_redirect): Avoid double-free.
+       (update_entries): Move error handling from validate_change.  Sync
+       messages between local & client/server.
+       (client_base_checkout): Handle temp checkouts.
+       (handle_temp_checkout): New function.
+       (client_base_merge): Move error handling from validate_change.  Use
+       temp checkouts.  Sync messages.  Fix bugs in xcmp tests.
+       * base.h (update_existing, translate_exists, validate_change): Move
+       structs and protos from...
+       * client.h: ...here.
+       * checkin.c (Checkin): Update base file in local mode.
+       * difflib.h (merge), difflib.c (merge): Reorder args for clarity.
+       * server.c (server_updated): Expand traces.
+       (iserver_base_checkout): New function factored from...
+       (server_base_checkout): ...here.
+       (server_temp_checkout): New function.
+       * server.h (server_temp_checkout): New proto.
+       * update.c (checkout_file): Copy backup for error checks.
+       (RegisterMerge): Add traces.
+       (merge_file): Update base files when done.
+       (join_file): Sync messages.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+       (mcopy): Disable this test.
+
+2005-12-06  Derek Price  <address@hidden>
+
+       * client.c (client_base_checkout): Make base checkouts work when in
+       noexec mode.
+       * server.c (server_base_checkout): Unlink temp file in noexec mode.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+
+2005-12-05  Derek Price  <address@hidden>
+
+       * client.c (update_entries): Create timestamp when LAST_MERGE_CONFLICT.
+
+       * server.c (server_updated): Don't dereference NULL.  Don't send diffs
+       when revisions are identical.
+
+       * cvs.h (Register): Move proto to...
+       * entries.h: ...here.  Include hash.h.
+       * entries.c (Entnode_Destroy): Add traces.
+       * hash.c: Verify interface.
+       * hash.h: Include <stddef.h> for size_t.
+       * update.c (update_fileproc): Fix vers_ts->entdata after a merge.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+
+2005-12-02  Derek Price  <address@hidden>
+
+       * base.c (base_remove), rcs,c (RCS_checkin), server.c (server_updated):
+        Add traces.
+       * client.c (update_entries): Don't assume UPDATE_ENTRIES_CHECKIN
+       actually means this was a checkin.
+       * server.c (server_base_checkout): Name (tag) changes could also create
+       a diff.
+
+       * checkin.c (Checkin): Actually pass the previous options.
+
+       * server.c (server_base_checkout), server.h: Accept new previous tag
+       and options arguments and use them when checking out the previous
+       revision to build a diff.
+       * base.c (base_checkout, base_merge): Accept new previous tag and
+       previous options arguments and pass them through to
+       server_base_checkout.
+       * add.c, base.c, base.h, checkin.c, update.c: Update all references.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+
+2005-12-01  Derek Price  <address@hidden>
+
+       * client.c (client_base_merge): Print `Merging differences' message
+       only when !REALLY_QUIET.
+       (handle_base_merged): New function.
+       (responses): Add Base-merged.
+       * server.c (server_updated): Send Base-merged for merges.
+       * update.c (join_file): Handle replacing files and binaries correctly.
+
+       * client.c (base_merge_rev1, base_merge_rev2, last_merge_no_change):
+       New globals.
+       (update_entries): Delete merge temp files when not needed.  Don't
+       ignore merges (only joins), since rev changes.
+       (merge): Skip deleting temp files since this function cannot know which
+       is needed.
+       * edit.c (edit_file): Deal with read-only edit base files.
+
+       * filesubr.c (force_xchmod, ixchmod, force_copy_file): New functions.
+       (copy_file, xchmod): Wrap the force_* functions.
+       * cvs.h (xchmod): Move proto...
+       * filesubr.h (xchmod): ...here.
+       (force_xchmod, force_copy_file): New protos.
+       * client.c (client_base_merge), difflib.c (merge): Use new force_* API
+       rather than saving NOEXEC.
+
+       * base.c (base_walk): Invert fopen error detection.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+
+2005-11-30  Derek Price  <address@hidden>
+
+       * client.c (discard_file): Move code which discards stored metadata...
+       (validate_change): ...here.
+
+       * update.c (join_file): Don't preserve keyword modes when adding files
+       via join.
+
+       * commit.c (checkaddfile): Provide more information when changing
+       keyword expansion mode.
+
+       * client.c (update_entries): Honor noexec.
+       (client_base_merge): Ignore noexec when working with temp files.
+       * difflib.c (merge): Ditto.
+       * filesubr.c (unlink_file): Expand header comment block.
+       * server.c (server_base_checkout): Keep temp files in tmp.  Ignore
+       noexec when removing temp files.
+
+       * client.c (update_entries): Avoid removing base files when they are
+       still needed.
+
+       * update.c (join_file): Avoid dereferencing NULL.
+
+       * client.c (update_entries): Don't output update status lines when
+       REALLY_QUIET.
+
+       * update.c (update, do_update): Set bases separately from -u.
+       (merge_file, join_file): Consistently output "already contains the
+       differences" messages when !QUIET.
+
+       * server.c (server_base_checkout): Accept poptions argument & resend
+       Base files when options have changed.
+       * base.c, server.h: Change all references.
+       * base.c (base_checkout): Accept poptions argument.
+       * add.c, base.c, base.h, checkin.c, update.c: Change all references.
+       * client.c (call_in_directory): Remove leading "./" from short_pathname
+       when present.
+       (update_entries): Output "C" & "M" lines when needed.
+       (client_base_checkout): Allow Base files to be replaced.
+       (client_base_merge): Try to pretend merges never happened when they
+       have no effect.
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Other minor corrections.
+
+       * difflib.c (merge): Add label argument.
+       * base.c, client.c, difflib.h: Update all references.
+       * client.c (update_entries, client_base_copy): Handle existance
+       errors.
+       * update.c (checkout_file): Set correct existance flags.
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.
+
+2005-11-29  Derek Price  <address@hidden>
+
+       * sanity.sh: Compensate for new read-only Base files by forcing some
+       directory removals.  Compensate for new output.
+
+       * Makefile.am (cvs_SOURCES): Add difflib.[ch].
+       * difflib.c, difflib.h: New files with content from...
+       * rcscmds.c: ...here.
+       * base.c (base_checkout): Move writable processing...
+       (base_copy): ...here.
+       (base_merge): New function.
+       * add.c, base.h, checkin.c, update.c: Update all references.
+       * client.c (last_merge, last_merge_conflict): Keep track of whether
+       merges for update_entries.
+       (update_entries): Use merge result.
+       (client_base_copy): Handle new flags.
+       (client_base_merge, handle_base_merge): New functions.
+       (responses): Add "Base-merge" response.
+       * server.h: Move some protos in from...
+       * cvs.h: ...here and move some run.c stuff...
+       * run.h: ...here.
+       * filesubr.c: Reorg headers.
+       * filesubr.h: Give standalone API.  Move copy_file proto from cvs.h.
+       * server.c (server_base_checkout, server_base_copy): Push data to
+       client when done.
+       (server_base_merge): New function.
+       (server_updated): Assume base handling.
+       * update.c (RegisterMerge, merge_file, join_file): Offload merging to
+       client.
+       * add.c, checkin.c, commit.c, update.c: Update all references.
+       * sanity.sh: Misc accomodations.
+
+2005-11-28  Derek Price  <address@hidden>
+
+       * sanity.sh (errmsg4): Protect keyword.
+
+2005-11-22  Derek Price  <address@hidden>
+
+       * base.c (base_checkout): Add trace.  Avoid using bases with export.
+       (base_copy): Likewise.  Replace read-only files.
+       (base_remove): Deal with leading '-' in revision number.
+       * checkin.c (Checkin): Copy correct base revision when keywords are
+       present.
+       * checkout.c (checkout_proc): Bury sacrificial chicken.
+       * classify.c (Classify_File): Add trace.
+       * client.c (update_entries): Don't remove base files when noexec.
+       Print UPDATED_FNAME for base updates.
+       (client_base_checkout): Make CVS/BAse dir when needed.
+       (client_base_copy): Add trace.
+       * entries.c (Scratch_Entry): Remove base files.
+       (Register): Make trace first call.
+       * server.c (do_cvs_command): Set protocol buf to NULL after closing.
+       (server_updated): Avoid using base commands with export.
+       (server_cleanup): Set error_use_protocol to 0 while setting buf_to_net
+       to NULL.
+       (server_base_checkout): Expand header block comment.  Add trace.  Avoid
+       sending diffs when PREV is 0.  Compute diff in correct order.  Check
+       that diff will really be sent before telling the client that it will
+       be.
+       (cvs_trace): Use cvs_outerr instead of fprintf.
+       * update.c (update_fileproc): Add trace.
+       (checkout_file): Prefer bool to int.  Add trace.
+       * vers_ts.c (Version_TS): Add traces.
+       * sanity.sh (basicb): Remove old debugging cruft.
+       (basic2): Handle s/P/U/.
+       
+       * base.c (base_checkout): Assume this function is not called from the
+       client.
+       (base_remove): New function.
+       * base.h (base_remove): New proto.
+       * checkin.c (Checkin): Use base files when possible.
+       * client.c (validate_change): Expand header comment block.
+       (update_entries): Create base files on checkin.  Remove old base files
+       when creating new ones.
+       (client_base_checkout): Handle diffs.
+       * server.c (server_use_bases): New function.
+       (server_base_checkout): Send diffs when possible.
+       * server.h (server_base_checkout): Update proto.
+       * update.c (checkout_to_buffer): Remove obsolete function.
+       (bases): New global.
+       (update): Set BASES.
+       (update_fileproc): Use base functions for T_NEED_PATCH && T_CHECKOUT.
+       (checkout_file): Expand header comment block.  Use bases when possible.
+       
+2005-11-18  Derek Price  <address@hidden>
+
+       * add.c (add): Begin using new base functions.
+       * base.c (base_checkout, base_copy): New functions.
+       * base.h: Ditto for the protos.
+       * client.c (enum update_existing): Extract decl from...
+       (struct update_entries_data): ...this struct.  Add UPDATE_ENTRIES_BASE.
+       (read_file_from_server): Drop filename arg.
+       (validate_change): New function factored from...
+       (update_entries): ...here.  Add support for UPDATE_ENTRIES_BASE.
+       (client_base_checkout, handle_base_checkout, translates_exists,
+       client_base_copy, handle_base_copy, handle_base_entry): New functions.
+       (responses): Add Base-checkout, Base-copy, & Base-entry.
+       * server.c (server_base_checkout): Send data for non-diffs.
+       (server_base_copy): New function.
+       (server_updated): Send Base-entry when possible.  Accept temporary
+       USE_BASE arg.
+       * add.c, checkin.c, commit.c, update.c, server.h: Update all callers.
+
+2005-11-17  Derek Price  <address@hidden>
+
+       * client.c (read_file_from_sever, discard_file): New functions...
+       (update_entries): ...factored from here.
+       * server.h (gunzip_to_mem): New function proto.
+       * zlib.c (gunzip_to_mem): New function factored from...
+       (gunzip_and_write): ...here.
+
+2005-11-15  Derek Price  <address@hidden>
+
+       * cvs.h (struct entnode, Entnode, struct vers_ts, Vers_TS): Move to...
+       * entries.h: ...this new file and...
+       * vers_ts.h: ...this new file.
+       * entries.c: Include config.h directly.  Validate API.
+       * server.c: Ditto.
+       (server_send_checksum, output_mode_string, server_send_buffer_as_file,
+       server_send_file): New functions factored from...
+       (server_updated): ...here.
+       (server_base_checkout): New stub.
+       * server.h: Include root.h & vers_ts.h in order to add...
+       (server_base_checkout): This new proto.
+
+2005-11-09  Derek Price  <address@hidden>
+
+       * Makefile.am (cvs_SOURCES): Add base.c & base.h.
+       * cvs.h (base_get, base_register, base_deregister): Move protos to...
+       * base.h: ...this new file.
+       * entries.c (base_get, base_register, base_deregister): Move to...
+       * base.c: ...this new file.  Split update_dir & file name out of finfo
+       arg into two args.
+       * edit.c: Update all callers.
+       (edit_file): Try to copy upcoming update-base file as edit
+       base before falling back to the 1.11 way.
+
+2005-11-07  Derek Price  <address@hidden>
+       
+       * sanity.sh (errmsg4): New test for keyword-when-signed warning.
+
+2005-10-31  Derek Price  <address@hidden>
+
+       * rcs.c (contains_keyword): Convert return type to bool.
+
+2005-10-29  Derek Price  <address@hidden>
+
+       * commit.c (check_fileproc): Warn when a signed file contains keywords.
+       * rcs.c (next_keyword): New function factored from...
+       (expand_keyword): ...here.
+       (contains_keyword): New function.
+       * rcs.h (contains_keyword): Prototype new function.
+       * subr.c (file_contains_keyword): New function.
+       * subr.h (file_contains_keyword): Proto for same.
+       * sanity.sh: Compensate for the new warning.
+
+2005-10-28  Derek Price  <address@hidden>
+
+       * sanity.sh: Print a warning when GPG is not being used.
+
+       * sanity.sh (OPENPGP_PHRASE): Only add the trailing EOL when there is
+       content.
+
+2005-10-27  Derek Price  <address@hidden>
+
+       * rcs.c (RCS_checkin): Base64 encode GPG signatures to avoid having
+       tools like grep and diff decide signed files are binary.
+       * sanity.sh: Compensate for new signatures in RCS archive content.
+
+2005-10-19  Derek Price  <address@hidden>
+
+       * sanity.sh: $GPG == `gpg' now when no gpg was found.
+
+       * sanity.sh: Cause GPG to create its option file with a noop command.
+       Allow secret key import during setup.
+
+2005-10-18  Derek Price  <address@hidden>
+
+       * sign.c: #include "wait.h" from GNULIB.
+
+       * filesubr.h: #include <sys/types.h> for ssize_t.
+       * filesubr.c (islink): Add FIXME.
+
+2005-10-16  Derek Price  <address@hidden>
+
+       * sign.c (sign_commits): Base defaults on new HAVE_OPENPGP macro rather
+       than obsolete GPG_PROGRAM.
+
+       * client.c (send_signature, send_fileproc, client_process_import_file):
+       Use new APIs.
+       * cvs.h: Move function prototypes into...
+       * filesubr.h: ...this new header.
+       * hash.c (nodetypestring): Add RCSSTRING.
+       * hash.h (Ntype): Add RCSSTRING.
+       (Node): Add data len field.
+       * rcs.c: Verify interface.
+       (rcsbuf_get_node_type): New function.
+       (RCS_reparsercsfile, RCS_fully_parse, getdelta, RCS_getdeltatext):
+       Handle new RCSSTRING newphrase node type.
+       (RCS_checkin): Generate and save OpenPGP signature when needed.
+       (putrcsfield_proc): Remove FIXME.  Handle new Node type.  Use Node len
+       when available.
+       * server.c (serve_modified): Get sig file name via new API.
+       * sign.c (get_sign_commits): Return false in serve_mode.
+       (get_sigfile_name, have_sigfile, read_signature): New functions.
+       (gen_signature): New function with content originally from...
+       (get_signature): ...this function, which now also handles loading from
+       a sigfile when required.
+       * sign.h (get_sign_commits, get_signature): Add server_active arg.
+       (gen_signature, have_sigfile): New function protos.
+
+       * sign.h (DEFAULT_SIGN_PROGRAM, DEFAULT_SIGN_TEXTMODE): Move to
+       configure.in.
+
+       * cvs.h (BAKPREFIX): Move to...
+       * subr.h (BAKPREFIX): ...this more appropriate location.
+
+       * sanity.sh (crerepos): Remove CVS_CLIENT_LOG set while debugging.
+
+2005-10-14  Derek Price  <address@hidden>
+
+       * sign.h: Protos for new signature API.
+       * sign.c (init_signatures, set_sign_commits, set_sign_template,
+       set_sign_textmode, add_sign_arg, get_sign_commits, get_signature): New
+       signing API.
+       (sign_args_list_to_args_proc, get_signature): Move from...
+       * client.c (sign_args_list_to_args_proc): ...here...
+       (send_signature): ...and here.
+       (send_files): Only accept SEND_SIGNATURES flag to differentiate commit
+       from other callers.
+       (send_signature): Use new signing interface.
+       (client_send_import_file): Send signatures.
+       * client.h (send_files): Update proto.
+       * add.c, admin.c, annotate.c, client.c, diff.c, edit.c, log.c, ls.c,
+       remove.c, status.c, tag.c, update.c, watch.c: Change all callers.
+       * commit.c (commit): Move sign arg handling to...
+       * main.c (main): ...here.
+       * server.c (serve_modified): Save signatures to a temp file.
+       (serve_signature): Send error message on receipt of multiple sigs.
+
+       * rcs.c: Test interface.
+       * rcs.h: Protect against double-inclusion.
+       (struct file_info): Move from...
+       * cvs.h: ...here.  #include "run.h".
+       * subr.c, subr.h: Include "rcs.h" to imporve interface.
+       * run.c: #include "run.h".
+       * run.h: New file.
+
+       * gpg.c: Remove unsightly comments.
+
+       * Makefile.am (cvs_SOURCES): Add gpg.c & gpg.h.
+       * gpg.c, gpg.h: New files.
+       * server.c (sig_buf): New global.
+       (serve_signature): Extract signature correctly & store it.
+       * buffer.c, root.c: #include buffer.h first, to test interface.
+       * buffer.c (buf_read_data): Handle input from nonio (memory) buffers.
+       * buffer.h, root.h: Protect against double inclusion.  #include enough
+       headers to make interface standalone.
+
+2005-10-11  Derek Price  <address@hidden>
+
+       * commit.c (commit_usage), main.c (opt_usage): Describe OpenPGP related
+       options.
+
+       * Makefile.am (cvs_SOURCES): Add sign.c & sign.h.
+       * client.c (sign_args_list_to_args_proc, send_signature): New
+       functions.
+       (struct send_data): Add sign mode and template.
+       (send_fileproc): Send signature.
+       (send_files): Accept sign mode and sign template.
+       * client.h (send_files): Update proto.
+       * add.c, admin.c, annotate.c, client.c, diff.c, edit.c, log.c, ls.c,
+       remove.c, status.c, tag.c, update.c, watch.c: Change all callers.
+       * commit.c (commit): Accept and handle new sign options.
+       * hash.h: Avoid double-inclusion.
+       * main.c (main): Handle new sign options.
+       * root.c (new_cvsroot_t, free_cvsroot_t, parse_cvsroot_t), sign.h
+       (cvsroot_t): Handle new sign method options.
+       * server.c (serve_signature): New stub function.
+       (requests): Add `Signature' request.
+       * sign.c, sign.h: New files.
+       * subr.c (format_cmdline): Handle NULL data.
+       * sanity.config.sh: Set $GPG.
+       * sanity.sh: Set up gpg keys for tests when $GPG is set.
+       (writeproxy*): Compensate for new server requests.
+
 2006-04-20  Derek Price  <address@hidden>
 
        * buffer.c (fd_buffer_input, fd_buffer_output): Assert error return
Index: ccvs/src/Makefile.am
diff -u ccvs/src/Makefile.am:1.47 ccvs/src/Makefile.am:1.48
--- ccvs/src/Makefile.am:1.47   Sun Sep 25 00:28:51 2005
+++ ccvs/src/Makefile.am        Mon Apr 24 18:50:25 2006
@@ -29,6 +29,7 @@
        add.c \
        admin.c \
        annotate.c \
+       base.c base.h \
        buffer.c \
        checkin.c \
        checkout.c \
@@ -38,6 +39,7 @@
        create_adm.c \
        cvsrc.c \
        diff.c \
+       difflib.c difflib.h \
        edit.c \
        entries.c \
        error.c \
@@ -46,6 +48,7 @@
        fileattr.c \
        filesubr.c \
        find_names.c \
+       gpg.c gpg.h \
        hardlink.c \
        hash.c \
        history.c \
@@ -76,11 +79,13 @@
        run.c \
        scramble.c \
        server.c \
+       sign.c sign.h \
        stack.c stack.h \
        status.c \
        subr.c subr.h \
        tag.c \
        update.c \
+       verify.c verify.h \
        version.c \
        vers_ts.c \
        watch.c \
@@ -127,20 +132,35 @@
        build_src.com \
        sanity.sh
 
-check-local: localcheck remotecheck proxycheck
+check-local: localcheck remotecheck nobaseremotecheck proxycheck
+
+.PHONY: maintainercheck-local
+maintainercheck-local: check-local nobaselocalcheck nobaseproxycheck
 
 .PHONY: localcheck
-localcheck: sanity.config.sh
+localcheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaselocalcheck
+nobaselocalcheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -B `pwd`/cvs$(EXEEXT)
+
 .PHONY: remotecheck
 remotecheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaseremotecheck
+nobaseremotecheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -Br `pwd`/cvs$(EXEEXT)
+
 .PHONY: proxycheck
 proxycheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh -p `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaseproxycheck
+nobaseproxycheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -Bp `pwd`/cvs$(EXEEXT)
+
 # Our distclean targets
 distclean-local:
        rm -f check.log check.plog check.plog~
Index: ccvs/src/Makefile.in
diff -u ccvs/src/Makefile.in:1.167 ccvs/src/Makefile.in:1.168
--- ccvs/src/Makefile.in:1.167  Wed Apr 12 19:52:46 2006
+++ ccvs/src/Makefile.in        Mon Apr 24 18:50:25 2006
@@ -65,8 +65,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -141,12 +141,13 @@
 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
 PROGRAMS = $(bin_PROGRAMS)
 am_cvs_OBJECTS = add.$(OBJEXT) admin.$(OBJEXT) annotate.$(OBJEXT) \
-       buffer.$(OBJEXT) checkin.$(OBJEXT) checkout.$(OBJEXT) \
-       classify.$(OBJEXT) client.$(OBJEXT) commit.$(OBJEXT) \
-       create_adm.$(OBJEXT) cvsrc.$(OBJEXT) diff.$(OBJEXT) \
-       edit.$(OBJEXT) entries.$(OBJEXT) error.$(OBJEXT) \
-       exithandle.$(OBJEXT) expand_path.$(OBJEXT) fileattr.$(OBJEXT) \
-       filesubr.$(OBJEXT) find_names.$(OBJEXT) hardlink.$(OBJEXT) \
+       base.$(OBJEXT) buffer.$(OBJEXT) checkin.$(OBJEXT) \
+       checkout.$(OBJEXT) classify.$(OBJEXT) client.$(OBJEXT) \
+       commit.$(OBJEXT) create_adm.$(OBJEXT) cvsrc.$(OBJEXT) \
+       diff.$(OBJEXT) difflib.$(OBJEXT) edit.$(OBJEXT) \
+       entries.$(OBJEXT) error.$(OBJEXT) exithandle.$(OBJEXT) \
+       expand_path.$(OBJEXT) fileattr.$(OBJEXT) filesubr.$(OBJEXT) \
+       find_names.$(OBJEXT) gpg.$(OBJEXT) hardlink.$(OBJEXT) \
        hash.$(OBJEXT) history.$(OBJEXT) ignore.$(OBJEXT) \
        import.$(OBJEXT) lock.$(OBJEXT) log.$(OBJEXT) \
        log-buffer.$(OBJEXT) login.$(OBJEXT) logmsg.$(OBJEXT) \
@@ -156,10 +157,11 @@
        rcs.$(OBJEXT) rcscmds.$(OBJEXT) recurse.$(OBJEXT) \
        release.$(OBJEXT) remove.$(OBJEXT) repos.$(OBJEXT) \
        root.$(OBJEXT) rsh-client.$(OBJEXT) run.$(OBJEXT) \
-       scramble.$(OBJEXT) server.$(OBJEXT) stack.$(OBJEXT) \
-       status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) update.$(OBJEXT) \
-       version.$(OBJEXT) vers_ts.$(OBJEXT) watch.$(OBJEXT) \
-       wrapper.$(OBJEXT) zlib.$(OBJEXT)
+       scramble.$(OBJEXT) server.$(OBJEXT) sign.$(OBJEXT) \
+       stack.$(OBJEXT) status.$(OBJEXT) subr.$(OBJEXT) tag.$(OBJEXT) \
+       update.$(OBJEXT) verify.$(OBJEXT) version.$(OBJEXT) \
+       vers_ts.$(OBJEXT) watch.$(OBJEXT) wrapper.$(OBJEXT) \
+       zlib.$(OBJEXT)
 cvs_OBJECTS = $(am_cvs_OBJECTS)
 am__DEPENDENCIES_1 =
 binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
@@ -193,6 +195,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -208,6 +211,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
@@ -322,6 +326,7 @@
        add.c \
        admin.c \
        annotate.c \
+       base.c base.h \
        buffer.c \
        checkin.c \
        checkout.c \
@@ -331,6 +336,7 @@
        create_adm.c \
        cvsrc.c \
        diff.c \
+       difflib.c difflib.h \
        edit.c \
        entries.c \
        error.c \
@@ -339,6 +345,7 @@
        fileattr.c \
        filesubr.c \
        find_names.c \
+       gpg.c gpg.h \
        hardlink.c \
        hash.c \
        history.c \
@@ -369,11 +376,13 @@
        run.c \
        scramble.c \
        server.c \
+       sign.c sign.h \
        stack.c stack.h \
        status.c \
        subr.c subr.h \
        tag.c \
        update.c \
+       verify.c verify.h \
        version.c \
        vers_ts.c \
        watch.c \
@@ -514,6 +523,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@@ -523,6 +533,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@@ -531,6 +542,7 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@@ -563,12 +575,14 @@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@@ -761,20 +775,35 @@
        uninstall-info-am
 
 
-check-local: localcheck remotecheck proxycheck
+check-local: localcheck remotecheck nobaseremotecheck proxycheck
+
+.PHONY: maintainercheck-local
+maintainercheck-local: check-local nobaselocalcheck nobaseproxycheck
 
 .PHONY: localcheck
-localcheck: sanity.config.sh
+localcheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaselocalcheck
+nobaselocalcheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -B `pwd`/cvs$(EXEEXT)
+
 .PHONY: remotecheck
 remotecheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh -r `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaseremotecheck
+nobaseremotecheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -Br `pwd`/cvs$(EXEEXT)
+
 .PHONY: proxycheck
 proxycheck: all sanity.config.sh
        $(SHELL) $(srcdir)/sanity.sh -p `pwd`/cvs$(EXEEXT)
 
+.PHONY: nobaseproxycheck
+nobaseproxycheck: all sanity.config.sh
+       $(SHELL) $(srcdir)/sanity.sh -Bp `pwd`/cvs$(EXEEXT)
+
 # Our distclean targets
 distclean-local:
        rm -f check.log check.plog check.plog~
Index: ccvs/src/add.c
diff -u ccvs/src/add.c:1.121 ccvs/src/add.c:1.122
--- ccvs/src/add.c:1.121        Sun Sep  4 00:48:21 2005
+++ ccvs/src/add.c      Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -30,9 +30,25 @@
  */
 
 #include <assert.h>
-#include "cvs.h"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "save-cwd.h"
+
+/* CVS headers.  */
+#include "base.h"
 #include "fileattr.h"
+#include "ignore.h"
+#include "logmsg.h"
+#include "repos.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
 
 static int add_directory (struct file_info *finfo);
 static int build_entry (const char *repository, const char *user,
@@ -469,7 +485,7 @@
                             */
                            char *prev = previous_rev (vers->srcfile,
                                                       vers->vn_rcs);
-                           int status;
+                           char *tempfile;
                            if (prev == NULL)
                            {
                                /* There is no previous revision.  Either:
@@ -493,12 +509,11 @@
                                error (0, 0,
 "Resurrecting file `%s' from revision %s.",
                                       finfo.fullname, prev);
-                           status = RCS_checkout (vers->srcfile, finfo.file,
-                                                  prev, vers->tag,
-                                                  vers->options, RUN_TTY,
-                                                  NULL, NULL);
-                           xchmod (finfo.file, 1);
-                           if (status != 0)
+                           tempfile = temp_checkout (vers->srcfile, &finfo,
+                                                     NULL, prev, NULL,
+                                                     vers->tag,
+                                                     NULL, vers->options);
+                           if (!tempfile)
                            {
                                error (0, 0, "Failed to resurrect revision %s",
                                       prev);
@@ -507,11 +522,13 @@
                            else
                            {
                                /* I don't actually set vers->ts_user here
-                                * because it would confuse server_update().
+                                * because it would confuse server_update ().
                                 */
+                               temp_copy (&finfo, "ny", tempfile);
                                timestamp = time_stamp (finfo.file);
                                if (!really_quiet)
                                    write_letter (&finfo, 'U');
+                               free (tempfile);
                            }
                            free (prev);
                        }
@@ -601,18 +618,19 @@
                else
                {
                    int status;
+                   char *tmp;
+
                    /*
                     * There is an RCS file, so remove the "-" from the
                     * version number and restore the file
                     */
-                   char *tmp = xstrdup (vers->vn_user + 1);
-                   (void) strcpy (vers->vn_user, tmp);
-                   free (tmp);
-                   status = RCS_checkout (vers->srcfile, finfo.file,
-                                          vers->vn_user, vers->tag,
-                                          vers->options, RUN_TTY,
-                                          NULL, NULL);
-                   xchmod (finfo.file, cvswrite);
+                   memmove (vers->vn_user, vers->vn_user + 1,
+                            strlen (vers->vn_user));
+                   status = base_checkout (vers->srcfile, &finfo,
+                                           vers->vn_user, vers->vn_user,
+                                           vers->entdata->tag, vers->tag,
+                                           vers->entdata->options,
+                                           vers->options);
                    if (status != 0)
                    {
                        error (0, 0, "Failed to resurrect revision %s.",
@@ -625,8 +643,11 @@
                        /* I don't actually set vers->ts_user here because it
                         * would confuse server_update().
                         */
+                       base_copy (&finfo, vers->vn_user,
+                                  cvswrite ? "ny" : "nn");
                        tmp = time_stamp (finfo.file);
-                       write_letter (&finfo, 'U');
+                       if (!really_quiet)
+                           write_letter (&finfo, 'U');
                        if (!quiet)
                             error (0, 0, "`%s', version %s, resurrected",
                                    finfo.fullname, vers->vn_user);
Index: ccvs/src/admin.c
diff -u ccvs/src/admin.c:1.112 ccvs/src/admin.c:1.113
--- ccvs/src/admin.c:1.112      Wed Dec 21 02:17:10 2005
+++ ccvs/src/admin.c    Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -14,11 +14,25 @@
  * 
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* ANSI C headers.  */
 #ifdef CVS_ADMIN_GROUP
-#include <grp.h>
+# include <grp.h>
 #endif
 
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+#include "repos.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 static Dtype admin_dirproc (void *callerdat, const char *dir,
                             const char *repos, const char *update_dir,
                             List *entries);
Index: ccvs/src/annotate.c
diff -u ccvs/src/annotate.c:1.21 ccvs/src/annotate.c:1.22
--- ccvs/src/annotate.c:1.21    Sat Dec 31 23:33:43 2005
+++ ccvs/src/annotate.c Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -17,8 +17,18 @@
  * all the files in the directory (recursive by default).
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+
 #include "cvs.h"
 
+
+
 /* Options from the command line.  */
 
 static int force_tag_match = 1;
Index: ccvs/src/buffer.c
diff -u ccvs/src/buffer.c:1.70 ccvs/src/buffer.c:1.71
--- ccvs/src/buffer.c:1.70      Thu Apr 20 20:32:27 2006
+++ ccvs/src/buffer.c   Mon Apr 24 18:50:25 2006
@@ -14,9 +14,18 @@
 
 /* Code for the buffer data structure.  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
 #include "buffer.h"
 
+/* CVS headers.  */
+#include "cvs.h"
+
+
+
 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
 
 # include <sys/socket.h>
@@ -950,8 +959,6 @@
 int
 buf_read_data (struct buffer *buf, size_t want, char **retdata, size_t *got)
 {
-    assert (buf->input != NULL);
-
     while (buf->data != NULL && buf->data->size == 0)
     {
        struct buffer_data *next;
@@ -969,6 +976,12 @@
        int status;
        size_t get, nbytes;
 
+       if (!buf->input)
+           /* nonio (memory) buffers have no underlying input methods.  If
+            * there are no buffer datas, just return EOF.
+            */
+           return -1;
+
        data = get_buffer_data ();
        if (data == NULL)
        {
Index: ccvs/src/buffer.h
diff -u ccvs/src/buffer.h:1.27 ccvs/src/buffer.h:1.28
--- ccvs/src/buffer.h:1.27      Tue Mar 28 15:30:23 2006
+++ ccvs/src/buffer.h   Mon Apr 24 18:50:25 2006
@@ -14,6 +14,16 @@
 
 /* Declarations concerning the buffer data structure.  */
 
+#ifndef BUFFER_H
+#define BUFFER_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "root.h"
+
 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
 
 # include "getpagesize.h"
@@ -194,3 +204,5 @@
 #   define blocking_error(err) ((err) == EAGAIN)
 # endif
 #endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
+
+#endif /* BUFFER_H */
Index: ccvs/src/checkin.c
diff -u ccvs/src/checkin.c:1.56 ccvs/src/checkin.c:1.57
--- ccvs/src/checkin.c:1.56     Thu Nov 10 15:13:14 2005
+++ ccvs/src/checkin.c  Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -20,15 +20,25 @@
  * Returns non-zero on error.
  */
 
-#include "cvs.h"
-#include "fileattr.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS */
+#include "base.h"
 #include "edit.h"
+#include "fileattr.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
 
 int
 Checkin (int type, struct file_info *finfo, char *rev, char *tag,
         char *options, char *message)
 {
-    Vers_TS *vers;
+    Vers_TS *vers, *pvers;
     int set_time;
     char *tocvsPath = NULL;
 
@@ -51,6 +61,7 @@
      */
     assert (finfo->rcs != NULL);
 
+    pvers = Version_TS (finfo, NULL, tag, NULL, 1, 0);
     switch (RCS_checkin (finfo->rcs, finfo->update_dir, finfo->file, message,
                         rev, 0, RCS_FLAGS_KEEPFILE))
     {
@@ -80,24 +91,42 @@
 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
                 && options
                 && (!strcmp (options, "-ko") || !strcmp (options, "-kb")))
-               || !RCS_cmp_file (finfo->rcs, rev, NULL, NULL,
+               || !RCS_cmp_file (finfo->rcs, pvers->tag, rev, NULL, NULL,
                                  options, finfo->file))
-           {
                /* The existing file is correct.  We don't have to do
                    anything.  */
                set_time = 0;
-           }
            else
+               set_time = 1;
+
+           vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
+
+           if (set_time)
            {
                /* The existing file is incorrect.  We need to check
                    out the correct file contents.  */
-               if (RCS_checkout (finfo->rcs, finfo->file, rev, NULL,
-                                 options, RUN_TTY, NULL, NULL) != 0)
+               if (base_checkout (finfo->rcs, finfo, pvers->vn_user,
+                                  vers->vn_rcs, pvers->entdata->tag,
+                                  vers->tag, pvers->entdata->options,
+                                  options))
                    error (1, 0, "failed when checking out new copy of %s",
                           finfo->fullname);
-               xchmod (finfo->file, 1);
+               base_copy (finfo, vers->vn_rcs,
+                          cvswrite && !fileattr_get (finfo->file, "_watched")
+                          ? "yy" : "yn");
                set_time = 1;
            }
+           else if (!suppress_bases)
+           {
+               /* Still need to update the base file.  */
+               char *basefile;
+               mkdir_if_needed (CVSADM_BASE);
+               basefile = make_base_file_name (finfo->file, vers->vn_rcs);
+               copy_file (finfo->file, basefile);
+               free (basefile);
+           }
+           /* Remove the previous base file, in local mode.  */
+           base_remove (finfo->file, pvers->vn_user);
 
            wrap_fromcvs_process_file (finfo->file);
 
@@ -109,7 +138,6 @@
                xchmod (finfo->file, 0);
 
            /* Re-register with the new data.  */
-           vers = Version_TS (finfo, NULL, tag, NULL, 1, set_time);
            if (strcmp (vers->options, "-V4") == 0)
                vers->options[0] = '\0';
            Register (finfo->entries, finfo->file, vers->vn_rcs, vers->ts_user,
Index: ccvs/src/checkout.c
diff -u ccvs/src/checkout.c:1.145 ccvs/src/checkout.c:1.146
--- ccvs/src/checkout.c:1.145   Wed Nov 23 01:29:08 2005
+++ ccvs/src/checkout.c Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -38,8 +38,20 @@
  * edited by the user, if necessary (when the repository is moved, e.g.)
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+#include "repos.h"
+#include "wrapper.h"
+
 #include "cvs.h"
 
+
+
 static char *findslash (char *start, char *p);
 static int checkout_proc (int argc, char **argv, char *where,
                          char *mwhere, char *mfile, int shorten,
Index: ccvs/src/classify.c
diff -u ccvs/src/classify.c:1.37 ccvs/src/classify.c:1.38
--- ccvs/src/classify.c:1.37    Fri Sep 23 03:41:56 2005
+++ ccvs/src/classify.c Mon Apr 24 18:50:25 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -12,6 +12,16 @@
  * 
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "classify.h"
+
+/* CVS Headers.  */
+#include "no_diff.h"
+
 #include "cvs.h"
 
 static void sticky_ck (struct file_info *finfo, int aflag,
@@ -43,6 +53,10 @@
     Vers_TS *vers;
     Ctype ret;
 
+    TRACE (TRACE_FUNCTION, "classify_file (%s, %s, %s, %s)",
+          finfo->fullname, tag ? tag : "(null)", date ? date : "(null)",
+          options ? options : "(null)");
+
     /* get all kinds of good data about the file */
     vers = Version_TS (finfo, options, tag, date,
                       force_tag_match, 0);
Index: ccvs/src/client.c
diff -u ccvs/src/client.c:1.445 ccvs/src/client.c:1.446
--- ccvs/src/client.c:1.445     Wed Apr 12 19:52:46 2006
+++ ccvs/src/client.c   Mon Apr 24 18:50:26 2006
@@ -1,37 +1,56 @@
-/* CVS client-related stuff.
+/* 
+ * Copyright (C) 2006 The 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 2, 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.
+ */
 
-   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 2, 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.  */
+/*
+ * CVS client-related stuff.
+ */
 
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include "cvs.h"
+/* Verify interface.  */
+#include "client.h"
 
 /* C99 Headers.  */
 #include <inttypes.h>
 
-/* GNULIB Headers.  */
+/* GNULIB headers.  */
 #include "getline.h"
-#include "save-cwd.h"
 
-/* CVS Headers.  */
+/* CVS headers.  */
+#include "base.h"
 #include "buffer.h"
 #include "command_line_opt.h"
+#include "diff.h"
+#include "difflib.h"
 #include "edit.h"
+#include "gpg.h"
+#include "ignore.h"
+#include "recurse.h"
+#include "repos.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
 
 #ifdef CLIENT_SUPPORT
 
 # include "log-buffer.h"
 # include "md5.h"
+# include "sign.h"
 
 #include "socket-client.h"
 #include "rsh-client.h"
@@ -46,6 +65,23 @@
 
 
 
+/* Whether the last Base-merge command from the server resulted in a conflict
+ * or not.
+ */
+static bool last_merge;
+static bool last_merge_conflict;
+static bool last_merge_no_change;
+static bool last_merge_made_base;
+static char *base_merge_rev1;
+static char *base_merge_rev2;
+static char *temp_checkout1;
+static char *temp_checkout2;
+
+/* Similarly, to ignore bad entries on error.  */
+static bool base_copy_error;
+
+
+
 /* Keep track of any paths we are sending for Max-dotdot so that we can verify
  * that uplevel paths coming back form the server are valid.
  *
@@ -782,7 +818,11 @@
        ++filename;
 
     short_pathname = xmalloc (strlen (pathname) + strlen (filename) + 5);
-    strcpy (short_pathname, pathname);
+    /* Leave off the path when it is the CWD.  */
+    if (strcmp (pathname, "./"))
+       strcpy (short_pathname, pathname);
+    else
+       short_pathname[0] = '\0';
     strcat (short_pathname, filename);
 
     /* Now that we know the path to the file we were requested to operate on,
@@ -1320,6 +1360,8 @@
 char **failed_patches;
 int failed_patches_count;
 
+
+
 struct update_entries_data
 {
     enum {
@@ -1328,6 +1370,10 @@
        * correct.
        */
       UPDATE_ENTRIES_CHECKIN,
+
+      /* The file content may be in a temp file, waiting to be renamed.  */
+      UPDATE_ENTRIES_BASE,
+
       /* We are getting the file contents as well.  */
       UPDATE_ENTRIES_UPDATE,
       /*
@@ -1342,14 +1388,7 @@
       UPDATE_ENTRIES_RCS_DIFF
     } contents;
 
-    enum {
-       /* We are replacing an existing file.  */
-       UPDATE_ENTRIES_EXISTING,
-       /* We are creating a new file.  */
-       UPDATE_ENTRIES_NEW,
-       /* We don't know whether it is existing or new.  */
-       UPDATE_ENTRIES_EXISTING_OR_NEW
-    } existp;
+    enum update_existing existp;
 
     /*
      * String to put in the timestamp field or NULL to use the timestamp
@@ -1360,6 +1399,113 @@
 
 
 
+static void
+discard_file (void)
+{
+    char *mode_string;
+    char *size_string;
+    size_t size, nread;
+
+    read_line (&mode_string);
+    free (mode_string);
+
+    read_line (&size_string);
+    if (size_string[0] == 'z')
+       size = atoi (size_string + 1);
+    else
+       size = atoi (size_string);
+    free (size_string);
+
+    /* Now read and discard the file contents.  */
+    nread = 0;
+    while (nread < size)
+    {
+       char buf[8192];
+       size_t toread;
+
+       toread = size - nread;
+       if (toread > sizeof buf)
+           toread = sizeof buf;
+
+       nread += try_read_from_server (buf, toread);
+       if (nread == size)
+           break;
+    }
+
+    return;
+}
+
+
+
+static char *
+newfilename (const char *filename)
+{
+#ifdef USE_VMS_FILENAMES
+    /* A VMS rename of "blah.dat" to "foo" to implies a
+     * destination of "foo.dat" which is unfortinate for CVS.
+     */
+    return Xasprintf ("%s_new_", filename);
+#else
+#ifdef _POSIX_NO_TRUNC
+    return Xasprintf (".new.%.9s", filename);
+#else /* _POSIX_NO_TRUNC */
+    return Xasprintf (".new.%s", filename);
+#endif /* _POSIX_NO_TRUNC */
+#endif /* USE_VMS_FILENAMES */
+}
+
+
+
+static char *
+read_file_from_server (const char *fullname, char **mode_string, size_t *size)
+{
+    char *size_string;
+    bool use_gzip;
+    char *buf;
+    char *s;
+
+    read_line (mode_string);
+    
+    read_line (&size_string);
+    if (size_string[0] == 'z')
+    {
+       use_gzip = true;
+       s = size_string + 1;
+    }
+    else
+    {
+       use_gzip = false;
+       s = size_string;
+    }
+    *size = strto_file_size (s);
+    free (size_string);
+
+    buf = xmalloc (*size);
+    read_from_server (buf, *size);
+
+    if (use_gzip)
+    {
+       char *outbuf;
+
+       if (gunzip_in_mem (fullname, (unsigned char *) buf, size, &outbuf))
+           error (1, 0, "aborting due to compression error");
+
+       free (buf);
+       buf = outbuf;
+    }
+
+    return buf;
+}
+
+
+
+/* Cache for OpenPGP signatures so they may be written to a file only on a
+ * successful commit.
+ */
+static List *sig_cache;
+
+
+
 /* Update the Entries line for this file.  */
 static void
 update_entries (void *data_arg, List *ent_list, const char *short_pathname,
@@ -1378,7 +1524,8 @@
     char *date = NULL;
     char *tag_or_date;
     char *scratch_entries = NULL;
-    int bin;
+    bool bin;
+    char *temp_filename;
 
 #ifdef UTIME_EXPECTS_WRITABLE
     int change_it_back = 0;
@@ -1423,114 +1570,32 @@
 
     /* Done parsing the entries line. */
 
+    temp_filename = newfilename (filename);
+
     if (data->contents == UPDATE_ENTRIES_UPDATE
        || data->contents == UPDATE_ENTRIES_PATCH
        || data->contents == UPDATE_ENTRIES_RCS_DIFF)
     {
-       char *size_string;
        char *mode_string;
        size_t size;
        char *buf;
-       char *temp_filename;
-       int use_gzip;
-       int patch_failed;
-       char *s;
-
-       read_line (&mode_string);
-       
-       read_line (&size_string);
-       if (size_string[0] == 'z')
-       {
-           use_gzip = 1;
-           s = size_string + 1;
-       }
-       else
-       {
-           use_gzip = 0;
-           s = size_string;
-       }
-
-       size = strto_file_size (s);
-       free (size_string);
+       bool patch_failed;
 
-       /* Note that checking this separately from writing the file is
-          a race condition: if the existence or lack thereof of the
-          file changes between now and the actual calls which
-          operate on it, we lose.  However (a) there are so many
-          cases, I'm reluctant to try to fix them all, (b) in some
-          cases the system might not even have a system call which
-          does the right thing, and (c) it isn't clear this needs to
-          work.  */
-       if (data->existp == UPDATE_ENTRIES_EXISTING
-           && !isfile (filename))
-           /* Emit a warning and update the file anyway.  */
-           error (0, 0, "warning: %s unexpectedly disappeared",
-                  short_pathname);
+       if (get_verify_checkouts (true) && strcmp (cvs_cmd_name, "export"))
+           error (get_verify_checkouts_fatal (), 0,
+                  "No signature for `%s'.", short_pathname);
 
-       if (data->existp == UPDATE_ENTRIES_NEW
-           && isfile (filename))
+       if (!validate_change (data->existp, filename, short_pathname))
        {
-           /* Emit a warning and refuse to update the file; we don't want
-              to clobber a user's file.  */
-           size_t nread;
-           size_t toread;
-
-           /* size should be unsigned, but until we get around to fixing
-              that, work around it.  */
-           size_t usize;
-
-           char buf[8192];
-
-           /* This error might be confusing; it isn't really clear to
-              the user what to do about it.  Keep in mind that it has
-              several causes: (1) something/someone creates the file
-              during the time that CVS is running, (2) the repository
-              has two files whose names clash for the client because
-              of case-insensitivity or similar causes, See 3 for
-              additional notes.  (3) a special case of this is that a
-              file gets renamed for example from a.c to A.C.  A
-              "cvs update" on a case-insensitive client will get this
-              error.  In this case and in case 2, the filename
-              (short_pathname) printed in the error message will likely _not_
-              have the same case as seen by the user in a directory listing.
-              (4) the client has a file which the server doesn't know
-              about (e.g. "? foo" file), and that name clashes with a file
-              the server does know about, (5) classify.c will print the same
-              message for other reasons.
-
-              I hope the above paragraph makes it clear that making this
-              clearer is not a one-line fix.  */
-           error (0, 0, "move away `%s'; it is in the way", short_pathname);
+           /* The Mode, Mod-time, and Checksum responses should not carry
+            * over to a subsequent Created (or whatever) response, even
+            * in the error case.
+            */
            if (updated_fname)
            {
-               cvs_output ("C ", 0);
-               cvs_output (updated_fname, 0);
-               cvs_output ("\n", 1);
-           }
-           failure_exit = true;
-
-       discard_file_and_return:
-           /* Now read and discard the file contents.  */
-           usize = size;
-           nread = 0;
-           while (nread < usize)
-           {
-               toread = usize - nread;
-               if (toread > sizeof buf)
-                   toread = sizeof buf;
-
-               nread += try_read_from_server (buf, toread);
-               if (nread == usize)
-                   break;
+               free (updated_fname);
+               updated_fname = NULL;
            }
-
-           free (mode_string);
-           free (scratch_entries);
-           free (entries_line);
-
-           /* The Mode, Mod-time, and Checksum responses should not carry
-              over to a subsequent Created (or whatever) response, even
-              in the error case.  */
            if (stored_mode)
            {
                free (stored_mode);
@@ -1539,28 +1604,16 @@
            stored_modtime_valid = 0;
            stored_checksum_valid = 0;
 
-           if (updated_fname)
-           {
-               free (updated_fname);
-               updated_fname = NULL;
-           }
+           failure_exit = true;
+
+       discard_file_and_return:
+           discard_file ();
+           free (scratch_entries);
+           free (entries_line);
            return;
        }
 
-       temp_filename = xmalloc (strlen (filename) + 80);
-#ifdef USE_VMS_FILENAMES
-        /* A VMS rename of "blah.dat" to "foo" to implies a
-           destination of "foo.dat" which is unfortinate for CVS */
-       sprintf (temp_filename, "%s_new_", filename);
-#else
-#ifdef _POSIX_NO_TRUNC
-       sprintf (temp_filename, ".new.%.9s", filename);
-#else /* _POSIX_NO_TRUNC */
-       sprintf (temp_filename, ".new.%s", filename);
-#endif /* _POSIX_NO_TRUNC */
-#endif /* USE_VMS_FILENAMES */
-
-       buf = xmalloc (size);
+       buf = read_file_from_server (short_pathname, &mode_string, &size);
 
         /* Some systems, like OS/2 and Windows NT, end lines with CRLF
            instead of just LF.  Format translation is done in the C
@@ -1568,24 +1621,12 @@
            convert -- if this file is marked "binary" with the RCS -kb
            flag, then we don't want to convert, else we do (because
            CVS assumes text files by default). */
-
        if (options)
            bin = !strcmp (options, "-kb");
        else
-           bin = 0;
-
-       if (data->contents == UPDATE_ENTRIES_RCS_DIFF)
-       {
-           /* This is an RCS change text.  We just hold the change
-              text in memory.  */
-
-           if (use_gzip)
-               error (1, 0,
-                      "server error: gzip invalid with RCS change text");
+           bin = false;
 
-           read_from_server (buf, size);
-       }
-       else
+       if (data->contents != UPDATE_ENTRIES_RCS_DIFF)
        {
            int fd;
 
@@ -1609,25 +1650,14 @@
                goto discard_file_and_return;
            }
 
-           if (size > 0)
-           {
-               read_from_server (buf, size);
-
-               if (use_gzip)
-               {
-                   if (gunzip_and_write (fd, short_pathname, 
-                                         (unsigned char *) buf, size))
-                       error (1, 0, "aborting due to compression error");
-               }
-               else if (write (fd, buf, size) != size)
-                   error (1, errno, "writing %s", short_pathname);
-           }
+           if (write (fd, buf, size) != size)
+               error (1, errno, "writing %s", short_pathname);
 
            if (close (fd) < 0)
                error (1, errno, "writing %s", short_pathname);
        }
 
-       patch_failed = 0;
+       patch_failed = false;
 
        if (data->contents == UPDATE_ENTRIES_UPDATE)
        {
@@ -1645,7 +1675,7 @@
            error (0, 0,
                   "unsupported patch format received for `%s'; will refetch",
                   short_pathname);
-           patch_failed = 1;
+           patch_failed = true;
        }
        else
        {
@@ -1671,12 +1701,12 @@
                The contents of the patch from the network are in BUF,
                and the length of the patch is in SIZE.  */
 
-           if (! rcs_change_text (short_pathname, filebuf, nread, buf, size,
+           if (!rcs_change_text (short_pathname, filebuf, nread, buf, size,
                                   &patchedbuf, &patchedlen))
            {
                error (0, 0, "patch failed for `%s'; will refetch",
                       short_pathname);
-               patch_failed = 1;
+               patch_failed = true;
            }
            else
            {
@@ -1694,13 +1724,13 @@
 "checksum failure after patch to `%s'; will refetch",
                               short_pathname);
 
-                       patch_failed = 1;
+                       patch_failed = true;
                    }
 
                    stored_checksum_valid = 0;
                }
 
-               if (! patch_failed)
+               if (!patch_failed)
                {
                    FILE *e;
 
@@ -1720,9 +1750,10 @@
            free (filebuf);
        }
 
+       free (buf);
        free (temp_filename);
 
-       if (stored_checksum_valid && ! patch_failed)
+       if (stored_checksum_valid && !patch_failed)
        {
            FILE *e;
            struct md5_ctx context;
@@ -1765,7 +1796,7 @@
                       "checksum failure after patch to `%s'; will refetch",
                       short_pathname);
 
-               patch_failed = 1;
+               patch_failed = true;
            }
        }
 
@@ -1781,7 +1812,6 @@
            stored_checksum_valid = 0;
 
            free (mode_string);
-           free (buf);
            free (scratch_entries);
            free (entries_line);
 
@@ -1808,199 +1838,1103 @@
                error (0, status, "cannot change mode of %s", short_pathname);
        }
 
-       free (mode_string);
-       free (buf);
-    }
+       free (mode_string);
+    }
+    else if (data->contents == UPDATE_ENTRIES_BASE)
+    {
+       Node *n;
+       if (!noexec && (n = findnode_fn (ent_list, filename)))
+       {
+           Entnode *e = n->data;
+           /* After a join, control can get here without having changed the
+            * version number.  In this case, do not remove the base file.
+            */
+           if (strcmp (vn, e->version))
+               base_remove (filename, e->version);
+       }
+
+       if (last_merge)
+       {
+           /* Won't need these now that the merge is complete.  */
+           if (strcmp (vn, base_merge_rev1))
+               base_remove (filename, base_merge_rev1);
+           free (base_merge_rev1);
+           if (strcmp (vn, base_merge_rev2))
+               base_remove (filename, base_merge_rev2);
+           free (base_merge_rev2);
+       }
+
+       if (base_copy_error)
+       {
+           /* The previous base_copy command returned an error, such as in the
+            * "move away `FILE'; it is in the way" case.  Do not allow the
+            * entry to be updated.
+            */
+           if (updated_fname)
+           {
+               /* validate_change() has already printed "C filename" via the
+                * call from client_base_copy().
+                */
+               free (updated_fname);
+               updated_fname = false;
+           }
+           base_copy_error = false;
+           return;
+       }
+       if (!noexec)
+           rename_file (temp_filename, filename);
+       if (updated_fname)
+       {
+           cvs_output ("U ", 0);
+           cvs_output (updated_fname, 0);
+           cvs_output ("\n", 1);
+           free (updated_fname);
+           updated_fname = NULL;
+       }
+    }
+    else if (data->contents == UPDATE_ENTRIES_CHECKIN
+            && !noexec
+            /* This isn't add or remove.  */
+            && strcmp (vn, "0") && *vn != '-')
+    {
+       /* On checkin, create the base file.  */
+       Node *n;
+       bool makebase = true;
+
+       if ((n = findnode_fn (ent_list, filename)))
+       {
+           /* This could be a readd of a locally removed file or, for
+            * instance, an update that changed keyword options without
+            * changing the revision number or the base file.
+            */
+           Entnode *e = n->data;
+           if (strcmp (vn, e->version))
+               /* The version number has changed.  */
+               base_remove (filename, e->version);
+           else
+               /* The version number has not changed.  */
+               makebase = false;
+       }
+
+       if (makebase)
+       {
+           /* A real checkin.  */
+           char *basefile = make_base_file_name (filename, vn);
+
+           mkdir_if_needed (CVSADM_BASE);
+           copy_file (filename, basefile);
+
+           if ((n = findnode_fn (sig_cache, short_pathname)))
+           {
+               char *sigfile = Xasprintf ("%s%s", basefile, ".sig");
+               write_file (sigfile, n->data, n->len);
+               delnode (n);
+               free (sigfile);
+           }
+           else if (get_sign_commits (supported_request ("Signature")))
+               error (0, 0,
+"Internal error: OpenPGP signature for `%s' not found in cache.",
+                      short_pathname);
+           free (basefile);
+       }
+    }
+    else if (data->contents != UPDATE_ENTRIES_CHECKIN)
+       /* This error is important.  It makes sure that all three cases which
+        * write files are caught by the openpgp2 set of tests when the user
+        * has requested that failed checkout verification is fatal and the
+        * server attempts to bypass signatures by sending old-style responses
+        * which do not support signatures.  (The `Checkin' response does not
+        * count since it does not accept any file data from the server and is
+        * used in both modes.)
+        */
+       error (1, 0, "internal error: unhandled update_entries cases.");
+
+    if (stored_mode)
+    {
+       change_mode (filename, stored_mode, 1);
+       free (stored_mode);
+       stored_mode = NULL;
+    }
+   
+    if (stored_modtime_valid)
+    {
+       struct utimbuf t;
+
+       memset (&t, 0, sizeof (t));
+       t.modtime = stored_modtime;
+       (void) time (&t.actime);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+       if (!iswritable (filename))
+       {
+           xchmod (filename, 1);
+           change_it_back = 1;
+       }
+#endif  /* UTIME_EXPECTS_WRITABLE  */
+
+       if (utime (filename, &t) < 0)
+           error (0, errno, "cannot set time on %s", filename);
+
+#ifdef UTIME_EXPECTS_WRITABLE
+       if (change_it_back)
+       {
+           xchmod (filename, 0);
+           change_it_back = 0;
+       }
+#endif  /*  UTIME_EXPECTS_WRITABLE  */
+
+       stored_modtime_valid = 0;
+    }
+
+    /*
+     * Process the entries line.  Do this after we've written the file,
+     * since we need the timestamp.
+     */
+    if (strcmp (cvs_cmd_name, "export"))
+    {
+       char *local_timestamp;
+       char *file_timestamp;
+       bool ignore_merge;
+
+       (void) time (&last_register_time);
+
+       local_timestamp = data->timestamp;
+       if (!local_timestamp || ts[0] == '+' || last_merge_conflict)
+           file_timestamp = time_stamp (filename);
+       else
+           file_timestamp = NULL;
+
+       /*
+        * These special version numbers signify that it is not up to
+        * date.  Create a dummy timestamp which will never compare
+        * equal to the timestamp of the file.
+        */
+       if (vn[0] == '\0' || !strcmp (vn, "0") || vn[0] == '-')
+           local_timestamp = "dummy timestamp";
+       else if (!local_timestamp)
+       {
+           local_timestamp = file_timestamp;
+
+           /* Checking for cvs_cmd_name of "commit" doesn't seem like
+              the cleanest way to handle this, but it seem to roughly
+              parallel what the :local: code which calls
+              mark_up_to_date ends up amounting to.  Some day, should
+              think more about what the Checked-in response means
+              vis-a-vis both Entries and Base and clarify
+              cvsclient.texi accordingly.  */
+
+           if (!strcmp (cvs_cmd_name, "commit"))
+           {
+               char *update_dir = dir_name (short_pathname);
+               mark_up_to_date (update_dir, filename);
+               free (update_dir);
+           }
+       }
+
+       if (last_merge)
+       {
+           if (last_merge_made_base)
+           {
+               Node *n;
+               Entnode *e;
+
+               n = findnode_fn (ent_list, filename);
+               assert (n);
+
+               e = n->data;
+               if (strcmp (vn, e->version))
+                   /* Merge.  */
+                   ignore_merge = false;
+               else
+                   /* Join. */
+                   ignore_merge = true;
+           }
+           else
+               ignore_merge = false;
+       }
+       else
+           ignore_merge = true;
+       
+       Register (ent_list, filename, vn,
+                 ignore_merge ? local_timestamp : "Result of merge",
+                 options, tag, date,
+                 ts[0] == '+' || last_merge_conflict ? file_timestamp : NULL);
+       if (last_merge_conflict)
+       {
+           assert (!ignore_merge);
+           if (!really_quiet)
+           {
+               cvs_output ("C ", 2);
+               cvs_output (short_pathname, 0);
+               cvs_output ("\n", 1);
+           }
+       }
+       else if (!ignore_merge)
+       {
+           if (!really_quiet)
+           {
+               cvs_output ("M ", 2);
+               cvs_output (short_pathname, 0);
+               cvs_output ("\n", 1);
+           }
+       }
+       last_merge = false;
+       last_merge_conflict = false;
+       last_merge_made_base = false;
+       last_merge_no_change = false;
+
+       if (file_timestamp)
+           free (file_timestamp);
+
+    }
+    free (scratch_entries);
+    free (entries_line);
+}
+
+
+
+static void
+handle_checked_in (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_CHECKIN;
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_new_entry (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_CHECKIN;
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = "dummy timestamp from new-entry";
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_updated (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_UPDATE;
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_created (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_UPDATE;
+    dat.existp = UPDATE_ENTRIES_NEW;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_update_existing (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_UPDATE;
+    dat.existp = UPDATE_ENTRIES_EXISTING;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_merged (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_UPDATE;
+    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = "Result of merge";
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_patched (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_PATCH;
+    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+static void
+handle_rcs_diff (char *args, size_t len)
+{
+    struct update_entries_data dat;
+    dat.contents = UPDATE_ENTRIES_RCS_DIFF;
+    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
+    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
+    dat.timestamp = NULL;
+    call_in_directory (args, update_entries, &dat);
+}
+
+
+
+/*
+ * The OpenPGP-signature response gives the signature for the file to be
+ * transmitted in the next Base-checkout or Temp-checkout response.
+ */
+static struct buffer *stored_signatures;
+static void
+handle_openpgp_signature (char *args, size_t len)
+{
+    int status;
+
+    if (!stored_signatures)
+       stored_signatures = buf_nonio_initialize (NULL);
+
+    status = next_signature (global_from_server, stored_signatures);
+    if (status == -2)
+       xalloc_die ();
+    else if (status)
+       error (1, 0, "Malformed signature received from server.");
+}
+
+
+
+/* Write the signatures in the global STORED_SIGNATURES to SIGFILE.  Use
+ * WRITABLE to set permissions.  If SIGCOPY is not NULL, assume that SIGLEN
+ * isn't either and save a copy of the signature in newly allocated memory
+ * stored at *SIGCOPY and set *SIGLEN to its length.
+ */
+static void
+client_write_sigfile (const char *sigfile, bool writable, char **sigcopy,
+                     size_t *siglen)
+{
+    FILE *e;
+    size_t want;
+
+    assert (!sigcopy || siglen);
+
+    if (!stored_signatures)
+       return;
+
+    if (!writable && isfile (sigfile))
+       xchmod (sigfile, true);
+    e = xfopen (sigfile, FOPEN_BINARY_WRITE);
+
+    want = buf_length (stored_signatures);
+    if (sigcopy)
+    {
+       *sigcopy = NULL;
+       *siglen = 0;
+    }
+    while (want > 0)
+    {
+       char *data;
+       size_t got;
+
+       buf_read_data (stored_signatures, want, &data, &got);
+
+       if (fwrite (data, sizeof *data, got, e) != got)
+           error (1, errno, "cannot write signature file `%s'", sigfile);
+
+       if (sigcopy)
+       {
+           *sigcopy = xrealloc (*sigcopy, *siglen + got);
+           memcpy (*sigcopy + *siglen, data, got);
+           *siglen += got;
+       }
+
+       want -= got;
+    }
+       
+    if (fclose (e) == EOF)
+       error (0, errno, "cannot close signature file `%s'", sigfile);
+
+    if (!writable)
+       xchmod (sigfile, false);
+
+    buf_free (stored_signatures);
+    stored_signatures = NULL;
+}
+
+
+
+static void
+client_base_checkout (void *data_arg, List *ent_list,
+                     const char *short_pathname, const char *filename)
+{
+    /* Options for this file, a Previous REVision if this is a diff, and the
+     * REVision of the new file.
+     */
+    char *options, *prev, *rev;
+
+    /* The base file to be created.  */
+    char *basefile;
+    char *update_dir;
+    char *fullbase;
+
+    /* File buf from net.  May be an RCS diff from PREV to REV.  */
+    char *buf;
+    char *mode_string;
+    size_t size;
+
+    bool bin;
+    bool patch_failed;
+    bool *istemp = data_arg;
+
+    TRACE (TRACE_FUNCTION, "client_base_checkout (%s)", short_pathname);
+
+    /* Read OPTIONS, PREV, and REV from the server.  */
+    read_line (&options);
+    read_line (&prev);
+    read_line (&rev);
+
+    /* Use these values to get our base file name.  */
+    if (*istemp)
+    {
+       if (temp_checkout2)
+           error (1, 0,
+                  "Server sent more than two temp files without using them.");
+       basefile = cvs_temp_name ();
+       if (temp_checkout1)
+           temp_checkout2 = basefile;
+       else
+           temp_checkout1 = basefile;
+    }
+    else
+       basefile = make_base_file_name (filename, rev);
+
+    /* FIXME?  It might be nice to verify that base files aren't being
+     * overwritten except when the keyword mode has changed.
+     */
+    if (!*istemp && isfile (basefile))
+       force_xchmod (basefile, true);
+
+    update_dir = dir_name (short_pathname);
+    if (*istemp || !*update_dir) fullbase = xstrdup (basefile);
+    else fullbase = Xasprintf ("%s/%s", update_dir, basefile);
+
+    /* Read the file or patch from the server.  */
+    /* FIXME: Read/write to file is repeated and could be optimized to
+     * write directly to disk without using so much mem.
+     */
+    buf = read_file_from_server (fullbase, &mode_string, &size);
+
+    if (options) bin = !strcmp (options, "-kb");
+    else bin = false;
+
+    if (*prev && strcmp (prev, rev))
+    {
+       char *filebuf;
+       size_t filebufsize;
+       size_t nread;
+       char *patchedbuf;
+       size_t patchedlen;
+       char *pbasefile;
+       char *pfullbase;
+
+       /* Handle UPDATE_ENTRIES_RCS_DIFF.  */
+
+       pbasefile = make_base_file_name (filename, prev);
+       if (!*update_dir) pfullbase = xstrdup (pbasefile);
+       else pfullbase = Xasprintf ("%s/%s", update_dir, pbasefile);
+
+       if (!isfile (pbasefile))
+           error (1, 0, "patch original file `%s' does not exist",
+                  pfullbase);
+
+       filebuf = NULL;
+       filebufsize = 0;
+       nread = 0;
+
+       get_file (pbasefile, pfullbase, bin ? FOPEN_BINARY_READ : "r",
+                 &filebuf, &filebufsize, &nread);
+       /* At this point the contents of the existing file are in
+        * FILEBUF, and the length of the contents is in NREAD.
+        * The contents of the patch from the network are in BUF,
+        * and the length of the patch is in SIZE.
+        */
+
+       patch_failed = !rcs_change_text (fullbase, filebuf, nread, buf,
+                                        size, &patchedbuf, &patchedlen);
+
+       if (!patch_failed)
+       {
+           free (buf);
+           buf = patchedbuf;
+           size = patchedlen;
+       }
+       else
+           free (patchedbuf);
+
+       free (filebuf);
+       free (pbasefile);
+       free (pfullbase);
+    }
+    else
+       patch_failed = false;
+
+    if (!patch_failed)
+    {
+       FILE *e;
+       int status;
+       bool verify = get_verify_checkouts (true);
+
+       if (!*istemp)
+           mkdir_if_needed (CVSADM_BASE);
+       e = xfopen (basefile, bin ? FOPEN_BINARY_WRITE : "w");
+       if (fwrite (buf, sizeof *buf, size, e) != size)
+           error (1, errno, "cannot write `%s'", fullbase);
+       if (fclose (e) == EOF)
+           error (0, errno, "cannot close `%s'", fullbase);
+
+       status = change_mode (basefile, mode_string, 1);
+       if (status != 0)
+           error (0, status, "cannot change mode of `%s'", fullbase);
+
+       if (stored_signatures)
+       {
+           char *sigfile = Xasprintf ("%s.sig", basefile);
+           char *sigcopy;
+           size_t siglen;
+
+           /* A lot of trouble is gone through here to copy the signatures
+            * into a buffer in addition to writing them to disk.  Writing to
+            * disk requires a call to fsync () before the call to
+            * verify_signature otherwise, and fsync () is quite slow.
+            */
+           client_write_sigfile (sigfile, *istemp,
+                                 verify ? &sigcopy : NULL, &siglen);
+
+           /* Verify the signature here, when configured to do so.  */
+           if (verify /* cannot be `cvs export'. */)
+           {
+               char *repos = Name_Repository (NULL, update_dir);
+               const char *srepos = Short_Repository (repos);
+               if (!verify_signature (srepos, sigcopy, siglen, basefile, bin,
+                                      get_verify_checkouts_fatal ()))
+               {
+                   /* verify_signature exits when VERIFY_FATAL.  */
+                   assert (!get_verify_checkouts_fatal ());
+                   error (0, 0, "Bad signature for `%s'.", fullbase);
+               }
+               free (repos);
+               free (sigcopy);
+           }
+
+           if (istemp && CVS_UNLINK (sigfile) < 0)
+               error (0, errno, "Failed to remove temp sig file `%s'",
+                      sigfile);
+
+           free (sigfile);
+       }
+       else if (verify /* cannot be `cvs export'. */)
+           error (get_verify_checkouts_fatal (), 0,
+                  "No signature for `%s'.", fullbase);
+    }
+
+    free (buf);
+    free (rev);
+    free (prev);
+    if (!*istemp)
+       free (basefile);
+    free (update_dir);
+    free (fullbase);
+}
+
+
+
+static void
+handle_base_checkout (char *args, size_t len)
+{
+    bool istemp = false;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_checkout, &istemp);
+}
+
+
+
+static void
+handle_temp_checkout (char *args, size_t len)
+{
+    bool istemp = true;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_checkout, &istemp);
+}
+
+
+
+static void
+client_base_signatures (void *data_arg, List *ent_list,
+                       const char *short_pathname, const char *filename)
+{
+    char *rev;
+    char *basefile;
+    char *sigfile;
+    bool *clear = data_arg;
+
+    TRACE (TRACE_FUNCTION, "client_base_signatures (%s)", short_pathname);
+
+    if (!stored_signatures && !*clear)
+       error (1, 0,
+              "Server sent `Base-signatures' response without signature.");
+
+    if (stored_signatures && *clear)
+       error (1, 0, "Server sent unused signature data.");
+
+    /* Read REV from the server.  */
+    read_line (&rev);
+
+    basefile = make_base_file_name (filename, rev);
+    sigfile = Xasprintf ("%s.sig", basefile);
+
+    if (*clear)
+    {
+       if (unlink_file (sigfile) < 0 && !existence_error (errno))
+           error (0, 0, "Failed to delete signature file `%s'",
+                  sigfile);
+    }
+    else
+       client_write_sigfile (sigfile, false, NULL, NULL);
+
+    free (rev);
+    free (basefile);
+    free (sigfile);
+}
+
+
+
+static void
+handle_base_signatures (char *args, size_t len)
+{
+    bool clear = false;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_signatures, &clear);
+}
+
+
+
+static void
+handle_base_clear_signatures (char *args, size_t len)
+{
+    bool clear = true;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_signatures, &clear);
+}
+
+
+
+/* Create am up-to-date temporary workfile from a base file.
+ *
+ * NOTES
+ *   Base-copy needs to be able to copy temp files in the case of a join which
+ *   adds a file.  Though keeping a base file in this case could potentially
+ *   be interesting, this is not what certain portions of the code currently
+ *   expect.
+ */
+static void
+client_base_copy (void *data_arg, List *ent_list, const char *short_pathname,
+                 const char *filename)
+{
+    char *rev, *flags;
+    char *basefile;
+    char *temp_filename;
+
+    TRACE (TRACE_FUNCTION, "client_base_copy (%s)", short_pathname);
+
+    read_line (&rev);
+
+    read_line (&flags);
+    if (!validate_change (translate_exists (flags), filename, short_pathname))
+    {
+       /* The Mode, Mod-time, and Checksum responses should not carry
+        * over to a subsequent Created (or whatever) response, even
+        * in the error case.
+        */
+       if (updated_fname)
+       {
+           free (updated_fname);
+           updated_fname = NULL;
+       }
+       if (stored_mode)
+       {
+           free (stored_mode);
+           stored_mode = NULL;
+       }
+       stored_modtime_valid = 0;
+       stored_checksum_valid = 0;
+
+       failure_exit = true;
+       base_copy_error = true;
+       free (rev);
+       free (flags);
+       return;
+    }
+
+    if (temp_checkout1)
+    {
+       if (temp_checkout2)
+           error (1, 0, "Server sent two temp files before a Base-copy.");
+       basefile = temp_checkout1;
+    }
+    else
+       basefile = make_base_file_name (filename, rev);
+
+    temp_filename = newfilename (filename);
+    copy_file (basefile, temp_filename);
+
+    if (flags[0] && flags[1] == 'n')
+       xchmod (temp_filename, false);
+    else
+       xchmod (temp_filename, true);
+
+    /* I think it is ok to assume that if the server is sending base_copy,
+     * then it sent the commands necessary to create the required base file.
+     * If not, then it may be necessary to provide a way to request the base
+     * file be sent.
+     */
 
-    if (stored_mode)
+    if (temp_checkout1)
     {
-       change_mode (filename, stored_mode, 1);
-       free (stored_mode);
-       stored_mode = NULL;
+       temp_checkout1 = NULL;
+       if (CVS_UNLINK (basefile) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", basefile);
     }
-   
-    if (stored_modtime_valid)
-    {
-       struct utimbuf t;
 
-       memset (&t, 0, sizeof (t));
-       t.modtime = stored_modtime;
-       (void) time (&t.actime);
+    free (flags);
+    free (temp_filename);
+    free (basefile);
+    free (rev);
+}
 
-#ifdef UTIME_EXPECTS_WRITABLE
-       if (!iswritable (filename))
-       {
-           xchmod (filename, 1);
-           change_it_back = 1;
-       }
-#endif  /* UTIME_EXPECTS_WRITABLE  */
 
-       if (utime (filename, &t) < 0)
-           error (0, errno, "cannot set time on %s", filename);
 
-#ifdef UTIME_EXPECTS_WRITABLE
-       if (change_it_back)
-       {
-           xchmod (filename, 0);
-           change_it_back = 0;
-       }
-#endif  /*  UTIME_EXPECTS_WRITABLE  */
+static void
+handle_base_copy (char *args, size_t len)
+{
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_copy, NULL);
+}
 
-       stored_modtime_valid = 0;
+
+
+static void
+client_base_merge (void *data_arg, List *ent_list, const char *short_pathname,
+                  const char *filename)
+{
+    char *f1, *f2;
+    char *temp_filename;
+    int status;
+
+    TRACE (TRACE_FUNCTION, "client_base_merge (%s)", short_pathname);
+
+    read_line (&base_merge_rev1);
+    read_line (&base_merge_rev2);
+
+    if (!really_quiet)
+    {
+       cvs_output ("Merging differences between ", 0);
+       cvs_output (base_merge_rev1, 0);
+       cvs_output (" and ", 5);
+       cvs_output (base_merge_rev2, 0);
+       cvs_output (" into `", 7);
+       cvs_output (short_pathname, 0);
+       cvs_output ("'\n", 2);
     }
 
-    /*
-     * Process the entries line.  Do this after we've written the file,
-     * since we need the timestamp.
-     */
-    if (strcmp (cvs_cmd_name, "export"))
+    if (temp_checkout1)
     {
-       char *local_timestamp;
-       char *file_timestamp;
+       f1 = temp_checkout1;
+       if (temp_checkout2)
+           f2 = temp_checkout2;
+       else
+       {
+           f2 = make_base_file_name (filename, base_merge_rev2);
+           if (!isfile (f2))
+               error (1, 0, "Server sent only one temp file before a merge.");
+       }
+    }
+    else
+    {
+       f1 = make_base_file_name (filename, base_merge_rev1);
+       f2 = make_base_file_name (filename, base_merge_rev2);
+    }
 
-       (void) time (&last_register_time);
+    temp_filename = newfilename (filename);
 
-       local_timestamp = data->timestamp;
-       if (!local_timestamp || ts[0] == '+')
-           file_timestamp = time_stamp (filename);
-       else
-           file_timestamp = NULL;
+    force_copy_file (filename, temp_filename);
+    force_xchmod (temp_filename, true);
 
-       /*
-        * These special version numbers signify that it is not up to
-        * date.  Create a dummy timestamp which will never compare
-        * equal to the timestamp of the file.
+    status = merge (temp_filename, filename, f1, base_merge_rev1, f2,
+                   base_merge_rev2);
+
+    if (status != 0 && status != 1)
+       error (status == -1, status == -1 ? errno : 0,
+              "could not merge differences between %s & %s of `%s'",
+              base_merge_rev1, base_merge_rev2, short_pathname);
+
+    if (last_merge && !noexec)
+       error (1, 0,
+"protocol error: received two `Base-merge' responses without a `Base-entry'");
+    last_merge = true;
+
+    if (status == 1)
+    {
+       /* The server won't send a response telling the client to update the
+        * entry in noexec mode.  Normally the client delays printing the
+        * "C filename" line until then.
         */
-       if (vn[0] == '\0' || !strcmp (vn, "0") || vn[0] == '-')
-           local_timestamp = "dummy timestamp";
-       else if (!local_timestamp)
+       last_merge_conflict = true;
+       if (noexec && !really_quiet)
        {
-           local_timestamp = file_timestamp;
-
-           /* Checking for cvs_cmd_name of "commit" doesn't seem like
-              the cleanest way to handle this, but it seem to roughly
-              parallel what the :local: code which calls
-              mark_up_to_date ends up amounting to.  Some day, should
-              think more about what the Checked-in response means
-              vis-a-vis both Entries and Base and clarify
-              cvsclient.texi accordingly.  */
+           cvs_output ("C ", 2);
+           cvs_output (short_pathname, 0);
+           cvs_output ("\n", 1);
+       }
+    }
+    else
+    {
+       Node *n;
 
-           if (!strcmp (cvs_cmd_name, "commit"))
+       if (!xcmp (temp_filename, filename))
+       {
+           if (!quiet)
            {
-               char *update_dir = dir_name (short_pathname);
-               mark_up_to_date (update_dir, filename);
-               free (update_dir);
+               cvs_output ("`", 1);
+               cvs_output (short_pathname, 0);
+               cvs_output ("' already contains the differences between ", 0);
+               cvs_output (base_merge_rev1, 0);
+               cvs_output (" and ", 5);
+               cvs_output (base_merge_rev2, 0);
+               cvs_output ("\n", 1);
            }
+           last_merge_no_change = true;
        }
 
-       Register (ent_list, filename, vn, local_timestamp,
-                 options, tag, date, ts[0] == '+' ? file_timestamp : NULL);
+       /* This next is a separate case because a join could restore the file
+        * to its state at checkout time.
+        */
+       if ((n = findnode_fn (ent_list, filename)))
+       {
+           Entnode *e = n->data;
+           char *basefile = make_base_file_name (filename, e->version);
+           if (isfile (basefile) && !xcmp (basefile, temp_filename))
+               /* The user's file is identical to the base file.
+                * Pretend this merge never happened.
+                */
+               last_merge_made_base = true;
+           free (basefile);
+       }
+    }
 
-       if (file_timestamp)
-           free (file_timestamp);
+    /* In the noexec case, just remove our results.  */
+    if (noexec && CVS_UNLINK (temp_filename) < 0)
+       error (0, errno, "Failed to remove `%s'", temp_filename);
+
+    /* Let update_entries remove our "temporary" base files, since it should
+     * know which one should be kept.
+     */
 
+    if (temp_checkout1)
+    {
+       temp_checkout1 = NULL;
+       if (CVS_UNLINK (f1) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", f1);
     }
-    free (scratch_entries);
-    free (entries_line);
+    if (temp_checkout2)
+    {
+       temp_checkout2 = NULL;
+       if (CVS_UNLINK (f2) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", f2);
+    }
+    free (f1);
+    free (f2);
 }
 
 
 
 static void
-handle_checked_in (char *args, size_t len)
+handle_base_merge (char *args, size_t len)
 {
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_CHECKIN;
-    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = NULL;
-    call_in_directory (args, update_entries, &dat);
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_merge, NULL);
 }
 
 
 
 static void
-handle_new_entry (char *args, size_t len)
+handle_base_entry (char *args, size_t len)
 {
     struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_CHECKIN;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    dat.contents = UPDATE_ENTRIES_BASE;
     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = "dummy timestamp from new-entry";
+    dat.timestamp = NULL;
     call_in_directory (args, update_entries, &dat);
 }
 
 
 
 static void
-handle_updated (char *args, size_t len)
+handle_base_merged (char *args, size_t len)
 {
     struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_UPDATE;
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    dat.contents = UPDATE_ENTRIES_BASE;
     dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = NULL;
+    dat.timestamp = "Result of merge";
     call_in_directory (args, update_entries, &dat);
 }
 
 
 
 static void
-handle_created (char *args, size_t len)
+client_base_diff (void *data_arg, List *ent_list, const char *short_pathname,
+                 const char *filename)
 {
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_UPDATE;
-    dat.existp = UPDATE_ENTRIES_NEW;
-    dat.timestamp = NULL;
-    call_in_directory (args, update_entries, &dat);
-}
+    struct diff_info *di = data_arg;
+    struct file_info finfo;
+    char *ft1, *ft2, *rev1, *rev2, *label1, *label2;
+    const char *f1 = NULL, *f2 = NULL;
+    bool used_t1 = false, used_t2 = false;
 
+    read_line (&ft1);
 
+    read_line (&rev1);
+    if (!*rev1)
+    {
+       free (rev1);
+       rev1 = NULL;
+    }
 
-static void
-handle_update_existing (char *args, size_t len)
-{
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_UPDATE;
-    dat.existp = UPDATE_ENTRIES_EXISTING;
-    dat.timestamp = NULL;
-    call_in_directory (args, update_entries, &dat);
-}
+    read_line (&label1);
+    if (!*label1)
+    {
+       free (label1);
+       label1 = NULL;
+    }
 
+    read_line (&ft2);
 
+    read_line (&rev2);
+    if (!*rev2)
+    {
+       free (rev2);
+       rev2 = NULL;
+    }
 
-static void
-handle_merged (char *args, size_t len)
-{
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_UPDATE;
-    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
-    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = "Result of merge";
-    call_in_directory (args, update_entries, &dat);
-}
+    read_line (&label2);
+    if (!*label2)
+    {
+       free (label2);
+       label2 = NULL;
+    }
 
+    if (!strcmp (ft1, "TEMP"))
+    {
+       if (!temp_checkout1)
+           error (1, 0,
+                  "Server failed to send enough files before Base-diff.");
+       f1 = temp_checkout1;
 
+       used_t1 = true;
+    }
+    else if (!strcmp (ft1, "DEVNULL"))
+       f1 = DEVNULL;
+    else
+       error (1, 0, "Server sent unrecognized diff file type (`%s')", ft1);
 
-static void
-handle_patched (char *args, size_t len)
-{
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_PATCH;
-    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
-    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = NULL;
-    call_in_directory (args, update_entries, &dat);
+    if (!strcmp (ft2, "TEMP"))
+    {
+       if ((used_t1 && !temp_checkout2) || (!used_t1 && !temp_checkout1))
+           error (1, 0,
+                  "Server failed to send enough files before Base-diff.");
+
+       if (used_t1)
+       {
+           f2 = temp_checkout2;
+           used_t2 = true;
+       }
+       else
+       {
+           f2 = temp_checkout1;
+           used_t1 = true;
+       }
+    }
+    else if (!strcmp (ft2, "DEVNULL"))
+       f2 = DEVNULL;
+    else if (!strcmp (ft2, "WORKFILE"))
+       f2 = filename;
+    else
+       error (1, 0, "Server sent unrecognized diff file type (`%s')", ft2);
+
+    if ((!used_t1 && temp_checkout1)
+       || (!used_t2 && temp_checkout2))
+       error (1, 0, "Unused temp files sent from server before Base-diff.");
+
+    finfo.file = filename;
+    finfo.fullname = short_pathname;
+
+    diff_mark_errors (base_diff (&finfo, di->diff_argc, di->diff_argv,
+                                f1, rev1, label1, f2,
+                                rev2, label2, di->empty_files));
+
+    if (ft1) free (ft1);
+    if (ft2) free (ft2);
+    if (rev1) free (rev1);
+    if (rev2) free (rev2);
+    if (label1) free (label1);
+    if (label2) free (label2);
+    if (temp_checkout1)
+    {
+       char *tmp = temp_checkout1;
+       temp_checkout1 = NULL;
+       if (CVS_UNLINK (tmp) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", tmp);
+       free (tmp);
+    }
+    if (temp_checkout2)
+    {
+       char *tmp = temp_checkout2;
+       temp_checkout2 = NULL;
+       if (CVS_UNLINK (tmp) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", tmp);
+       free (tmp);
+    }
+
+    return;
 }
 
 
 
 static void
-handle_rcs_diff (char *args, size_t len)
+handle_base_diff (char *args, size_t len)
 {
-    struct update_entries_data dat;
-    dat.contents = UPDATE_ENTRIES_RCS_DIFF;
-    /* Think this could be UPDATE_ENTRIES_EXISTING, but just in case...  */
-    dat.existp = UPDATE_ENTRIES_EXISTING_OR_NEW;
-    dat.timestamp = NULL;
-    call_in_directory (args, update_entries, &dat);
+    if (suppress_bases)
+       error (1, 0, "Server sent Base-* response when asked not to.");
+    call_in_directory (args, client_base_diff, get_diff_info ());
 }
 
 
@@ -3088,6 +4022,30 @@
     RSP_LINE("E", handle_e, response_type_normal, rs_essential),
     RSP_LINE("F", handle_f, response_type_normal, rs_optional),
     RSP_LINE("MT", handle_mt, response_type_normal, rs_optional),
+
+    /* The server makes the assumption that if the client handles one of the
+     * Base-* responses, then it will handle all of them.
+     */
+    RSP_LINE("Base-checkout", handle_base_checkout, response_type_normal,
+            rs_optional),
+    RSP_LINE("Temp-checkout", handle_temp_checkout, response_type_normal,
+            rs_optional),
+    RSP_LINE("Base-copy", handle_base_copy, response_type_normal, rs_optional),
+    RSP_LINE("Base-merge", handle_base_merge, response_type_normal,
+            rs_optional),
+    RSP_LINE("Base-entry", handle_base_entry, response_type_normal,
+            rs_optional),
+    RSP_LINE("Base-merged", handle_base_merged, response_type_normal,
+            rs_optional),
+    RSP_LINE("Base-diff", handle_base_diff, response_type_normal, rs_optional),
+
+    RSP_LINE("Base-signatures", handle_base_signatures, response_type_normal,
+            rs_optional),
+    RSP_LINE("Base-clear-signatures", handle_base_clear_signatures,
+            response_type_normal, rs_optional),
+    RSP_LINE("OpenPGP-signature", handle_openpgp_signature,
+            response_type_normal, rs_optional),
+
     /* Possibly should be response_type_error.  */
     RSP_LINE(NULL, NULL, response_type_normal, rs_essential)
 
@@ -4020,6 +4978,12 @@
            {
                if (suppress_redirect && !strcmp (rs->name, "Redirect"))
                    continue;
+               if (suppress_bases && !strncmp (rs->name, "Base-", 5))
+                   continue;
+               if (suppress_bases && !strcmp (rs->name, "OpenPGP-signature"))
+                   continue;
+               if (suppress_bases && !strcmp (rs->name, "Temp-checkout"))
+                   continue;
 
                send_to_server (" ", 0);
                send_to_server (rs->name, 0);
@@ -4433,16 +5397,47 @@
 
 
 
+/* Generate and send an OpenPGP signature to the server.
+ */
+static void
+send_signature (const char *srepos, const char *filename, const char *fullname,
+               bool bin)
+{
+    char *sigbuf;
+    size_t len;
+    Node *n;
+
+    sigbuf = gen_signature (srepos, filename, bin, &len);
+
+    send_to_server ("Signature\012", 0);
+    send_to_server (sigbuf, len);
+
+    /* Cache the signature for use with the base file which will be
+     * automatically generated later since the server will not send a new base
+     * file and signature unless keywords cause the file to change after it is
+     * committed.
+     */
+    if (!sig_cache) sig_cache = getlist ();
+    n = getnode ();
+    n->key = xstrdup (fullname);
+    n->data = sigbuf;
+    n->len = len;
+    addnode (sig_cache, n);
+}
+
+
+
 /* The address of an instance of this structure is passed to
    send_fileproc, send_filesdoneproc, and send_direntproc, as the
    callerdat parameter.  */
 struct send_data
 {
     /* Each of the following flags are zero for clear or nonzero for set.  */
-    int build_dirs;
-    int force;
-    int no_contents;
-    int backup_modified;
+    bool build_dirs;
+    bool force;
+    bool no_contents;
+    bool backup_modified;
+    bool force_signatures;
 };
 
 /* Deal with one file.  */
@@ -4455,6 +5450,7 @@
     /* File name to actually use.  Might differ in case from
        finfo->file.  */
     const char *filename;
+    bool may_be_modified;
 
     send_a_repository ("", finfo->repository, finfo->update_dir);
 
@@ -4543,38 +5539,78 @@
        /* File no longer exists.  Don't do anything, missing files
           just happen.  */
     }
-    else if (!vers->ts_rcs || args->force
-            || strcmp (vers->ts_conflict
-                       ? vers->ts_conflict : vers->ts_rcs, vers->ts_user)
+    else if (!vers->ts_rcs || args->force)
+       may_be_modified = true;
+    else if (strcmp (vers->ts_conflict
+                    ? vers->ts_conflict : vers->ts_rcs, vers->ts_user)
             || (vers->ts_conflict && !strcmp (cvs_cmd_name, "diff")))
     {
-       if (args->no_contents
-           && supported_request ("Is-modified"))
-       {
-           send_to_server ("Is-modified ", 0);
-           send_to_server (filename, 0);
-           send_to_server ("\012", 1);
-       }
+       char *basefn = make_base_file_name (filename, vers->ts_user);
+       if (!isfile (basefn) || xcmp (filename, basefn))
+           may_be_modified = true;
        else
-           send_modified (filename, finfo->fullname, vers);
-
-        if (args->backup_modified)
-        {
-            char *bakname;
-            bakname = backup_file (filename, vers->vn_user);
-            /* This behavior is sufficiently unexpected to
-               justify overinformativeness, I think. */
-            if (! really_quiet)
-                printf ("(Locally modified %s moved to %s)\n",
-                        filename, bakname);
-            free (bakname);
-        }
+           may_be_modified = false;
+       free (basefn);
     }
     else
     {
-       send_to_server ("Unchanged ", 0);
-       send_to_server (filename, 0);
-       send_to_server ("\012", 1);
+       may_be_modified = false;
+    }
+
+    if (vers->ts_user)
+    {
+       if (may_be_modified)
+       {
+           if (args->force_signatures
+               || (!strcmp (cvs_cmd_name, "commit")
+                   && get_sign_commits (supported_request ("Signature"))))
+           {
+               if (!supported_request ("Signature"))
+                   error (1, 0, "Server doesn't support commit signatures.");
+
+               send_signature (Short_Repository (finfo->repository),
+                               finfo->file, finfo->fullname,
+                               vers && !strcmp (vers->options, "-kb"));
+           }
+
+           if (args->no_contents
+               && supported_request ("Is-modified"))
+           {
+               send_to_server ("Is-modified ", 0);
+               send_to_server (filename, 0);
+               send_to_server ("\012", 1);
+           }
+           else
+               send_modified (filename, finfo->fullname, vers);
+
+           if (args->backup_modified)
+           {
+               char *bakname;
+               bakname = backup_file (filename, vers->vn_user);
+               /* This behavior is sufficiently unexpected to
+                  justify overinformativeness, I think. */
+               if (! really_quiet)
+                   printf ("(Locally modified %s moved to %s)\n",
+                           filename, bakname);
+               free (bakname);
+           }
+       }
+       else
+       {
+           if (args->force_signatures)
+           {
+               if (!supported_request ("Signature"))
+                   error (1, 0, "Server doesn't support commit signatures.");
+
+               send_signature (Short_Repository (finfo->repository),
+                               finfo->file, finfo->fullname,
+                               vers && !strcmp (vers->options, "-kb"));
+           }
+
+           send_to_server ("Unchanged ", 0);
+           send_to_server (filename, 0);
+           send_to_server ("\012", 1);
+       }
     }
 
     /* if this directory has an ignore list, add this file to it */
@@ -4941,15 +5977,27 @@
 
 
 
-/* Send Repository, Modified and Entry.  argc and argv contain only
-  the files to operate on (or empty for everything), not options.
-  local is nonzero if we should not recurse (-l option).  flags &
-  SEND_BUILD_DIRS is nonzero if nonexistent directories should be
-  sent.  flags & SEND_FORCE is nonzero if we should send unmodified
-  files to the server as though they were modified.  flags &
-  SEND_NO_CONTENTS means that this command only needs to know
-  _whether_ a file is modified, not the contents.  Also sends Argument
-  lines for argc and argv, so should be called after options are sent.  */
+/*
+ * Send Repository, Modified and Entry.  Also sends Argument lines for argc
+ * and argv, so should be called after options are sent.  
+ *
+ * ARGUMENTS
+ *   argc      # of files to operate on (0 for everything).
+ *   argv      Paths to file to operate on.
+ *   local     nonzero if we should not recurse (-l option).
+ *   flags     FLAGS & SEND_BUILD_DIRS if nonexistent directories should be
+ *             sent.
+ *             FLAGS & SEND_FORCE if we should send unmodified files to the
+ *             server as though they were modified.
+ *             FLAGS & SEND_NO_CONTENTS means that this command only needs to
+ *             know _whether_ a file is modified, not the contents.
+ *             FLAGS & FORCE_SIGNATURES means that OpenPGP signatures should
+ *             be sent with files regardless of other settings, including
+ *             server support.
+ *
+ * RETURNS
+ *   Nothing.
+ */
 void
 send_files (int argc, char **argv, int local, int aflag, unsigned int flags)
 {
@@ -4967,6 +6015,7 @@
     args.force = flags & SEND_FORCE;
     args.no_contents = flags & SEND_NO_CONTENTS;
     args.backup_modified = flags & BACKUP_MODIFIED_FILES;
+    args.force_signatures = flags & FORCE_SIGNATURES;
     err = start_recursion
        (send_fileproc, send_filesdoneproc, send_dirent_proc,
          send_dirleave_proc, &args, argc, argv, local, W_LOCAL, aflag,
@@ -5068,6 +6117,17 @@
            error (0, 0,
                   "warning: ignoring -d option due to server limitations");
     }
+
+    /* Send signature.  */
+    if (get_sign_commits (supported_request ("Signature")))
+    {
+       if (!supported_request ("Signature"))
+           error (1, 0, "Server doesn't support commit signatures.");
+
+       send_signature (Short_Repository (repository), vfile, fullname,
+                       vers.options && !strcmp (vers.options, "-kb"));
+    }
+
     send_modified (vfile, fullname, &vers);
     if (vers.options)
        free (vers.options);
Index: ccvs/src/client.h
diff -u ccvs/src/client.h:1.61 ccvs/src/client.h:1.62
--- ccvs/src/client.h:1.61      Tue Oct 11 23:09:05 2005
+++ ccvs/src/client.h   Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1994-2006 The 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
@@ -14,6 +14,14 @@
 
 /* Interface between the client and the rest of CVS.  */
 
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#include <sys/types.h>
+#include "root.h"
+
+
+
 /* Stuff shared with the server.  */
 char *mode_to_string (mode_t);
 int change_mode (const char *, const char *, int);
@@ -112,15 +120,15 @@
  * the files to operate on (or empty for everything), not options.
  * local is nonzero if we should not recurse (-l option).
  */
-void
-send_files (int argc, char **argv, int local, int aflag,
-                 unsigned int flags);
+void send_files (int argc, char **argv, int local, int aflag,
+                unsigned int flags);
 
 /* Flags for send_files.  */
 # define SEND_BUILD_DIRS       (1 << 0)
 # define SEND_FORCE            (1 << 1)
 # define SEND_NO_CONTENTS      (1 << 2)
 # define BACKUP_MODIFIED_FILES (1 << 3)
+# define FORCE_SIGNATURES      (1 << 4)
 
 /* Send an argument to the remote server.  */
 void
@@ -219,3 +227,5 @@
 #endif
 
 #endif /* CLIENT_SUPPORT */
+
+#endif /* CLIENT_H */
Index: ccvs/src/commit.c
diff -u ccvs/src/commit.c:1.258 ccvs/src/commit.c:1.259
--- ccvs/src/commit.c:1.258     Mon Jan  9 21:24:31 2006
+++ ccvs/src/commit.c   Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -19,10 +19,23 @@
  *
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "getline.h"
+
+/* CVS headers.  */
 #include "edit.h"
 #include "fileattr.h"
+#include "ignore.h"
+#include "logmsg.h"
+#include "recurse.h"
+#include "repos.h"
+#include "wrapper.h"
+
+#include "cvs.h"
 #include "hardlink.h"
 
 static Dtype check_direntproc (void *callerdat, const char *dir,
@@ -86,7 +99,8 @@
 
 static const char *const commit_usage[] =
 {
-    "Usage: %s %s [-cRlf] [-m msg | -F logfile] [-r rev] files...\n",
+    "Usage: %s %s [-cRlf] [-m msg | -F logfile] [-r rev] [files...]\n",
+    "\n",
     "    -c          Check for valid edits before committing.\n",
     "    -R          Process directories recursively.\n",
     "    -l          Local directory only (not recursive).\n",
@@ -332,17 +346,25 @@
 
 
 
-#ifdef SERVER_SUPPORT
-# define COMMIT_OPTIONS "+cnlRm:fF:r:"
-#else /* !SERVER_SUPPORT */
-# define COMMIT_OPTIONS "+clRm:fF:r:"
-#endif /* SERVER_SUPPORT */
+/* Commit options both the client and server accept.  */
+#define COMMIT_OPTIONS "+cgG:lRm:fF:r:"
+
+    
+    
 int
 commit (int argc, char **argv)
 {
     int c;
     int err = 0;
     int local = 0;
+    int flags;
+
+#ifdef SERVER_SUPPORT
+    /* See below for documentation of the `-n' option.  */
+    const char short_options[] = COMMIT_OPTIONS"n";
+#else /* !SERVER_SUPPORT */
+    const char short_options[] = COMMIT_OPTIONS;
+#endif /* SERVER_SUPPORT */
 
     if (argc == -1)
        usage (commit_usage);
@@ -370,13 +392,14 @@
 #endif /* CVS_BADROOT */
 
     optind = 0;
-    while ((c = getopt (argc, argv, COMMIT_OPTIONS)) != -1)
+    while ((c = getopt (argc, argv, short_options)) != EOF)
     {
        switch (c)
        {
             case 'c':
                 check_valid_edit = 1;
                 break;
+
 #ifdef SERVER_SUPPORT
            case 'n':
                /* Silently ignore -n for compatibility with old
@@ -600,8 +623,8 @@
           _sure_ why this is needed, but if it is because the "ci"
           program, which we used to call, wanted the file to exist,
           then it would be relatively simple to fix in the server.  */
-       send_files (find_args.argc, find_args.argv, local, 0,
-                   find_args.force ? SEND_FORCE : 0);
+       flags = find_args.force ? SEND_FORCE : 0;
+       send_files (find_args.argc, find_args.argv, local, 0, flags);
 
        /* Sending only the names of the files which were modified, added,
           or removed means that the server will only do an up-to-date
@@ -914,6 +937,22 @@
                       finfo->fullname);
            }
 
+           if ((status == T_ADDED || status == T_MODIFIED)
+               && !force_ci && !really_quiet
+               /* This will not be called from the client.  */
+               && (get_sign_commits (true) || have_sigfile (finfo->file))
+               && file_contains_keyword (finfo))
+           {
+               /* Make this a warning, not an error, because the user may
+                * be intentionally signing a file with keywords.  Such a file
+                * may still be verified when checked out -ko.
+                */
+               if (!quiet)
+                   error (0, 0,
+"warning: signed file `%s' contains at least one RCS keyword",
+                          finfo->fullname);
+           }
+
            if (status == T_REMOVED)
            {
                if (vers->ts_user != NULL)
@@ -2100,7 +2139,9 @@
            /* We tell the user about this, because it means that the
               old revisions will no longer retrieve the way that they
               used to.  */
-           error (0, 0, "changing keyword expansion mode to %s", options);
+           error (0, 0,
+"changing keyword expansion mode of `%s' from `-k%s' to `%s'",
+                  file, oldexpand ? oldexpand : "kv", options);
            RCS_setexpand (rcs, options + 2);
        }
 
Index: ccvs/src/create_adm.c
diff -u ccvs/src/create_adm.c:1.52 ccvs/src/create_adm.c:1.53
--- ccvs/src/create_adm.c:1.52  Wed Mar 16 22:00:49 2005
+++ ccvs/src/create_adm.c       Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -16,6 +16,13 @@
  * "Entries" file is prefilled from the "initrecord" argument.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS Headers.  */
+#include "repos.h"
+
 #include "cvs.h"
 
 
Index: ccvs/src/cvs.h
diff -u ccvs/src/cvs.h:1.346 ccvs/src/cvs.h:1.347
--- ccvs/src/cvs.h:1.346        Tue Jan 10 17:23:24 2006
+++ ccvs/src/cvs.h      Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -233,12 +233,6 @@
 #define        CVSLCKSLEEP     30              /* wait 30 seconds before 
retrying */
 #define        CVSBRANCH       "1.1.1"         /* RCS branch used for vendor 
srcs */
 
-#ifdef USE_VMS_FILENAMES
-# define BAKPREFIX     "_$"
-#else /* USE_VMS_FILENAMES */
-# define BAKPREFIX     ".#"            /* when rcsmerge'ing */
-#endif /* USE_VMS_FILENAMES */
-
 /*
  * Special tags. -rHEAD        refers to the head of an RCS file, regardless 
of any
  * sticky tags. -rBASE refers to the current revision the user has checked
@@ -251,7 +245,19 @@
 #define        CVSREAD_ENV     "CVSREAD"       /* make files read-only */
 #define        CVSREAD_DFLT    0               /* writable files by default */
 
-#define        CVSREADONLYFS_ENV "CVSREADONLYFS" /* repository is read-only */
+                                       /* repository is read-only */
+#define        CVSREADONLYFS_ENV "CVSREADONLYFS"
+
+                                       /* verify checkouts */
+#define        CVS_VERIFY_CHECKOUTS_ENV \
+                       "CVS_VERIFY_CHECKOUTS"
+                                       /* verify template */
+#define        CVS_VERIFY_TEMPLATE_ENV \
+                       "CVS_VERIFY_TEMPLATE"
+
+                                       /* sign commits */
+#define        CVS_SIGN_COMMITS_ENV \
+                       "CVS_SIGN_COMMITS"
 
 #define        TMPDIR_ENV      "TMPDIR"        /* Temporary directory */
 #define        CVS_PID_ENV     "CVS_PID"       /* pid of running cvs */
@@ -271,6 +277,10 @@
 
 #define        CVSUMASK_ENV    "CVSUMASK"      /* Effective umask for 
repository */
 
+#define        CVSNOBASES_ENV  "CVSNOBASES"    /* Suppress use of base files 
when
+                                        * set.
+                                        */
+
 /*
  * If the beginning of the Repository matches the following string, strip it
  * so that the output to the logfile does not contain a full pathname.
@@ -284,30 +294,7 @@
    command line, the client, etc.  */
 #define MAXDATELEN     50
 
-/* The type of an entnode.  */
-enum ent_type
-{
-    ENT_FILE, ENT_SUBDIR
-};
-
-/* structure of a entry record */
-struct entnode
-{
-    enum ent_type type;
-    char *user;
-    char *version;
-
-    /* Timestamp, or "" if none (never NULL).  */
-    char *timestamp;
-
-    /* Keyword expansion options, or "" if none (never NULL).  */
-    char *options;
-
-    char *tag;
-    char *date;
-    char *conflict;
-};
-typedef struct entnode Entnode;
+#include "entries.h"
 
 /* The type of request that is being done in do_module() */
 enum mtype
@@ -334,30 +321,6 @@
     int subdirs;
 };
 
-/* Flags for find_{names,dirs} routines */
-#define W_LOCAL                        0x01    /* look for files locally */
-#define W_REPOS                        0x02    /* look for files in the 
repository */
-#define W_ATTIC                        0x04    /* look for files in the attic 
*/
-
-/* Flags for return values of direnter procs for the recursion processor */
-enum direnter_type
-{
-    R_PROCESS = 1,                     /* process files and maybe dirs */
-    R_SKIP_FILES,                      /* don't process files in this dir */
-    R_SKIP_DIRS,                       /* don't process sub-dirs */
-    R_SKIP_ALL                         /* don't process files or dirs */
-};
-#ifdef ENUMS_CAN_BE_TROUBLE
-typedef int Dtype;
-#else
-typedef enum direnter_type Dtype;
-#endif
-
-/* Recursion processor lock types */
-#define CVS_LOCK_NONE  0
-#define CVS_LOCK_READ  1
-#define CVS_LOCK_WRITE 2
-
 /* Option flags for Parse_Info() */
 #define PIOPT_ALL 1    /* accept "all" keyword */
 
@@ -391,10 +354,10 @@
 char *emptydir_name (void);
 int safe_location (char *);
 
-extern int trace;              /* Show all commands */
 extern int noexec;             /* Don't modify disk anywhere */
 extern int readonlyfs;         /* fail on all write locks; succeed all read 
locks */
 extern int logoff;             /* Don't write history entry */
+extern bool suppress_bases;
 
 
 
@@ -418,8 +381,6 @@
 
 /* Externs that are included directly in the CVS sources */
 
-int RCS_merge (RCSNode *, const char *, const char *, const char *,
-               const char *, const char *);
 /* Flags used by RCS_* functions.  See the description of the individual
    functions for which flags mean what for each function.  */
 #define RCS_FLAGS_FORCE 1
@@ -470,13 +431,8 @@
 char *gmformat_time_t (time_t unixtime);
 char *format_date_alloc (char *text);
 
-char *Name_Repository (const char *dir, const char *update_dir);
-const char *Short_Repository (const char *repository);
-void Sanitize_Repository_Name (char *repository);
-
 char *entries_time (time_t unixtime);
 time_t unix_time_stamp (const char *file);
-char *time_stamp (const char *file);
 
 typedef        int (*CALLPROC) (const char *repository, const char *value,
                          void *closure);
@@ -485,57 +441,12 @@
 
 typedef        RETSIGTYPE (*SIGCLEANUPPROC)    (int);
 int SIG_register (int sig, SIGCLEANUPPROC sigcleanup);
-bool isdir (const char *file);
-bool isfile (const char *file);
-ssize_t islink (const char *file);
-bool isdevice (const char *file);
-bool isreadable (const char *file);
-bool iswritable (const char *file);
-bool isaccessible (const char *file, const int mode);
-const char *last_component (const char *path);
-char *get_homedir (void);
-char *strcat_filename_onto_homedir (const char *, const char *);
-char *cvs_temp_name (void);
-FILE *cvs_temp_file (char **filename);
-
-int ls (int argc, char *argv[]);
-int unlink_file (const char *f);
-int unlink_file_dir (const char *f);
 
-/* This is the structure that the recursion processor passes to the
-   fileproc to tell it about a particular file.  */
-struct file_info
-{
-    /* Name of the file, without any directory component.  */
-    const char *file;
-
-    /* Name of the directory we are in, relative to the directory in
-       which this command was issued.  We have cd'd to this directory
-       (either in the working directory or in the repository, depending
-       on which sort of recursion we are doing).  If we are in the directory
-       in which the command was issued, this is "".  */
-    const char *update_dir;
-
-    /* update_dir and file put together, with a slash between them as
-       necessary.  This is the proper way to refer to the file in user
-       messages.  */
-    const char *fullname;
-
-    /* Name of the directory corresponding to the repository which contains
-       this file.  */
-    const char *repository;
-
-    /* The pre-parsed entries for this directory.  */
-    List *entries;
-
-    RCSNode *rcs;
-};
-
-/* This needs to be included after the struct file_info definition since some
- * of the functions subr.h defines refer to struct file_info.
- */
+#include "filesubr.h"
 #include "subr.h"
 
+int ls (int argc, char *argv[]);
+
 int update (int argc, char *argv[]);
 /* The only place this is currently used outside of update.c is add.c.
  * Restricting its use to update.c seems to be in the best interest of
@@ -581,19 +492,8 @@
 void cat_module (int status);
 void check_entries (char *dir);
 void close_module (DBM * db);
-void copy_file (const char *from, const char *to);
 void fperrmsg (FILE * fp, int status, int errnum, char *message,...);
 
-int ign_name (char *name);
-void ign_add (char *ign, int hold);
-void ign_add_file (char *file, int hold);
-void ign_setup (void);
-void ign_dir_add (char *name);
-int ignore_directory (const char *name);
-typedef void (*Ignore_proc) (const char *, const char *);
-void ignore_files (List *, List *, const char *, Ignore_proc);
-extern int ign_inhibit_server;
-
 #include "update.h"
 
 void make_directories (const char *name);
@@ -616,12 +516,8 @@
 
 void update_delproc (Node * p);
 void usage (const char *const *cpp);
-void xchmod (const char *fname, int writable);
 List *Find_Names (char *repository, int which, int aflag,
                  List ** optentries);
-void Register (List * list, const char *fname, const char *vn, const char *ts,
-               const char *options, const char *tag, const char *date,
-               const char *ts_conflict);
 void Update_Logfile (const char *repository, const char *xmessage,
                      FILE *xlogfp, List *xchanges);
 void do_editor (const char *dir, char **messagep,
@@ -633,17 +529,6 @@
        char *mwhere, char *mfile, int shorten, int local_specified,
        char *omodule, char *msg);
 
-
-typedef        int (*FILEPROC) (void *callerdat, struct file_info *finfo);
-typedef        int (*FILESDONEPROC) (void *callerdat, int err,
-                              const char *repository, const char *update_dir,
-                              List *entries);
-typedef        Dtype (*DIRENTPROC) (void *callerdat, const char *dir,
-                             const char *repos, const char *update_dir,
-                             List *entries);
-typedef        int (*DIRLEAVEPROC) (void *callerdat, const char *dir, int err,
-                             const char *update_dir, List *entries);
-
 int mkmodules (char *dir);
 int init (int argc, char **argv);
 
@@ -653,194 +538,26 @@
                char *extra_arg);
 void history_write (int type, const char *update_dir, const char *revs,
                     const char *name, const char *repository);
-int start_recursion (FILEPROC fileproc, FILESDONEPROC filesdoneproc,
-                    DIRENTPROC direntproc, DIRLEAVEPROC dirleaveproc,
-                    void *callerdat,
-                    int argc, char *argv[], int local, int which,
-                    int aflag, int locktype, char *update_preload,
-                    int dosrcs, char *repository);
 void SIG_beginCrSect (void);
 void SIG_endCrSect (void);
 int SIG_inCrSect (void);
 void read_cvsrc (int *argc, char ***argv, const char *cmdname);
 
-/* flags for run_exec(), the fast system() for CVS */
-#define        RUN_NORMAL            0x0000    /* no special behaviour */
-#define        RUN_COMBINED          0x0001    /* stdout is duped to stderr */
-#define        RUN_REALLY            0x0002    /* do the exec, even if noexec 
is on */
-#define        RUN_STDOUT_APPEND     0x0004    /* append to stdout, don't 
truncate */
-#define        RUN_STDERR_APPEND     0x0008    /* append to stderr, don't 
truncate */
-#define        RUN_SIGIGNORE         0x0010    /* ignore interrupts for 
command */
-#define        RUN_TTY               (char *)0 /* for the benefit of lint */
-
-void run_add_arg_p (int *, size_t *, char ***, const char *s);
-void run_arg_free_p (int, char **);
-void run_add_arg (const char *s);
-void run_print (FILE * fp);
-void run_setup (const char *prog);
-int run_exec (const char *stin, const char *stout, const char *sterr,
-              int flags);
-int run_piped (int *, int *);
-
-/* other similar-minded stuff from run.c.  */
-FILE *run_popen (const char *, const char *);
-int piped_child (char *const *, int *, int *, bool);
-void close_on_exec (int);
+#include "run.h"
 
 pid_t waitpid (pid_t, int *, int);
 
-/*
- * a struct vers_ts contains all the information about a file including the
- * user and rcs file names, and the version checked out and the head.
- *
- * this is usually obtained from a call to Version_TS which takes a
- * tag argument for the RCS file if desired
- */
-struct vers_ts
-{
-    /* rcs version user file derives from, from CVS/Entries.
-       It can have the following special values:
-
-       NULL = file is not mentioned in Entries (this is also used for a
-             directory).
-       "" = INVALID!  The comment used to say that it meant "no user file"
-           but as far as I know CVS didn't actually use it that way.
-           Note that according to cvs.texinfo, "" is not valid in the
-           Entries file.
-       0 = user file is new
-       -vers = user file to be removed.  */
-    char *vn_user;
-
-    /* Numeric revision number corresponding to ->vn_tag (->vn_tag
-       will often be symbolic).  */
-    char *vn_rcs;
-    /* If ->tag is a simple tag in the RCS file--a tag which really
-       exists which is not a magic revision--and if ->date is NULL,
-       then this is a copy of ->tag.  Otherwise, it is a copy of
-       ->vn_rcs.  */
-    char *vn_tag;
-
-    /* This is the timestamp from stating the file in the working directory.
-       It is NULL if there is no file in the working directory.  It is
-       "Is-modified" if we know the file is modified but don't have its
-       contents.  */
-    char *ts_user;
-    /* Timestamp from CVS/Entries.  For the server, ts_user and ts_rcs
-       are computed in a slightly different way, but the fact remains that
-       if they are equal the file in the working directory is unmodified
-       and if they differ it is modified.  */
-    char *ts_rcs;
-
-    /* Options from CVS/Entries (keyword expansion), malloc'd.  If none,
-       then it is an empty string (never NULL).  */
-    char *options;
-
-    /* If non-NULL, there was a conflict (or merely a merge?  See merge_file)
-       and the time stamp in this field is the time stamp of the working
-       directory file which was created with the conflict markers in it.
-       This is from CVS/Entries.  */
-    char *ts_conflict;
+#include "vers_ts.h"
 
-    /* Tag specified on the command line, or if none, tag stored in
-       CVS/Entries.  */
-    char *tag;
-    /* Date specified on the command line, or if none, date stored in
-       CVS/Entries.  */
-    char *date;
-    /* If this is 1, then tag is not a branch tag.  If this is 0, then
-       tag may or may not be a branch tag.  */
-    int nonbranch;
-
-    /* Pointer to entries file node  */
-    Entnode *entdata;
-
-    /* Pointer to parsed src file info */
-    RCSNode *srcfile;
-};
-typedef struct vers_ts Vers_TS;
-
-Vers_TS *Version_TS (struct file_info *finfo, char *options, char *tag,
-                           char *date, int force_tag_match,
-                           int set_time);
-void freevers_ts (Vers_TS ** versp);
-
 /* Miscellaneous CVS infrastructure which layers on top of the recursion
    processor (for example, needs struct file_info).  */
 
 int Checkin (int type, struct file_info *finfo, char *rev,
             char *tag, char *options, char *message);
-int No_Difference (struct file_info *finfo, Vers_TS *vers);
 /* TODO: can the finfo argument to special_file_mismatch be changed? -twp */
 int special_file_mismatch (struct file_info *finfo,
                                  char *rev1, char *rev2);
 
-/* CVSADM_BASEREV stuff, from entries.c.  */
-char *base_get (struct file_info *);
-void base_register (struct file_info *, char *);
-void base_deregister (struct file_info *);
-
-/*
- * defines for Classify_File() to determine the current state of a file.
- * These are also used as types in the data field for the list we make for
- * Update_Logfile in commit, import, and add.
- */
-enum classify_type
-{
-    T_UNKNOWN = 1,                     /* no old-style analog existed   */
-    T_CONFLICT,                                /* C (conflict) list            
 */
-    T_NEEDS_MERGE,                     /* G (needs merging) list        */
-    T_MODIFIED,                                /* M (needs checked in) list    
 */
-    T_CHECKOUT,                                /* O (needs checkout) list      
 */
-    T_ADDED,                           /* A (added file) list           */
-    T_REMOVED,                         /* R (removed file) list         */
-    T_REMOVE_ENTRY,                    /* W (removed entry) list        */
-    T_UPTODATE,                                /* File is up-to-date           
 */
-    T_PATCH,                           /* P Like C, but can patch       */
-    T_TITLE                            /* title for node type           */
-};
-typedef enum classify_type Ctype;
-
-Ctype Classify_File (struct file_info *finfo, char *tag, char *date, char 
*options,
-      int force_tag_match, int aflag, Vers_TS **versp, int pipeout);
-
-/*
- * structure used for list nodes passed to Update_Logfile() and
- * do_editor().
- */
-struct logfile_info
-{
-  enum classify_type type;
-  char *tag;
-  char *rev_old;               /* rev number before a commit/modify,
-                                  NULL for add or import */
-  char *rev_new;               /* rev number after a commit/modify,
-                                  add, or import, NULL for remove */
-};
-
-/* Wrappers.  */
-
-typedef enum { WRAP_MERGE, WRAP_COPY } WrapMergeMethod;
-typedef enum {
-    /* -t and -f wrapper options.  Treating directories as single files.  */
-    WRAP_TOCVS,
-    WRAP_FROMCVS,
-    /* -k wrapper option.  Default keyword expansion options.  */
-    WRAP_RCSOPTION
-} WrapMergeHas;
-
-void  wrap_setup (void);
-int   wrap_name_has (const char *name,WrapMergeHas has);
-char *wrap_rcsoption (const char *fileName, int asFlag);
-char *wrap_tocvs_process_file (const char *fileName);
-int   wrap_merge_is_copy (const char *fileName);
-void wrap_fromcvs_process_file (const char *fileName);
-void wrap_add_file (const char *file,int temp);
-void wrap_add (char *line,int temp);
-void wrap_send (void);
-#if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT)
-void wrap_unparse_rcs_options (char **, int);
-#endif /* SERVER_SUPPORT || CLIENT_SUPPORT */
-
 /* Pathname expansion */
 char *expand_path (const char *name, const char *cvsroot, bool formatsafe,
                   const char *file, int line);
@@ -906,14 +623,6 @@
 
 #include "server.h"
 
-/* From server.c and documented there.  */
-void cvs_output (const char *, size_t);
-void cvs_output_binary (char *, size_t);
-void cvs_outerr (const char *, size_t);
-void cvs_flusherr (void);
-void cvs_flushout (void);
-void cvs_output_tagged (const char *, const char *);
-
 extern const char *global_session_id;
 
 /* From find_names.c.  */
Index: ccvs/src/diff.c
diff -u ccvs/src/diff.c:1.116 ccvs/src/diff.c:1.117
--- ccvs/src/diff.c:1.116       Fri May 27 18:07:48 2005
+++ ccvs/src/diff.c     Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -19,11 +19,28 @@
  * files.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "diff.h"
+
+/* CVS headers.  */
+#include "base.h"
+#include "ignore.h"
+#include "rcs.h"
+#include "recurse.h"
+#include "wrapper.h"
+
 #include "cvs.h"
 
+
+
 enum diff_file
 {
     DIFF_ERROR,
+    DIFF_CLIENT,
     DIFF_ADDED,
     DIFF_REMOVED,
     DIFF_DIFFERENT,
@@ -39,10 +56,7 @@
 static int diff_dirleaveproc (void *callerdat, const char *dir,
                               int err, const char *update_dir,
                               List *entries);
-static enum diff_file diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
-                                        enum diff_file, char **rev1_cache );
 static int diff_fileproc (void *callerdat, struct file_info *finfo);
-static void diff_mark_errors (int err);
 
 
 /* Global variables.  Would be cleaner if we just put this stuff in a
@@ -52,8 +66,7 @@
 static char *diff_rev1, *diff_rev2;
 /* Command line dates, from -D option.  Malloc'd.  */
 static char *diff_date1, *diff_date2;
-static char *use_rev1, *use_rev2;
-static int have_rev1_label, have_rev2_label;
+static bool have_rev1_label, have_rev2_label;
 
 /* Revision of the user file, if it is unchanged from something in the
    repository and we want to use that fact.  */
@@ -64,7 +77,7 @@
 static int diff_argc;
 static size_t diff_arg_allocated;
 static int diff_errors;
-static int empty_files;
+static bool empty_files;
 
 static const char *const diff_usage[] =
 {
@@ -290,8 +303,6 @@
     if (argc == -1)
        usage (diff_usage);
 
-    have_rev1_label = have_rev2_label = 0;
-
     /*
      * Note that we catch all the valid arguments here, so that we can
      * intercept the -r arguments for doing revision diffs; and -l/-R for a
@@ -389,7 +400,7 @@
                    diff_date1 = Make_Date (optarg);
                break;
            case 'N':
-               empty_files = 1;
+               empty_files = true;
                break;
            case '?':
            default:
@@ -405,7 +416,10 @@
        options = xstrdup ("");
 
 #ifdef CLIENT_SUPPORT
-    if (current_parsed_root->isremote) {
+    if (current_parsed_root->isremote)
+    {
+       int flags;
+
        /* We're the client side.  Fire up the remote server.  */
        start_server ();
        
@@ -429,10 +443,12 @@
        send_arg ("--");
 
        /* Send the current files unless diffing two revs from the archive */
-       if (!diff_rev2 && !diff_date2)
-           send_files (argc, argv, local, 0, 0);
-       else
-           send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
+       flags = 0;
+       if ((!suppress_bases && supported_request ("Base-diff"))
+           || diff_rev2 || diff_date2)
+           flags |= SEND_NO_CONTENTS;
+
+       send_files (argc, argv, local, 0, flags);
 
        send_file_names (argc, argv, SEND_EXPAND_WILD);
 
@@ -440,7 +456,7 @@
         err = get_responses_and_close ();
        free (options);
        options = NULL;
-       return err;
+       return diff_errors ? diff_errors : err;
     }
 #endif
 
@@ -475,21 +491,273 @@
 
 
 /*
+ * verify that a file is different
+ *
+ * INPUTS
+ *   finfo
+ *   vers
+ *   empty_file
+ *
+ * OUTPUTS
+ *   rev1_cache                Cache the contents of rev1 if we look it up.
+ */
+static enum diff_file
+diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
+                  enum diff_file empty_file, char **rev1_cache,
+                 const char *arg_rev1, char **use_rev1, char **use_rev2)
+{
+    Vers_TS *xvers;
+    int retcode;
+
+    TRACE (TRACE_FUNCTION, "diff_file_nodiff (%s, %d)",
+           finfo->fullname ? finfo->fullname : "(null)", empty_file);
+
+    /* free up any old use_rev* variables and reset 'em */
+    *use_rev1 = *use_rev2 = NULL;
+
+    if (diff_rev1 || diff_date1)
+    {
+       /* special handling for TAG_HEAD */
+       if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
+       {
+           if (vers->vn_rcs != NULL && vers->srcfile != NULL)
+               *use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+       }
+       else
+       {
+           xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
+           if (xvers->vn_rcs != NULL)
+               *use_rev1 = xstrdup (xvers->vn_rcs);
+           freevers_ts (&xvers);
+       }
+    }
+    if (diff_rev2 || diff_date2)
+    {
+       /* special handling for TAG_HEAD */
+       if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
+       {
+           if (vers->vn_rcs && vers->srcfile)
+               *use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
+       }
+       else
+       {
+           xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
+           if (xvers->vn_rcs != NULL)
+               *use_rev2 = xstrdup (xvers->vn_rcs);
+           freevers_ts (&xvers);
+       }
+
+       if (!*use_rev1 || RCS_isdead (vers->srcfile, *use_rev1))
+       {
+           /* The first revision does not exist.  If EMPTY_FILES is
+               true, treat this as an added file.  Otherwise, warn
+               about the missing tag.  */
+           if (!*use_rev2 || RCS_isdead (vers->srcfile, *use_rev2))
+               /* At least in the case where DIFF_REV1 and DIFF_REV2
+                * are both numeric (and non-existant (NULL), as opposed to
+                * dead?), we should be returning some kind of error (see
+                * basicb-8a0 in testsuite).  The symbolic case may be more
+                * complicated.
+                */
+               return DIFF_SAME;
+           if (empty_files)
+               return DIFF_ADDED;
+           if (*use_rev1)
+           {
+               if (diff_rev1)
+               {
+                   error (0, 0,
+                      "Tag %s refers to a dead (removed) revision in file 
`%s'.",
+                      diff_rev1, finfo->fullname);
+               }
+               else
+               {
+                   error (0, 0,
+                      "Date %s refers to a dead (removed) revision in file 
`%s'.",
+                      diff_date1, finfo->fullname);
+               }
+               error (0, 0,
+                      "No comparison available.  Pass `-N' to `%s diff'?",
+                      program_name);
+           }
+           else if (diff_rev1)
+               error (0, 0, "tag %s is not in file %s", diff_rev1,
+                      finfo->fullname);
+           else
+               error (0, 0, "no revision for date %s in file %s",
+                      diff_date1, finfo->fullname);
+           return DIFF_ERROR;
+       }
+
+       assert (*use_rev1);
+       if (!*use_rev2 || RCS_isdead (vers->srcfile, *use_rev2))
+       {
+           /* The second revision does not exist.  If EMPTY_FILES is
+               true, treat this as a removed file.  Otherwise warn
+               about the missing tag.  */
+           if (empty_files)
+               return DIFF_REMOVED;
+           if (*use_rev2)
+           {
+               if (diff_rev2)
+               {
+                   error( 0, 0,
+                      "Tag %s refers to a dead (removed) revision in file 
`%s'.",
+                      diff_rev2, finfo->fullname );
+               }
+               else
+               {
+                   error( 0, 0,
+                      "Date %s refers to a dead (removed) revision in file 
`%s'.",
+                      diff_date2, finfo->fullname );
+               }
+               error( 0, 0,
+                      "No comparison available.  Pass `-N' to `%s diff'?",
+                      program_name );
+           }
+           else if (diff_rev2)
+               error (0, 0, "tag %s is not in file %s", diff_rev2,
+                      finfo->fullname);
+           else
+               error (0, 0, "no revision for date %s in file %s",
+                      diff_date2, finfo->fullname);
+           return DIFF_ERROR;
+       }
+       /* Now, see if we really need to do the diff.  We can't assume that the
+        * files are different when the revs are.
+        */
+       assert (*use_rev2);
+       if (!strcmp (*use_rev1, *use_rev2))
+           return DIFF_SAME;
+       /* else fall through and do the diff */
+    }
+
+    /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0...
+     * err...  ok, then both rev1 & rev2 must have resolved to an existing,
+     * live version due to if statement we just closed.
+     */
+    assert (!(diff_rev2 || diff_date2) || (*use_rev1 && *use_rev2));
+
+    if ((diff_rev1 || diff_date1) &&
+       (!*use_rev1 || RCS_isdead (vers->srcfile, *use_rev1)))
+    {
+       /* The first revision does not exist, and no second revision
+           was given.  */
+       if (empty_files)
+       {
+           if (empty_file == DIFF_REMOVED)
+               return DIFF_SAME;
+           if (user_file_rev && !*use_rev2)
+               *use_rev2 = xstrdup (user_file_rev);
+           return DIFF_ADDED;
+       }
+       if (*use_rev1)
+       {
+           if (diff_rev1)
+           {
+               error( 0, 0,
+                  "Tag %s refers to a dead (removed) revision in file `%s'.",
+                  diff_rev1, finfo->fullname );
+           }
+           else
+           {
+               error( 0, 0,
+                  "Date %s refers to a dead (removed) revision in file `%s'.",
+                  diff_date1, finfo->fullname );
+           }
+           error( 0, 0,
+                  "No comparison available.  Pass `-N' to `%s diff'?",
+                  program_name );
+       }
+       else if ( diff_rev1 )
+           error( 0, 0, "tag %s is not in file %s", diff_rev1,
+                  finfo->fullname );
+       else
+           error( 0, 0, "no revision for date %s in file %s",
+                  diff_date1, finfo->fullname );
+       return DIFF_ERROR;
+    }
+
+    assert (!diff_rev1 || *use_rev1);
+
+    if (user_file_rev)
+    {
+        /* drop user_file_rev into first unused use_rev */
+        if (!*use_rev1) 
+           *use_rev1 = xstrdup (user_file_rev);
+       else if (!*use_rev2)
+           *use_rev2 = xstrdup (user_file_rev);
+       /* and if not, it wasn't needed anyhow */
+       user_file_rev = NULL;
+    }
+
+    /* Now, see if we really need to do the diff.  We can't assume that the
+     * files are different when the revs are.
+     */
+    if (*use_rev1 && *use_rev2) 
+    {
+       if (!strcmp (*use_rev1, *use_rev2))
+           return DIFF_SAME;
+       /* Fall through and do the diff. */
+    }
+    /* Don't want to do the timestamp check with both *USE_REV1 & *USE_REV2 
set.
+     * The timestamp check is just for the default case of diffing the
+     * workspace file against its base revision.
+     */
+    else if (!*use_rev1
+             || (vers->vn_user
+                 && !strcmp (*use_rev1, vers->vn_user)))
+    {
+       if ((empty_file == DIFF_DIFFERENT || empty_file == DIFF_CLIENT)
+           && vers->ts_user != NULL
+           && strcmp (vers->ts_rcs, vers->ts_user) == 0
+           && (!(*options) || strcmp (options, vers->options) == 0))
+       {
+           return DIFF_SAME;
+       }
+       if (!*use_rev1
+           && (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0'))
+       {
+           if (vers->vn_user[0] == '-')
+               *use_rev1 = xstrdup (vers->vn_user + 1);
+           else
+               *use_rev1 = xstrdup (vers->vn_user);
+       }
+    }
+
+    /* If we already know that the file is being added or removed,
+       then we don't want to do an actual file comparison here.  */
+    if (empty_file != DIFF_DIFFERENT)
+       return empty_file;
+
+    /*
+     * Run a quick cmp to see if we should bother with a full diff.
+     */
+
+    retcode = RCS_cmp_file (vers->srcfile, diff_rev1, *use_rev1, rev1_cache,
+                            *use_rev2, *options ? options : vers->options,
+                           finfo->file);
+
+    return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
+}
+
+
+
+/*
  * Do a file diff
  */
 /* ARGSUSED */
 static int
 diff_fileproc (void *callerdat, struct file_info *finfo)
 {
-    int status, err = 2;               /* 2 == trouble, like rcsdiff */
+    int err = 2;               /* 2 == trouble, like rcsdiff */
     Vers_TS *vers;
-    enum diff_file empty_file = DIFF_DIFFERENT;
-    char *tmp = NULL;
-    char *tocvsPath = NULL;
-    char *fname = NULL;
-    char *label1;
-    char *label2;
+    enum diff_file empty_file = server_use_bases ()
+                               ? DIFF_CLIENT : DIFF_DIFFERENT;
     char *rev1_cache = NULL;
+    char *use_rev1 = NULL, *use_rev2 = NULL;
+    const char *f1 = NULL, *f2 = NULL;
+    char *label1 = NULL, *label2 = NULL;
 
     user_file_rev = 0;
     vers = Version_TS (finfo, NULL, NULL, NULL, 1, 0);
@@ -639,7 +907,10 @@
        }
     }
 
-    empty_file = diff_file_nodiff (finfo, vers, empty_file, &rev1_cache);
+    empty_file = diff_file_nodiff (finfo, vers, empty_file, &rev1_cache,
+                                  diff_rev1 && !isdigit (diff_rev1[0])
+                                  ? diff_rev1 : vers->tag,
+                                  &use_rev1, &use_rev2);
     if (empty_file == DIFF_SAME)
     {
        /* In the server case, would be nice to send a "Checked-in"
@@ -655,150 +926,102 @@
     else if (empty_file == DIFF_ERROR)
        goto out;
 
-    /* Output an "Index:" line for patch to use */
-    cvs_output ("Index: ", 0);
-    cvs_output (finfo->fullname, 0);
-    cvs_output ("\n", 1);
-
-    tocvsPath = wrap_tocvs_process_file (finfo->file);
-    if (tocvsPath)
-    {
-       /* Backup the current version of the file to CVS/,,filename */
-       fname = Xasprintf (fname, "%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
-       if (unlink_file_dir (fname) < 0)
-           if (!existence_error (errno))
-               error (1, errno, "cannot remove %s", fname);
-       rename_file (finfo->file, fname);
-       /* Copy the wrapped file to the current directory then go to work */
-       copy_file (tocvsPath, finfo->file);
+    if (empty_file == DIFF_ADDED)
+       f1 = DEVNULL;
+    else if (rev1_cache)
+    {
+       /* If this is cached, temp_checkout was not called for the client.
+        */
+       assert (empty_file != DIFF_CLIENT);
+       f1 = rev1_cache;
+    }
+    else
+    {
+       f1 = temp_checkout (vers->srcfile, finfo,
+                           vers->vn_user && *(vers->vn_user) == '-'
+                           ? vers->vn_user + 1 : vers->vn_user,
+                           use_rev1, vers->tag,
+                           diff_rev1 && !isdigit (diff_rev1[0])
+                           ? diff_rev1 : vers->tag,
+                           vers->options, *options ? options : vers->options);
+       if (!f1)
+           goto out;
+    }
+
+    if (empty_file == DIFF_REMOVED)
+       f2 = DEVNULL;
+    else if (use_rev2)
+    {
+       f2 = temp_checkout (vers->srcfile, finfo,
+                           vers->vn_user && *(vers->vn_user) == '-'
+                           ? vers->vn_user + 1 : vers->vn_user,
+                           use_rev2, vers->tag,
+                           diff_rev2 && !isdigit (diff_rev2[0])
+                           ? diff_rev2 : NULL,
+                           vers->options, *options ? options : vers->options);
+       if (!f2)
+           goto out;
     }
+    else
+       f2 = finfo->file;
 
     /* Set up file labels appropriate for compatibility with the Larry Wall
      * implementation of patch if the user didn't specify.  This is irrelevant
      * according to the POSIX.2 specification.
-     */
-    label1 = NULL;
-    label2 = NULL;
-    /* The user cannot set the rev2 label without first setting the rev1
+     *
+     * The user cannot set the rev2 label without first setting the rev1
      * label.
      */
     if (!have_rev2_label)
     {
        if (empty_file == DIFF_REMOVED)
-           label2 = make_file_label (DEVNULL, NULL, NULL);
+           label2 = make_file_label (DEVNULL, NULL, NULL, NULL);
        else
            label2 = make_file_label (finfo->fullname, use_rev2,
-                                     vers->srcfile);
+                                     /* FIXME: make_file_label should be able
+                                      * to trust vers->ts_user, but
+                                      * Version_TS isn't setting it correctly
+                                      * when base files are suppressed.
+                                      */
+                                     server_active
+                                     ? "Is-modified" : vers->ts_user,
+                                     finfo->rcs);
        if (!have_rev1_label)
        {
            if (empty_file == DIFF_ADDED)
-               label1 = make_file_label (DEVNULL, NULL, NULL);
+               label1 = make_file_label (DEVNULL, NULL, NULL, NULL);
            else
                label1 = make_file_label (finfo->fullname, use_rev1,
-                                         vers->srcfile);
+                                         NULL, finfo->rcs);
        }
     }
 
-    if (empty_file == DIFF_ADDED || empty_file == DIFF_REMOVED)
-    {
-       /* This is fullname, not file, possibly despite the POSIX.2
-        * specification, because that's the way all the Larry Wall
-        * implementations of patch (are there other implementations?) want
-        * things and the POSIX.2 spec appears to leave room for this.
-        */
-       cvs_output ("\
-===================================================================\n\
-RCS file: ", 0);
-       cvs_output (finfo->fullname, 0);
-       cvs_output ("\n", 1);
-
-       cvs_output ("diff -N ", 0);
-       cvs_output (finfo->fullname, 0);
-       cvs_output ("\n", 1);
-
-       if (empty_file == DIFF_ADDED)
-       {
-           if (use_rev2 == NULL)
-                status = diff_exec (DEVNULL, finfo->file, label1, label2,
-                                   diff_argc, diff_argv, RUN_TTY);
-           else
-           {
-               int retcode;
+    err = base_diff (finfo, diff_argc, diff_argv, f1, use_rev1, label1,
+                    f2, use_rev2, label2, empty_files);
 
-               tmp = cvs_temp_name ();
-               retcode = RCS_checkout (vers->srcfile, NULL, use_rev2, NULL,
-                                       *options ? options : vers->options,
-                                       tmp, NULL, NULL);
-               if (retcode != 0)
-                   goto out;
-
-               status = diff_exec (DEVNULL, tmp, label1, label2,
-                                   diff_argc, diff_argv, RUN_TTY);
-           }
-       }
-       else
-       {
-           int retcode;
-
-           tmp = cvs_temp_name ();
-           retcode = RCS_checkout (vers->srcfile, NULL, use_rev1, NULL,
-                                   *options ? options : vers->options,
-                                   tmp, NULL, NULL);
-           if (retcode != 0)
-               goto out;
-
-           status = diff_exec (tmp, DEVNULL, label1, label2,
-                               diff_argc, diff_argv, RUN_TTY);
-       }
+out:
+    if (empty_file != DIFF_ADDED && !rev1_cache && f1)
+    {
+       if (CVS_UNLINK (f1) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", f1);
+       free ((char *)f1);
     }
-    else
+    if (empty_file != DIFF_REMOVED && use_rev2 && f2)
     {
-       status = RCS_exec_rcsdiff (vers->srcfile, diff_argc, diff_argv,
-                                   *options ? options : vers->options,
-                                   use_rev1, rev1_cache, use_rev2,
-                                   label1, label2, finfo->file);
-
+       if (CVS_UNLINK (f2) < 0)
+           error (0, errno, "Failed to remove temp file `%s'", f2);
+       free ((char *)f2);
     }
 
+    if (use_rev1) free (use_rev1);
+    if (use_rev2) free (use_rev2);
     if (label1) free (label1);
     if (label2) free (label2);
 
-    switch (status)
-    {
-       case -1:                        /* fork failed */
-           error (1, errno, "fork failed while diffing %s",
-                  vers->srcfile->path);
-       case 0:                         /* everything ok */
-           err = 0;
-           break;
-       default:                        /* other error */
-           err = status;
-           break;
-    }
-
-out:
-    if( tocvsPath != NULL )
-    {
-       if (unlink_file_dir (finfo->file) < 0)
-           if (! existence_error (errno))
-               error (1, errno, "cannot remove %s", finfo->file);
-
-       rename_file (fname, finfo->file);
-       if (unlink_file (tocvsPath) < 0)
-           error (1, errno, "cannot remove %s", tocvsPath);
-       free (fname);
-    }
-
     /* Call CVS_UNLINK() rather than unlink_file() below to avoid the check
      * for noexec.
      */
-    if (tmp != NULL)
-    {
-       if (CVS_UNLINK (tmp) < 0)
-           error (0, errno, "cannot remove %s", tmp);
-       free (tmp);
-    }
-    if (rev1_cache != NULL)
+    if (rev1_cache)
     {
        if (CVS_UNLINK (rev1_cache) < 0)
            error (0, errno, "cannot remove %s", rev1_cache);
@@ -807,6 +1030,7 @@
 
     freevers_ts (&vers);
     diff_mark_errors (err);
+
     return err;
 }
 
@@ -815,7 +1039,7 @@
 /*
  * Remember the exit status for each file.
  */
-static void
+void
 diff_mark_errors (int err)
 {
     if (err > diff_errors)
@@ -873,256 +1097,17 @@
 
 
 
-/*
- * verify that a file is different
- *
- * INPUTS
- *   finfo
- *   vers
- *   empty_file
- *
- * OUTPUTS
- *   rev1_cache                Cache the contents of rev1 if we look it up.
- */
-static enum diff_file
-diff_file_nodiff (struct file_info *finfo, Vers_TS *vers,
-                  enum diff_file empty_file, char **rev1_cache)
+struct diff_info *
+get_diff_info (void)
 {
-    Vers_TS *xvers;
-    int retcode;
+    static struct diff_info di;
 
-    TRACE (TRACE_FUNCTION, "diff_file_nodiff (%s, %d)",
-           finfo->fullname ? finfo->fullname : "(null)", empty_file);
+    if (strcmp ("diff", cvs_cmd_name))
+       return NULL;
 
-    /* free up any old use_rev* variables and reset 'em */
-    if (use_rev1)
-       free (use_rev1);
-    if (use_rev2)
-       free (use_rev2);
-    use_rev1 = use_rev2 = NULL;
+    di.diff_argc = diff_argc;
+    di.diff_argv = diff_argv;
+    di.empty_files = empty_files;
 
-    if (diff_rev1 || diff_date1)
-    {
-       /* special handling for TAG_HEAD */
-       if (diff_rev1 && strcmp (diff_rev1, TAG_HEAD) == 0)
-       {
-           if (vers->vn_rcs != NULL && vers->srcfile != NULL)
-               use_rev1 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
-       }
-       else
-       {
-           xvers = Version_TS (finfo, NULL, diff_rev1, diff_date1, 1, 0);
-           if (xvers->vn_rcs != NULL)
-               use_rev1 = xstrdup (xvers->vn_rcs);
-           freevers_ts (&xvers);
-       }
-    }
-    if (diff_rev2 || diff_date2)
-    {
-       /* special handling for TAG_HEAD */
-       if (diff_rev2 && strcmp (diff_rev2, TAG_HEAD) == 0)
-       {
-           if (vers->vn_rcs && vers->srcfile)
-               use_rev2 = RCS_branch_head (vers->srcfile, vers->vn_rcs);
-       }
-       else
-       {
-           xvers = Version_TS (finfo, NULL, diff_rev2, diff_date2, 1, 0);
-           if (xvers->vn_rcs != NULL)
-               use_rev2 = xstrdup (xvers->vn_rcs);
-           freevers_ts (&xvers);
-       }
-
-       if (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1))
-       {
-           /* The first revision does not exist.  If EMPTY_FILES is
-               true, treat this as an added file.  Otherwise, warn
-               about the missing tag.  */
-           if (use_rev2 == NULL || RCS_isdead (vers->srcfile, use_rev2))
-               /* At least in the case where DIFF_REV1 and DIFF_REV2
-                * are both numeric (and non-existant (NULL), as opposed to
-                * dead?), we should be returning some kind of error (see
-                * basicb-8a0 in testsuite).  The symbolic case may be more
-                * complicated.
-                */
-               return DIFF_SAME;
-           if (empty_files)
-               return DIFF_ADDED;
-           if (use_rev1 != NULL)
-           {
-               if (diff_rev1)
-               {
-                   error (0, 0,
-                      "Tag %s refers to a dead (removed) revision in file 
`%s'.",
-                      diff_rev1, finfo->fullname);
-               }
-               else
-               {
-                   error (0, 0,
-                      "Date %s refers to a dead (removed) revision in file 
`%s'.",
-                      diff_date1, finfo->fullname);
-               }
-               error (0, 0,
-                      "No comparison available.  Pass `-N' to `%s diff'?",
-                      program_name);
-           }
-           else if (diff_rev1)
-               error (0, 0, "tag %s is not in file %s", diff_rev1,
-                      finfo->fullname);
-           else
-               error (0, 0, "no revision for date %s in file %s",
-                      diff_date1, finfo->fullname);
-           return DIFF_ERROR;
-       }
-
-       assert( use_rev1 != NULL );
-       if( use_rev2 == NULL || RCS_isdead( vers->srcfile, use_rev2 ) )
-       {
-           /* The second revision does not exist.  If EMPTY_FILES is
-               true, treat this as a removed file.  Otherwise warn
-               about the missing tag.  */
-           if (empty_files)
-               return DIFF_REMOVED;
-           if( use_rev2 != NULL )
-           {
-               if (diff_rev2)
-               {
-                   error( 0, 0,
-                      "Tag %s refers to a dead (removed) revision in file 
`%s'.",
-                      diff_rev2, finfo->fullname );
-               }
-               else
-               {
-                   error( 0, 0,
-                      "Date %s refers to a dead (removed) revision in file 
`%s'.",
-                      diff_date2, finfo->fullname );
-               }
-               error( 0, 0,
-                      "No comparison available.  Pass `-N' to `%s diff'?",
-                      program_name );
-           }
-           else if (diff_rev2)
-               error (0, 0, "tag %s is not in file %s", diff_rev2,
-                      finfo->fullname);
-           else
-               error (0, 0, "no revision for date %s in file %s",
-                      diff_date2, finfo->fullname);
-           return DIFF_ERROR;
-       }
-       /* Now, see if we really need to do the diff.  We can't assume that the
-        * files are different when the revs are.
-        */
-       assert( use_rev2 != NULL );
-       if( strcmp (use_rev1, use_rev2) == 0 )
-           return DIFF_SAME;
-       /* else fall through and do the diff */
-    }
-
-    /* If we had a r1/d1 & r2/d2, then at this point we must have a C3P0...
-     * err...  ok, then both rev1 & rev2 must have resolved to an existing,
-     * live version due to if statement we just closed.
-     */
-    assert (!(diff_rev2 || diff_date2) || (use_rev1 && use_rev2));
-
-    if ((diff_rev1 || diff_date1) &&
-       (use_rev1 == NULL || RCS_isdead (vers->srcfile, use_rev1)))
-    {
-       /* The first revision does not exist, and no second revision
-           was given.  */
-       if (empty_files)
-       {
-           if (empty_file == DIFF_REMOVED)
-               return DIFF_SAME;
-           if( user_file_rev && use_rev2 == NULL )
-               use_rev2 = xstrdup( user_file_rev );
-           return DIFF_ADDED;
-       }
-       if( use_rev1 != NULL )
-       {
-           if (diff_rev1)
-           {
-               error( 0, 0,
-                  "Tag %s refers to a dead (removed) revision in file `%s'.",
-                  diff_rev1, finfo->fullname );
-           }
-           else
-           {
-               error( 0, 0,
-                  "Date %s refers to a dead (removed) revision in file `%s'.",
-                  diff_date1, finfo->fullname );
-           }
-           error( 0, 0,
-                  "No comparison available.  Pass `-N' to `%s diff'?",
-                  program_name );
-       }
-       else if ( diff_rev1 )
-           error( 0, 0, "tag %s is not in file %s", diff_rev1,
-                  finfo->fullname );
-       else
-           error( 0, 0, "no revision for date %s in file %s",
-                  diff_date1, finfo->fullname );
-       return DIFF_ERROR;
-    }
-
-    assert( !diff_rev1 || use_rev1 );
-
-    if (user_file_rev)
-    {
-        /* drop user_file_rev into first unused use_rev */
-        if (!use_rev1) 
-           use_rev1 = xstrdup (user_file_rev);
-       else if (!use_rev2)
-           use_rev2 = xstrdup (user_file_rev);
-       /* and if not, it wasn't needed anyhow */
-       user_file_rev = NULL;
-    }
-
-    /* Now, see if we really need to do the diff.  We can't assume that the
-     * files are different when the revs are.
-     */
-    if( use_rev1 && use_rev2) 
-    {
-       if (strcmp (use_rev1, use_rev2) == 0)
-           return DIFF_SAME;
-       /* Fall through and do the diff. */
-    }
-    /* Don't want to do the timestamp check with both use_rev1 & use_rev2 set.
-     * The timestamp check is just for the default case of diffing the
-     * workspace file against its base revision.
-     */
-    else if( use_rev1 == NULL
-             || ( vers->vn_user != NULL
-                  && strcmp( use_rev1, vers->vn_user ) == 0 ) )
-    {
-       if (empty_file == DIFF_DIFFERENT
-           && vers->ts_user != NULL
-           && strcmp (vers->ts_rcs, vers->ts_user) == 0
-           && (!(*options) || strcmp (options, vers->options) == 0))
-       {
-           return DIFF_SAME;
-       }
-       if (use_rev1 == NULL
-           && (vers->vn_user[0] != '0' || vers->vn_user[1] != '\0'))
-       {
-           if (vers->vn_user[0] == '-')
-               use_rev1 = xstrdup (vers->vn_user + 1);
-           else
-               use_rev1 = xstrdup (vers->vn_user);
-       }
-    }
-
-    /* If we already know that the file is being added or removed,
-       then we don't want to do an actual file comparison here.  */
-    if (empty_file != DIFF_DIFFERENT)
-       return empty_file;
-
-    /*
-     * Run a quick cmp to see if we should bother with a full diff.
-     */
-
-    retcode = RCS_cmp_file( vers->srcfile, use_rev1, rev1_cache,
-                            use_rev2, *options ? options : vers->options,
-                           finfo->file );
-
-    return retcode == 0 ? DIFF_SAME : DIFF_DIFFERENT;
+    return &di;
 }
Index: ccvs/src/edit.c
diff -u ccvs/src/edit.c:1.91 ccvs/src/edit.c:1.92
--- ccvs/src/edit.c:1.91        Sat Feb 25 19:39:53 2006
+++ ccvs/src/edit.c     Mon Apr 24 18:50:26 2006
@@ -1,22 +1,42 @@
-/* Implementation for "cvs edit", "cvs watch on", and related commands
+/*
+ * Copyright (C) 2006 The Free Software Foundation, Inc.
+ *
+ * Implementation for "cvs edit", "cvs watch on", and related commands
+ *
+ * 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 2, 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.
+ */
 
-   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 2, 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.  */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-#include "cvs.h"
+/* Verify interface.  */
+#include "edit.h"
+
+/* GNULIB headers.  */
 #include "getline.h"
 #include "yesno.h"
+
+/* CVS headers.  */
+#include "base.h"
+#include "ignore.h"
+#include "recurse.h"
+#include "repos.h"
+
+#include "cvs.h"
 #include "watch.h"
-#include "edit.h"
 #include "fileattr.h"
 
+
+
 static bool check_edited = false;
 static int setting_default;
 static int turning_on;
@@ -318,24 +338,49 @@
 {
     Node *node;
     struct file_info finfo;
-    char *basefilename;
+    char *editbasefn, *basefn, *rev;
 
-    xchmod (filename, 1);
 
+    node = findnode_fn (ent_list, filename);
+
+    /* I'm not sure why this isn't an error.  */
+    if (!node) return;
+    rev = ((Entnode *) node->data)->version;
+
+    xchmod (filename, 1);
     mkdir_if_needed (CVSADM_BASE);
-    basefilename = Xasprintf ("%s/%s", CVSADM_BASE, filename);
-    copy_file (filename, basefilename);
-    free (basefilename);
+    basefn = make_base_file_name (filename, rev);
 
-    node = findnode_fn (ent_list, filename);
-    if (node != NULL)
+    if (!isfile (basefn))
     {
-       finfo.file = filename;
-       finfo.fullname = short_pathname;
-       finfo.update_dir = dir_name (short_pathname);
-       base_register (&finfo, ((Entnode *) node->data)->version);
-       free ((char *)finfo.update_dir);
+       /* If this client is interoperating with clients older than 1.12.14,
+        * then the CVS/Base/.#FILENAME.REV may not have been created on
+        * checkout/update/commit.
+        */
+       if (!quiet)
+       {
+           error (0, 0, "Base revision (%s) for `%s' is missing.",
+                  rev, short_pathname);
+           error (0, 0, "Using `%s' to create unedit fallback.",
+                  short_pathname);
+       }
+
+       free (basefn);
+       basefn = xstrdup (filename);
     }
+
+    editbasefn = Xasprintf ("%s/%s", CVSADM_BASE, filename);
+    if (isfile (editbasefn))
+       xchmod (editbasefn, true);
+    copy_file (basefn, editbasefn);
+    free (basefn);
+    free (editbasefn);
+
+    finfo.file = filename;
+    finfo.fullname = short_pathname;
+    finfo.update_dir = dir_name (short_pathname);
+    base_register (finfo.update_dir, finfo.file, rev);
+    free ((char *)finfo.update_dir);
 }
 
 
@@ -666,7 +711,7 @@
        Node *node;
        Entnode *entdata;
 
-       baserev = base_get (finfo);
+       baserev = base_get (finfo->update_dir, finfo->file);
        node = findnode_fn (finfo->entries, finfo->file);
        /* The case where node is NULL probably should be an error or
           something, but I don't want to think about it too hard right
@@ -699,7 +744,7 @@
                      entdata->conflict);
        }
        free (baserev);
-       base_deregister (finfo);
+       base_deregister (finfo->update_dir, finfo->file);
     }
 
     xchmod (finfo->file, 0);
Index: ccvs/src/edit.h
diff -u ccvs/src/edit.h:1.12 ccvs/src/edit.h:1.13
--- ccvs/src/edit.h:1.12        Thu Nov 10 15:13:16 2005
+++ ccvs/src/edit.h     Mon Apr 24 18:50:26 2006
@@ -1,14 +1,25 @@
-/* Interface to "cvs edit", "cvs watch on", and related features
+/*
+ * Copyright (C) 2006 The Free Software Foundation, Inc.
+ *
+ * Interface to "cvs edit", "cvs watch on", and related features
+ *
+ * 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 2, 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.
+ */
+
+#ifndef EDIT_H
+#define EDIT_H
+
+#include "hash.h"
+
 
-   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 2, 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.  */
 
 int watch_on (int argc, char **argv);
 int watch_off (int argc, char **argv);
@@ -42,3 +53,5 @@
 
 void edit_file (void *data, List *ent_list, const char *short_pathname,
                const char *filename);
+
+#endif /* EDIT_H */
Index: ccvs/src/entries.c
diff -u ccvs/src/entries.c:1.66 ccvs/src/entries.c:1.67
--- ccvs/src/entries.c:1.66     Thu Sep 22 02:22:41 2005
+++ ccvs/src/entries.c  Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -16,9 +16,23 @@
  * the Entries file.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Validate API.  */
+#include "entries.h"
+
+/* GNULIB */
 #include "getline.h"
 
+/* CVS */
+#include "base.h"
+
+#include "cvs.h"
+
+
+
 static Node *AddEntryNode (List * list, Entnode *entnode);
 
 static Entnode *fgetentent (FILE *, char *, int *);
@@ -40,7 +54,11 @@
                 const char *date, const char *ts_conflict)
 {
     Entnode *ent;
-    
+ 
+    TRACE (TRACE_FLOW,
+          "Entnode_Create (%s, %s, %s, %s, %s, %s, %s)",
+          user, vn, ts, options, tag, date, ts_conflict);
+
     /* Note that timestamp and options must be non-NULL */
     ent = xmalloc (sizeof (Entnode));
     ent->type      = type;
@@ -63,6 +81,8 @@
 static void
 Entnode_Destroy (Entnode *ent)
 {
+    TRACE (TRACE_FLOW, "Entnode_Destroy ()");
+
     free (ent->user);
     free (ent->version);
     free (ent->timestamp);
@@ -156,6 +176,7 @@
 
 /*
  * Removes the argument file from the Entries file if necessary.
+ * Deletes the base file, if it existed.
  */
 void
 Scratch_Entry (List *list, const char *fname)
@@ -169,6 +190,9 @@
     {
        if (!noexec)
        {
+           Entnode *e = node->data;
+           base_remove (fname, e->version);
+
            entfilename = CVSADM_ENTLOG;
            entfile = xfopen (entfilename, "a");
 
@@ -198,12 +222,17 @@
  */
 void
 Register (List *list, const char *fname, const char *vn, const char *ts,
-          const char *options, const char *tag, const char *date,
-          const char *ts_conflict)
+         const char *options, const char *tag, const char *date,
+         const char *ts_conflict)
 {
     Entnode *entnode;
     Node *node;
 
+    TRACE (TRACE_FUNCTION, "Register(%s, %s, %s%s%s, %s, %s %s)",
+          fname, vn, ts ? ts : "",
+          ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
+          options, tag ? tag : "", date ? date : "");
+
 #ifdef SERVER_SUPPORT
     if (server_active)
     {
@@ -211,11 +240,6 @@
     }
 #endif
 
-    TRACE (TRACE_FUNCTION, "Register(%s, %s, %s%s%s, %s, %s %s)",
-          fname, vn, ts ? ts : "",
-          ts_conflict ? "+" : "", ts_conflict ? ts_conflict : "",
-          options, tag ? tag : "", date ? date : "");
-
     entnode = Entnode_Create (ENT_FILE, fname, vn, ts, options, tag, date,
                              ts_conflict);
     node = AddEntryNode (list, entnode);
@@ -441,6 +465,8 @@
     FILE *fpin;
     int sawdir;
 
+    TRACE (TRACE_FLOW, "EntriesOpen (%s)", update_dir);
+
     /* get a fresh list... */
     entries = getlist ();
 
@@ -576,6 +602,9 @@
 {
     Node *p;
 
+    TRACE (TRACE_FLOW, "AddEntryNode (%s, %s)",
+          entdata->user, entdata->timestamp);
+
     /* was it already there? */
     if ((p  = findnode_fn (list, entdata->user)) != NULL)
     {
@@ -931,203 +960,3 @@
            delnode (p);
     }
 }
-
-
-
-/* OK, the following base_* code tracks the revisions of the files in
-   CVS/Base.  We do this in a file CVS/Baserev.  Separate from
-   CVS/Entries because it needs to go in separate data structures
-   anyway (the name in Entries must be unique), so this seemed
-   cleaner.  The business of rewriting the whole file in
-   base_deregister and base_register is the kind of thing we used to
-   do for Entries and which turned out to be slow, which is why there
-   is now the Entries.Log machinery.  So maybe from that point of
-   view it is a mistake to do this separately from Entries, I dunno.  */
-
-enum base_walk
-{
-    /* Set the revision for FILE to *REV.  */
-    BASE_REGISTER,
-    /* Get the revision for FILE and put it in a newly malloc'd string
-       in *REV, or put NULL if not mentioned.  */
-    BASE_GET,
-    /* Remove FILE.  */
-    BASE_DEREGISTER
-};
-
-static void base_walk (enum base_walk, struct file_info *, char **);
-
-/* Read through the lines in CVS/Baserev, taking the actions as documented
-   for CODE.  */
-
-static void
-base_walk (enum base_walk code, struct file_info *finfo, char **rev)
-{
-    FILE *fp;
-    char *line;
-    size_t line_allocated;
-    FILE *newf;
-    char *baserev_fullname;
-    char *baserevtmp_fullname;
-
-    line = NULL;
-    line_allocated = 0;
-    newf = NULL;
-
-    /* First compute the fullnames for the error messages.  This
-       computation probably should be broken out into a separate function,
-       as recurse.c does it too and places like Entries_Open should be
-       doing it.  */
-    if (finfo->update_dir[0] != '\0')
-    {
-       baserev_fullname = Xasprintf ("%s/%s", finfo->update_dir,
-                                     CVSADM_BASEREV);
-       baserevtmp_fullname = Xasprintf ("%s/%s", finfo->update_dir,
-                                        CVSADM_BASEREVTMP);
-    }
-    else
-    {
-       baserev_fullname = xstrdup (CVSADM_BASEREV);
-       baserevtmp_fullname = xstrdup (CVSADM_BASEREVTMP);
-    }
-
-    fp = CVS_FOPEN (CVSADM_BASEREV, "r");
-    if (fp == NULL)
-    {
-       if (!existence_error (errno))
-       {
-           error (0, errno, "cannot open %s for reading", baserev_fullname);
-           goto out;
-       }
-    }
-
-    switch (code)
-    {
-       case BASE_REGISTER:
-       case BASE_DEREGISTER:
-           newf = CVS_FOPEN (CVSADM_BASEREVTMP, "w");
-           if (newf == NULL)
-           {
-               error (0, errno, "cannot open %s for writing",
-                      baserevtmp_fullname);
-               goto out;
-           }
-           break;
-       case BASE_GET:
-           *rev = NULL;
-           break;
-    }
-
-    if (fp != NULL)
-    {
-       while (getline (&line, &line_allocated, fp) >= 0)
-       {
-           char *linefile;
-           char *p;
-           char *linerev;
-
-           if (line[0] != 'B')
-               /* Ignore, for future expansion.  */
-               continue;
-
-           linefile = line + 1;
-           p = strchr (linefile, '/');
-           if (p == NULL)
-               /* Syntax error, ignore.  */
-               continue;
-           linerev = p + 1;
-           p = strchr (linerev, '/');
-           if (p == NULL)
-               continue;
-
-           linerev[-1] = '\0';
-           if (fncmp (linefile, finfo->file) == 0)
-           {
-               switch (code)
-               {
-               case BASE_REGISTER:
-               case BASE_DEREGISTER:
-                   /* Don't copy over the old entry, we don't want it.  */
-                   break;
-               case BASE_GET:
-                   *p = '\0';
-                   *rev = xstrdup (linerev);
-                   *p = '/';
-                   goto got_it;
-               }
-           }
-           else
-           {
-               linerev[-1] = '/';
-               switch (code)
-               {
-               case BASE_REGISTER:
-               case BASE_DEREGISTER:
-                   if (fprintf (newf, "%s\n", line) < 0)
-                       error (0, errno, "error writing %s",
-                              baserevtmp_fullname);
-                   break;
-               case BASE_GET:
-                   break;
-               }
-           }
-       }
-       if (ferror (fp))
-           error (0, errno, "cannot read %s", baserev_fullname);
-    }
- got_it:
-
-    if (code == BASE_REGISTER)
-    {
-       if (fprintf (newf, "B%s/%s/\n", finfo->file, *rev) < 0)
-           error (0, errno, "error writing %s",
-                  baserevtmp_fullname);
-    }
-
- out:
-
-    if (line != NULL)
-       free (line);
-
-    if (fp != NULL)
-    {
-       if (fclose (fp) < 0)
-           error (0, errno, "cannot close %s", baserev_fullname);
-    }
-    if (newf != NULL)
-    {
-       if (fclose (newf) < 0)
-           error (0, errno, "cannot close %s", baserevtmp_fullname);
-       rename_file (CVSADM_BASEREVTMP, CVSADM_BASEREV);
-    }
-
-    free (baserev_fullname);
-    free (baserevtmp_fullname);
-}
-
-/* Return, in a newly malloc'd string, the revision for FILE in CVS/Baserev,
-   or NULL if not listed.  */
-
-char *
-base_get (struct file_info *finfo)
-{
-    char *rev;
-    base_walk (BASE_GET, finfo, &rev);
-    return rev;
-}
-
-/* Set the revision for FILE to REV.  */
-
-void
-base_register (struct file_info *finfo, char *rev)
-{
-    base_walk (BASE_REGISTER, finfo, &rev);
-}
-
-/* Remove FILE.  */
-
-void
-base_deregister (struct file_info *finfo)
-{
-    base_walk (BASE_DEREGISTER, finfo, NULL);
-}
Index: ccvs/src/fileattr.c
diff -u ccvs/src/fileattr.c:1.36 ccvs/src/fileattr.c:1.37
--- ccvs/src/fileattr.c:1.36    Thu Mar 17 22:41:06 2005
+++ ccvs/src/fileattr.c Mon Apr 24 18:50:26 2006
@@ -1,19 +1,36 @@
-/* Implementation for file attribute munging features.
+/*
+ * Copyright (C) 2006 The Free Software Foundation, Inc.
+ *
+ * Implementation for file attribute munging features.
+ *
+ * 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 2, 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.
+ */
 
-   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 2, 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.  */
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-#include "cvs.h"
-#include "getline.h"
+/* Verify interface.  */
 #include "fileattr.h"
 
+/* GNULIB headers.  */
+#include "getline.h"
+
+/* CVS headers.  */
+#include "repos.h"
+
+#include "cvs.h"
+
+
+
 static void fileattr_read (void);
 static int writeattr_proc (Node *, void *);
 
Index: ccvs/src/filesubr.c
diff -u ccvs/src/filesubr.c:1.106 ccvs/src/filesubr.c:1.107
--- ccvs/src/filesubr.c:1.106   Fri Apr  7 01:49:03 2006
+++ ccvs/src/filesubr.c Mon Apr 24 18:50:26 2006
@@ -17,29 +17,36 @@
    definitions under operating systems (like, say, Windows NT) with different
    file system semantics.  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "filesubr.h"
+
+/* GNULIB */
 #include "lstat.h"
 #include "save-cwd.h"
 #include "xsize.h"
 
+/* CVS */
+#include "cvs.h"
+
 static int deep_remove_dir (const char *path);
 
+
+
 /*
- * Copies "from" to "to".
+ * Copies FROM to TO.  Ignores NOEXEC.
  */
 void
-copy_file (const char *from, const char *to)
+force_copy_file (const char *from, const char *to)
 {
     struct stat sb;
     struct utimbuf t;
     int fdin, fdout;
     ssize_t rsize;
 
-    TRACE (TRACE_FUNCTION, "copy(%s,%s)", from, to);
-
-    if (noexec)
-       return;
-
     /* If the file to be copied is a link or a device, then just create
        the new link or device appropriately. */
     if ((rsize = islink (from)) > 0)
@@ -109,6 +116,19 @@
 
 
 
+/*
+ * Copies FROM to TO.  Honors NOEXEC.
+ */
+void
+copy_file (const char *from, const char *to)
+{
+    TRACE (TRACE_FUNCTION, "copy (%s, %s)", from, to);
+    if (noexec) return;
+    force_copy_file (from, to);
+}
+
+
+
 /* FIXME-krp: these functions would benefit from caching the char * &
    stat buf.  */
 
@@ -131,6 +151,11 @@
 /*
  * Returns 0 if the argument file is not a symbolic link.
  * Returns size of the link if it is a symbolic link.
+ *
+ * FIXME: Is there a good reason that the off_t specified by POSIX for st_size
+ *        (http://www.opengroup.org/susv3xbd/sys/stat.h.html) is converted to
+ *        ssize_t here?  rcs.h uses off_t, so it's not because off_t isn't
+ *        portable.
  */
 ssize_t
 islink (const char *file)
@@ -324,6 +349,8 @@
     return 0;
 }
 
+
+
 /*
  * Change the mode of a file, either adding write permissions, or removing
  * all write permissions.  Either change honors the current umask setting.
@@ -331,8 +358,8 @@
  * Don't do anything if PreservePermissions is set to `yes'.  This may
  * have unexpected consequences for some uses of xchmod.
  */
-void
-xchmod (const char *fname, int writable)
+static void
+ixchmod (const char *fname, bool writable, bool noexec)
 {
     struct stat sb;
     mode_t mode, oumask;
@@ -351,16 +378,12 @@
     oumask = umask (0);
     (void) umask (oumask);
     if (writable)
-    {
        mode = sb.st_mode | (~oumask
                             & (((sb.st_mode & S_IRUSR) ? S_IWUSR : 0)
                                | ((sb.st_mode & S_IRGRP) ? S_IWGRP : 0)
                                | ((sb.st_mode & S_IROTH) ? S_IWOTH : 0)));
-    }
     else
-    {
        mode = sb.st_mode & ~(S_IWRITE | S_IWGRP | S_IWOTH) & ~oumask;
-    }
 
     TRACE (TRACE_FUNCTION, "chmod(%s,%o)", fname, (unsigned int) mode);
 
@@ -371,6 +394,26 @@
        error (0, errno, "cannot change mode of file %s", fname);
 }
 
+
+
+/* See description for ixchmod.  Ignores NOEXEC.  */
+void
+force_xchmod (const char *fname, bool writable)
+{
+    ixchmod (fname, writable, false);
+}
+
+
+
+/* See description for ixchmod.  Honors NOEXEC.  */
+void
+xchmod (const char *fname, bool writable)
+{
+    ixchmod (fname, writable, noexec);
+}
+
+
+
 /*
  * Rename a file and die if it fails
  */
@@ -387,7 +430,8 @@
 }
 
 /*
- * unlink a file, if possible.
+ * unlink a file, if possible.  Use CVS_UNLINK if you want to ignore the
+ * noexec flag.
  */
 int
 unlink_file (const char *f)
Index: ccvs/src/find_names.c
diff -u ccvs/src/find_names.c:1.43 ccvs/src/find_names.c:1.44
--- ccvs/src/find_names.c:1.43  Thu May 26 17:48:06 2005
+++ ccvs/src/find_names.c       Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -21,9 +21,20 @@
  * repository (and optionally the attic)
  */
 
-#include "cvs.h"
-#include <glob.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* ANSI C headers.  */
 #include <assert.h>
+#include <glob.h>
+
+/* CVS headers.  */
+#include "recurse.h"
+
+#include "cvs.h"
+
+
 
 static int find_dirs (char *dir, List * list, int checkadm,
                            List *entries);
Index: ccvs/src/hash.c
diff -u ccvs/src/hash.c:1.48 ccvs/src/hash.c:1.49
--- ccvs/src/hash.c:1.48        Mon May  9 18:22:12 2005
+++ ccvs/src/hash.c     Mon Apr 24 18:50:26 2006
@@ -12,6 +12,14 @@
  * Polk's hash list manager.  So cool.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "hash.h"
+
+/* CVS */
 #include "cvs.h"
 
 /* Global caches.  The idea is that we maintain a linked list of "free"d
@@ -523,6 +531,7 @@
     case VARIABLE:     return "VARIABLE";
     case RCSFIELD:     return "RCSFIELD";
     case RCSCMPFLD:    return "RCSCMPFLD";
+    case RCSSTRING:    return "RCSSTRING";
     }
 
     return "<trash>";
Index: ccvs/src/hash.h
diff -u ccvs/src/hash.h:1.21 ccvs/src/hash.h:1.22
--- ccvs/src/hash.h:1.21        Mon May  9 18:22:16 2005
+++ ccvs/src/hash.h     Mon Apr 24 18:50:26 2006
@@ -10,6 +10,11 @@
  * specified in the README file that comes with the CVS source distribution.
  */
 
+#ifndef HASH_H
+#define HASH_H
+
+#include <stddef.h>
+
 /*
  * The number of buckets for the hash table contained in each list.  This
  * should probably be prime.
@@ -23,7 +28,7 @@
 {
     NT_UNKNOWN, HEADER, ENTRIES, FILES, LIST, RCSNODE,
     RCSVERS, DIRS, UPDATE, LOCK, NDBMNODE, FILEATTR,
-    VARIABLE, RCSFIELD, RCSCMPFLD
+    VARIABLE, RCSFIELD, RCSCMPFLD, RCSSTRING
 };
 typedef enum ntype Ntype;
 
@@ -36,6 +41,7 @@
     struct node *hashprev;
     char *key;
     void *data;
+    size_t len;                        /* Length of DATA.  */
     void (*delproc) (struct node *);
 };
 typedef struct node Node;
@@ -64,3 +70,5 @@
 void freenode (Node *p);
 void sortlist (List *list, int (*)(const Node *, const Node *));
 int fsortcmp (const Node *p, const Node *q);
+
+#endif /* HASH_H */
Index: ccvs/src/history.c
diff -u ccvs/src/history.c:1.96 ccvs/src/history.c:1.97
--- ccvs/src/history.c:1.96     Thu Feb  2 13:13:02 2006
+++ ccvs/src/history.c  Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1994-2006 The 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
@@ -12,6 +12,24 @@
  * GNU General Public License for more details.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "history.h"
+
+/* GNULIB headers.  */
+#include "save-cwd.h"
+
+/* CVS headers.  */
+#include "ignore.h"
+#include "repos.h"
+
+#include "cvs.h"
+
+
+
 /* **************** History of Users and Module ****************
  *
  * LOGGING:  Append record to "${CVSROOT}/CVSROOTADM/CVSROOTADM_HISTORY".
@@ -187,9 +205,7 @@
  *
  */
 
-#include "cvs.h"
-#include "history.h"
-#include "save-cwd.h"
+
 
 static struct hrec
 {
Index: ccvs/src/ignore.c
diff -u ccvs/src/ignore.c:1.56 ccvs/src/ignore.c:1.57
--- ccvs/src/ignore.c:1.56      Fri Sep  2 21:51:08 2005
+++ ccvs/src/ignore.c   Mon Apr 24 18:50:26 2006
@@ -1,21 +1,39 @@
-/* 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 2, 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.  */
+/*
+ * Copyright (C) 2006 The 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 2, 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.
+ */
 
 /*
  * .cvsignore file support contributed by David G. Grubbs <address@hidden>
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "ignore.h"
+
+/* GNULIB headers.  */
 #include "getline.h"
 #include "lstat.h"
 
+/* CVS headers.  */
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 /*
  * Ignore file section.
  * 
Index: ccvs/src/import.c
diff -u ccvs/src/import.c:1.175 ccvs/src/import.c:1.176
--- ccvs/src/import.c:1.175     Fri Sep  2 21:51:08 2005
+++ ccvs/src/import.c   Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -21,10 +21,24 @@
  * Additional arguments specify more Vendor Release Tags.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
+#include "base64.h"
 #include "lstat.h"
 #include "save-cwd.h"
 
+/* CVS headers.  */
+#include "ignore.h"
+#include "logmsg.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 static char *get_comment (const char *user);
 static int add_rev (char *message, RCSNode *rcs, char *vfile,
                          char *vers);
@@ -476,6 +490,12 @@
            if (server_active && strcmp (dp->d_name, CVSADM) == 0)
                goto one_more_time_boys;
 
+           /* FIXME: .#filename.sig is where the server currently saves the
+            * signature data when available.  For now just ignore it.
+            */
+           if (server_active && !fnmatch (".#*.sig", dp->d_name, 0))
+               goto one_more_time_boys;
+
            if (ign_name (dp->d_name))
            {
                add_log ('I', dp->d_name);
@@ -702,7 +722,7 @@
            not NULL?  */
        expand = (vers->srcfile->expand != NULL
                  && vers->srcfile->expand[0] == 'b') ? "-kb" : "-ko";
-       different = RCS_cmp_file (vers->srcfile, vers->vn_rcs, NULL,
+       different = RCS_cmp_file (vers->srcfile, vers->tag, vers->vn_rcs, NULL,
                                  NULL, expand, vfile);
        if (tocvsPath)
            if (unlink_file_dir (tocvsPath) < 0)
@@ -1054,6 +1074,11 @@
  * RETURNS
  *   Return value is 0 for success, or nonzero for failure (in which
  *   case an error message will have already been printed).
+ *
+ * FIXME
+ *   I see very few reasons why this shoudn't be merged with RCS_rewrite ()
+ *   or better yet RCS_checkin () and I would guess this would ease
+ *   maintenance.
  */
 int
 add_rcs_file (const char *message, const char *rcs, const char *user,
@@ -1076,6 +1101,10 @@
     mode_t file_type;
     char *dead_revision = NULL;
 
+    TRACE (TRACE_FUNCTION,
+          "add_rcs_file (`%s', `%s', `%s', `%s', `%s', `%s', `%s')",
+          rcs, user, add_vhead, key_opt, add_vbranch, vtag, desctext);
+
     if (noexec)
        return 0;
 
@@ -1307,6 +1336,30 @@
        if (fprintf (fprcs, "commitid        %s;\012", global_session_id) < 0)
            goto write_error;
 
+       if (!add_vbranch
+           && (get_sign_commits (true) || have_sigfile (userfile)))
+       {
+           char *rawsig;
+           size_t rawlen;
+           char *b64sig;
+
+           TRACE (TRACE_DATA, "add_rcs_file: found signature.");
+
+           rawsig = get_signature ("", userfile,
+                                   key_opt && !strcmp (key_opt, "b"),
+                                   &rawlen);
+           base64_encode_alloc (rawsig, rawlen, &b64sig);
+           if (!b64sig) xalloc_die ();
+           free (rawsig);
+
+           if (fprintf (fprcs, "openpgp-signatures        %s;\012",
+                        b64sig) < 0)
+               goto write_error;
+           free (b64sig);
+       }
+       else
+           TRACE (TRACE_DATA, "add_rcs_file: signature not found.");
+
 #ifdef PRESERVE_PERMISSIONS_SUPPORT
        /* Store initial permissions if necessary. */
        if (config->preserve_perms)
@@ -1317,7 +1370,7 @@
        }
 #endif
 
-       if (add_vbranch != NULL)
+       if (add_vbranch)
        {
            if (fprintf (fprcs, "\012%s.1\012", add_vbranch) < 0 ||
                fprintf (fprcs, "date     %s;  author %s;  state Exp;\012",
@@ -1327,6 +1380,29 @@
                fprintf (fprcs, "commitid        %s;\012", global_session_id) < 
0)
                goto write_error;
 
+           if (get_sign_commits (true) || have_sigfile (userfile))
+           {
+               char *rawsig;
+               size_t rawlen;
+               char *b64sig;
+
+               TRACE (TRACE_DATA, "add_rcs_file: found signature.");
+
+               rawsig = get_signature ("", userfile,
+                                       key_opt && !strcmp (key_opt, "b"),
+                                       &rawlen);
+               base64_encode_alloc (rawsig, rawlen, &b64sig);
+               if (!b64sig) xalloc_die ();
+               free (rawsig);
+
+               if (fprintf (fprcs, "openpgp-signatures        %s;\012",
+                            b64sig) < 0)
+                   goto write_error;
+               free (b64sig);
+           }
+           else
+               TRACE (TRACE_DATA, "add_rcs_file: signature not found.");
+
 #ifdef PRESERVE_PERMISSIONS_SUPPORT
            /* Store initial permissions if necessary. */
            if (config->preserve_perms)
Index: ccvs/src/lock.c
diff -u ccvs/src/lock.c:1.118 ccvs/src/lock.c:1.119
--- ccvs/src/lock.c:1.118       Mon Feb 27 16:54:15 2006
+++ ccvs/src/lock.c     Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -69,6 +69,14 @@
    which can handle various connections in one process, but there is
    much, much work still to be done before this is feasible.  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS headers.  */
+#include "recurse.h"
+#include "repos.h"
+
 #include "cvs.h"
 
 
Index: ccvs/src/log.c
diff -u ccvs/src/log.c:1.103 ccvs/src/log.c:1.104
--- ccvs/src/log.c:1.103        Tue Mar 22 13:19:57 2005
+++ ccvs/src/log.c      Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -17,9 +17,26 @@
  * (recursive by default).
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h> 
+#endif
+
+/* ANSI C Headers.  */
 #include <assert.h>
 
+/* GNULIB Headers.  */
+#include "base64.h"
+
+/* CVS Headers.  */
+#include "gpg.h"
+#include "ignore.h"
+#include "recurse.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 /* This structure holds information parsed from the -r option.  */
 
 struct option_revlist
@@ -1669,6 +1686,43 @@
        cvs_output ("\n", 1);
     }
 
+    p = findnode (ver->other_delta, "openpgp-signatures");
+    if (p)
+    {
+       char *rawsig;
+       size_t rawsiglen;
+       struct buffer *membuf;
+       struct openpgp_signature sig;
+       int rc;
+
+       if (!base64_decode_alloc (p->data, p->len, &rawsig, &rawsiglen))
+           error (0, 0, "Unable to base64-decode OpenPGP signature.");
+       if (!rawsig)
+           xalloc_die ();
+
+       membuf = buf_nonio_initialize (NULL);
+       buf_output (membuf, rawsig, rawsiglen);
+
+       while (!(rc = parse_signature (membuf, &sig)))
+       {
+           /* GnuPG truncates this too.  */
+           unsigned long long printablesig = sig.keyid & 0xFFFFFFFF;
+           char *hexsig;
+           cvs_output_tagged ("openpgp-keyid-header",
+                              "OpenPGP signature using key ID 0x");
+           hexsig = Xasprintf ("%llx", printablesig);
+           cvs_output_tagged ("openpgp-keyid", hexsig);
+           free (hexsig);
+           cvs_output_tagged ("openpgp-keyid-footer", ";");
+           cvs_output_tagged ("newline", NULL);
+       }
+
+       if (rc == -2)
+           error (1, 0, "Memory allocation failure parsing signature.");
+
+       buf_free (membuf);
+    }
+
     p = findnode (ver->other, "log");
     /* The p->date == NULL case is the normal one for an empty log
        message (rcs-14 in sanity.sh).  I don't think the case where
Index: ccvs/src/logmsg.c
diff -u ccvs/src/logmsg.c:1.100 ccvs/src/logmsg.c:1.101
--- ccvs/src/logmsg.c:1.100     Wed Apr  5 09:07:34 2006
+++ ccvs/src/logmsg.c   Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -11,10 +11,23 @@
  * specified in the README file that comes with the CVS source distribution.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-#include "cvs.h"
+/* Verify interface.  */
+#include "logmsg.h"
+
+/* GNULIB Headers.  */
 #include "getline.h"
 
+/* CVS Headers.  */
+#include "repos.h"
+
+#include "cvs.h"
+
+
+
 static int find_type (Node * p, void *closure);
 static int fmt_proc (Node * p, void *closure);
 static int logfile_write (const char *repository, const char *filter,
Index: ccvs/src/ls.c
diff -u ccvs/src/ls.c:1.18 ccvs/src/ls.c:1.19
--- ccvs/src/ls.c:1.18  Wed Feb 23 20:45:30 2005
+++ ccvs/src/ls.c       Mon Apr 24 18:50:26 2006
@@ -1,8 +1,9 @@
 /*
+ * Copyright (C) 2006 The Free Software Foundation, Inc.
+ * Copyright (c) 2004, Derek R. Price & Ximbiot <http://ximbiot.com>
+ * Copyright (c) 2001, Tony Hoyle
  * Copyright (c) 1992, Brian Berliner and Jeff Polk
  * Copyright (c) 1989-1992, Brian Berliner
- * Copyright (c) 2001, Tony Hoyle
- * Copyright (c) 2004, Derek R. Price & Ximbiot <http://ximbiot.com>
  *
  * You may distribute under the terms of the GNU General Public License as
  * specified in the README file that comes with the CVS source distribution.
@@ -10,9 +11,22 @@
  * Query CVS/Entries from server
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* ANSI C headers.  */
 #include <stdbool.h>
 
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 static int ls_proc (int argc, char **argv, char *xwhere, char *mwhere,
                     char *mfile, int shorten, int local, char *mname,
                     char *msg);
Index: ccvs/src/main.c
diff -u ccvs/src/main.c:1.265 ccvs/src/main.c:1.266
--- ccvs/src/main.c:1.265       Wed Apr  5 14:19:05 2006
+++ ccvs/src/main.c     Mon Apr 24 18:50:26 2006
@@ -17,7 +17,9 @@
  *
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
 /* GNULIB Headers.  */
 #include "closeout.h"
@@ -27,6 +29,11 @@
 
 /* CVS Headers.  */
 #include "command_line_opt.h"
+#include "gpg.h"
+#include "sign.h"
+#include "verify.h"
+
+#include "cvs.h"
 
 
 
@@ -45,7 +52,6 @@
 int cvswrite = !CVSREAD_DFLT;
 int really_quiet = 0;
 int quiet = 0;
-int trace = 0;
 int noexec = 0;
 int readonlyfs = 0;
 int logoff = 0;
@@ -66,9 +72,8 @@
 struct config *config;
 
 
-
+bool suppress_bases = false;
 mode_t cvsumask = UMASK_DFLT;
-
 char *CurDir;
 
 /*
@@ -182,10 +187,12 @@
 #ifdef SERVER_SUPPORT
     { "server",   NULL,       NULL,        server,    
CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
 #endif
+    { "sign",   "sig",        NULL,        sign,      0 },
     { "status",   "st",       "stat",      cvsstatus, CVS_CMD_USES_WORK_DIR },
     { "tag",      "ta",       "freeze",    cvstag,    
CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "unedit",   NULL,       NULL,        unedit,    
CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "update",   "up",       "upd",       update,    CVS_CMD_USES_WORK_DIR },
+    { "verify",   "ver",      NULL,        verify,    0 },
     { "version",  "ve",       "ver",       version,   0 },
     { "watch",    NULL,       NULL,        watch,     
CVS_CMD_MODIFIES_REPOSITORY | CVS_CMD_USES_WORK_DIR },
     { "watchers", NULL,       NULL,        watchers,  CVS_CMD_USES_WORK_DIR },
@@ -307,6 +314,7 @@
     "    -d CVS_root  Overrides $CVSROOT as the root of the CVS tree.\n",
     "    -f           Do not use the ~/.cvsrc file.\n",
 #ifdef CLIENT_SUPPORT
+    "    -B           Suppress use of base files.\n",
     "    -z #         Request compression level '#' for net traffic.\n",
 #ifdef ENCRYPTION
     "    -x           Encrypt all net traffic.\n",
@@ -314,6 +322,27 @@
     "    -a           Authenticate all net traffic.\n",
 #endif
     "    -s VAR=VAL   Set CVS user variable.\n",
+    "\n",
+    "    -g           Force OpenPGP commit signatures (default 
autonegotiates).\n",
+    "    --sign[=(on | off | auto)] | --no-sign\n",
+    "                 Force (or forbid) OpenPGP commit signatures\n",
+    "                 (default autonegotiates).\n",
+    "    -G TEMPLATE\n",
+    "    --sign-template TEMPLATE\n",
+    "                 Use TEMPLATE to generate OpenPGP signatures.\n",
+    "    --sign-arg ARG\n",
+    "                 Pass ARG to OpenPGP TEMPLATE when sigining.\n",
+    "    --openpgp-textmode ARG\n",
+    "                 Pass ARG to OpenPGP TEMPLATE when verifying or\n",
+    "                 generating signatures.\n",
+    "    --verify[=(off | warn | fatal)] | --no-verify\n",
+    "                 Force (or forbid) OpenPGP signature verification\n",
+    "                 on checkout (default warns on failure).\n",
+    "    -G TEMPLATE\n",
+    "    --verify-template TEMPLATE\n",
+    "                 Use TEMPLATE to verify OpenPGP signatures.\n",
+    "    --verify-arg ARG\n",
+    "                 Pass ARG to OpenPGP TEMPLATE when verifying.\n",
     "(Specify the --help option for a list of other help options)\n",
     NULL
 };
@@ -525,7 +554,7 @@
     int help = 0;              /* Has the user asked for help?  This
                                   lets us support the `cvs -H cmd'
                                   convention to give help for cmd. */
-    static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
+    static const char short_options[] = "+QBqrwtnRvb:T:e:d:Hfz:s:xag::G:";
     static struct option long_options[] =
     {
         {"help", 0, NULL, 'H'},
@@ -533,9 +562,19 @@
        {"help-commands", 0, NULL, 1},
        {"help-synonyms", 0, NULL, 2},
        {"help-options", 0, NULL, 4},
+       {"sign", optional_argument, NULL, 'g'},
+       {"no-sign", 0, NULL, 5},
+       {"sign-template", required_argument, NULL, 'G'},
+       {"sign-arg", required_argument, NULL, 6},
+       {"openpgp-textmode", required_argument, NULL, 7},
+       {"no-openpgp-textmode", 0, NULL, 8},
+       {"verify", optional_argument, NULL, 9},
+       {"no-verify", 0, NULL, 10},
+       {"verify-template", required_argument, NULL, 11},
+       {"verify-arg", required_argument, NULL, 12},
 #ifdef SERVER_SUPPORT
        {"allow-root", required_argument, NULL, 3},
-       {"timeout", required_argument, NULL, 5},
+       {"timeout", required_argument, NULL, 13},
 #endif /* SERVER_SUPPORT */
         {0, 0, 0, 0}
     };
@@ -562,8 +601,9 @@
 #endif
 
     /*
-     * Just save the last component of the path for error messages
+     * Initialize globals.
      */
+    /* Just save the last component of the path for error messages.  */
     program_path = xstrdup (argv[0]);
 #ifdef ARGV0_NOT_PROGRAM_NAME
     /* On some systems, e.g. VMS, argv[0] is not the name of the command
@@ -573,6 +613,7 @@
     program_name = last_component (argv[0]);
 #endif
 
+
     /*
      * Query the environment variables up-front, so that
      * they can be overridden by command line arguments
@@ -589,6 +630,53 @@
        readonlyfs = 1;
        logoff = 1;
     }
+    if ((cp = getenv (CVS_VERIFY_CHECKOUTS_ENV)))
+    {
+       if (!strcasecmp (cp, "warn"))
+           set_verify_checkouts (VERIFY_WARN);
+       else if (!strcasecmp (cp, "fatal"))
+           set_verify_checkouts (VERIFY_FATAL);
+       else
+       {
+           bool on;
+           if (readBool ("environment", CVS_VERIFY_CHECKOUTS_ENV, cp, &on))
+           {
+               if (on)
+                   set_verify_checkouts (VERIFY_FATAL);
+               else
+                   set_verify_checkouts (VERIFY_OFF);
+           }
+           else
+               error (1, 0,
+                      "Unrecognized content (`%s') in $%s",
+                      cp, CVS_VERIFY_CHECKOUTS_ENV);
+       }
+    }
+    if ((cp = getenv (CVS_SIGN_COMMITS_ENV)))
+    {
+       if (!strcasecmp (cp, "auto")
+           || !strcasecmp (cp, "server"))
+           set_sign_commits (SIGN_DEFAULT);
+       else if (!strcasecmp (cp, ""))
+           set_sign_commits (SIGN_NEVER);
+       else
+       {
+           bool on;
+           if (readBool ("environment", CVS_SIGN_COMMITS_ENV, cp, &on))
+           {
+               if (on)
+                   set_sign_commits (SIGN_ALWAYS);
+               else
+                   set_sign_commits (SIGN_NEVER);
+           }
+           else
+               error (0, 0,
+                      "Unrecognized content (`%s') in $%s ignored",
+                      cp, CVS_SIGN_COMMITS_ENV);
+       }
+    } 
+    if ((cp = getenv (CVS_VERIFY_TEMPLATE_ENV)))
+       set_verify_template (cp);
 
     /* Set this to 0 to force getopt initialization.  getopt() sets
        this to 1 internally.  */
@@ -655,12 +743,85 @@
                /* --help-options */
                usage (opt_usage);
                break;
+           case 'g':
+               /* --sign */
+               if (optarg)
+               {
+                   if (!strcasecmp (optarg, "auto")
+                       || !strcasecmp (optarg, "server"))
+                       set_sign_commits (SIGN_DEFAULT);
+                   else if (!strcasecmp (optarg, "on"))
+                       set_sign_commits (SIGN_ALWAYS);
+                   else if (!strcasecmp (optarg, "off"))
+                       set_sign_commits (SIGN_NEVER);
+                   else
+                       error (1, 0, "Unrecognized argument to --sign (`%s')",
+                              optarg);
+               }
+               else
+                   set_sign_commits (SIGN_ALWAYS);
+               break;
+           case 5:
+               /* --no-sign */
+               set_sign_commits (SIGN_NEVER);
+               break;
+           case 'G':
+               /* --sign-template */
+               set_sign_template (optarg);
+               break;
+           case 6:
+               /* --sign-arg */
+               add_sign_arg (optarg);
+               break;
+           case 7:
+               /* --openpgp-textmode */
+               set_openpgp_textmode (optarg);
+               break;
+           case 8:
+               /* --no-openpgp-textmode */
+               set_openpgp_textmode ("");
+               break;
+           case 9:
+               /* --verify */
+               if (optarg)
+               {
+                   if (!strcasecmp (optarg, "off")
+                       || !strcasecmp (optarg, "never")
+                       || !strcasecmp (optarg, "false"))
+                       set_verify_checkouts (VERIFY_OFF);
+                   else if (!strcasecmp (optarg, "warn"))
+                       set_verify_checkouts (VERIFY_WARN);
+                   else if (!strcasecmp (optarg, "always")
+                            || !strcasecmp (optarg, "fatal")
+                            || !strcasecmp (optarg, "on")
+                            || !strcasecmp (optarg, "true"))
+                       set_verify_checkouts (VERIFY_FATAL);
+                   else
+                       error (1, 0,
+                              "Unrecognized argument to --verify (`%s')",
+                              optarg);
+               }
+               else
+                   set_verify_checkouts (VERIFY_FATAL);
+               break;
+           case 10:
+               /* --no-verify */
+               set_verify_checkouts (VERIFY_OFF);
+               break;
+           case 11:
+               /* --verify-template */
+               set_verify_template (optarg);
+               break;
+           case 12:
+               /* --verify-arg */
+               add_verify_arg (optarg);
+               break;
 #ifdef SERVER_SUPPORT
            case 3:
                /* --allow-root */
                root_allow_add (optarg, gConfigPath);
                break;
-           case 5:
+           case 13:
                /* --timeout */
                connection_timeout = strtol (optarg, &end, 10);
                if (*end != '\0')
@@ -776,6 +937,9 @@
                 * `cvs -z -n up' which read -n as the argument to -z without
                 * complaining.  */
                break;
+           case 'B':
+               suppress_bases = true;
+               break;
            case 's':
                variable_set (optarg);
                break;
@@ -909,6 +1073,9 @@
                       CVSUMASK_ENV, cp);
        }
 
+       if (getenv (CVSNOBASES_ENV))
+           suppress_bases = true;
+
        /* HOSTNAME & SERVER_HOSTNAME need to be set before they are
         * potentially used in gserver_authenticate_connection() (called from
         * pserver_authenticate_connection, below).
Index: ccvs/src/mkmodules.c
diff -u ccvs/src/mkmodules.c:1.96 ccvs/src/mkmodules.c:1.97
--- ccvs/src/mkmodules.c:1.96   Fri Jan 13 21:21:58 2006
+++ ccvs/src/mkmodules.c        Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -10,11 +10,22 @@
  * You may distribute under the terms of the GNU General Public License as
  * specified in the README file that comes with the CVS kit.  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "getline.h"
-#include "history.h"
 #include "save-cwd.h"
 
+/* CVS headers.  */
+#include "history.h"
+#include "ignore.h"
+
+#include "cvs.h"
+
+
+
 #ifndef DBLKSIZ
 #define        DBLKSIZ 4096                    /* since GNU ndbm doesn't 
define it */
 #endif
Index: ccvs/src/modules.c
diff -u ccvs/src/modules.c:1.98 ccvs/src/modules.c:1.99
--- ccvs/src/modules.c:1.98     Wed Aug 31 16:51:01 2005
+++ ccvs/src/modules.c  Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -26,10 +26,20 @@
  *     command line.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "save-cwd.h"
 
-
+/* CVS headers.  */
+#include "ignore.h"
+
+#include "cvs.h"
+
+
+
 /* Defines related to the syntax of the modules file.  */
 
 /* Options in modules file.  Note that it is OK to use GNU getopt features;
Index: ccvs/src/no_diff.c
diff -u ccvs/src/no_diff.c:1.38 ccvs/src/no_diff.c:1.39
--- ccvs/src/no_diff.c:1.38     Thu Mar 17 17:15:19 2005
+++ ccvs/src/no_diff.c  Mon Apr 24 18:50:26 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -19,8 +19,30 @@
  * returns 0 if no differences are found and non-zero otherwise
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "no_diff.h"
+
+/* ANSI C headers.  */
 #include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* GNULIB headers.  */
+#include "error.h"
+#include "xalloc.h"
+
+/* CVS headers.  */
+#include "rcs.h"
+#include "server.h"
+#include "system.h"
+#include "vers_ts.h"
+#include "wrapper.h"
+
+
 
 int
 No_Difference (struct file_info *finfo, Vers_TS *vers)
@@ -53,7 +75,8 @@
        options = xstrdup ("");
 
     tocvsPath = wrap_tocvs_process_file (finfo->file);
-    retcode = RCS_cmp_file (vers->srcfile, vers->vn_user, NULL, NULL, options,
+    retcode = RCS_cmp_file (vers->srcfile, vers->tag, vers->vn_user, NULL,
+                           NULL, options,
                            tocvsPath == NULL ? finfo->file : tocvsPath);
     if (retcode == 0)
     {
@@ -87,7 +110,7 @@
        /* Need to call unlink myself because the noexec variable
         * has been set to 1.  */
        TRACE (TRACE_FUNCTION, "unlink (%s)", tocvsPath);
-       if ( CVS_UNLINK (tocvsPath) < 0)
+       if (CVS_UNLINK (tocvsPath) < 0)
            error (0, errno, "could not remove %s", tocvsPath);
     }
 
Index: ccvs/src/parseinfo.c
diff -u ccvs/src/parseinfo.c:1.85 ccvs/src/parseinfo.c:1.86
--- ccvs/src/parseinfo.c:1.85   Sat Nov 12 20:27:10 2005
+++ ccvs/src/parseinfo.c        Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -11,9 +11,21 @@
  * specified in the README file that comes with the CVS source distribution.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "parseinfo.h"
+
+/* GNULIB includes.  */
 #include "getline.h"
+
+/* CVS includes.  */
 #include "history.h"
+#include "repos.h"
+
+#include "cvs.h"
 
 
 /* From admin.c.  */
@@ -22,6 +34,15 @@
 
 
 
+/***
+ ***
+ ***   CVSROOT/config options
+ ***
+ ***/
+struct config *config;
+
+
+
 /*
  * Parse the INFOFILE file for the specified REPOSITORY.  Invoke CALLPROC for
  * the first line in the file that matches the REPOSITORY, or if ALL != 0, any
@@ -529,7 +550,11 @@
 
        /* The first '=' separates keyword from value.  */
        p = strchr (line, '=');
-       if (!p)
+       if (p)
+           *p++ = '\0';
+       else if (
+                /* The following keys have optional arguments.  */
+                strcmp (line, "VerifyCommits"))
        {
            if (!parse_error (infopath, ln))
                error (0, 0,
@@ -538,7 +563,6 @@
            continue;
        }
 
-       *p++ = '\0';
 
        if (strcmp (line, "RCSBIN") == 0)
        {
@@ -703,6 +727,60 @@
            readSizeT (infopath, "MaxCompressionLevel", p,
                       &retval->MaxCompressionLevel);
 #endif /* SERVER_SUPPORT */
+       else if (!strcmp (line, "VerifyCommits"))
+       {
+           if (retval->VerifyCommits != VERIFY_DEFAULT)
+               error (0, 0,
+"%s [%u]: warning: duplicate VerifyCommits entry found.",
+                      infopath, ln);
+
+           if (!p)
+               retval->VerifyCommits = VERIFY_FATAL;
+           else if (!strcasecmp (p, "fatal"))
+               retval->VerifyCommits = VERIFY_FATAL;
+           else if (!strcasecmp (p, "warn"))
+               retval->VerifyCommits = VERIFY_WARN;
+           else
+           {
+               bool on;
+               if (readBool (infopath, "VerifyCommits", p, &on))
+               {
+                   if (on) retval->VerifyCommits = VERIFY_FATAL;
+                   else retval->VerifyCommits = VERIFY_OFF;
+               }
+               /* else
+                *   A warning was already printed.  Don't munge any
+                *   previous value on error.
+                */
+           }
+       }
+       else if (!strcmp (line, "VerifyTemplate"))
+       {
+           if (retval->VerifyTemplate)
+           {
+               free (retval->VerifyTemplate);
+               error (0, 0,
+"%s [%u]: warning: duplicate VerifyTemplate entry found.",
+                      infopath, ln);
+           }
+           retval->VerifyTemplate = xstrdup (p);
+       }
+       else if (!strcmp (line, "OpenPGPTextmode"))
+       {
+           if (retval->OpenPGPTextmode)
+           {
+               free (retval->OpenPGPTextmode);
+               error (0, 0,
+"%s [%u]: warning: duplicate OpenPGPTextmode entry found.",
+                      infopath, ln);
+           }
+           retval->OpenPGPTextmode = xstrdup (p);
+       }
+       else if (!strcmp (line, "VerifyArg"))
+       {
+           if (!retval->VerifyArgs) retval->VerifyArgs = getlist ();
+           push_string (retval->VerifyArgs, xstrdup (p));
+       }
        else
            /* We may be dealing with a keyword which was added in a
               subsequent version of CVS.  In that case it is a good idea
Index: ccvs/src/parseinfo.h
diff -u ccvs/src/parseinfo.h:1.7 ccvs/src/parseinfo.h:1.8
--- ccvs/src/parseinfo.h:1.7    Tue Sep  6 00:40:50 2005
+++ ccvs/src/parseinfo.h        Mon Apr 24 18:50:27 2006
@@ -1,10 +1,10 @@
 /*
- *    Copyright (c) 2004  Derek Price, Ximbiot <http://ximbiot.com>,
- *                        and the Free Software Foundation
+ *  Copyright (C) 2004, 2006 The Free Software Foundation, Inc.
+ *  Copyright (C) 2004  Derek Price, Ximbiot <http://ximbiot.com>
  *
- *    You may distribute under the terms of the GNU General Public License
- *    as specified in the README file that comes with the CVS source
- *    distribution.
+ *  You may distribute under the terms of the GNU General Public License
+ *  as specified in the README file that comes with the CVS source
+ *  distribution.
  *
  * This is the header file for definitions and functions shared by parseinfo.c
  * with other portions of CVS.
@@ -12,6 +12,16 @@
 #ifndef PARSEINFO_H
 # define PARSEINFO_H
 
+/* ANSI C headers.  */
+#include <stdbool.h>
+#include <stddef.h>    /* Get size_t.  */
+
+/* CVS headers.  */
+#include "root.h"
+#include "verify.h"
+
+
+
 struct config
 {
     void *keywords;
@@ -56,11 +66,28 @@
     size_t MinCompressionLevel;
     size_t MaxCompressionLevel;
 #endif /* SERVER_SUPPORT */
+
+    verify_state VerifyCommits;
+    char *VerifyTemplate;
+    char *OpenPGPTextmode;
+    List *VerifyArgs;
+
 #ifdef PRESERVE_PERMISSIONS_SUPPORT
     bool preserve_perms;
 #endif /* PRESERVE_PERMISSIONS_SUPPORT */
 };
 
+
+
+/***
+ ***
+ ***   CVSROOT/config options
+ ***
+ ***/
+extern struct config *config;
+
+
+
 bool parse_error (const char *, unsigned int);
 struct config *parse_config (const char *, const char *);
 void free_config (struct config *data);
Index: ccvs/src/patch.c
diff -u ccvs/src/patch.c:1.106 ccvs/src/patch.c:1.107
--- ccvs/src/patch.c:1.106      Thu Sep 22 23:26:25 2005
+++ ccvs/src/patch.c    Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -17,9 +17,21 @@
  * release as either a date or a revision number.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "getline.h"
 
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+
+#include "cvs.h"
+
+
+
 static RETSIGTYPE patch_cleanup (int);
 static Dtype patch_dirproc (void *callerdat, const char *dir,
                             const char *repos, const char *update_dir,
Index: ccvs/src/rcs.c
diff -u ccvs/src/rcs.c:1.361 ccvs/src/rcs.c:1.362
--- ccvs/src/rcs.c:1.361        Fri Apr  7 01:49:03 2006
+++ ccvs/src/rcs.c      Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -14,8 +14,23 @@
  * manipulation
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "rcs.h"
+
+/* GNULIB headers.  */
+#include "base64.h"
+
+/* CVS headers.  */
 #include "edit.h"
+#include "gpg.h"
+#include "repos.h"
+#include "sign.h"
+
+#include "cvs.h"
 #include "hardlink.h"
 
 /* These need to be source after cvs.h or HAVE_MMAP won't be set... */
@@ -428,6 +443,17 @@
 
 
 
+/* Return a Node type for a newphrase buffer entry.  */
+static Ntype
+rcsbuf_get_node_type (struct rcsbuffer *rcsbuf)
+{
+    if (rcsbuf_valcmp (rcsbuf)) return RCSCMPFLD;
+    /* else */ if (rcsbuf->at_string) return RCSSTRING;
+    /* else */ return RCSFIELD;
+}
+
+
+
 /* Do the real work of parsing an RCS file.
 
    On error, die with a fatal error; if it returns at all it was successful.
@@ -579,9 +605,10 @@
        if (rdata->other == NULL)
            rdata->other = getlist ();
        kv = getnode ();
-       kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
+        kv->type = rcsbuf_get_node_type (&rcsbuf);
        kv->key = xstrdup (key);
-       kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD, NULL);
+       kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type != RCSCMPFLD,
+                                  &kv->len);
        if (addnode (rdata->other, kv) != 0)
        {
            error (0, 0, "warning: duplicate key `%s' in RCS file `%s'",
@@ -783,10 +810,10 @@
                if (vnode->other == NULL)
                    vnode->other = getlist ();
                kv = getnode ();
-               kv->type = rcsbuf_valcmp (&rcsbuf) ? RCSCMPFLD : RCSFIELD;
+               kv->type = rcsbuf_get_node_type (&rcsbuf);
                kv->key = xstrdup (key);
-               kv->data = rcsbuf_valcopy (&rcsbuf, value, kv->type == RCSFIELD,
-                                          NULL);
+               kv->data = rcsbuf_valcopy (&rcsbuf, value,
+                                          kv->type != RCSCMPFLD, NULL);
                if (addnode (vnode->other, kv) != 0)
                {
                    error (0, 0,
@@ -3625,6 +3652,105 @@
 
 
 
+/* Search for keywords in the *LEN bytes starting at *START.  Return the
+ * struct rcs_keyword describing the keyword found, or NULL when none is found.
+ * On return, *START will point to the first character after the `$'
+ * introductin the keyword, *END will point to the trailing `$', and *LEN
+ * will be decremented by the number of characters *START was incremented by.
+ *
+ * Not sure how to delcare *START and *END as const here.  I keep getting
+ * warnings.
+ */
+static const struct rcs_keyword *
+next_keyword (char **start, size_t *len, char **end)
+{
+    char *srch, *srch_next, *s = NULL;
+    size_t srch_len;
+    const struct rcs_keyword *keywords, *keyword = NULL;
+
+    if (!config->keywords) config->keywords = new_keywords ();
+    keywords = config->keywords;
+
+    srch = *start;
+    srch_len = *len;
+    TRACE (TRACE_DATA, "next_keyword: searching `%s'", srch);
+    while ((srch_next = memchr (srch, '$', srch_len)))
+    {
+       const char *send;
+       size_t slen;
+
+       srch_len -= (srch_next + 1) - srch;
+       srch = srch_next + 1;
+
+       /* Look for the first non alphabetic character after the '$'.  */
+       send = srch + srch_len;
+       for (s = srch; s < send; s++)
+           if (!isalpha ((unsigned char) *s))
+               break;
+
+       /* If the first non alphabetic character is not '$' or ':',
+           then this is not an RCS keyword.  */
+       if (s == send || (*s != '$' && *s != ':'))
+           continue;
+
+       /* See if this is one of the keywords.  */
+       slen = s - srch;
+       for (keyword = keywords; keyword->string; keyword++)
+       {
+           if (keyword->expandit
+               && keyword->len == slen
+               && !strncmp (keyword->string, srch, slen))
+           {
+               break;
+           }
+       }
+       if (!keyword->string)
+           continue;
+
+       /* If the keyword ends with a ':', then the old value consists
+           of the characters up to the next '$'.  If there is no '$'
+           before the end of the line, though, then this wasn't an RCS
+           keyword after all.  */
+
+       if (*s == ':')
+       {
+           for (; s < send; s++)
+               if (*s == '$' || *s == '\n')
+                   break;
+           if (s == send || *s != '$')
+               /* not resetting this the last time through this loop can cause
+                * erroneous return codes.
+                */
+               keyword = NULL;
+       }
+
+       if (keyword)
+           break;
+    }
+
+    if (keyword && keyword->string)
+    {
+       *start = srch;
+       *end = s;
+       *len = srch_len;
+       TRACE (TRACE_DATA,
+              "next_keyword: returning keyword `%s' and remainder `%s'",
+              keyword->string, s);
+       return keyword;
+    }
+    /* else */ return NULL;
+}
+
+
+
+bool contains_keyword (char *buf, size_t len)
+{
+    char *s;
+    return !!next_keyword (&buf, &len, &s);
+}
+
+
+
 /* Expand RCS keywords in the memory buffer BUF of length LEN.  This
    applies to file RCS and version VERS.  If NAME is not NULL, and is
    not a numeric revision, then it is the symbolic tag used for the
@@ -3647,9 +3773,9 @@
     struct expand_buffer *ebuf_last = NULL;
     size_t ebuf_len = 0;
     char *locker;
-    char *srch, *srch_next;
+    char *srch, *s;
     size_t srch_len;
-    const struct rcs_keyword *keywords;
+    const struct rcs_keyword *keywords, *keyword;
 
     if (!config /* For `cvs init', config may not be set.  */
        ||expand == KFLAG_O || expand == KFLAG_B)
@@ -3675,59 +3801,15 @@
     /* RCS keywords look like $STRING$ or $STRING: VALUE$.  */
     srch = buf;
     srch_len = len;
-    while ((srch_next = memchr (srch, '$', srch_len)) != NULL)
+    while ((keyword = next_keyword (&srch, &srch_len, &s)))
     {
-       char *s, *send;
-       size_t slen;
-       const struct rcs_keyword *keyword;
        char *value;
        int free_value;
        char *sub;
        size_t sublen;
-
-       srch_len -= (srch_next + 1) - srch;
-       srch = srch_next + 1;
-
-       /* Look for the first non alphabetic character after the '$'.  */
-       send = srch + srch_len;
-       for (s = srch; s < send; s++)
-           if (! isalpha ((unsigned char) *s))
-               break;
-
-       /* If the first non alphabetic character is not '$' or ':',
-           then this is not an RCS keyword.  */
-       if (s == send || (*s != '$' && *s != ':'))
-           continue;
-
-       /* See if this is one of the keywords.  */
-       slen = s - srch;
-       for (keyword = keywords; keyword->string != NULL; keyword++)
-       {
-           if (keyword->expandit
-               && keyword->len == slen
-               && strncmp (keyword->string, srch, slen) == 0)
-           {
-               break;
-           }
-       }
-       if (keyword->string == NULL)
-           continue;
-
-       /* If the keyword ends with a ':', then the old value consists
-           of the characters up to the next '$'.  If there is no '$'
-           before the end of the line, though, then this wasn't an RCS
-           keyword after all.  */
-       if (*s == ':')
-       {
-           for (; s < send; s++)
-               if (*s == '$' || *s == '\n')
-                   break;
-           if (s == send || *s != '$')
-               continue;
-       }
-
+       
        /* At this point we must replace the string from SRCH to S
-           with the expansion of the keyword KW.  */
+           with the expansion of the keyword KEYWORD.  */
 
        /* Get the value to use.  */
        free_value = 0;
@@ -4699,6 +4781,241 @@
 
 
 
+static const char *
+iRCS_get_openpgp_signatures (RCSNode *rcs, const char *rev, size_t *len)
+{
+    RCSVers *vers;
+    Node *n;
+
+    if (rcs->flags & PARTIAL)
+       RCS_reparsercsfile (rcs, NULL, NULL);
+
+    n = findnode (rcs->versions, rev);
+    if (!n)
+       error (1, 0, "internal error: no revision information for r%s of %s",
+              rev, rcs->print_path);
+    vers = n->data;
+
+    n = findnode (vers->other_delta, "openpgp-signatures");
+    if (!n)
+       return NULL;
+    /* else */
+
+    if (len) *len = n->len;
+    return n->data;
+}
+
+
+
+/* Returns false on error.  It is not an error if the requested revision has
+ * no OpenPGP signatures, but *OUT will be set to NULL.
+ */
+bool
+RCS_get_openpgp_signatures (struct file_info *finfo, const char *rev,
+                           char **out, size_t *len)
+{
+    const char *b64sig;
+    size_t b64len;
+
+    b64sig = iRCS_get_openpgp_signatures (finfo->rcs, rev, &b64len);
+
+    if (!b64sig)
+    {
+       *out = NULL;
+       *len = 0;
+       return true;
+    }
+
+    if (!base64_decode_alloc (b64sig, b64len, out, len))
+    {
+       error (0, 0, "Failed to decode base64 signature for `%s'",
+              finfo->fullname);
+       return false;
+    }
+    else if (!*out)
+       xalloc_die ();
+
+    return true;
+}
+
+
+
+/* Return true if the specified revision has any OpenPGP signature data
+ * attached.
+ */
+bool
+RCS_has_openpgp_signatures (struct file_info *finfo, const char *rev)
+{
+    return !!iRCS_get_openpgp_signatures (finfo->rcs, rev, NULL);
+}
+
+
+
+void
+RCS_add_openpgp_signature (struct file_info *finfo, const char *rev)
+{
+    RCSVers *vers;
+    Node *n;
+    char *oldsigs;
+    size_t oldlen;
+    char *newsig;
+    size_t newlen;
+
+    TRACE (TRACE_FUNCTION, "RCS_add_openpgp_signature (%s, %s)",
+          finfo->fullname, rev);
+
+    if (finfo->rcs->flags & PARTIAL)
+       RCS_reparsercsfile (finfo->rcs, NULL, NULL);
+
+    n = findnode (finfo->rcs->versions, rev);
+    if (!n)
+       error (1, 0, "internal error: no revision information for %s", rev);
+    vers = n->data;
+
+    n = findnode (vers->other_delta, "openpgp-signatures");
+    if (!n)
+    {
+       n = getnode();
+       n->type = RCSSTRING;
+       n->key = xstrdup ("openpgp-signatures");
+       oldsigs = NULL;
+       oldlen = 0;
+       addnode (vers->other_delta, n);
+    }
+    else
+    {
+       TRACE (TRACE_DATA,
+              "RCS_add_openpgp_signature: found oldsigs = %s, len = %u",
+              (char *)n->data, (unsigned int)n->len);
+       if (!base64_decode_alloc (n->data, n->len, &oldsigs, &oldlen))
+           error (1, 0, "Invalid binhex data in signature (`%s', rev %s)",
+                  finfo->rcs->print_path, rev);
+       if (!oldsigs)
+           xalloc_die ();
+       free (n->data);
+    }
+
+    newsig = get_signature (Short_Repository (finfo->repository), finfo->file,
+                           finfo->rcs->expand
+                           && STREQ (finfo->rcs->expand, "b"),
+                           &newlen);
+
+    oldsigs = xrealloc (oldsigs, oldlen + newlen);
+    memcpy (oldsigs + oldlen, newsig, newlen);
+    free (newsig);
+
+    n->len = base64_encode_alloc (oldsigs, oldlen + newlen, (char **)&n->data);
+    free (oldsigs);
+
+    TRACE (TRACE_DATA,
+          "RCS_add_openpgp_signature: found oldsigs = %s, len = %u",
+          (char *)n->data, (unsigned int)n->len);
+
+    RCS_rewrite (finfo->rcs, NULL, NULL);
+}
+
+
+
+int
+RCS_delete_openpgp_signatures (struct file_info *finfo, const char *rev,
+                              uint32_t keyid)
+{
+    RCSVers *vers;
+    Node *n;
+    char *oldsigs;
+    size_t oldlen;
+    struct buffer *membuf;
+    struct openpgp_signature sig;
+    char *newsigs = NULL;
+    size_t newlen = 0;
+    bool found = false;
+    int rc;
+
+    TRACE (TRACE_FUNCTION, "RCS_delete_openpgp_signatures (%s, %s, %llx)",
+          finfo->fullname, rev, (unsigned long long)keyid);
+
+    if (finfo->rcs->flags & PARTIAL)
+       RCS_reparsercsfile (finfo->rcs, NULL, NULL);
+
+    n = findnode (finfo->rcs->versions, rev);
+    if (!n)
+       error (1, 0, "internal error: no revision information for %s", rev);
+    vers = n->data;
+
+    n = findnode (vers->other_delta, "openpgp-signatures");
+    if (!n)
+    {
+       error (0, 0, "No signatures attached to revision %s of `%s'",
+              rev, finfo->fullname);
+       return 1;
+    }
+
+    TRACE (TRACE_DATA,
+          "RCS_delete_openpgp_signatures: found oldsigs = %s, len = %u",
+          (char *)n->data, (unsigned int)n->len);
+
+    if (!base64_decode_alloc (n->data, n->len, &oldsigs, &oldlen))
+       error (1, 0, "Invalid binhex data in signature (`%s', rev %s)",
+              finfo->rcs->print_path, rev);
+    if (!oldsigs)
+       xalloc_die ();
+    free (n->data);
+
+    membuf = buf_nonio_initialize (NULL);
+    buf_output (membuf, oldsigs, oldlen);
+
+    while (!(rc = parse_signature (membuf, &sig)))
+    {
+       char *hexid1 = Xasprintf ("0x%llx", (unsigned long long) keyid);
+       char *hexid2 = Xasprintf ("0x%llx", (unsigned long long) sig.keyid);
+       if ((sig.keyid & 0xFFFFFFFF) == keyid)
+       {
+           TRACE (TRACE_DATA, "%s is a match for %s", hexid1, hexid2);
+           found = true;
+       }
+       else
+       {
+           TRACE (TRACE_DATA, "%s is not a match for %s", hexid1, hexid2);
+           newsigs = xrealloc (newsigs, newlen + sig.rawlen);
+           memcpy (newsigs + newlen, sig.raw, sig.rawlen);
+           newlen += sig.rawlen;
+       }
+       free (hexid1);
+       free (hexid2);
+       free (sig.raw);
+    }
+
+    if (!found)
+    {
+       char *hexid = Xasprintf ("0x%llx", (unsigned long long) keyid);
+       error (0, 0,
+              "No signatures with key ID %s found in revision %s of `%s'",
+              hexid, rev, finfo->fullname);
+       free (hexid);
+       if (newsigs) free (newsigs);
+       return 1;
+    }
+
+    if (newsigs)
+    {
+       n->len = base64_encode_alloc (newsigs, newlen, (char **)&n->data);
+       free (newsigs);
+    }
+    else
+       delnode (n);
+
+
+    TRACE (TRACE_DATA,
+          "RCS_add_openpgp_signature: found oldsigs = %s, len = %u",
+          (char *)n->data, (unsigned int)n->len);
+
+    RCS_rewrite (finfo->rcs, NULL, NULL);
+
+    return 0;
+}
+
+
+
 /* Find the delta currently locked by the user.  From the `ci' man page:
 
        "If rev is omitted, ci tries to  derive  the  new  revision
@@ -5032,6 +5349,9 @@
 #endif
     Node *np;
 
+    TRACE (TRACE_FUNCTION, "RCS_checkin (%s, %s, %s, %s, %s)",
+          rcs->print_path, update_dir, workfile_in, message, rev);
+
     commitpt = NULL;
 
     if (rcs->flags & PARTIAL)
@@ -5109,6 +5429,22 @@
     np->data = xstrdup(global_session_id);
     addnode (delta->other_delta, np);
 
+    /* Save the OpenPGP signature.  */
+    if (!delta->dead && (get_sign_commits (true) || have_sigfile (workfile)))
+    {
+       char *rawsig;
+       size_t rawlen;
+
+       np = getnode();
+       np->type = RCSSTRING;
+       np->key = xstrdup ("openpgp-signatures");
+       rawsig = get_signature ("", workfile,
+                               rcs->expand && STREQ (rcs->expand, "b"),
+                               &rawlen);
+       np->len = base64_encode_alloc (rawsig, rawlen, (char **)&np->data);
+       free (rawsig);
+       addnode (delta->other_delta, np);
+    }
 
 #ifdef PRESERVE_PERMISSIONS_SUPPORT
     /* If permissions should be preserved on this project, then
@@ -5661,8 +5997,9 @@
    expansion options.  Return 0 if the contents of the revision are
    the same as the contents of the file, 1 if they are different.  */
 int
-RCS_cmp_file (RCSNode *rcs, const char *rev1, char **rev1_cache,
-              const char *rev2, const char *options, const char *filename)
+RCS_cmp_file (RCSNode *rcs, const char *arg_rev1, const char *rev1,
+             char **rev1_cache, const char *rev2, const char *options,
+             const char *filename)
 {
     int binary;
 
@@ -5722,7 +6059,9 @@
        {
            /* Open & cache rev1 */
            tmpfile = cvs_temp_name();
-           if (RCS_checkout (rcs, NULL, rev1, NULL, options, tmpfile,
+           if (RCS_checkout (rcs, NULL, rev1,
+                             arg_rev1 && !isdigit (arg_rev1[0])
+                             ? arg_rev1 : NULL, options, tmpfile,
                              NULL, NULL))
                error (1, errno,
                       "cannot check out revision %s of %s",
@@ -7748,6 +8087,7 @@
            vnode->state = xstrdup (RCSDEAD);
            continue;
        }
+
        /* if we have a new revision number, we're done with this delta */
        for (cp = key;
             (isdigit ((unsigned char) *cp) || *cp == '.') && *cp != '\0';
@@ -7764,9 +8104,10 @@
        if (vnode->other_delta == NULL)
            vnode->other_delta = getlist ();
        kv = getnode ();
-       kv->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+       kv->type = rcsbuf_get_node_type (rcsbuf);
        kv->key = xstrdup (key);
-       kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type == RCSFIELD, NULL);
+       kv->data = rcsbuf_valcopy (rcsbuf, value, kv->type != RCSCMPFLD,
+                                  &kv->len);
        if (addnode (vnode->other_delta, kv) != 0)
        {
            /* Complaining about duplicate keys in newphrases seems
@@ -7849,9 +8190,10 @@
            break;
 
        p = getnode();
-       p->type = rcsbuf_valcmp (rcsbuf) ? RCSCMPFLD : RCSFIELD;
+       p->type = rcsbuf_get_node_type (rcsbuf);
        p->key = xstrdup (key);
-       p->data = rcsbuf_valcopy (rcsbuf, value, p->type == RCSFIELD, NULL);
+       p->data = rcsbuf_valcopy (rcsbuf, value, p->type != RCSCMPFLD,
+                                 &p->len);
        if (addnode (d->other, p) < 0)
        {
            error (0, 0, "warning: %s, delta %s: duplicate field `%s'",
@@ -7918,23 +8260,17 @@
     fprintf (fp, "\n%s\t", node->key);
     if (node->data != NULL)
     {
-       /* If the field's value contains evil characters,
+       /* If the field's value may contain evil characters,
           it must be stringified. */
-       /* FIXME: This does not quite get it right.  "7jk8f" is not a valid
-          value for a value in a newpharse, according to doc/RCSFILES,
-          because digits are not valid in an "id".  We might do OK by
-          always writing strings (enclosed in @@).  Would be nice to
-          explicitly mention this one way or another in doc/RCSFILES.
-          A case where we are wrong in a much more clear-cut way is that
-          we let through non-graphic characters such as whitespace and
-          control characters.  */
-
-       if (node->type == RCSCMPFLD || strpbrk (node->data, "$,.:;@") == NULL)
-           fputs (node->data, fp);
+       if (node->type != RCSSTRING)
+           fwrite (node->data, 1, node->len ? node->len : strlen (node->data),
+                   fp);
        else
        {
            putc ('@', fp);
-           expand_at_signs (node->data, (off_t) strlen (node->data), fp);
+           expand_at_signs (node->data,
+                            node->len ? node->len : strlen (node->data),
+                            fp);
            putc ('@', fp);
        }
     }
@@ -8689,7 +9025,8 @@
  * /dev/null to be parsed by patch properly.
  */
 char *
-make_file_label (const char *path, const char *rev, RCSNode *rcs)
+make_file_label (const char *path, const char *rev, const char *ts_user,
+                RCSNode *rcs)
 {
     char datebuf[MAXDATELEN + 1];
     char *label;
@@ -8698,33 +9035,33 @@
     {
        char date[MAXDATELEN + 1];
        /* revs cannot be attached to /dev/null ... duh. */
-       assert (strcmp(DEVNULL, path));
+       assert (strcmp (DEVNULL, path));
        RCS_getrevtime (rcs, rev, datebuf, 0);
        (void) date_to_internet (date, datebuf);
        label = Xasprintf ("-L%s\t%s\t%s", path, date, rev);
     }
-    else
+    else if (ts_user)
     {
-       struct stat sb;
-       struct tm *wm;
-
-       if (strcmp(DEVNULL, path))
+       if (strcmp (ts_user, "Is-modified"))
        {
-           const char *file = last_component (path);
-           if (stat (file, &sb) < 0)
-               /* Assume that if the stat fails,then the later read for the
-                * diff will too.
-                */
-               error (1, errno, "could not get info for `%s'", path);
-           wm = gmtime (&sb.st_mtime);
+           struct timespec t;
+           struct tm *wm;
+           assert (get_date (&t, ts_user, NULL));
+           wm = gmtime (&t.tv_sec);
+           tm_to_internet (datebuf, wm);
+           label = Xasprintf ("-L%s\t%s", path, datebuf);
        }
        else
-       {
-           time_t t = 0;
-           wm = gmtime(&t);
-       }
+           /* Can't get the user's timestamp from the server.  */
+           label = Xasprintf ("-L%s", path);
+    }
+    else
+    {
+       time_t t = 0;
+       struct tm *wm = gmtime (&t);
 
-       (void) tm_to_internet (datebuf, wm);
+       assert (!strcmp (DEVNULL, path));
+       tm_to_internet (datebuf, wm);
        label = Xasprintf ("-L%s\t%s", path, datebuf);
     }
     return label;
Index: ccvs/src/rcs.h
diff -u ccvs/src/rcs.h:1.83 ccvs/src/rcs.h:1.84
--- ccvs/src/rcs.h:1.83 Sat Dec 31 23:33:43 2005
+++ ccvs/src/rcs.h      Mon Apr 24 18:50:27 2006
@@ -13,6 +13,16 @@
  * RCS source control definitions needed by rcs.c and friends
  */
 
+#ifndef RCS_H
+#define RCS_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "hash.h"
+
 /* Strings which indicate a conflict if they occur at the start of a line.  */
 #define        RCS_MERGE_PAT_1 "<<<<<<< "
 #define        RCS_MERGE_PAT_2 "=======\n"
@@ -126,6 +136,42 @@
 
 typedef struct rcsnode RCSNode;
 
+
+
+/* This is the structure that the recursion processor passes to the
+ * fileproc to tell it about a particular file.
+ *
+ * FIXME: This should be in recurse.h.
+ */
+struct file_info
+{
+    /* Name of the file, without any directory component.  */
+    const char *file;
+
+    /* Name of the directory we are in, relative to the directory in
+       which this command was issued.  We have cd'd to this directory
+       (either in the working directory or in the repository, depending
+       on which sort of recursion we are doing).  If we are in the directory
+       in which the command was issued, this is "".  */
+    const char *update_dir;
+
+    /* update_dir and file put together, with a slash between them as
+       necessary.  This is the proper way to refer to the file in user
+       messages.  */
+    const char *fullname;
+
+    /* Name of the directory corresponding to the repository which contains
+       this file.  */
+    const char *repository;
+
+    /* The pre-parsed entries for this directory.  */
+    List *entries;
+
+    RCSNode *rcs;
+};
+
+
+
 struct deltatext {
     char *version;
 
@@ -229,11 +275,17 @@
 void RCS_setexpand (RCSNode *, const char *);
 int RCS_checkout (RCSNode *, const char *, const char *, const char *,
                   const char *, const char *, RCSCHECKOUTPROC, void *);
+bool RCS_get_openpgp_signatures (struct file_info *finfo, const char *rev,
+                                char **out, size_t *len);
+bool RCS_has_openpgp_signatures (struct file_info *finfo, const char *rev);
+void RCS_add_openpgp_signature (struct file_info *finfo, const char *rev);
+int RCS_delete_openpgp_signatures (struct file_info *finfo, const char *rev,
+                                  uint32_t keyid);
 int RCS_checkin (RCSNode *rcs, const char *update_dir, const char *workfile,
                 const char *message, const char *rev, time_t citime,
                 int flags);
-int RCS_cmp_file (RCSNode *, const char *, char **, const char *, const char *,
-                 const char * );
+int RCS_cmp_file (RCSNode *, const char *, const char *, char **, const char *,
+                 const char *, const char *);
 int RCS_settag (RCSNode *, const char *, const char *);
 int RCS_deltag (RCSNode *, const char *);
 int RCS_setbranch (RCSNode *, const char *);
@@ -252,7 +304,7 @@
                 char **, size_t *);
 void RCS_setincexc (void **, const char *arg);
 void RCS_setlocalid (const char *, unsigned int, void **, const char *arg);
-char *make_file_label (const char *, const char *, RCSNode *);
+char *make_file_label (const char *, const char *, const char *, RCSNode *);
 
 extern bool preserve_perms;
 extern int annotate_width;
@@ -263,3 +315,9 @@
                          const char *, int, char **, const char *, size_t,
                          FILE *, bool);
 void free_keywords (void *keywords);
+bool contains_keyword (char *buf, size_t len);
+void RCS_output_diff_options (int diff_argc, char * const *diff_argv,
+                             bool devnull, const char *rev1, const char *rev2,
+                             const char *workfile);
+
+#endif /* RCS_H */
Index: ccvs/src/rcscmds.c
diff -u ccvs/src/rcscmds.c:1.72 ccvs/src/rcscmds.c:1.73
--- ccvs/src/rcscmds.c:1.72     Wed Jun  1 01:42:35 2005
+++ ccvs/src/rcscmds.c  Mon Apr 24 18:50:27 2006
@@ -14,11 +14,20 @@
  * operations directly on RCS files. 
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Standard headers.  */
 #include <stdio.h>
-#include "diffrun.h"
+
+/* GNULIB */
 #include "quotearg.h"
 
+/* CVS */
+#include "difflib.h"
+#include "cvs.h"
+
 /* This file, rcs.h, and rcs.c, together sometimes known as the "RCS
    library", are intended to define our interface to RCS files.
 
@@ -56,8 +65,6 @@
    On a related note, see the comments at diff_exec, later in this file,
    for more on the diff library.  */
 
-static void RCS_output_diff_options (int, char * const *, const char *,
-                                    const char *, const char *);
 
 
 /* Stuff to deal with passing arguments the way libdiff.a wants to deal
@@ -65,410 +72,6 @@
    to resemble a command line rather than something closer to "struct
    log_data" in log.c.  */
 
-/* First call call_diff_setup to setup any initial arguments.  The
-   argument will be parsed into whitespace separated words and added
-   to the global call_diff_argv list.
-
-   Then, optionally, call call_diff_add_arg for each additional argument
-   that you'd like to pass to the diff library.
-
-   Finally, call call_diff or call_diff3 to produce the diffs.  */
-
-static char **call_diff_argv;
-static int call_diff_argc;
-static size_t call_diff_arg_allocated;
-
-static int call_diff (const char *out);
-static int call_diff3 (char *out);
-
-static void call_diff_write_output (const char *, size_t);
-static void call_diff_flush_output (void);
-static void call_diff_write_stdout (const char *);
-static void call_diff_error (const char *, const char *, const char *);
-
-
-
-/* VARARGS */
-static void
-call_diff_add_arg (const char *s)
-{
-    TRACE (TRACE_DATA, "call_diff_add_arg (%s)", s);
-    run_add_arg_p (&call_diff_argc, &call_diff_arg_allocated, &call_diff_argv,
-                  s);
-}
-
-
-
-static void 
-call_diff_setup (const char *prog, int argc, char * const *argv)
-{
-    int i;
-
-    /* clean out any malloc'ed values from call_diff_argv */
-    run_arg_free_p (call_diff_argc, call_diff_argv);
-    call_diff_argc = 0;
-
-    /* put each word into call_diff_argv, allocating it as we go */
-    call_diff_add_arg (prog);
-    for (i = 0; i < argc; i++)
-       call_diff_add_arg (argv[i]);
-}
-
-
-
-/* Callback function for the diff library to write data to the output
-   file.  This is used when we are producing output to stdout.  */
-
-static void
-call_diff_write_output (const char *text, size_t len)
-{
-    if (len > 0)
-       cvs_output (text, len);
-}
-
-/* Call back function for the diff library to flush the output file.
-   This is used when we are producing output to stdout.  */
-
-static void
-call_diff_flush_output (void)
-{
-    cvs_flushout ();
-}
-
-/* Call back function for the diff library to write to stdout.  */
-
-static void
-call_diff_write_stdout (const char *text)
-{
-    cvs_output (text, 0);
-}
-
-/* Call back function for the diff library to write to stderr.  */
-
-static void
-call_diff_error (const char *format, const char *a1, const char *a2)
-{
-    /* FIXME: Should we somehow indicate that this error is coming from
-       the diff library?  */
-    error (0, 0, format, a1, a2);
-}
-
-/* This set of callback functions is used if we are sending the diff
-   to stdout.  */
-
-static struct diff_callbacks call_diff_stdout_callbacks =
-{
-    call_diff_write_output,
-    call_diff_flush_output,
-    call_diff_write_stdout,
-    call_diff_error
-};
-
-/* This set of callback functions is used if we are sending the diff
-   to a file.  */
-
-static struct diff_callbacks call_diff_file_callbacks =
-{
-    NULL,
-    NULL,
-    call_diff_write_stdout,
-    call_diff_error
-};
-
-
-
-static int
-call_diff (const char *out)
-{
-    call_diff_add_arg (NULL);
-
-    if (out == RUN_TTY)
-       return diff_run( call_diff_argc, call_diff_argv, NULL,
-                        &call_diff_stdout_callbacks );
-    else
-       return diff_run( call_diff_argc, call_diff_argv, out,
-                        &call_diff_file_callbacks );
-}
-
-
-
-static int
-call_diff3 (char *out)
-{
-    if (out == RUN_TTY)
-       return diff3_run (call_diff_argc, call_diff_argv, NULL,
-                         &call_diff_stdout_callbacks);
-    else
-       return diff3_run (call_diff_argc, call_diff_argv, out,
-                         &call_diff_file_callbacks);
-}
-
-
-
-/* Merge revisions REV1 and REV2. */
-
-int
-RCS_merge (RCSNode *rcs, const char *path, const char *workfile,
-           const char *options, const char *rev1, const char *rev2)
-{
-    char *xrev1, *xrev2;
-    char *tmp1, *tmp2;
-    char *diffout = NULL;
-    int retval;
-
-    if (options != NULL && options[0] != '\0')
-      assert (options[0] == '-' && options[1] == 'k');
-
-    cvs_output ("RCS file: ", 0);
-    cvs_output (rcs->print_path, 0);
-    cvs_output ("\n", 1);
-
-    /* Calculate numeric revision numbers from rev1 and rev2 (may be
-       symbolic).
-       FIXME - No they can't.  Both calls to RCS_merge are passing in
-       numeric revisions.  */
-    xrev1 = RCS_gettag (rcs, rev1, 0, NULL);
-    xrev2 = RCS_gettag (rcs, rev2, 0, NULL);
-    assert (xrev1 && xrev2);
-
-    /* Check out chosen revisions.  The error message when RCS_checkout
-       fails is not very informative -- it is taken verbatim from RCS 5.7,
-       and relies on RCS_checkout saying something intelligent upon failure. */
-    cvs_output ("retrieving revision ", 0);
-    cvs_output (xrev1, 0);
-    cvs_output ("\n", 1);
-
-    tmp1 = cvs_temp_name();
-    if (RCS_checkout (rcs, NULL, xrev1, rev1, options, tmp1, NULL, NULL))
-    {
-       cvs_outerr ("rcsmerge: co failed\n", 0);
-       exit (EXIT_FAILURE);
-    }
-
-    cvs_output ("retrieving revision ", 0);
-    cvs_output (xrev2, 0);
-    cvs_output ("\n", 1);
-
-    tmp2 = cvs_temp_name();
-    if (RCS_checkout (rcs, NULL, xrev2, rev2, options, tmp2, NULL, NULL))
-    {
-       cvs_outerr ("rcsmerge: co failed\n", 0);
-       exit (EXIT_FAILURE);
-    }
-
-    /* Merge changes. */
-    cvs_output ("Merging differences between ", 0);
-    cvs_output (xrev1, 0);
-    cvs_output (" and ", 0);
-    cvs_output (xrev2, 0);
-    cvs_output (" into ", 0);
-    cvs_output (workfile, 0);
-    cvs_output ("\n", 1);
-
-    /* Remember that the first word in the `call_diff_setup' string is used now
-       only for diagnostic messages -- CVS no longer forks to run diff3. */
-    diffout = cvs_temp_name();
-    call_diff_setup ("diff3", 0, NULL);
-    call_diff_add_arg ("-E");
-    call_diff_add_arg ("-am");
-
-    call_diff_add_arg ("-L");
-    call_diff_add_arg (workfile);
-    call_diff_add_arg ("-L");
-    call_diff_add_arg (xrev1);
-    call_diff_add_arg ("-L");
-    call_diff_add_arg (xrev2);
-
-    call_diff_add_arg ("--");
-    call_diff_add_arg (workfile);
-    call_diff_add_arg (tmp1);
-    call_diff_add_arg (tmp2);
-
-    retval = call_diff3 (diffout);
-
-    if (retval == 1)
-       cvs_outerr ("rcsmerge: warning: conflicts during merge\n", 0);
-    else if (retval == 2)
-       exit (EXIT_FAILURE);
-
-    if (diffout)
-       copy_file (diffout, workfile);
-
-    /* Clean up. */
-    {
-       int save_noexec = noexec;
-       noexec = 0;
-       if (unlink_file (tmp1) < 0)
-       {
-           if (!existence_error (errno))
-               error (0, errno, "cannot remove temp file %s", tmp1);
-       }
-       free (tmp1);
-       if (unlink_file (tmp2) < 0)
-       {
-           if (!existence_error (errno))
-               error (0, errno, "cannot remove temp file %s", tmp2);
-       }
-       free (tmp2);
-       if (diffout)
-       {
-           if (unlink_file (diffout) < 0)
-           {
-               if (!existence_error (errno))
-                   error (0, errno, "cannot remove temp file %s", diffout);
-           }
-           free (diffout);
-       }
-       free (xrev1);
-       free (xrev2);
-       noexec = save_noexec;
-    }
-
-    return retval;
-}
-
-/* Diff revisions and/or files.  OPTS controls the format of the diff
-   (it contains options such as "-w -c", &c), or "" for the default.
-   OPTIONS controls keyword expansion, as a string starting with "-k",
-   or "" to use the default.  REV1 is the first revision to compare
-   against; it must be non-NULL.  If REV2 is non-NULL, compare REV1
-   and REV2; if REV2 is NULL compare REV1 with the file in the working
-   directory, whose name is WORKFILE.  LABEL1 and LABEL2 are default
-   file labels, and (if non-NULL) should be added as -L options
-   to diff.  Output goes to stdout.
-
-   Return value is 0 for success, -1 for a failure which set errno,
-   or positive for a failure which printed a message on stderr.
-
-   This used to exec rcsdiff, but now calls RCS_checkout and diff_exec.
-
-   An issue is what timezone is used for the dates which appear in the
-   diff output.  rcsdiff uses the -z flag, which is not presently
-   processed by CVS diff, but I'm not sure exactly how hard to worry
-   about this--any such features are undocumented in the context of
-   CVS, and I'm not sure how important to users.  */
-int
-RCS_exec_rcsdiff (RCSNode *rcsfile, int diff_argc,
-                 char * const *diff_argv, const char *options,
-                  const char *rev1, const char *rev1_cache, const char *rev2,
-                  const char *label1, const char *label2, const char *workfile)
-{
-    char *tmpfile1 = NULL;
-    char *tmpfile2 = NULL;
-    const char *use_file1, *use_file2;
-    int status, retval;
-
-
-    cvs_output ("\
-===================================================================\n\
-RCS file: ", 0);
-    cvs_output (rcsfile->print_path, 0);
-    cvs_output ("\n", 1);
-
-    /* Historically, `cvs diff' has expanded the $Name keyword to the
-       empty string when checking out revisions.  This is an accident,
-       but no one has considered the issue thoroughly enough to determine
-       what the best behavior is.  Passing NULL for the `nametag' argument
-       preserves the existing behavior. */
-
-    cvs_output ("retrieving revision ", 0);
-    cvs_output (rev1, 0);
-    cvs_output ("\n", 1);
-
-    if (rev1_cache != NULL)
-       use_file1 = rev1_cache;
-    else
-    {
-       tmpfile1 = cvs_temp_name();
-       status = RCS_checkout (rcsfile, NULL, rev1, NULL, options, tmpfile1,
-                              NULL, NULL);
-       if (status > 0)
-       {
-           retval = status;
-           goto error_return;
-       }
-       else if (status < 0)
-       {
-           error( 0, errno,
-                  "cannot check out revision %s of %s", rev1, rcsfile->path );
-           retval = 1;
-           goto error_return;
-       }
-       use_file1 = tmpfile1;
-    }
-
-    if (rev2 == NULL)
-    {
-       assert (workfile != NULL);
-       use_file2 = workfile;
-    }
-    else
-    {
-       tmpfile2 = cvs_temp_name ();
-       cvs_output ("retrieving revision ", 0);
-       cvs_output (rev2, 0);
-       cvs_output ("\n", 1);
-       status = RCS_checkout (rcsfile, NULL, rev2, NULL, options,
-                              tmpfile2, NULL, NULL);
-       if (status > 0)
-       {
-           retval = status;
-           goto error_return;
-       }
-       else if (status < 0)
-       {
-           error (0, errno,
-                  "cannot check out revision %s of %s", rev2, rcsfile->path);
-           return 1;
-       }
-       use_file2 = tmpfile2;
-    }
-
-    RCS_output_diff_options (diff_argc, diff_argv, rev1, rev2, workfile);
-    status = diff_exec (use_file1, use_file2, label1, label2,
-                       diff_argc, diff_argv, RUN_TTY);
-    if (status >= 0)
-    {
-       retval = status;
-       goto error_return;
-    }
-    else if (status < 0)
-    {
-       error (0, errno,
-              "cannot diff %s and %s", use_file1, use_file2);
-       retval = 1;
-       goto error_return;
-    }
-
- error_return:
-    {
-       /* Call CVS_UNLINK() below rather than unlink_file to avoid the check
-        * for noexec.
-        */
-       if( tmpfile1 != NULL )
-       {
-           if( CVS_UNLINK( tmpfile1 ) < 0 )
-           {
-               if( !existence_error( errno ) )
-                   error( 0, errno, "cannot remove temp file %s", tmpfile1 );
-           }
-           free( tmpfile1 );
-       }
-       if( tmpfile2 != NULL )
-       {
-           if( CVS_UNLINK( tmpfile2 ) < 0 )
-           {
-               if( !existence_error( errno ) )
-                   error( 0, errno, "cannot remove temp file %s", tmpfile2 );
-           }
-           free (tmpfile2);
-       }
-    }
-
-    return retval;
-}
-
-
 
 /* Show differences between two files.  This is the start of a diff library.
 
@@ -564,9 +167,9 @@
    which not to print.  The code below reproduces every rcsdiff run
    that I have seen. */
 
-static void
+void
 RCS_output_diff_options (int diff_argc, char * const *diff_argv,
-                        const char *rev1, const char *rev2,
+                        bool devnull, const char *rev1, const char *rev2,
                          const char *workfile)
 {
     int i;
@@ -577,19 +180,28 @@
         cvs_output (" ", 1);
        cvs_output (quotearg_style (shell_quoting_style, diff_argv[i]), 0);
     }
-    cvs_output (" -r", 3);
-    cvs_output (rev1, 0);
+
+    if (devnull)
+       cvs_output (" -N", 3);
+
+    if (rev1)
+    {
+       cvs_output (" -r", 3);
+       cvs_output (rev1, 0);
+    }
 
     if (rev2)
     {
        cvs_output (" -r", 3);
        cvs_output (rev2, 0);
     }
-    else
+
+    if (!rev1 || !rev2)
     {
-       assert (workfile != NULL);
+       assert (workfile);
        cvs_output (" ", 1);
        cvs_output (workfile, 0);
     }
+
     cvs_output ("\n", 1);
 }
Index: ccvs/src/recurse.c
diff -u ccvs/src/recurse.c:1.115 ccvs/src/recurse.c:1.116
--- ccvs/src/recurse.c:1.115    Thu Jan  5 15:55:05 2006
+++ ccvs/src/recurse.c  Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -14,10 +14,25 @@
  *
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "recurse.h"
+
+/* GNULIB headers.  */
 #include "save-cwd.h"
-#include "fileattr.h"
+
+/* CVS headers.  */
 #include "edit.h"
+#include "fileattr.h"
+#include "repos.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
 
 static int do_dir_proc (Node * p, void *closure);
 static int do_file_proc (Node * p, void *closure);
Index: ccvs/src/release.c
diff -u ccvs/src/release.c:1.71 ccvs/src/release.c:1.72
--- ccvs/src/release.c:1.71     Fri Sep  2 21:51:09 2005
+++ ccvs/src/release.c  Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1994-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1994-2006 The 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
@@ -19,11 +19,22 @@
  * delete the local working directory.
  */
 
-#include "cvs.h"
-#include "save-cwd.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "getline.h"
+#include "save-cwd.h"
 #include "yesno.h"
 
+/* CVS headers.  */
+#include "ignore.h"
+
+#include "cvs.h"
+
+
+
 static const char *const release_usage[] =
 {
     "Usage: %s %s [-d] directories...\n",
Index: ccvs/src/remove.c
diff -u ccvs/src/remove.c:1.63 ccvs/src/remove.c:1.64
--- ccvs/src/remove.c:1.63      Tue Mar 22 13:19:58 2005
+++ ccvs/src/remove.c   Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -20,8 +20,19 @@
  * correctly.
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS headers.  */
+#include "ignore.h"
+#include "recurse.h"
+#include "wrapper.h"
+
 #include "cvs.h"
 
+
+
 #ifdef CLIENT_SUPPORT
 static int remove_force_fileproc (void *callerdat,
                                         struct file_info *finfo);
Index: ccvs/src/repos.c
diff -u ccvs/src/repos.c:1.41 ccvs/src/repos.c:1.42
--- ccvs/src/repos.c:1.41       Thu May 26 17:48:06 2005
+++ ccvs/src/repos.c    Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -11,9 +11,19 @@
  * specified in the README file that comes with the CVS source distribution.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "repos.h"
+
+/* GNULIB headers.  */
 #include "getline.h"
 
+/* CVS headers.  */
+#include "cvs.h"
+
 
 
 /* Determine the name of the RCS repository for directory DIR in the
Index: ccvs/src/root.c
diff -u ccvs/src/root.c:1.124 ccvs/src/root.c:1.125
--- ccvs/src/root.c:1.124       Tue Feb 28 13:10:11 2006
+++ ccvs/src/root.c     Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -14,10 +14,27 @@
  * Determine the path to the CVSROOT and set "Root" accordingly.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "root.h"
+
+/* ANSI C headers.  */
 #include <assert.h>
+
+/* GNULIB headers.  */
 #include "getline.h"
 
+/* CVS headers.  */
+#include "repos.h"
+#include "stack.h"
+
+#include "cvs.h"
+
+
+
 /* Printable names for things in the current_parsed_root->method enum variable.
    Watch out if the enum is changed in cvs.h! */
 
@@ -392,6 +409,13 @@
     newroot->directory = NULL;
     newroot->method = null_method;
     newroot->isremote = false;
+    newroot->sign = SIGN_DEFAULT;
+    newroot->sign_template = NULL;
+    newroot->openpgp_textmode = NULL;
+    newroot->sign_args = getlist ();
+    newroot->verify = VERIFY_DEFAULT;
+    newroot->verify_template = NULL;
+    newroot->verify_args = getlist ();
 #if defined CLIENT_SUPPORT || defined SERVER_SUPPORT
     newroot->username = NULL;
     newroot->password = NULL;
@@ -423,6 +447,14 @@
        free (root->original);
     if (root->directory != NULL)
        free (root->directory);
+    if (root->sign_template)
+       free (root->sign_template);
+    if (root->openpgp_textmode)
+       free (root->openpgp_textmode);
+    dellist (&root->sign_args);
+    if (root->verify_template)
+       free (root->verify_template);
+    dellist (&root->verify_args);
 #ifdef CLIENT_SUPPORT
     if (root->username != NULL)
        free (root->username);
@@ -571,7 +603,7 @@
        while ((p = strtok (NULL, ";")))
        {
            char *q = strchr (p, '=');
-           if (q == NULL)
+           if (!q && (strcasecmp (p, "sign") || strcasecmp (p, "no-sign")))
            {
                error (0, 0, "Option (`%s') has no argument in CVSROOT.",
                        p);
@@ -603,6 +635,72 @@
 "CVSROOT may only specify a positive, non-zero, integer proxy port (not 
`%s').",
                           q);
            }
+           else if (!strcasecmp (p, "sign"))
+           {
+               if (!q)
+                   newroot->sign = SIGN_ALWAYS;
+               else if (!strcasecmp (q, "auto") || !strcasecmp (q, "server"))
+                   newroot->sign = SIGN_DEFAULT;
+               else
+               {
+                   bool on;
+                   if (readBool ("CVSROOT", "sign", q, &on))
+                   {
+                       if (on)
+                           newroot->sign = SIGN_ALWAYS;
+                       else
+                           newroot->sign = SIGN_NEVER;
+                   }
+                   else
+                       goto error_exit;
+               }
+           }
+           else if (!strcasecmp (p, "no-sign"))
+               newroot->sign = SIGN_NEVER;
+           else if (!strcasecmp (p, "sign-template"))
+               newroot->sign_template = xstrdup (q);
+           else if (!strcasecmp (p, "openpgp-textmode"))
+           {
+               if (newroot->openpgp_textmode)
+                   free (newroot->openpgp_textmode);
+               newroot->openpgp_textmode = xstrdup (q);
+           }
+           else if (!strcasecmp (p, "no-openpgp-textmode"))
+           {
+               if (newroot->openpgp_textmode)
+                   free (newroot->openpgp_textmode);
+               newroot->openpgp_textmode = xstrdup ("");
+           }
+           else if (!strcasecmp (p, "sign-arg"))
+               push_string (newroot->sign_args, q);
+           else if (!strcasecmp (p, "no-verify"))
+               newroot->verify = VERIFY_OFF;
+           else if (!strcasecmp (p, "verify"))
+           {
+               if (!q)
+                   newroot->verify = VERIFY_FATAL;
+               else if (!strcasecmp (q, "fatal"))
+                   newroot->verify = VERIFY_FATAL;
+               else if (!strcasecmp (q, "warn"))
+                   newroot->verify = VERIFY_WARN;
+               else
+               {
+                   bool on;
+                   if (readBool ("CVSROOT", "verify", q, &on))
+                   {
+                       if (on)
+                           newroot->verify = VERIFY_FATAL;
+                       else
+                           newroot->verify = VERIFY_OFF;
+                   }
+                   else
+                       goto error_exit;
+               }
+           }
+           else if (!strcasecmp (p, "verify-template"))
+               newroot->verify_template = xstrdup (q);
+           else if (!strcasecmp (p, "verify-arg"))
+               push_string (newroot->verify_args, q);
            else if (!strcasecmp (p, "CVS_RSH"))
            {
                /* override CVS_RSH environment variable */
Index: ccvs/src/root.h
diff -u ccvs/src/root.h:1.23 ccvs/src/root.h:1.24
--- ccvs/src/root.h:1.23        Wed Dec  7 20:04:49 2005
+++ ccvs/src/root.h     Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -13,6 +13,16 @@
 
 /* CVSroot data structures */
 
+#ifndef ROOT_H
+#define ROOT_H
+
+/* ANSI C includes.  */
+#include <stdbool.h>
+
+/* CVS Includes.  */
+#include "sign.h"
+#include "verify.h"
+
 /* Access method specified in CVSroot. */
 typedef enum {
     null_method = 0,
@@ -33,6 +43,22 @@
     CVSmethod method;          /* One of the enum values above. */
     char *directory;           /* The directory name. */
     bool isremote;             /* True if we are doing remote access. */
+    sign_state sign;           /* Whether to sign commits.  */
+    char *sign_template;       /* The template to use to launch the external
+                                * program to produce GPG signatures.
+                                */
+    List *sign_args;           /* Keep track of any additional arguments for
+                                * the sign tool.
+                                */
+    char *openpgp_textmode;     /* The arg GPG needs for text files.  */
+    verify_state verify;       /* Whether to verify checkouts.  */
+    char *verify_template;     /* The template to use to launch the external
+                                * program to verify GPG signatures.
+                                */
+    List *verify_args;         /* Keep track of any additional arguments for
+                                * the verify tool.
+                                */
+
 /* The following is required for servers now to allow Redirects to be sent
  * for remote roots when client support is disabled.
  */
@@ -69,3 +95,5 @@
 struct config *get_root_allow_config (const char *arg, const char *configPath);
 const char *primary_root_translate (const char *root_in);
 const char *primary_root_inverse_translate (const char *root_in);
+
+#endif /* ROOT_H */
Index: ccvs/src/run.c
diff -u ccvs/src/run.c:1.62 ccvs/src/run.c:1.63
--- ccvs/src/run.c:1.62 Tue Oct 18 17:31:14 2005
+++ ccvs/src/run.c      Mon Apr 24 18:50:27 2006
@@ -12,12 +12,19 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.  */
 
-/* CVS headers.  */
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* CONFIG_H */
+
+/* Verify interface.  */
+#include "run.h"
 
 /* GNULIB headers.  */
 #include "wait.h"
 
+/* CVS headers.  */
+#include "cvs.h"
+
 
 
 /*
Index: ccvs/src/sanity.config.sh.in
diff -u ccvs/src/sanity.config.sh.in:1.3 ccvs/src/sanity.config.sh.in:1.4
--- ccvs/src/sanity.config.sh.in:1.3    Mon Sep  5 02:37:41 2005
+++ ccvs/src/sanity.config.sh.in        Mon Apr 24 18:50:27 2006
@@ -1 +1,3 @@
address@hidden@
+RSH_DFLT="@RSH_DFLT@"
+GPG="@GPG@"
+DEFAULT_VERIFY_TEMPLATE="@DEFAULT_VERIFY_TEMPLATE@"
Index: ccvs/src/sanity.sh
diff -u ccvs/src/sanity.sh:1.1125 ccvs/src/sanity.sh:1.1126
--- ccvs/src/sanity.sh:1.1125   Fri Apr  7 14:25:10 2006
+++ ccvs/src/sanity.sh  Mon Apr 24 18:50:27 2006
@@ -2,9 +2,8 @@
 :
 #      sanity.sh -- a growing testsuite for cvs.
 #
-# The copyright notice said: "Copyright (C) 1992, 1993 Cygnus Support"
-# I'm not adding new copyright notices for new years as our recent 
-# practice has been to include copying terms without copyright notices.
+# Copyright (C) 2006 The Free Software Foundation, Inc.
+# Copyright (C) 1992, 1993 Cygnus Support
 #
 # 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
@@ -38,6 +37,7 @@
     usage
     echo
     echo "-H|--help    display this text"
+    echo "-q            Reduce verbosity."
     echo "-c CONFIG-FILE"
     echo "--config=CONFIG_FILE"
     echo "             use an alternate test suite config file (defaults to"
@@ -62,7 +62,7 @@
     echo "             --keep"
     echo "-l|--link-root"
     echo "             test CVS using a symlink to a real CVSROOT"
-    echo "-n|--noredirect"
+    echo "-n|--no-redirect"
     echo "              test a secondary/primary CVS server (writeproxy)"
     echo "              configuration with the Redirect response disabled"
     echo "              (implies --proxy)."
@@ -74,6 +74,7 @@
     echo "             use CVS-FOR-CVS-SERVER as the path to the CVS SERVER"
     echo "             executable to be tested (defaults to CVS-TO-TEST and"
     echo "             implies --remote)"
+    echo "-B|--no-bases suppress use of Base files."
     echo
     echo "CVS-TO-TEST  the path to the CVS executable to be tested; used as"
     echo "             the path to the CVS client when CVS-FOR-CVS-SERVER is"
@@ -129,14 +130,16 @@
 unset fromtest
 unset remotehost
 unset rootoptions
+bases=:
 keep=false
 linkroot=false
 noredirect=false
 proxy=false
+quiet=false
 remote=false
 servercvs=false
 skipfail=false
-while getopts Hc:ef:h:klnprs:-: option ; do
+while getopts BHc:ef:h:klnpqrs:-: option ; do
     # convert the long opts to short opts
     if test x$option = x-;  then
        # remove any argument
@@ -178,7 +181,15 @@
                option=l
                OPTARG=
                ;;
-           n|no|nor|nore|nored|noredi|noredir|noredire|noredirec|noredirect)
+           no-*)
+               echo "Ambiguous option \`$LONGOPT'" >&2
+               exit 2
+               ;;
+           no-b|no-ba|no-bas|no-base|no-bases)
+               option=B
+               OPTARG=
+               ;;
+           no-r|no-re|no-red|no-redi|no-redir|no-redire|no-redirec|no-redirect)
                option=n
                OPTARG=
                ;;
@@ -208,6 +219,9 @@
        esac
     fi
     case "$option" in
+       B)
+           bases=false
+           ;;
        c)
            configfile="$OPTARG"
            ;;
@@ -247,6 +261,9 @@
            proxy=:
            remote=:
            ;;
+       q)
+           quiet=:
+           ;;
        r)
            remote=:
            ;;
@@ -417,6 +434,25 @@
   testcvs_server_support=false
 fi
 
+if $bases; then
+  unset CVSNOBASES
+  # Accept the default GPG mode.
+  unset CVS_SIGN_COMMITS
+  unset CVS_VERIFY_CHECKOUTS
+else
+  # Force the client to not report base support to the server.
+  export CVSNOBASES=:
+  if $remote; then
+    # CVS doesn't support OpenPGP signatures without Base-* requests in
+    # client/server mode.  Stop the client from trying.
+    export CVS_VERIFY_CHECKOUTS=off
+    export CVS_SIGN_COMMITS=off
+    # This fools this script into believing configure couldn't find a working
+    # gpg.
+    GPG=gpg
+  fi
+fi
+
 
 
 dokeep() 
@@ -436,11 +472,15 @@
 # "debugger"
 #set -x
 
-echo 'This test should produce no other output than this message, and a final 
"OK".'
-echo '(Note that the test can take an hour or more to run and periodically 
stops'
-echo 'for as long as one minute.  Do not assume there is a problem just 
because'
-echo 'nothing seems to happen for a long time.  If you cannot live without'
-echo "running status, try the command: \`tail -f check.log' from another 
window.)"
+if $quiet; then :; else
+  cat <<EOF
+This test should produce no other output than this message, and a final "OK".
+(Note that the test can take an hour or more to run and periodically stops
+for as long as one minute.  Do not assume there is a problem just because
+nothing seems to happen for a long time.  If you cannot live without
+running status, try the command: \`tail -f check.log' from another window.)
+EOF
+fi
 
 # Regexp to match what the CVS client will call itself in output that it 
prints.
 # FIXME: we don't properly quote this--if the name contains . we'll
@@ -462,6 +502,9 @@
 # Regexp to match a commitid
 commitid="[a-zA-Z0-9]*"
 
+# Regexp to match an OpenPGP key id.
+keyid="0x[0-9a-f]*"
+
 # Regexp to match the name of a temporary file (from cvs_temp_name).
 # This appears in certain diff output.
 tempfile="cvs[-a-zA-Z0-9.%_]*"
@@ -469,6 +512,11 @@
 
 # Regexp to match a date in RFC822 format (as amended by RFC1123).
 RFCDATE="[a-zA-Z0-9 ][a-zA-Z0-9 ]* [0-9:][0-9:]* -0000"
+if $remote; then
+  LOCAL_RFCDATE=
+else
+  LOCAL_RFCDATE="      $RFCDATE"
+fi
 RFCDATE_EPOCH="1 Jan 1970 00:00:00 -0000"
 
 # Special times used in touch -t commands and the regular expresions
@@ -1234,6 +1282,24 @@
     modify_repo cp -Rp $TESTDIR/CVSROOT.save $CVSROOT_DIRNAME/CVSROOT
 }
 
+# OpenPGP signatures don't play nice with RCS keywords, so disable signatures
+# for the duration of a test.
+test_uses_keywords ()
+{
+  save_CVS_VERIFY_CHECKOUTS=$CVS_VERIFY_CHECKOUTS
+  CVS_VERIFY_CHECKOUTS=off; export CVS_VERIFY_CHECKOUTS
+}
+
+test_uses_keywords_done ()
+{
+  if test "x$save_CVS_VERIFY_CHECKOUTS" != x; then
+    CVS_VERIFY_CHECKOUTS=$save_CVS_VERIFY_CHECKOUTS
+    export CVS_VERIFY_CHECKOUTS
+  else
+    unset CVS_VERIFY_CHECKOUTS
+  fi
+}
+
 # Test that $RSYNC supports the options we need or try to find a
 # replacement. If $RSYNC works or we replace it, and return 0.
 # Otherwise, set $skipreason and return 77.
@@ -1700,6 +1766,108 @@
 mkdir home
 HOME=$TESTDIR/home; export HOME
 
+# If $GPG is set, create a key for these tests.
+OPENPGP_PHRASE=
+log_keyid=
+if test x"$GPG" != xgpg; then
+  # This works around a problem in at least a GnuPG 1.2.6 on an AMD64 running
+  # a Linux 2.6.9.
+  mkdir $HOME/.gnupg; chmod 0700 $HOME/.gnupg
+
+  # Output some status info to the log and create the key files.
+  $GPG --list-keys >>$LOGFILE 2>&1
+
+  # Import the test keys.
+  $GPG --import - <<EOF >>$LOGFILE 2>&1
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Version: GnuPG v1.4.2 (GNU/Linux)
+
+mQGiBENKukgRBADJERMkgpE7Uo+ZahIZ8rsgnhyiRtn96SQFumeBuclUcRIbT/XK
+2Qt1vvzd/QtunFP+U/V2sZHpt4e4dkXUNMssmTO8bZZgJJnhHkVTzEtMVY+qIfvC
+lgZw99aGAHthTjpn2NFRRFlU8dOlCeoEYMsQ9kG7lC2DWfr8QF6Wv537VwCg5a+q
+2Tp0OdnPzdx9ZczHeRPLyosD/2IWoMuz76O3M2WqWV07S0OwGFBWS9NulwSZafgz
+6AzWcgJN4DvXruSCHUg/89zE8gMkM+jCBABi9jUT5O/zCMccRfOyzprwP+Darfp/
+83s3OerU+nvZkG6fTkoUJt4oZkhJ+034aac6SiCE8vD4KvNZ+ZQyq9AQjXHGTfq/
+SUhzA/9MsX9FwkruhbMti9nOuSBV9tqsEM+8vWjSJ+hlSviWCkFWV0De8yHiTq6m
+7Bfymk4/mR336C0gSWVucA6qSfH5bYC+0jfqpc9poc/slxZA6T4gd9JZ41WvBqPj
+BOs4lsvBnTKk9f7Jyg5BzrXT9ukVPfeyTVi3I49+1TV/BMk2ubRuQ1ZTIFRlc3Qg
+U2NyaXB0IChUaGlzIHNlY3JldCBrZXkgaXMgcHVibGljIGFuZCB1c2VkIGZvciB0
+ZXN0aW5nIHNpZ25lZCBjb21taXRzIHdpdGggQ1ZTLikgPGJ1Zy1jdnNAbm9uZ251
+Lm9yZz6IYAQTEQIAIAUCQ0q6SAIbAwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJ
+EI4MLH7xM73pnmQAn36k+iNEi+fdfFxoWNdB8DPIzOY8AKCWVfBZa/jAH64FaQYL
+ls1jFXLbELkCDQRDSrpbEAgAm3FjA6iU71Dm/iJy+RoI5T7MIZeiz6vpIg1IA0Ch
+h2lSaEbPxNAImRQyz+KNyMPofIA/DsS5rAHmMfTXFQf5JWrnotaVokHY3ucnPU7y
+vZGiYR+DJNbSThCRW+sgxYSUQLXPsIGQ4/MnI2rJO+y8RIRvGQYi63OpkTzsGAAO
+vfi42ui6SAfEvKQ73KvzF/lf5a9NokmM+nDkFzOJCfSFitY4KD/UmL62fq5TadGT
+mPscQF+DZ+V1txxN+xcnXJAG3OiOkDsKRap8sY4kG8WSG0vPCVdm+O4xzTQY/JQe
+aCs4le1J5nR4OKcmEnojlOZqPA4oZ52mXGFxBLHevvzokwADBQf/TJVH/iFqjbKx
+28Sw7aB4iYmE5P7+mCQcDmJERR1DJI8/awU/5kLSIETGKsXuAA/V9NPPAyd/AKve
+ulwLqjFEFNyFU3Vm1CAL6EcSw+Km2MseaUqA8MJCEyCd3NKc66Evarf+0G7iFV7h
+xJDnzUfhhaZBULPDBVgJ6AqNjC7tQm0EsBuGKxDIlxBQ+skO/nrI9vX6dwbEtBDs
+ClnpLOGebqZZArGsv0xEpfjMq/qPnwy53jEQYk5hxvLUHy4wZlIHD0SE9Q+kAElp
+9NE6IxKOqRR6vLs3m9833BMeGsIIbY8oBPAOd6BVbdGxLsGMX/FVGRhvExZX8k6C
+iqU/6EnlkYhJBBgRAgAJBQJDSrpbAhsMAAoJEI4MLH7xM73p/wMAnRvt70NgB6st
+B0RRhW3h2s/P7BCMAKDKqifj54oz/mJotQABGP13nW/gOA==
+=7ufq
+-----END PGP PUBLIC KEY BLOCK-----
+EOF
+  $GPG --allow-secret-key-import --import - <<EOF >>$LOGFILE 2>&1
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+Version: GnuPG v1.4.2 (GNU/Linux)
+
+lQG7BENKukgRBADJERMkgpE7Uo+ZahIZ8rsgnhyiRtn96SQFumeBuclUcRIbT/XK
+2Qt1vvzd/QtunFP+U/V2sZHpt4e4dkXUNMssmTO8bZZgJJnhHkVTzEtMVY+qIfvC
+lgZw99aGAHthTjpn2NFRRFlU8dOlCeoEYMsQ9kG7lC2DWfr8QF6Wv537VwCg5a+q
+2Tp0OdnPzdx9ZczHeRPLyosD/2IWoMuz76O3M2WqWV07S0OwGFBWS9NulwSZafgz
+6AzWcgJN4DvXruSCHUg/89zE8gMkM+jCBABi9jUT5O/zCMccRfOyzprwP+Darfp/
+83s3OerU+nvZkG6fTkoUJt4oZkhJ+034aac6SiCE8vD4KvNZ+ZQyq9AQjXHGTfq/
+SUhzA/9MsX9FwkruhbMti9nOuSBV9tqsEM+8vWjSJ+hlSviWCkFWV0De8yHiTq6m
+7Bfymk4/mR336C0gSWVucA6qSfH5bYC+0jfqpc9poc/slxZA6T4gd9JZ41WvBqPj
+BOs4lsvBnTKk9f7Jyg5BzrXT9ukVPfeyTVi3I49+1TV/BMk2uQAAn2yLGViOPcBN
+n3q8J05O/mgSJII1CMq0bkNWUyBUZXN0IFNjcmlwdCAoVGhpcyBzZWNyZXQga2V5
+IGlzIHB1YmxpYyBhbmQgdXNlZCBmb3IgdGVzdGluZyBzaWduZWQgY29tbWl0cyB3
+aXRoIENWUy4pIDxidWctY3ZzQG5vbmdudS5vcmc+iGAEExECACAFAkNKukgCGwMG
+CwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCODCx+8TO96Z5kAJ9+pPojRIvn3Xxc
+aFjXQfAzyMzmPACgllXwWWv4wB+uBWkGC5bNYxVy2xCdAj0EQ0q6WxAIAJtxYwOo
+lO9Q5v4icvkaCOU+zCGXos+r6SINSANAoYdpUmhGz8TQCJkUMs/ijcjD6HyAPw7E
+uawB5jH01xUH+SVq56LWlaJB2N7nJz1O8r2RomEfgyTW0k4QkVvrIMWElEC1z7CB
+kOPzJyNqyTvsvESEbxkGIutzqZE87BgADr34uNroukgHxLykO9yr8xf5X+WvTaJJ
+jPpw5BcziQn0hYrWOCg/1Ji+tn6uU2nRk5j7HEBfg2fldbccTfsXJ1yQBtzojpA7
+CkWqfLGOJBvFkhtLzwlXZvjuMc00GPyUHmgrOJXtSeZ0eDinJhJ6I5TmajwOKGed
+plxhcQSx3r786JMAAwUH/0yVR/4hao2ysdvEsO2geImJhOT+/pgkHA5iREUdQySP
+P2sFP+ZC0iBExirF7gAP1fTTzwMnfwCr3rpcC6oxRBTchVN1ZtQgC+hHEsPiptjL
+HmlKgPDCQhMgndzSnOuhL2q3/tBu4hVe4cSQ581H4YWmQVCzwwVYCegKjYwu7UJt
+BLAbhisQyJcQUPrJDv56yPb1+ncGxLQQ7ApZ6Szhnm6mWQKxrL9MRKX4zKv6j58M
+ud4xEGJOYcby1B8uMGZSBw9EhPUPpABJafTROiMSjqkUery7N5vfN9wTHhrCCG2P
+KATwDnegVW3RsS7BjF/xVRkYbxMWV/JOgoqlP+hJ5ZEAAVICdnxl8jck88Pp3iBR
+9KOIKN6r1zfz4/9rlkHXH5yiNCTYxwPx2qLMH2LbGJ+ISQQYEQIACQUCQ0q6WwIb
+DAAKCRCODCx+8TO96f8DAJ9CnJg/ewM3MoWqO1AY+KSSMJkCGgCeI8vv810E1G+C
+B2xyFA1/6G+hv7k=
+=k49u
+-----END PGP PRIVATE KEY BLOCK-----
+EOF
+  $GPG --import-ownertrust <<EOF >>$LOGFILE 2>&1
+F1D6D5842814BC3A264BE7068E0C2C7EF133BDE9:6:
+EOF
+
+  # Some tests check the content of the RCS file and whether there is a
+  # signature phrase or not depends on whether they were being generated.
+  # The trailing EOL is important.
+  OPENPGP_PHRASE='openpgp-signatures   @[a-zA-Z0-9/+]*=*@;
+'
+  log_keyid="OpenPGP signature using key ID 0x[0-9a-f]*;
+"
+  gpg=:
+  CVS_VERIFY_TEMPLATE="`echo $DEFAULT_VERIFY_TEMPLATE \
+                       |sed 's/ -- / --quiet -- /'` 2>/dev/null"
+  export CVS_VERIFY_TEMPLATE
+else # GPG not set
+  echo "No working GPG was found.  This test suite will run, but OpenPGP" >&2
+  echo "commit signatures will not be tested." >&2
+  gpg=false
+fi # GPG set
+
+
 # Make sure this variable is not defined to anything that would
 # change the format of rcs dates.  Otherwise people using e.g.,
 # RCSINIT=-zLT get lots of spurious failures.
@@ -1740,7 +1908,7 @@
         tests="${tests} rstar-toplevel trailingslashes checkout_repository"
        # Log messages, error messages.
        tests="${tests} mflag editor env errmsg1 errmsg2 adderrmsg opterrmsg"
-       tests="${tests} errmsg3"
+       tests="$tests errmsg3 errmsg4"
        tests="${tests} close-stdout"
        tests="$tests debug-log-nonfatal"
        # Watches, binary files, history browsing, &c.
@@ -1748,7 +1916,7 @@
         tests="${tests} edit-check"
        tests="${tests} unedit-without-baserev"
        tests="${tests} ignore ignore-on-branch binfiles binfiles2 binfiles3"
-       tests="${tests} mcopy binwrap binwrap2"
+       tests="${tests} binwrap binwrap2"
        tests="${tests} binwrap3 mwrap info taginfo posttag"
        tests="$tests config config2 config3 config4 compression"
        tests="${tests} serverpatch log log2 logopt ann ann-id"
@@ -1778,6 +1946,7 @@
        tests="${tests} dottedroot fork commit-d template"
        tests="${tests} writeproxy writeproxy-noredirect writeproxy-ssh"
        tests="${tests} writeproxy-ssh-noredirect"
+       tests="$tests openpgp"
 else
        tests="$*"
 fi
@@ -2690,19 +2859,22 @@
 # Testing :pserver: would be hard (inetd issues).  (How about using tcpserver
 # and some high port number?  DRP)
 
-if $linkroot; then
-    mkdir ${TESTDIR}/realcvsroot
-    ln -s realcvsroot ${TESTDIR}/cvsroot
-fi
-CVSROOT_DIRNAME=${TESTDIR}/cvsroot
-CVSROOT=`newroot $CVSROOT_DIRNAME`; export CVSROOT
-
 
 
 ###
 ### Initialize the repository
 ###
-dotest init-1 "$testcvs init"
+CVSROOT_DIRNAME=$TESTDIR/cvsroot
+CVSROOT=`newroot $CVSROOT_DIRNAME`; export CVSROOT
+dotest init-1 "$testcvs -d$CVSROOT_DIRNAME init"
+
+
+
+# Hide the real root behind a symlink in $linkroot mode.
+if $linkroot; then
+    mv $CVSROOT_DIRNAME $TESTDIR/realcvsroot
+    ln -s realcvsroot mv $CVSROOT_DIRNAME
+fi
 
 # Now hide the primary root behind a secondary if requested.
 if $proxy; then
@@ -3000,6 +3172,7 @@
 "${SPROG} tag: nothing known about ssfile
 ${SPROG} "'\[tag aborted\]: correct the above errors first!'
          cd ../..
+
          dotest basica-5 "${testcvs} -q ci -m add-it" \
 "$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  sdir/ssdir/ssfile
 initial revision: 1\.1"
@@ -3013,37 +3186,25 @@
          dotest basica-6 "${testcvs} -q update" ''
          echo "ssfile line 2" >>sdir/ssdir/ssfile
          dotest_fail basica-6.2 "${testcvs} -q diff -c" \
-"Index: sdir/ssdir/ssfile
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
-retrieving revision 1\.1
-diff -c -r1\.1 ssfile
+"diff -c -r1\.1 sdir/ssdir/ssfile
 \*\*\* sdir/ssdir/ssfile       ${RFCDATE}      1\.1
---- sdir/ssdir/ssfile  ${RFCDATE}
+--- sdir/ssdir/ssfile$LOCAL_RFCDATE
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \*\*\* 1 \*\*\*\*
 --- 1,2 ----
   ssfile
 ${PLUS} ssfile line 2"
          dotest_fail basica-6.3 "${testcvs} -q diff -c -rBASE" \
-"Index: sdir/ssdir/ssfile
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
-retrieving revision 1\.1
-diff -c -r1\.1 ssfile
+"diff -c -r1\.1 sdir/ssdir/ssfile
 \*\*\* sdir/ssdir/ssfile       ${RFCDATE}      1\.1
---- sdir/ssdir/ssfile  ${RFCDATE}
+--- sdir/ssdir/ssfile$LOCAL_RFCDATE
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \*\*\* 1 \*\*\*\*
 --- 1,2 ----
   ssfile
 ${PLUS} ssfile line 2"
          dotest_fail basica-6.4 "${testcvs} -q diff -c -rBASE -C3isacrowd" \
-"Index: sdir/ssdir/ssfile
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/sdir/ssdir/ssfile,v
-retrieving revision 1\.1
-diff -c -C 3isacrowd -r1\.1 ssfile
+"diff -c -C 3isacrowd -r1\.1 sdir/ssdir/ssfile
 ${SPROG} diff: invalid context length argument"
          dotest basica-7 "${testcvs} -q ci -m modify-it" \
 "$CVSROOT_DIRNAME/first-dir/sdir/ssdir/ssfile,v  <--  sdir/ssdir/ssfile
@@ -3219,15 +3380,15 @@
 ----------------------------
 revision 3\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-bump-it
+${log_keyid}bump-it
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-it
+${log_keyid}modify-it
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add-it
+${log_keyid}add-it
 ============================================================================="
          dotest basica-o8 "${testcvs} -q update -p -r 1.1 ./ssfile" "ssfile"
          cd ../..
@@ -3235,7 +3396,7 @@
          cd ..
 
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r first-dir
+         rm -rf first-dir
          ;;
 
 
@@ -3266,7 +3427,7 @@
          dotest basicb-0e "${testcvs} add first-dir" \
 "Directory ${CVSROOT_DIRNAME}/first-dir added to the repository"
          cd ..
-         rm -r 2
+         rm -rf 2
 
          dotest basicb-1 "${testcvs} -q co first-dir" ''
 
@@ -3347,7 +3508,7 @@
          dotest basicb-cod-1 "${testcvs} -q co -d first-dir1 first-dir" \
 'U first-dir1/Emptydir/sfile1
 U first-dir1/sdir2/sfile2'
-         rm -r first-dir1
+         rm -rf first-dir1
 
          rm -r first-dir
 
@@ -3384,7 +3545,7 @@
 "sfile1 develops
 sfile2 starts"
 
-         rm -r newdir
+         rm -rf newdir
 
          # Hmm, this might be a case for CVSNULLREPOS, but CVS doesn't
          # seem to deal with it...
@@ -3433,7 +3594,7 @@
 deleting revision 1\.1
 ${SPROG} \[admin aborted\]: attempt to delete all revisions"
          cd ..
-         rm -r 1
+         rm -rf 1
 
          mkdir 1; cd 1
          # Note that -H is an invalid option.
@@ -3550,7 +3711,7 @@
 D/second-dir////"
 
          cd ..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -4230,7 +4391,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
@@ -4247,7 +4408,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 =============================================================================
 ${SPROG} log: Logging first-dir/dir1
 ${SPROG} log: file14 has been added, but not committed
@@ -4266,7 +4427,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/file7,v
@@ -4283,7 +4444,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 =============================================================================
 ${SPROG} log: Logging first-dir/dir1/dir2
 ${SPROG} log: file14 has been added, but not committed
@@ -4302,7 +4463,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/dir1/dir2/file7,v
@@ -4319,7 +4480,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-second dive
+${log_keyid}second dive
 ============================================================================="
 
                dotest basic2-14 "${testcvs} status first-dir" \
@@ -4691,9 +4852,8 @@
 
                dotest basic2-33 "directory_cmp first-dir second-dir"
 
-               rm -r second-dir
-
-               rm -r export-dir first-dir
+               rm -rf first-dir second-dir
+               rm -r export-dir
                mkdir first-dir
                (cd first-dir.cpy ; tar cf - . | (cd ../first-dir ; tar xf -))
 
@@ -4732,7 +4892,7 @@
                #### and fix or remove the test.
 #              dotest basic2-39 "directory_cmp 1dir first-dir"
 
-               rm -r 1dir first-dir
+               rm -rf 1dir first-dir
 
                # Test the cvs history command.
                #
@@ -4793,7 +4953,7 @@
 T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir 
\[rtagged-by-tag:rtagged-by-head\]
 T [0-9-]* [0-9:]* ${PLUS}0000 ${username} first-dir 
\[rtagged-by-revision:1\.1\]
 O [0-9-]* [0-9:]* ${PLUS}0000 ${username} \[1\.1\] first-dir           
=first-dir= <remote>/\*
-P [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir           
== <remote>
+[UP] [0-9-]* [0-9:]* ${PLUS}0000 ${username} 1\.2 file6     first-dir          
 == <remote>
 W [0-9-]* [0-9:]* ${PLUS}0000 ${username}     file7     first-dir           == 
<remote>"
          fi
 
@@ -5053,7 +5213,7 @@
 
          dokeep
          cd ../../..
-         rm -r ls
+         rm -rf ls
          modify_repo rm -rf $CVSROOT_DIRNAME/notcheckedout \
                             $CVSROOT_DIRNAME/cemetery
          unset output_living output_dead
@@ -5112,7 +5272,7 @@
          # Clean up
          CVSROOT=$CVSROOT_save
          cd ..
-         rm -r 1
+         rm -rf 1
          ;;
 
 
@@ -5265,7 +5425,7 @@
 "U first dir/a file"
          cd ..
 
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf "'$CVSROOT_DIRNAME/first dir'" \
                             $CVSROOT_DIRNAME/-b $CVSROOT_DIRNAME/-c,v
          ;;
@@ -5273,6 +5433,8 @@
 
 
        commit-readonly)
+         test_uses_keywords
+
          mkdir 1; cd 1
          module=x
 
@@ -5301,6 +5463,7 @@
          cd ../..
          rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/"$module"
+         test_uses_keywords_done
          ;;
 
 
@@ -5331,13 +5494,9 @@
 new revision: 1\.2; previous revision: 1\.1"
                cd ../first-dir
                echo force a conflict >>tfile
-               dotest status-init-7 "${testcvs} -q up" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/tfile,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into tfile
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in tfile
+               dotest status-init-7 "$testcvs -q up" \
+"Merging differences between 1\.1 and 1\.2 into \`tfile'
+$CPROG update: conflicts during merge
 C tfile"
 
                # Now note our status
@@ -5500,6 +5659,8 @@
 
        rdiff)
                # Test rdiff
+               test_uses_keywords
+
                mkdir testimport
                cd testimport
                echo '$''Id$' > foo
@@ -5520,20 +5681,14 @@
 U trdiff/foo"
                cd trdiff
                echo something >> foo
-               dotest rdiff-3 \
-                 "${testcvs} ci -m added-something foo" \
-"${CVSROOT_DIRNAME}/trdiff/foo,v  <--  foo
-new revision: 1\.2; previous revision: 1\.1"
+               dotest rdiff-3 "$testcvs -Q ci -m added-something foo"
                echo '#ident    "@(#)trdiff:$''Name$:$''Id$"' > new
                echo "new file" >> new
                dotest rdiff-4 \
                  "${testcvs} add -m new-file-description new" \
 "${SPROG} add: scheduling file \`new' for addition
 ${SPROG} add: use .${SPROG} commit. to add this file permanently"
-               dotest rdiff-5 \
-                 "${testcvs} commit -m added-new-file new" \
-"${CVSROOT_DIRNAME}/trdiff/new,v  <--  new
-initial revision: 1\.1"
+               dotest rdiff-5 "$testcvs -Q commit -m added-new-file new"
                dotest rdiff-6 \
                  "${testcvs} tag local-v0" \
 "${SPROG} tag: Tagging .
@@ -5558,7 +5713,7 @@
        TRDIFF                          (branch: 1\.1\.1)"
 
                cd ..
-               rm -r trdiff
+               rm -rf trdiff
 
                dotest rdiff-8 \
                  "${testcvs} rdiff -r T1 -r local-v0 trdiff" \
@@ -5589,6 +5744,7 @@
                cd ..
                rm -r testimport
                modify_repo rm -rf $CVSROOT_DIRNAME/trdiff
+               test_uses_keywords_done
                ;;
 
 
@@ -5788,11 +5944,7 @@
          echo "#include <winsock.h>" >abc
          # check the behavior of the --ifdef=MACRO option
          dotest_fail diff-7 "${testcvs} -q diff --ifdef=HAVE_WINSOCK_H" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.2
-diff --ifdef HAVE_WINSOCK_H -r1\.2 abc
+"diff --ifdef HAVE_WINSOCK_H -r1\.2 abc
 #ifndef HAVE_WINSOCK_H
 extern int gethostname ();
 #else /\* HAVE_WINSOCK_H \*/
@@ -5827,21 +5979,13 @@
          # change to line near EOF
          ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nsix")}' </dev/null >abc
          dotest_fail diffnl-100 "${testcvs} diff abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.1
-diff -r1\.1 abc
+"diff -r1\.1 abc
 5d4
 < five"
           dotest_fail diffnl-101 "${testcvs} diff -u abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.1
-diff -u -r1\.1 abc
+"diff -u -r1\.1 abc
 --- abc        ${RFCDATE}      1\.1
-+++ abc        ${RFCDATE}
++++ abc$LOCAL_RFCDATE
 @@ -2,5 +2,4 @@
  two
  three
@@ -5856,11 +6000,7 @@
           # Change to last line
          ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null 
>abc
           dotest_fail diffnl-200 "${testcvs} diff abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.2
-diff -r1\.2 abc
+"diff -r1\.2 abc
 5c5
 < six
 \\\\ No newline at end of file
@@ -5868,13 +6008,9 @@
 > seven
 \\\\ No newline at end of file"
          dotest_fail diffnl-201 "${testcvs} diff -u abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.2
-diff -u -r1\.2 abc
+"diff -u -r1\.2 abc
 --- abc        ${RFCDATE}      1\.2
-+++ abc        ${RFCDATE}
++++ abc$LOCAL_RFCDATE
 @@ -2,4 +2,4 @@
  two
  three
@@ -5894,24 +6030,16 @@
 four
 seven" > abc
          dotest_fail diffnl-300 "${testcvs} diff abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.3
-diff -r1\.3 abc
+"diff -r1\.3 abc
 5c5
 < seven
 \\\\ No newline at end of file
 ---
 > seven"
          dotest_fail diffnl-301 "${testcvs} diff -u abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.3
-diff -u -r1\.3 abc
+"diff -u -r1\.3 abc
 --- abc        ${RFCDATE}      1\.3
-+++ abc        ${RFCDATE}
++++ abc$LOCAL_RFCDATE
 @@ -2,4 +2,4 @@
  two
  three
@@ -5926,24 +6054,16 @@
          # Removal of newline
          ${AWK} 'BEGIN {printf("one\ntwo\nthree\nfour\nseven")}' </dev/null 
>abc
          dotest_fail diffnl-400 "${testcvs} diff abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.4
-diff -r1\.4 abc
+"diff -r1\.4 abc
 5c5
 < seven
 ---
 > seven
 \\\\ No newline at end of file"
          dotest_fail diffnl-401 "${testcvs} diff -u abc" \
-"Index: abc
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/abc,v
-retrieving revision 1\.4
-diff -u -r1\.4 abc
+"diff -u -r1\.4 abc
 --- abc        ${RFCDATE}      1\.4
-+++ abc        ${RFCDATE}
++++ abc$LOCAL_RFCDATE
 @@ -2,4 +2,4 @@
  two
  three
@@ -6154,81 +6274,49 @@
                fi
 
                # commit
-               if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
-                   pass 80
-               else
-                   fail 80
-               fi
+               dotest death-80 "$testcvs -Q ci -m test"
 
                # change the first file
                echo line2 from branch1 >> file1
 
                # commit
-               if ${CVS} ci -m test  >> ${LOGFILE} 2>&1; then
-                   pass 81
-               else
-                   fail 81
-               fi
+               dotest death-81 "$testcvs -Q ci -m test"
 
                # remove the second
                rm file2
-               if ${CVS} rm file2  2>> ${LOGFILE}; then
-                   pass 82
-               else
-                   fail 82
-               fi
+               dotest death-82 "$testcvs -Q rm file2"
 
                # commit
-               if ${CVS} ci -m test  >>${LOGFILE}; then
-                   pass 83
-               else
-                   fail 83
-               fi
+               dotest death-83 "$testcvs -Q ci -m test"
 
                # back to the trunk.
-               if ${CVS} update -A  2>> ${LOGFILE}; then
-                   pass 84
-               else
-                   fail 84
-               fi
+               dotest death-84 "$testcvs -Q update -A"
 
                dotest_fail death-file4-4 "test -f file4" ''
 
-               if test -f file3 ; then
-                   fail 85
-               else
-                   pass 85
-               fi
+               dotest_fail death-85 "test -f file3"
 
                # join
                dotest death-86 "$testcvs -q update -j branch1" \
-"RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
-retrieving revision 1\.3
-retrieving revision 1\.3\.2\.1
-Merging differences between 1\.3 and 1\.3\.2\.1 into file1
-${SPROG} update: scheduling \`file2' for removal
-U file3"
+"$SPROG update: Replacing \`file1' with contents of revision 1\.3\.2\.1\.
+M file1
+$SPROG update: scheduling \`file2' for removal
+$SPROG update: scheduling addition from revision 1\.1\.2\.3 of \`file3'\."
+               dotest_fail death-file4-5 "test -f file4"
 
-               dotest_fail death-file4-5 "test -f file4" ''
-
-               if test -f file3 ; then
-                   pass 87
-               else
-                   fail 87
-               fi
+               dotest death-87 "test -f file3"
 
                # Make sure that we joined the correct change to file1
                dotest death-87a "echo line2 from branch1 |$diff_u - file1"
 
                # update
-               if ${CVS} update  ; then
-                   pass 88
-               else
-                   fail 88
-               fi
+               dotest death-88 "$testcvs -q update" \
+"M file1
+R file2
+A file3"
 
                # commit
-               dotest 89 "${testcvs} -q ci -m test" \
+               dotest death-89 "$testcvs -q ci -m test" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.4; previous revision: 1\.3
 $CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
@@ -6238,80 +6326,53 @@
                cd ..
                mkdir 2
                cd 2
-               dotest 89a "${testcvs} -q co first-dir" 'U first-dir/file1
+               dotest death-89a "$testcvs -q co first-dir" \
+'U first-dir/file1
 U first-dir/file3'
                cd ..
-               rm -r 2
+               rm -rf 2
                cd first-dir
 
                # remove first file.
                rm file1
-               if ${CVS} rm file1  2>> ${LOGFILE}; then
-                   pass 90
-               else
-                   fail 90
-               fi
+               dotest death-90 "$testcvs -Q rm file1"
 
                # commit
-               if ${CVS} ci -m test  >>${LOGFILE}; then
-                   pass 91
-               else
-                   fail 91
-               fi
-
-               if test -f file1 ; then
-                   fail 92
-               else
-                   pass 92
-               fi
+               dotest death-91 "$testcvs -Q ci -m test"
+               dotest_fail death-92 "test -f file1"
 
                # typo; try to get to the branch and fail
                dotest_fail 92.1a "$testcvs update -r brnach1" \
                  "$SPROG \[update aborted\]: no such tag \`brnach1'"
                # Make sure we are still on the trunk
-               if test -f file1 ; then
-                   fail 92.1b
-               else
-                   pass 92.1b
-               fi
-               if test -f file3 ; then
-                   pass 92.1c
-               else
-                   fail 92.1c
-               fi
+               dotest_fail death-92.1b "test -f file1"
+               dotest death-92.1c "test -f file3"
 
                # back to branch1
-               if ${CVS} update -r branch1  2>> ${LOGFILE}; then
-                   pass 93
-               else
-                   fail 93
-               fi
-
-               dotest_fail death-file4-6 "test -f file4" ''
+               dotest death-93 "$testcvs -q update -r branch1" \
+"U file1
+U file3"
 
-               if test -f file1 ; then
-                   pass 94
-               else
-                   fail 94
-               fi
+               dotest_fail death-file4-6 "test -f file4"
+               dotest death-94 "test -f file1"
 
                # and join
-               dotest 95 "${testcvs} -q update -j HEAD" \
-"${SPROG}"' update: file file1 has been modified, but has been removed in 
revision HEAD
-'"${SPROG}"' update: file file3 exists, but has been added in revision HEAD'
+               dotest death-95 "$testcvs -q update -j HEAD" \
+"$SPROG update: file file1 has been modified, but has been removed in revision 
HEAD
+$SPROG update: file file3 exists, but has been added in revision HEAD"
 
-               dotest_fail death-file4-7 "test -f file4" ''
+               dotest_fail death-file4-7 "test -f file4"
 
                # file2 should not have been recreated.  It was
                # deleted on the branch, and has not been modified on
                # the trunk.  That means that there have been no
                # changes between the greatest common ancestor (the
                # trunk version) and HEAD.
-               dotest_fail death-file2-1 "test -f file2" ''
+               dotest_fail death-file2-1 "test -f file2"
 
                dokeep
                cd ..
-               rm -r first-dir
+               rm -rf first-dir
                modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
                ;;
 
@@ -6358,12 +6419,8 @@
          # Test diff of the removed file before it is committed.
          dotest_fail death2-diff-1 "${testcvs} -q diff file1" \
 "${SPROG} diff: file1 was removed, no comparison available"
-
          dotest_fail death2-diff-2 "${testcvs} -q diff -N -c file1" \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N -r1\.1 file1
 \*\*\* file1   ${RFCDATE}      [0-9.]*
 --- /dev/null  ${RFCDATE_EPOCH}
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6385,13 +6442,9 @@
 "${testcvs} -q diff -rbranch -r1.1 -c file1" \
 "${SPROG} diff: Tag branch refers to a dead (removed) revision in file 
.file1.\.
 ${SPROG} diff: No comparison available\.  Pass .-N. to .${SPROG} 
diff.${QUESTION}"
-
          dotest_fail death2-diff-4 \
 "${testcvs} -q diff -r1.1 -rbranch -N -c file1" \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N -r1\.1 -r1\.1\.2\.1
 \*\*\* file1   ${RFCDATE}      [0-9.]*
 --- /dev/null  ${RFCDATE_EPOCH}
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6401,10 +6454,7 @@
          # and in reverse
          dotest_fail death2-diff-4a \
 "${testcvs} -q diff -rbranch -r1.1 -N -c file1" \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N -r1\.1\.2\.1 -r1\.1
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
 --- file1      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6417,10 +6467,7 @@
 "${SPROG} diff: file1 no longer exists, no comparison available"
 
          dotest_fail death2-diff-6 "${testcvs} -q diff -rtag -N -c ." \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N -r1\.1 file1
 \*\*\* file1   [-a-zA-Z0-9: ]* [0-9.]*
 --- /dev/null  ${RFCDATE_EPOCH}
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6453,12 +6500,9 @@
 "${SPROG} diff: file1 is a new entry, no comparison available"
 
          dotest_fail death2-diff-8 "${testcvs} -q diff -N -c file1" \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N file1
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
---- file1      ${RFCDATE}
+--- file1$LOCAL_RFCDATE
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \*\*\* 0 \*\*\*\*
 --- 1 ----
@@ -6528,10 +6572,7 @@
 "$SPROG diff: tag tag is not in file file3"
 
          dotest_fail death2-diff-10 "${testcvs} -q diff -rtag -N -c file3" \
-"Index: file3
-===================================================================
-RCS file: file3
-diff -N file3
+"diff -c -N -r1\.1\.2\.1 file3
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
 --- file3      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6540,12 +6581,7 @@
 ${PLUS} first revision"
 
          dotest_fail death2-diff-11 "${testcvs} -q diff -rtag -c ." \
-"Index: file1
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.2
-diff -c -r1\.1 -r1\.1\.2\.2
+"diff -c -r1\.1 -r1\.1\.2\.2
 \*\*\* file1   ${RFCDATE}      [0-9.]*
 --- file1      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6558,12 +6594,7 @@
 ${SPROG} diff: file4 no longer exists, no comparison available"
 
          dotest_fail death2-diff-12 "${testcvs} -q diff -rtag -c -N ." \
-"Index: file1
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.2
-diff -c -r1\.1 -r1\.1\.2\.2
+"diff -c -N -r1\.1 -r1\.1\.2\.2
 \*\*\* file1   ${RFCDATE}      [0-9.]*
 --- file1      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6571,30 +6602,21 @@
 ! first revision
 --- 1 ----
 ! second revision
-Index: file2
-===================================================================
-RCS file: file2
-diff -N file2
+diff -c -N -r1\.1\.2\.2 file2
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
 --- file2      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \*\*\* 0 \*\*\*\*
 --- 1 ----
 ${PLUS} branch revision
-Index: file3
-===================================================================
-RCS file: file3
-diff -N file3
+diff -c -N -r1\.1\.2\.1 file3
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
 --- file3      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \*\*\* 0 \*\*\*\*
 --- 1 ----
 ${PLUS} first revision
-Index: file4
-===================================================================
-RCS file: file4
-diff -N file4
+diff -c -N -r1\.1 file4
 \*\*\* file4   ${RFCDATE}      [0-9.]*
 --- /dev/null  ${RFCDATE_EPOCH}
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6617,10 +6639,7 @@
 ${SPROG} diff: No comparison available\.  Pass .-N. to .${SPROG} 
diff.${QUESTION}"
 
          dotest_fail death2-diff-14 "${testcvs} -q diff -r rdiff-tag -c -N" \
-"Index: file1
-===================================================================
-RCS file: file1
-diff -N file1
+"diff -c -N -r1\.1\.2\.1 -r1\.1
 \*\*\* /dev/null       ${RFCDATE_EPOCH}
 --- file1      ${RFCDATE}      [0-9.]*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -6654,7 +6673,7 @@
 
          dokeep
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -6754,7 +6773,7 @@
 
          dokeep
          cd ../..
-         rm -r rm-update-message
+         rm -rf rm-update-message
          modify_repo rm -rf $CVSROOT_DIRNAME/rm-update-message
          ;;
 
@@ -6989,7 +7008,8 @@
          dotest rmadd2-6 "${testcvs} -q ci -m remove" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: delete; previous revision: 1\.1"
-         dotest rmadd2-7 "$testcvs -q update -j 1.2 -j 1.1 file1" "U file1"
+         dotest rmadd2-7 "$testcvs -q update -j 1.2 -j 1.1 file1" \
+"$SPROG update: scheduling addition from revision 1\.1 of \`file1'\."
          dotest rmadd2-8 "${testcvs} -q ci -m readd" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.3; previous revision: 1\.2"
@@ -6997,11 +7017,9 @@
          dotest rmadd2-9 "${testcvs} -q ci -m modify" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.4; previous revision: 1\.3"
-         dotest rmadd2-10 "${testcvs} -q update -j 1.4 -j 1.3 file1" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.4
-retrieving revision 1\.3
-Merging differences between 1\.4 and 1\.3 into file1"
+         dotest rmadd2-10 "$testcvs -q update -j 1.4 -j 1.3 file1" \
+"$SPROG update: Replacing \`file1' with contents of revision 1\.3\.
+M file1"
          dotest rmadd2-11 "${testcvs} -q ci -m undo" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.5; previous revision: 1\.4"
@@ -7046,7 +7064,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -7154,7 +7172,7 @@
 $SPROG add: Re-adding file \`file1' after dead revision 1\.2\.
 $SPROG add: Resurrecting file \`file1' from revision 1\.1\.
 $SPROG add: use \`$SPROG commit' to add this file permanently"
-         dotest resurrection-4 "$testcvs -q diff -r1.1 file1" ""
+         dotest resurrection-4 "$testcvs -q diff -r1.1 file1"
          dotest resurrection-5 "$testcvs -q ci -mreadd" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.3; previous revision: 1\.2"
@@ -7195,7 +7213,7 @@
          dotest_sort resurrection-14 "$testcvs -r add file1" \
 "U file1
 $SPROG add: \`file1', version 1\.3, resurrected"
-         dotest_fail resurrection-15 'test -w file1' ''
+         dotest_fail resurrection-15 'test -w file1'
 
          dokeep
          cd ../..
@@ -7262,7 +7280,7 @@
 Are you sure you want to release (and delete) directory .dir1/sdir': .. 
.release' aborted by user choice."
 
          # OK, if "cvs release" won't help, we'll try it the other way...
-         rm -r dir1/sdir
+         rm -rf dir1/sdir
 
          dotest dirs-5 "cat dir1/CVS/Entries" \
 "/file1/1.1.1.1/[a-zA-Z0-9 :]*//
@@ -7276,7 +7294,7 @@
 
          dokeep
          cd ..
-         rm -r imp-dir 1
+         rm -rf imp-dir 1
          modify_repo rm -rf $CVSROOT_DIRNAME/dir1
          ;;
 
@@ -7311,7 +7329,7 @@
 ${CPROG} update: move away \`sdir/file1'; it is in the way
 C sdir/file1"
            rm sdir/file1
-           rm -r sdir/CVS
+           rm -rf sdir/CVS
 
            # This is where things are not just like conflicts3-23
            dotest dirs2-7r "${testcvs} update -d" \
@@ -7335,7 +7353,7 @@
          dotest dirs2-8 "${testcvs} -q co first-dir" 'U first-dir/sdir/file1'
          cd first-dir
          dotest dirs2-9 "${testcvs} -q tag -b br" "T sdir/file1"
-         rm -r sdir/CVS
+         rm -rf sdir/CVS
 
          if $remote; then
            # val-tags used to have a cute little quirk; if an update didn't
@@ -7378,7 +7396,7 @@
 new revision: delete; previous revision: 1\.1"
          cd ../../2/first-dir
          if $remote; then
-           dotest dirs2-14 "${testcvs} update -d -r br" \
+           dotest dirs2-14r "${testcvs} update -d -r br" \
 "${QUESTION} sdir/file1
 ${SPROG} update: Updating \.
 ${SPROG} update: Updating sdir"
@@ -7390,7 +7408,7 @@
 
          dokeep
          cd ../..
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -7510,38 +7528,33 @@
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-trunk-change-after-branch
+${log_keyid}trunk-change-after-branch
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
 branches:  1\.2\.2;
-trunk-before-branch
+${log_keyid}trunk-before-branch
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add-it
+${log_keyid}add-it
 ----------------------------
 revision 1\.2\.2\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-change-on-br1
+${log_keyid}change-on-br1
 ----------------------------
 revision 1\.2\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
 branches:  1\.2\.2\.1\.2;
-modify
+${log_keyid}modify
 ----------------------------
 revision 1\.2\.2\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-modify
+${log_keyid}modify
 ============================================================================="
          dotest_fail branches-14.4 \
            "${testcvs} diff -c -r 1.1 -r 1.3 file4" \
-"Index: file4
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
-retrieving revision 1\.1
-retrieving revision 1\.3
-diff -c -r1\.1 -r1\.3
+"diff -c -r1\.1 -r1\.3
 \*\*\* file4   ${RFCDATE}      1\.1
 --- file4      ${RFCDATE}      1\.3
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -7551,12 +7564,7 @@
 ! 4:trunk-3"
          dotest_fail branches-14.5 \
            "${testcvs} diff -c -r 1.1 -r 1.2.2.1 file4" \
-"Index: file4
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file4,v
-retrieving revision 1\.1
-retrieving revision 1\.2\.2\.1
-diff -c -r1\.1 -r1\.2\.2\.1
+"diff -c -r1\.1 -r1\.2\.2\.1
 \*\*\* file4   ${RFCDATE}      1\.1
 --- file4      ${RFCDATE}      1\.2\.2\.1
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -7565,12 +7573,10 @@
 --- 1 ----
 ! 4:br1"
          dotest branches-15 \
-           "${testcvs} update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \
-           "RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1\.2\.1
-retrieving revision 1\.1\.2\.1\.2\.1
-Merging differences between 1\.1\.2\.1 and 1\.1\.2\.1\.2\.1 into file1
-rcsmerge: warning: conflicts during merge"
+           "$testcvs update -j 1.1.2.1 -j 1.1.2.1.2.1 file1" \
+"Merging differences between 1\.1\.2\.1 and 1\.1\.2\.1\.2\.1 into \`file1'
+$CPROG update: conflicts during merge
+C file1"
          dotest branches-16 "cat file1" '<<<<<<< file1
 1:ancest
 [=]======
@@ -7590,7 +7596,7 @@
          dokeep
          cd ..
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r first-dir
+         rm -rf first-dir
          ;;
 
 
@@ -7883,10 +7889,11 @@
          # tacky, although people generally expect it to work.  Maybe
          # we should release it instead.  We do it a few other places
          # below as well.
-         rm -r dir1
-         dotest branches2-15 "${testcvs} update -d -j b1 dir1" \
-"${SPROG} update: Updating dir1
-U dir1/file3"
+         rm -rf dir1
+         dotest branches2-15 "$testcvs update -d -j b1 dir1" \
+"$SPROG update: Updating dir1
+$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`dir1/file3'\."
+
          # FIXCVS: The `No revision control file' stuff seems to be
          # CVS's way of telling us that we're adding the file on a
          # branch, and the file is not on that branch yet.  This
@@ -7939,10 +7946,10 @@
    Sticky Date:                (none)
    Sticky Options:     (none)"
 
-         rm -r dir1
-         dotest branches2-21 "${testcvs} update -d -P -j b1 dir1" \
-"${SPROG} update: Updating dir1
-U dir1/file3"
+         rm -rf dir1
+         dotest branches2-21 "$testcvs update -d -P -j b1 dir1" \
+"$SPROG update: Updating dir1
+$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`dir1/file3'\."
          dotest branches2-22 "${testcvs} -q status" \
 "===================================================================
 File: file1                    Status: Up-to-date
@@ -7965,7 +7972,7 @@
    Sticky Options:     (none)"
 
          cd ../..
-         rm -r b1 b2
+         rm -rf b1 b2
 
          # Check out branch b1 twice.  Crate a new directory in one
          # working directory, then do a cvs update in the other
@@ -8014,7 +8021,7 @@
 
          # Test update -A on a subdirectory
          cd ..
-         rm -r dir2
+         rm -rf dir2
          dotest branches2-31 "${testcvs} update -A -d dir2" \
 "${SPROG} update: Updating dir2"
          cd dir2
@@ -8062,7 +8069,7 @@
          dokeep
          cd ../../..
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r trunk b1a b1b
+         rm -rf trunk b1a b1b
          ;;
 
 
@@ -8112,7 +8119,7 @@
 ----------------------------
 revision 1.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
            dokeep
@@ -8271,7 +8278,7 @@
 
          dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -8442,12 +8449,8 @@
          # directories so that the update -r br would need to
          # a merge to get from 1.1.2.1 to the head of the 1.1.2 branch.
          dotest tagf-13 "${testcvs} -q update -r br" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1\.2\.1
-retrieving revision 1\.1
-Merging differences between 1\.1\.2\.1 and 1\.1 into file1
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in file1
+"Merging differences between 1\.1\.2\.1 and 1\.1 into \`file1'
+$CPROG update: conflicts during merge
 C file1
 M file2"
          # CVS is giving a conflict because we are trying to get back to
@@ -8563,7 +8566,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -8707,13 +8710,9 @@
          # problem.  Hopefully, if a new issue arises, one of the above tests
          # will catch the problem.
 
-         if $keep; then
-           echo Keeping $TESTDIR and exiting due to --keep
-           exit 0
-         fi
-
+         dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -8727,6 +8726,7 @@
          # neither tag should be expanded in the output.  Also diff
          # one revision with the working copy.
 
+         test_uses_keywords
          modify_repo mkdir $CVSROOT_DIRNAME/first-dir
          dotest rcslib-diff1 "${testcvs} -q co first-dir" ''
          cd first-dir
@@ -8734,11 +8734,9 @@
          dotest rcslib-diff2 "${testcvs} add -m new-file foo.c" \
 "${SPROG} add: scheduling file .foo\.c. for addition
 ${SPROG} add: use .${SPROG} commit. to add this file permanently"
-         dotest rcslib-diff3 "${testcvs} commit -m rev1 foo.c" \
-"${CVSROOT_DIRNAME}/first-dir/foo.c,v  <--  foo\.c
-initial revision: 1\.1"
-         dotest rcslib-diff4 "${testcvs} tag first foo.c" "T foo\.c"
-         dotest rcslib-diff5 "${testcvs} update -p -r first foo.c" \
+         dotest rcsdiff-3 "$testcvs -Q commit -m rev1 foo.c"
+         dotest rcsdiff-4 "${testcvs} tag first foo.c" "T foo\.c"
+         dotest rcsdiff-5 "${testcvs} update -p -r first foo.c" \
 "===================================================================
 Checking out foo\.c
 RCS:  ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
@@ -8747,11 +8745,9 @@
 I am the first foo, and my name is \$""Name: first \$\."
 
          echo "I am the second foo, and my name is $""Name$." > foo.c
-         dotest rcslib-diff6 "${testcvs} commit -m rev2 foo.c" \
-"${CVSROOT_DIRNAME}/first-dir/foo\.c,v  <--  foo\.c
-new revision: 1\.2; previous revision: 1\.1"
-         dotest rcslib-diff7 "${testcvs} tag second foo.c" "T foo\.c"
-         dotest rcslib-diff8 "${testcvs} update -p -r second foo.c" \
+         dotest rcsdiff-6 "$testcvs -Q commit -m rev2 foo.c"
+         dotest rcsdiff-7 "${testcvs} tag second foo.c" "T foo\.c"
+         dotest rcsdiff-8 "${testcvs} update -p -r second foo.c" \
 "===================================================================
 Checking out foo\.c
 RCS:  ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
@@ -8761,27 +8757,18 @@
 
        dotest_fail rcslib-diff9 "${testcvs} diff -r first -r second" \
 "${SPROG} diff: Diffing \.
-Index: foo\.c
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
-retrieving revision 1\.1
-retrieving revision 1\.2
 diff -r1\.1 -r1\.2
 1c1
-< I am the first foo, and my name is \$""Name:  \$\.
+< I am the first foo, and my name is \$""Name: first \$\.
 ---
-> I am the second foo, and my name is \$""Name:  \$\."
+> I am the second foo, and my name is \$""Name: second \$\."
 
          echo "I am the once and future foo, and my name is $""Name$." > foo.c
          dotest_fail rcslib-diff10 "${testcvs} diff -r first" \
 "${SPROG} diff: Diffing \.
-Index: foo\.c
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/foo\.c,v
-retrieving revision 1\.1
 diff -r1\.1 foo\.c
 1c1
-< I am the first foo, and my name is \$""Name:  \$\.
+< I am the first foo, and my name is \$""Name: first \$\.
 ---
 > I am the once and future foo, and my name is \$""Name\$\."
 
@@ -8820,13 +8807,9 @@
          # Incidentally test that CVS no longer splits diff arguments on
          # spaces.
          dotest_fail rcslib-diffrgx-3 "$testcvs diff -c -F'.* (' rgx.c" \
-"Index: rgx\.c
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/rgx\.c,v
-retrieving revision 1\.1
-diff -c -F '\.\* (' -r1\.1 rgx\.c
+"diff -c -F '\.\* (' -r1\.1 rgx\.c
 \*\*\* rgx\.c  ${RFCDATE}      1\.1
---- rgx\.c     ${RFCDATE}
+--- rgx\.c$LOCAL_RFCDATE
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\* test_regex (whiz, bang)
 \*\*\* 3,7 \*\*\*\*
   foo;
@@ -8849,7 +8832,7 @@
          cd ..
 
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r first-dir
+         rm -rf first-dir
 
          mkdir 1; cd 1
          dotest rcslib-merge-1 "$testcvs -q co -l ."
@@ -8866,13 +8849,9 @@
          echo '3' >> file1
          dotest rcslib-merge-4 "${testcvs} -q add file1" \
 "${SPROG} add: use .${SPROG} commit. to add this file permanently"
-         dotest rcslib-merge-5 "${testcvs} -q commit -m '' file1" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-initial revision: 1\.1"
+         dotest rcslib-merge-5 "$testcvs -Q commit -mr1 file1"
          sed -e 's/2/two/' file1 > f; mv f file1
-         dotest rcslib-merge-6 "${testcvs} -q commit -m '' file1" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.2; previous revision: 1\.1"
+         dotest rcslib-merge-6 "$testcvs -Q commit -mr2 file1"
          dotest rcslib-merge-7 "${testcvs} -q tag -b -r 1.1 patch1" "T file1"
          dotest rcslib-merge-8 "${testcvs} -q update -r patch1" "U file1"
          dotest rcslib-merge-9 "${testcvs} -q status" \
@@ -8890,16 +8869,12 @@
 2
 3'
          sed -e 's/3/three/' file1 > f; mv f file1
-         dotest rcslib-merge-11 "${testcvs} -q commit -m '' file1" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.1\.2\.1; previous revision: 1\.1"
-         dotest rcslib-merge-12 "${testcvs} -q update -kv -j1.2" \
+         dotest rcslib-merge-11 "$testcvs -Q commit -mb1 file1"
+         dotest rcslib-merge-12 "$testcvs -q update -kv -j1.2" \
 "U file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into file1
-rcsmerge: warning: conflicts during merge"
+Merging differences between 1\.1 and 1\.2 into \`file1'
+$CPROG update: conflicts during merge
+C file1"
          dotest rcslib-merge-13 "cat file1" \
 "<<<<<<< file1
 1\.1\.2\.1
@@ -8923,9 +8898,7 @@
          fi
          dotest rcslib-symlink-2 "$testcvs update file2" "U file2"
          echo "This is a change" >> file2
-         dotest rcslib-symlink-3 "$testcvs ci -m because file2" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file2
-new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
+         dotest rcslib-symlink-3 "$testcvs -Q ci -m b2 file2"
 
          # Switch as for rcslib-symlink-1
          if test -n "$remotehost"; then
@@ -8959,19 +8932,35 @@
          else
            modify_repo ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file2,v
          fi
+         if $remote && $bases; then
+           dotest_fail rcslib-symlink-3gr "$testcvs update file2" \
+"$SPROG \[update aborted\]: could not find desired version 1\.1\.2\.3 in 
$CVSROOT_DIRNAME/first-dir/file2,v"
+         else
+           # FIXCVS?  Local mode silently overwrites what it thinks is
+           # revision 1.1.2.3 of file2 with revision 1.1.2.1 of file2 when
+           # the later revisions disappear.  This doesn't sound right.
+           dotest rcslib-symlink-3g "$testcvs update file2" "U file2"
+         fi
 
-         dotest rcslib-symlink-3g "$testcvs update file2" "U file2"
+         if test -n "$remotehost"; then
+           modify_repo "$CVS_RSH $remotehost 'ln -s Attic/file3,v 
$CVSROOT_DIRNAME/first-dir/file4,v'"
+         else
+           modify_repo ln -s Attic/file3,v $CVSROOT_DIRNAME/first-dir/file4,v
+         fi
+         dotest rcslib-symlink-3g-2 "$testcvs update file4" "U file4"
 
          # restore the link to file1 for the following tests
-         dotest rcslib-symlink-3i "$testcvs -Q rm -f file3" ''
+         dotest rcslib-symlink-3i "$testcvs -Q rm -f file3"
          dotest rcslib-symlink-3j "$testcvs -Q ci -mwhatever file3"
+         dotest rcslib-symlink-3k "$testcvs -Q up file2"
          rm -f $CVSROOT_DIRNAME/first-dir/file2,v
+         rm -f $CVSROOT_DIRNAME/first-dir/file4,v
          rm -f $CVSROOT_DIRNAME/first-dir/Attic/file3,v
          # As for rcslib-symlink-1
          if test -n "$remotehost"; then
-           modify_repo "$CVS_RSH $remotehost 'ln -s file1,v 
$CVSROOT_DIRNAME/first-dir/file2,v'"
+           modify_repo "$CVS_RSH $remotehost 'ln -s file1,v 
$CVSROOT_DIRNAME/first-dir/file4,v'"
          else
-           modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
+           modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file4,v
          fi
 
          # Test 5 reveals a problem with having symlinks in the
@@ -8984,14 +8973,24 @@
          dotest rcslib-symlink-5 "$testcvs tag the_tag" \
 "$SPROG tag: Tagging .
 T file1
-W file2 : the_tag already exists on version 1.1.2.3 : NOT MOVING tag to 
version 1.1.2.1"
+W file4 : the_tag already exists on version 1.1.2.3 : NOT MOVING tag to 
version 1.1.2.1"
          # As for rcslib-symlink-1
          if test -n "$remotehost"; then
-           dotest rcslib-symlink-6 "$CVS_RSH $remotehost 'ls -l 
$CVSROOT_DIRNAME/first-dir/file2,v'" \
-".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+           dotest rcslib-symlink-6 "$CVS_RSH $remotehost 'ls -l 
$CVSROOT_DIRNAME/first-dir/file4,v'" \
+".*$CVSROOT_DIRNAME/first-dir/file4,v -> file1,v"
          else
-           dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file2,v" \
-".*$CVSROOT_DIRNAME/first-dir/file2,v -> file1,v"
+           dotest rcslib-symlink-6 "ls -l $CVSROOT_DIRNAME/first-dir/file4,v" \
+".*$CVSROOT_DIRNAME/first-dir/file4,v -> file1,v"
+         fi
+
+         # Restore file2 link for the next few tests.
+         rm -f $CVSROOT_DIRNAME/first-dir/file4,v
+         dotest rcslib-symlink-6b "$testcvs -Q up file4"
+         # As for rcslib-symlink-1
+         if test -n "$remotehost"; then
+           modify_repo "$CVS_RSH $remotehost 'ln -s file1,v 
$CVSROOT_DIRNAME/first-dir/file2,v'"
+         else
+           modify_repo ln -s file1,v $CVSROOT_DIRNAME/first-dir/file2,v
          fi
 
          # Symlinks tend to interact poorly with the Attic.
@@ -9063,8 +9062,9 @@
          echo change-it >>fileX
 
          # Writes actually cause symlinks to be resolved.
+         # $DOTSTAR here accounts for the keyword-in-signed-file warning.
          dotest rcslib-long-symlink-3 "$testcvs -q ci -mwrite-it" \
-"$CVSROOT_DIRNAME/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/file1,v
  <--  fileX
+"$DOTSTAR$CVSROOT_DIRNAME/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/123456789012345678901234567890/file1,v
  <--  fileX
 new revision: 1\.5; previous revision: 1\.4"
 
          dokeep
@@ -9086,7 +9086,8 @@
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
                             $CVSROOT_DIRNAME/second-dir \
                             $CVSROOT_DIRNAME/123456789012345678901234567890
-         rm -r first-dir second-dir 2
+         rm -rf first-dir second-dir 2
+         test_uses_keywords_done
          ;;
 
 
@@ -9145,21 +9146,21 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;  1\.1\.4;
-add-it
+${log_keyid}add-it
 ----------------------------
 revision 1\.1\.4\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-br2
+${log_keyid}modify-on-br2
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-modify-on-br1
+${log_keyid}modify-on-br1
 ============================================================================="
 
          dokeep
          cd ..
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r first-dir
+         rm -rf first-dir
          ;;
 
 
@@ -9184,6 +9185,8 @@
                # import-CVS -- refuse to import directories named "CVS".
                # import-quirks -- short tests of import quirks.
 
+               test_uses_keywords
+
                # import
                mkdir import-dir ; cd import-dir
 
@@ -9238,11 +9241,12 @@
                echo local-change >> imported-f2
 
                # commit
-               dotest import-100 "${testcvs} ci -m local-changes" \
-"${CPROG} commit: Examining .
-${CVSROOT_DIRNAME}/first-dir/imported-f1,v  <--  imported-f1
+               # $DOTSTAR accounts for the keyword-in-signed-file warning.
+               dotest import-100 "$testcvs ci -m local-changes" \
+"$CPROG commit: Examining .
+$DOTSTAR$CVSROOT_DIRNAME/first-dir/imported-f1,v  <--  imported-f1
 new revision: delete; previous revision: 1\.1\.1\.1
-${CVSROOT_DIRNAME}/first-dir/imported-f2,v  <--  imported-f2
+$CVSROOT_DIRNAME/first-dir/imported-f2,v  <--  imported-f2
 new revision: 1\.2; previous revision: 1\.1"
 
                # log
@@ -9272,7 +9276,7 @@
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-first-import
+${log_keyid}first-import
 ============================================================================="
 
                # update into the vendor branch.
@@ -9354,15 +9358,11 @@
                cd ..
 
                dotest import-113 \
-"${testcvs} -q co -jjunk-1_0 -jjunk-2_0 first-dir" \
-"${SPROG} checkout: file first-dir/imported-f1 does not exist, but is present 
in revision junk-2_0
-RCS file: ${CVSROOT_DIRNAME}/first-dir/imported-f2,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.2
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into imported-f2
-rcsmerge: warning: conflicts during merge
-first-dir/imported-f3 already contains the differences between 1\.1\.1\.1 and 
1\.1\.1\.2
-first-dir/imported-f4 already contains the differences between 1\.1\.1\.1 and 
1\.1\.1\.3"
+"$testcvs -q co -jjunk-1_0 -jjunk-2_0 first-dir" \
+"$SPROG checkout: file first-dir/imported-f1 does not exist, but is present in 
revision junk-2_0
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into 
\`first-dir/imported-f2'
+$CPROG checkout: conflicts during merge
+C first-dir/imported-f2"
 
                cd first-dir
 
@@ -9384,9 +9384,10 @@
 
                dokeep
                cd ..
-               rm -r first-dir
+               rm -rf first-dir
                modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
                rm -r import-dir
+               test_uses_keywords_done
                ;;
 
 
@@ -9481,16 +9482,16 @@
 ----------------------------
 revision 1\.1\.3\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -9582,11 +9583,11 @@
 revision 1\.1\.1\.1
 date: ${ISO8601DATE2034};  author: ${username};  state: Exp;  lines: ${PLUS}0 
-0;  commitid: ${commitid};
 branches:  1\.1\.1\.1\.2;
-import-it
+${log_keyid}import-it
 ----------------------------
 revision 1\.1\.1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify
+${log_keyid}modify
 ============================================================================="
 
          dotest importc-9 "${testcvs} -q log bdir/subdir/file1" "
@@ -9611,7 +9612,7 @@
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE1971};  author: ${username};  state: Exp;  lines: ${PLUS}0 
-0;  commitid: ${commitid};
-import-it
+${log_keyid}import-it
 ============================================================================="
          cd ..
 
@@ -9628,7 +9629,7 @@
          dokeep
          TZ=$save_TZ
          cd ..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -9730,11 +9731,11 @@
 ----------------------------
 revision 1\.1\.1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          dotest importX-6 "${testcvs} -q log file1" "
@@ -9763,15 +9764,15 @@
 ----------------------------
 revision 1\.1\.1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf ${CVSROOT_DIRNAME}/first-dir
          ;;
 
@@ -9844,14 +9845,14 @@
 ----------------------------
 revision 1\.1\.1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          dokeep
          cd ../..
          restore_adm
          rm -r 1
-         rm -r wnt
+         rm -rf wnt
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10057,7 +10058,7 @@
 
          dokeep
          cd ../..
-         rm -r branch-after-import
+         rm -rf branch-after-import
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10315,15 +10316,15 @@
 "$SPROG \[checkout aborted\]: no such tag \`no-such-tag'"
 
          dotest join-16b "$testcvs -q co -jT1 -jT2 first-dir" \
-"U first-dir/file1
+"$SPROG checkout: scheduling addition from revision 1\.1\.2\.1 of 
\`first-dir/file1'\.
 U first-dir/file2
-${SPROG} checkout: file first-dir/file2 exists, but has been added in revision 
T2
+$SPROG checkout: file first-dir/file2 exists, but has been added in revision T2
 U first-dir/file3
-${SPROG} checkout: scheduling \`first-dir/file3' for removal
+$SPROG checkout: scheduling \`first-dir/file3' for removal
 U first-dir/file4
-${SPROG} checkout: scheduling \`first-dir/file4' for removal
+$SPROG checkout: scheduling \`first-dir/file4' for removal
 U first-dir/file7
-${SPROG} checkout: file first-dir/file9 does not exist, but is present in 
revision T2"
+$SPROG checkout: file first-dir/file9 does not exist, but is present in 
revision T2"
 
          # Verify that the right changes have been scheduled.
          cd first-dir
@@ -10336,7 +10337,7 @@
          cd ../../1/first-dir
          echo 'third revision of file4' > file4
          dotest join-18 "${testcvs} -q update -jT1 -jT2 ." \
-"U file1
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`file1'\.
 $SPROG update: file file2 exists, but has been added in revision T2
 $SPROG update: scheduling \`file3' for removal
 M file4
@@ -10361,20 +10362,18 @@
          # revision which can be used as the source for files added
          # on branches.
          cd ../../3
-         rm -r first-dir
-         dotest join-20 "${testcvs} -q co -jbranch first-dir" \
-"U first-dir/file1
+         rm -rf first-dir
+         dotest join-20 "$testcvs -q co -jbranch first-dir" \
+"$SPROG checkout: scheduling addition from revision 1\.1\.2\.1 of 
\`first-dir/file1'\.
 U first-dir/file2
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.2
-Merging differences between 1\.1 and 1\.1\.2\.2 into file2
+Merging differences between 1\.1 and 1\.1\.2\.2 into \`first-dir/file2'
+M first-dir/file2
 U first-dir/file3
-${SPROG} checkout: scheduling \`first-dir/file3' for removal
+$SPROG checkout: scheduling \`first-dir/file3' for removal
 U first-dir/file4
-${SPROG} checkout: file first-dir/file4 has been modified, but has been 
removed in revision branch
+$SPROG checkout: file first-dir/file4 has been modified, but has been removed 
in revision branch
 U first-dir/file7
-${SPROG} checkout: file first-dir/file9 does not exist, but is present in 
revision branch"
+$SPROG checkout: file first-dir/file9 does not exist, but is present in 
revision branch"
 
          # Verify that the right changes have been scheduled.
          # The M file2 line is a bug; see above join-20.
@@ -10386,7 +10385,7 @@
 
          # Checkout the main line again.
          cd ../../1
-         rm -r first-dir
+         rm -rf first-dir
          dotest join-22 "${testcvs} -q co first-dir" \
 'U first-dir/file2
 U first-dir/file3
@@ -10399,15 +10398,13 @@
          cd first-dir
          echo 'third revision of file4' > file4
          dotest join-23 "${testcvs} -q update -jbranch ." \
-"U file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.2
-Merging differences between 1\.1 and 1\.1\.2\.2 into file2
-${SPROG} update: scheduling \`file3' for removal
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`file1'\.
+$SPROG update: Replacing \`file2' with contents of revision 1\.1\.2\.2\.
+M file2
+$SPROG update: scheduling \`file3' for removal
 M file4
-${SPROG} update: file file4 is locally modified, but has been removed in 
revision branch
-${SPROG} update: file file9 does not exist, but is present in revision branch"
+$SPROG update: file file4 is locally modified, but has been removed in 
revision branch
+$SPROG update: file file9 does not exist, but is present in revision branch"
 
          # Verify that the right changes have been scheduled.
          # The M file2 line is a bug; see above join-20
@@ -10421,7 +10418,7 @@
 
          # Checkout the main line again and make a new branch which we
          # merge to.
-         rm -r first-dir
+         rm -rf first-dir
          dotest join-25 "${testcvs} -q co first-dir" \
 'U first-dir/file2
 U first-dir/file3
@@ -10437,16 +10434,14 @@
          # The handling of file8 and file9 here look fishy to me.  I don't
          # see why it should be different from the case where we merge to
          # the trunk (e.g. join-23).
-         dotest join-28 "${testcvs} -q update -j branch" \
-"U file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-retrieving revision 1.1
-retrieving revision 1.1.2.2
-Merging differences between 1.1 and 1.1.2.2 into file2
-${SPROG} update: scheduling \`file3' for removal
-${SPROG} update: file file4 has been modified, but has been removed in 
revision branch
-U file8
-U file9"
+         dotest join-28 "$testcvs -q update -j branch" \
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`file1'\.
+$SPROG update: Replacing \`file2' with contents of revision 1\.1\.2\.2\.
+M file2
+$SPROG update: scheduling \`file3' for removal
+$SPROG update: file file4 has been modified, but has been removed in revision 
branch
+$SPROG update: scheduling addition from revision 1\.1 of \`file8'\.
+$SPROG update: scheduling addition from revision 1\.1\.2\.2 of \`file9'\."
          # Verify that the right changes have been scheduled.
          dotest join-29 "${testcvs} -q update" \
 "A file1
@@ -10462,30 +10457,28 @@
          # once that if the file was removed in the update then it wouldn't be
          # readded in the merge
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          dotest join-twobranch-1 "${testcvs} -q co -rbranch first-dir" \
 'U first-dir/file1
 U first-dir/file2
 U first-dir/file8
 U first-dir/file9'
          cd first-dir
-         dotest join-twobranch-2 "${testcvs} -q update -rbr2 -jbranch" \
-"${SPROG} update: \`file1' is no longer in the repository
-U file1
+         dotest join-twobranch-2 "$testcvs -q update -rbr2 -jbranch" \
+"$SPROG update: \`file1' is no longer in the repository
+$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`file1'\.
 U file2
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.2
-Merging differences between 1\.1 and 1\.1\.2\.2 into file2
+$SPROG update: Replacing \`file2' with contents of revision 1\.1\.2\.2\.
+M file2
 U file3
-${SPROG} update: scheduling \`file3' for removal
+$SPROG update: scheduling \`file3' for removal
 U file4
-${SPROG} update: file file4 has been modified, but has been removed in 
revision branch
+$SPROG update: file file4 has been modified, but has been removed in revision 
branch
 U file7
-${SPROG} update: \`file8' is no longer in the repository
-U file8
-${SPROG} update: \`file9' is no longer in the repository
-U file9"
+$SPROG update: \`file8' is no longer in the repository
+$SPROG update: scheduling addition from revision 1\.1 of \`file8'\.
+$SPROG update: \`file9' is no longer in the repository
+$SPROG update: scheduling addition from revision 1\.1\.2\.2 of \`file9'\."
          # Verify that the right changes have been scheduled.
          dotest join-twobranch-3 "${testcvs} -q update" \
 "A file1
@@ -10497,7 +10490,7 @@
          # Checkout the mainline again to try merging from the trunk
          # to a branch.
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          dotest join-30 "${testcvs} -q co first-dir" \
 'U first-dir/file2
 U first-dir/file3
@@ -10527,9 +10520,9 @@
 
          # Now update branch to T3.
          cd ../../2/first-dir
-         dotest join-34 "${testcvs} -q up -jT3" \
-"${SPROG} update: file file4 does not exist, but is present in revision T3
-U file7"
+         dotest join-34 "$testcvs -q up -jT3" \
+"$SPROG update: file file4 does not exist, but is present in revision T3
+$SPROG update: scheduling addition from revision 1\.1 of \`file7'\."
 
          # Verify that the right changes have been scheduled.
          dotest join-35 "${testcvs} -q update" \
@@ -10540,10 +10533,8 @@
          # happens to do the right thing; see above join-20.
          dotest join-36 "${testcvs} -q up -j T3 -j T4" \
 "A file7
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file7,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into file7"
+Merging differences between 1\.1 and 1\.2 into \`file7'
+M file7"
 
          # Verify that the right changes have been scheduled.
          dotest join-37 "${testcvs} -q update" \
@@ -10551,7 +10542,7 @@
 
          dokeep
          cd ../..
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10604,10 +10595,8 @@
          dotest join2-10 "cat CVS/Tag" "Tbr1"
 
          dotest join2-11 "${testcvs} -q update -j br1 file1" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.1
-Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+"$SPROG update: Replacing \`file1' with contents of revision 1\.1\.2\.1\.
+M file1"
          dotest join2-12 "cat file1" "initial contents of file1
 modify on branch"
          # We should have no sticky tag on file1
@@ -10644,7 +10633,8 @@
 U file1"
 :        dotest join2-17 "${testcvs} -q update -A bradd" \
 "${SPROG} update: warning: \`bradd' is not (any longer) pertinent"
-         dotest join2-18 "${testcvs} -q update -j br1 bradd" "U bradd"
+         dotest join2-18 "$testcvs -q update -j br1 bradd" \
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`bradd'\."
          dotest join2-19 "${testcvs} -q status bradd" \
 "===================================================================
 File: bradd                    Status: Locally Added
@@ -10661,7 +10651,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10711,13 +10701,11 @@
          # Before we actually have any revision on br2, let's try a join
          dotest join3-11 "${testcvs} -q update -r br1" "U file1
 ${SPROG} update: \`file2' is no longer in the repository"
-         dotest join3-12 "${testcvs} -q update -j br2" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into file1
-rcsmerge: warning: conflicts during merge
-U file2"
+         dotest join3-12 "$testcvs -q update -j br2" \
+"Merging differences between 1\.1 and 1\.2 into \`file1'
+$CPROG update: conflicts during merge
+C file1
+$SPROG update: scheduling addition from revision 1\.1 of \`file2'\."
          dotest join3-13 "cat file1" \
 "initial contents of file1
 [<]<<<<<< file1
@@ -10728,8 +10716,8 @@
          rm file1
 
          # OK, we'll try the same thing with a revision on br2.
-         dotest join3-14 "${testcvs} -q update -r br2 file1" \
-"${SPROG} update: warning: \`file1' was lost
+         dotest join3-14 "$testcvs -q update -r br2 file1" \
+"$SPROG update: warning: \`file1' was lost
 U file1" "U file1"
          echo 'br2:line1' >>file1
          dotest join3-15 "${testcvs} -q ci -m modify file1" \
@@ -10743,11 +10731,9 @@
          # and so it merges both the 1.1->1.2 and 1.2->1.2.2.1 changes.
          # This seems like a reasonably plausible behavior.
          dotest join3-17 "${testcvs} -q update -j br2 file1" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.2\.2\.1
-Merging differences between 1\.1 and 1\.2\.2\.1 into file1
-rcsmerge: warning: conflicts during merge"
+"Merging differences between 1\.1 and 1\.2\.2\.1 into \`file1'
+$CPROG update: conflicts during merge
+C file1"
          dotest join3-18 "cat file1" \
 "initial contents of file1
 [<]<<<<<< file1
@@ -10759,7 +10745,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10920,14 +10906,14 @@
          # Modify file4 locally, and do an update with a merge.
          cd ../../1/first-dir
          echo 'third revision of file4' > file4
-         dotest join4-18 "${testcvs} -q update -jT1 -jT2 ." \
-"U file1
+         dotest join4-18 "$testcvs -q update -jT1 -jT2 ." \
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of \`file1'\.
 R file10
 A file2
-${SPROG} update: file file2 exists, but has been added in revision T2
-${SPROG} update: scheduling \`file3' for removal
+$SPROG update: file file2 exists, but has been added in revision T2
+$SPROG update: scheduling \`file3' for removal
 M file4
-${SPROG} update: file file4 is locally modified, but has been removed in 
revision T2
+$SPROG update: file file4 is locally modified, but has been removed in 
revision T2
 R file6
 A file7
 R file8
@@ -10948,7 +10934,7 @@
 
          dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -10988,19 +10974,15 @@
          cd 1/join5
          echo "but maybe it could charge bytheword" >>-file
          # This is the test that used to spew complaints from diff3:
-         dotest join5 "${testcvs} up" \
-"${SPROG} update: Updating \.
-RCS file: ${CVSROOT_DIRNAME}/join5/-file,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into -file
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in -file
+         dotest join5-1 "$testcvs up" \
+"$SPROG update: Updating \.
+Merging differences between 1\.1 and 1\.2 into \`-file'
+$CPROG update: conflicts during merge
 C -file"
 
          dokeep
          cd ../../..
-         rm -r join5
+         rm -rf join5
          modify_repo rm -rf $CVSROOT_DIRNAME/join5
          ;;
 
@@ -11030,9 +11012,9 @@
          # matches the second argument to -j: CVS doesn't bother attempting
          # the merge since it already knows that the target contains the
          # change.
-         dotest join6-3.3 "${testcvs} update -j1.1 -j1.2 temp.txt" \
-"temp\.txt already contains the differences between 1\.1 and 1\.2"
-         dotest join6-3.4 "${testcvs} diff temp.txt" ""
+         dotest join6-3.3 "$testcvs update -j1.1 -j1.2 temp.txt" \
+"\`temp\.txt' already contains the differences between 1\.1 and 1\.2"
+         dotest join6-3.4 "$testcvs diff temp.txt"
 
          # The case where the merge target is modified but already contains
          # the change.
@@ -11041,52 +11023,33 @@
          echo ddd >>temp.txt
          dotest join6-3.5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
 "M temp\.txt
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into temp\.txt
-temp\.txt already contains the differences between 1\.1 and 1\.2"
+Merging differences between 1\.1 and 1\.2 into \`temp\.txt'
+\`temp\.txt' already contains the differences between 1\.1 and 1\.2
+M temp\.txt"
          dotest_fail join6-3.6 "${testcvs} diff temp.txt" \
-"Index: temp\.txt
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.2
-diff -r1\.2 temp.txt
+"diff -r1\.2 temp.txt
 1d0
 < aaa"
 
          cp temp2.txt temp.txt
          dotest_fail join6-4 "${testcvs} diff temp.txt" \
-"Index: temp.txt
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.2
-diff -r1\.2 temp\.txt
+"diff -r1\.2 temp\.txt
 4d3
 < ddd"
 
          dotest join6-5 "${testcvs} update -j1.1 -j1.2 temp.txt" \
 "M temp\.txt
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into temp\.txt"
+Merging differences between 1\.1 and 1\.2 into \`temp\.txt'"
          dotest join6-6 "${testcvs} diff temp.txt" ""
          mv temp.txt temp3.txt
          dotest join6-7 "sed 's/ddd/dddd/' < temp3.txt > temp.txt" ""
          dotest join6-8 "${testcvs} update -j1.1 -j1.2 temp.txt" \
 "M temp\.txt
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into temp\.txt
-rcsmerge: warning: conflicts during merge"
+Merging differences between 1\.1 and 1\.2 into \`temp\.txt'
+$CPROG update: conflicts during merge
+C temp\.txt"
          dotest_fail join6-9 "${testcvs} diff temp.txt" \
-"Index: temp\.txt
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
-retrieving revision 1\.2
-diff -r1\.2 temp\.txt
+"diff -r1\.2 temp\.txt
 3a4,6
 > <<<<<<< temp\.txt
 > dddd
@@ -11099,19 +11062,12 @@
 new revision: 1\.3; previous revision: 1\.2"
           cp temp3.txt temp.txt
          dotest_fail join6-11 "${testcvs} diff temp.txt" \
-"Index: temp\.txt
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
-retrieving revision 1\.3
-diff -r1\.3 temp\.txt
+"diff -r1\.3 temp\.txt
 3a4
 > ddd"
-         dotest join6-12 "${testcvs} update -j1.2 -j1.3 temp.txt" \
+         dotest join6-12 "$testcvs update -j1.2 -j1.3 temp.txt" \
 "M temp\.txt
-RCS file: ${CVSROOT_DIRNAME}/join6/temp\.txt,v
-retrieving revision 1\.2
-retrieving revision 1\.3
-Merging differences between 1\.2 and 1\.3 into temp\.txt"
+Merging differences between 1\.2 and 1\.3 into \`temp\.txt'"
          dotest join6-13 "${testcvs} diff temp.txt" ""
 
          # The case where the merge target wasn't created until after the
@@ -11131,13 +11087,9 @@
          dotest join6-24 "${testcvs} -q ci -m." \
 "$CVSROOT_DIRNAME/join6/temp.txt,v  <--  temp\.txt
 new revision: 1\.4; previous revision: 1\.3"
-         dotest join6-25 "${testcvs} -q up -jt1 -jt2" \
-"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.3
-Merging differences between 1\.1 and 1\.3 into temp.txt
-temp.txt already contains the differences between 1\.1 and 1\.3
-temp2.txt already contains the differences between creation and 1\.1"
+         dotest join6-25 "$testcvs -q up -jt1 -jt2" \
+"Merging differences between 1\.1 and 1\.3 into \`temp.txt'"
+         dotest join6-25-2 "$testcvs -q up"
 
          # Now for my next trick: delete the file, recreate it, and
          # try to merge
@@ -11147,33 +11099,27 @@
 "$CVSROOT_DIRNAME/join6/temp2\.txt,v  <--  temp2\.txt
 new revision: delete; previous revision: 1\.1"
          echo new >temp2.txt
-         # FIXCVS: Local and remote really shouldn't be different and there
-         # really shouldn't be two different status lines for temp2.txt
-         if $remote; then
-           dotest_fail join6-32 "${testcvs} -q up -jt1 -jt2" \
+         dotest_fail join6-32 "$testcvs up -jt1 -jt2" \
 "? temp2\.txt
-RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.3
-Merging differences between 1\.1 and 1\.3 into temp.txt
-temp.txt already contains the differences between 1\.1 and 1\.3
-$CPROG update: move away .\./temp2\.txt.; it is in the way
-C temp2\.txt"
-         else
-           dotest join6-32 "${testcvs} -q up -jt1 -jt2" \
-"RCS file: ${CVSROOT_DIRNAME}/join6/temp.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.3
-Merging differences between 1\.1 and 1\.3 into temp.txt
-temp.txt already contains the differences between 1\.1 and 1\.3
-${SPROG} update: use .${SPROG} add. to create an entry for .temp2\.txt.
-U temp2\.txt
-? temp2\.txt"
-         fi
+$SPROG update: Updating \.
+Merging differences between 1\.1 and 1\.3 into \`temp.txt'
+\`temp.txt' already contains the differences between 1\.1 and 1\.3
+$SPROG update: scheduling addition from revision 1\.1 of \`temp2\.txt'\.
+$CPROG update: move away \`temp2\.txt'; it is in the way
+C temp2.txt" \
+"$SPROG update: Updating \.
+Merging differences between 1\.1 and 1\.3 into \`temp.txt'
+\`temp.txt' already contains the differences between 1\.1 and 1\.3
+$SPROG update: use \`cvs add' to create an entry for \`temp2\.txt'
+$SPROG update: scheduling addition from revision 1\.1 of \`temp2\.txt'\.
+$CPROG update: move away \`temp2\.txt'; it is in the way
+C temp2.txt"
+
+         dotest join6-33 "$testcvs -q up" "? temp2\.txt"
 
          dokeep
          cd ../../..
-         rm -r join6
+         rm -rf join6
          modify_repo rm -rf $CVSROOT_DIRNAME/join6
          ;;
 
@@ -11204,28 +11150,19 @@
 ""
          cd ../join7
          dotest join7-5 \
-"${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
-"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.2
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
-rcsmerge: warning: conflicts during merge"
+"$testcvs -n update -jvers-1 -jvers-2 temp.txt" \
+"Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into \`temp\.txt'
+$CPROG update: conflicts during merge
+C temp\.txt"
          touch temp.txt
-         dotest join7-6 "${testcvs} -n update -jvers-1 -jvers-2 temp.txt" \
-"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.2
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
-rcsmerge: warning: conflicts during merge" \
-"RCS file: $CVSROOT_DIRNAME/join7/temp.txt,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.2
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into temp.txt
-rcsmerge: warning: conflicts during merge"
+         dotest join7-6 "$testcvs -n update -jvers-1 -jvers-2 temp.txt" \
+"Merging differences between 1\.1\.1\.1 and 1\.1\.1\.2 into \`temp.txt'
+$CPROG update: conflicts during merge
+C temp\.txt"
 
          dokeep
          cd ../..
-         rm -r join7
+         rm -rf join7
          modify_repo rm -rf $CVSROOT_DIRNAME/join7
          ;;
 
@@ -11271,12 +11208,8 @@
          # preserve a file's read-only permissions.
          echo conflict > $file; chmod u-w $file
          dotest join-readonly-conflict-8 "$testcvs update -r B $file" \
-"RCS file: $CVSROOT_DIRNAME/$module/$file,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.1
-Merging differences between 1\.1 and 1\.1\.2\.1 into $file
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in $file
+"Merging differences between 1\.1 and 1\.1\.2\.1 into \`$file'
+$CPROG update: conflicts during merge
 C $file"
 
          # restore to the trunk
@@ -11294,23 +11227,20 @@
            pass "join-readonly-conflict-10"
          fi
          dotest join-readonly-conflict-11 "$testcvs update -r B $file" \
-"RCS file: $CVSROOT_DIRNAME/$module/$file,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.1
-Merging differences between 1\.1 and 1\.1\.2\.1 into $file
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in $file
-C m"
+"Merging differences between 1\.1 and 1\.1\.2\.1 into \`$file'
+$CPROG update: conflicts during merge
+C $file"
 
          dokeep
          cd ../..
-         rm -r join-readonly-conflict
+         rm -rf join-readonly-conflict
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
          ;;
 
 
 
        join-admin)
+         test_uses_keywords
          mkdir 1; cd 1
          dotest join-admin-0-1 "$testcvs -q co -l ."
          module=x
@@ -11332,8 +11262,8 @@
          dotest join-admin-0-9 "$testcvs -Q tag -b M2" ''
 
          dotest join-admin-0-10 "$testcvs -Q update -r B" ''
-         dotest join-admin-0-11 "$testcvs -Q update -kk -jM1 -jM2" ''
-         dotest join-admin-0-12 "$testcvs -Q ci -m. b" ''
+         dotest join-admin-0-11 "$testcvs -Q update -kk -jM1 -jM2"
+         dotest join-admin-0-12 "$testcvs -Q ci -m. b"
 
          dotest join-admin-0-13 "$testcvs -Q update -A" ''
 
@@ -11354,6 +11284,7 @@
          cd ../..
          rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
+         test_uses_keywords_done
          ;;
 
 
@@ -11363,6 +11294,7 @@
          # removes a file, then modifies another containing an $Id...$ line,
          # the resulting file contains the unexpanded `$Id.$' string, as
          # -kk requires.
+         test_uses_keywords
          mkdir 1; cd 1
          dotest join-admin-2-1 "$testcvs -q co -l ." ''
          module=x
@@ -11394,24 +11326,18 @@
 
          dotest join-admin-2-13 "$testcvs -Q update -r T" '' "${QUESTION} e0"
          dotest join-admin-2-14 "$testcvs update -kk -jM1 -jM2" \
-"${SPROG} update: Updating .
-U b
+"$SPROG update: Updating .
+$SPROG update: scheduling addition from revision 1\.1 of \`b'\.
 U e
-RCS file: ${CVSROOT_DIRNAME}/x/e,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into e
-e already contains the differences between 1\.1 and 1\.2
-${QUESTION} e0" \
-"${QUESTION} e0
-${SPROG} update: Updating .
-U b
+Merging differences between 1\.1 and 1\.2 into \`e'
+\`e' already contains the differences between 1\.1 and 1\.2
+$QUESTION e0" \
+"$QUESTION e0
+$SPROG update: Updating .
+$SPROG update: scheduling addition from revision 1\.1 of \`b'\.
 U e
-RCS file: ${CVSROOT_DIRNAME}/x/e,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into e
-e already contains the differences between 1\.1 and 1\.2"
+Merging differences between 1\.1 and 1\.2 into \`e'
+\`e' already contains the differences between 1\.1 and 1\.2"
 
          # Verify that the $Id.$ string is not expanded.
          dotest join-admin-2-15 "cat e" '$''Id$'
@@ -11420,6 +11346,7 @@
          cd ../..
          rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
+         test_uses_keywords_done
          ;;
 
 
@@ -11498,7 +11425,7 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
 branches:  1.1.2;
-add-em
+${log_keyid}add-em
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: $username;  state: dead;  lines: ${PLUS}0 -0;  
commitid: ${commitid};
@@ -11531,7 +11458,7 @@
          dokeep
          cd ../..
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
-         rm -r $module
+         rm -rf $module
          ;;
 
 
@@ -11722,32 +11649,20 @@
    Sticky Tag:         (none)
    Sticky Date:                (none)
    Sticky Options:     (none)"
-               dotest conflicts-129a "${testcvs} -nq update a" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into a
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in a
+               dotest conflicts-129a "$testcvs -nq update a" \
+"Merging differences between 1\.1 and 1\.2 into \`a'
+$CPROG update: conflicts during merge
 C a"
-               dotest conflicts-130 "${testcvs} -q update" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into a
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in a
+               dotest conflicts-130 "$testcvs -q update" \
+"Merging differences between 1\.1 and 1\.2 into \`a'
+$CPROG update: conflicts during merge
 C a
-${QUESTION} dir1
-${QUESTION} sdir" \
-"${QUESTION} dir1
-${QUESTION} sdir
-RCS file: ${CVSROOT_DIRNAME}/first-dir/a,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into a
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in a
+$QUESTION dir1
+$QUESTION sdir" \
+"$QUESTION dir1
+$QUESTION sdir
+Merging differences between 1\.1 and 1\.2 into \`a'
+$CPROG update: conflicts during merge
 C a"
                rmdir dir1 sdir
 
@@ -11872,7 +11787,7 @@
 
                dokeep
                cd ../..
-               rm -r 1 2 3
+               rm -rf 1 2 3
                modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
                restore_adm
                ;;
@@ -12038,14 +11953,14 @@
          # the local CVS behavior for remote without the cvs add seems 
          # pretty difficult).
          if $remote; then
-           dotest_fail conflicts2-142d2r "${testcvs} -q update" \
-"${QUESTION} aa\.c
-${QUESTION} same\.c
-${CPROG} update: move away \`\./aa\.c'; it is in the way
+           dotest_fail conflicts2-142d2r "$testcvs -q update" \
+"$QUESTION aa\.c
+$QUESTION same\.c
+$CPROG update: move away \`aa\.c'; it is in the way
 C aa\.c
-${SPROG} update: conflict: \`bb\.c' created independently by second party
+$SPROG update: conflict: \`bb\.c' created independently by second party
 C bb\.c
-${CPROG} update: move away \`\./same\.c'; it is in the way
+$CPROG update: move away \`same\.c'; it is in the way
 C same\.c"
          else
            dotest_fail conflicts2-142d2 "${testcvs} -q update" \
@@ -12116,7 +12031,7 @@
 
          dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -12246,7 +12161,7 @@
          cd first-dir
 
          dotest conflicts3-21 "${testcvs} -q update -d sdir" "U sdir/sfile"
-         rm -r sdir/CVS
+         rm -rf sdir/CVS
          dotest conflicts3-22 "${testcvs} -q update" "${QUESTION} sdir"
          if $remote; then
            dotest_fail conflicts3-23 "${testcvs} -q update -PdA" \
@@ -12264,7 +12179,7 @@
          # by removing each file (and using update -P or some such).  Then
          # suppose that the build process creates an sdir directory which
          # is not supposed to be under CVS.
-         rm -r sdir
+         rm -rf sdir
          dotest conflicts3-24 "${testcvs} -q update -d sdir" "U sdir/sfile"
          rm sdir/sfile
          dotest conflicts3-25 "${testcvs} rm sdir/sfile" \
@@ -12343,13 +12258,9 @@
 new revision: 1\.2; previous revision: 1\.1"
          cd ../first-dir
          echo "fish" >> cleanme.txt
-         dotest clean-17 "${testcvs} -nq update" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/cleanme\.txt,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into cleanme\.txt
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in cleanme\.txt
+         dotest clean-17 "$testcvs -nq update" \
+"Merging differences between 1\.1 and 1\.2 into \`cleanme\.txt'
+$CPROG update: conflicts during merge
 C cleanme\.txt"
          dotest clean-18 "${testcvs} -q update -C" \
 "(Locally modified cleanme\.txt moved to \.#cleanme\.txt\.1\.1)
@@ -12383,6 +12294,8 @@
            continue
          fi
 
+         test_uses_keywords
+
          mkdir keywordexpand; cd keywordexpand
 
          dotest keywordexpand-1 "${testcvs} -q co CVSROOT" \
@@ -12501,6 +12414,7 @@
          rm -rf $TESTDIR/keywordexpand
           modify_repo rm -rf $CVSROOT_DIRNAME/keywordexpand
          restore_adm
+         test_uses_keywords_done
          ;;
 
 
@@ -12776,7 +12690,7 @@
          # We tolerate the creation of the dirmodule directory, since that
          # is what CVS does, not because we view that as preferable to not
          # creating it.
-         dotest_fail modules-150g2 "test -f dirmodule/a || test -f 
dirmodule/b" ""
+         dotest_fail modules-150g2 "test -f dirmodule/a || test -f dirmodule/b"
          rm -r dirmodule
 
          # Now test that a module using -d checks out to the specified
@@ -12798,10 +12712,10 @@
          dotest modules-151 "${testcvs} co aliasmodule" ""
          dotest_fail modules-152 "test -d aliasmodule" ""
          echo abc >>first-dir/subdir/a
-         dotest modules-153 "${testcvs} -q co aliasmodule" "M 
first-dir/subdir/a"
+         dotest modules-153 "$testcvs -q co aliasmodule" "M first-dir/subdir/a"
 
          cd ..
-         rm -r 1
+         rm -rf 1
 
          mkdir 2
          cd 2
@@ -12825,7 +12739,7 @@
 U first-dir/subdir/a
 U first-dir/subdir/b"
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # Test checking out a module which lists at least two
          # specific files twice.  At one time, this failed over
@@ -12843,14 +12757,14 @@
 "${SPROG}"' add: scheduling file `file1'\'' for addition
 '"${SPROG}"' add: scheduling file `file2'\'' for addition
 '"${SPROG}"' add: use .'"${SPROG}"' commit. to add these files permanently'
-         dotest modules-155c3 "${testcvs} -q ci -m add-it" \
+         dotest modules-155c3 "$testcvs -q ci -m add-it" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 initial revision: 1\.1
 $CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
 initial revision: 1\.1"
 
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          dotest modules-155c4 "${testcvs} -q co topfiles" \
 "U first-dir/file1
 U first-dir/file2"
@@ -12864,13 +12778,13 @@
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: delete; previous revision: 1\.1"
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          dotest modules-155c8 "$testcvs -q co topfiles" \
 "U first-dir/file2"
 
          dokeep
          cd ..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -13008,9 +12922,9 @@
 ${SPROG} checkout: Updating first-dir
 U first-dir/amper1"
          dotest modules2-15 "test -f combmodule/file3" ""
-         dotest modules2-16 "test -f combmodule/first-dir/amper1" ""
+         dotest modules2-16 "test -f combmodule/first-dir/amper1"
          cd combmodule
-         rm -r first-dir
+         rm -rf first-dir
          # At least for now there is no way to tell CVS that
          # some files/subdirectories come from one repository directory,
          # and others from another.
@@ -13026,7 +12940,7 @@
 "U first-dir/amper1"
          dotest modules2-19 "test -f combmodule/first-dir/amper1" ""
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # Now test the "ampdirmod" and "badmod" modules to be sure that
          # options work with ampersand modules but don't prevent the
@@ -13043,7 +12957,7 @@
 "${SPROG} server: modules file missing directory for module badmod
 ${CPROG} \[checkout aborted\]: cannot expand modules"
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # Confirm that a rename with added depth nested in an ampersand
          # module works.
@@ -13054,7 +12968,7 @@
          dotest modules2-nestedrename-3 "test -d messymod/sdir/CVS" ''
          dotest modules2-nestedrename-4 "test -d messymod/sdir/child" ''
          dotest modules2-nestedrename-5 "test -d messymod/sdir/child/CVS" ''
-         cd ..; rm -r 1
+         cd ..; rm -rf 1
 
          # FIXME:  client/server has a bug.  It should be working like a local
          # repository in this case, but fails to check out the second module
@@ -13066,13 +12980,13 @@
          dotest modules2-ampertag-1 "${testcvs} -q co -rtag ampermodule" \
 "U first-dir/amper1"
          if $remote; then
-           dotest_fail modules2-ampertag-2 "test -d ampermodule/second-dir" ''
-           dotest_fail modules2-ampertag-3 "test -d 
ampermodule/second-dir/CVS" ''
+           dotest_fail modules2-ampertag-2r "test -d ampermodule/second-dir" ''
+           dotest_fail modules2-ampertag-3r "test -d 
ampermodule/second-dir/CVS" ''
          else
            dotest modules2-ampertag-2 "test -d ampermodule/second-dir" ''
            dotest modules2-ampertag-3 "test -d ampermodule/second-dir/CVS" ''
          fi
-         cd ..; rm -r 1
+         cd ..; rm -rf 1
 
          # Test for tag files when an ampermod is renamed with more path
          # elements than it started with.
@@ -13090,7 +13004,7 @@
          else
            dotest modules2-tagfiles-2 "cat messymod/sdir/CVS/Tag" 'Ttag'
          fi
-         cd ..; rm -r 1
+         cd ..; rm -rf 1
 
          # Test that CVS gives an error if one combines -a with
          # other options.
@@ -13165,7 +13079,7 @@
          rm -r first-dir
          dotest modules3-7 "${testcvs} -q co bigmod" 'U first-dir/file1'
          cd ..
-         rm -r 1
+         rm -rf 1
 
          mkdir 1; cd 1
          mkdir suba
@@ -13217,7 +13131,7 @@
 'U src/sub/dir/file1'
          dotest modules3-9 "test -f src/sub/dir/file1" ''
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # Try the same thing, but with the directories nested even
          # deeper (deeply enough so they are nested more deeply than
@@ -13231,13 +13145,13 @@
          # While we are doing things like twisted uses of '/' (e.g.
          # modules3-12), try this one.
          if $remote; then
-           dotest_fail modules3-11b \
+           dotest_fail modules3-11br \
 "${testcvs} -q update ${TESTDIR}/1/src/sub1/sub2/sub3/dir/file1" \
 "absolute pathnames invalid for server (specified 
.${TESTDIR}/1/src/sub1/sub2/sub3/dir.)"
          fi # end of remote-only tests
 
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # This one is almost too twisted for words.  The pathname output
          # in the message from "co" doesn't include the "path/in/modules",
@@ -13257,7 +13171,7 @@
            dotest modules3-12 "${testcvs} -q co path/in/modules" \
 "U first-dir/file1"
            dotest modules3-13 "test -f path/in/modules/first-dir/file1" ''
-           cd ..; rm -r 1
+           cd ..; rm -rf 1
          fi # end of tests skipped for remote
 
          # Now here is where it used to get seriously bogus.
@@ -13281,7 +13195,7 @@
          dotest modules3-17 "cat another/path/test/file1" 'file1'
 
          dokeep
-         cd ..; rm -r 2
+         cd ..; rm -rf 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -13352,14 +13266,14 @@
 "U first-dir/file1
 U first-dir/subdir/file2
 U first-dir/subdir_long/file3"
-         rm -r first-dir
+         rm -rf first-dir
 
          dotest modules4-11 "${testcvs} -q co some" \
 "U first-dir/file1
 U first-dir/subdir_long/file3"
          dotest_fail modules4-12 "test -d first-dir/subdir" ''
          dotest modules4-13 "test -d first-dir/subdir_long" ''
-         rm -r first-dir
+         rm -rf first-dir
 
          if $remote; then
            # But remote seems to do it the other way.
@@ -13380,13 +13294,13 @@
            dotest modules4-14-2 "test -d first-dir/subdir" ''
            dotest modules4-14-3 "test -d first-dir/subdir_long" ''
          fi
-         rm -r first-dir
+         rm -rf first-dir
 
          dotest modules4-15 "${testcvs} -q co other" \
 "U first-dir/file1"
          dotest_fail modules4-16 "test -d first-dir/subdir" ''
          dotest_fail modules4-17 "test -d first-dir/subdir_long" ''
-         rm -r first-dir
+         rm -rf first-dir
 
          cd ..
          rm -r 2
@@ -13411,12 +13325,12 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add-it
+${log_keyid}add-it
 ============================================================================="
 
          dokeep
          cd ../../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -13856,7 +13770,7 @@
          dokeep
          restore_adm
          cd ..
-         rm -r modules6
+         rm -rf modules6
          ;;
 
 
@@ -13940,7 +13854,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          ;;
 
 
@@ -14028,7 +13942,7 @@
          dokeep
          cd ../..
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
-         rm -r $module
+         rm -rf $module
          ;;
 
 
@@ -15226,7 +15140,7 @@
          # This tests the code in find_dirs which skips Emptydir.
          dotest emptydir-11 "${testcvs} -q -n update -d -P" ''
          cd ../..
-         rm -r edir
+         rm -rf edir
          cd ..
 
          # Now start playing with moda.
@@ -15254,14 +15168,14 @@
 U dir2d1/sub/sub2d1/file1"
 
          if $remote; then
-           dotest emptydir-17 "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir"
+           dotest emptydir-17r "cat dir2d1/CVS/Repository" "CVSROOT/Emptydir"
          else
            dotest_fail emptydir-17 "test -d dir2d1/CVS"
          fi
 
          dokeep
          cd ..
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/moda
          # I guess for the moment the convention is going to be
          # that we don't need to remove $CVSROOT_DIRNAME/CVSROOT/Emptydir
@@ -15325,7 +15239,7 @@
          dotest abspath-2b "cat ${TESTDIR}/1/CVS/Repository" "mod1"
 
          # Done.  Clean up.
-         rm -r $TESTDIR/1
+         rm -rf $TESTDIR/1
 
 
          # Now try in a subdirectory.  We're not covering any more
@@ -15339,11 +15253,11 @@
          if $remote; then :; else
            dotest abspath-3.1 "$testcvs -q co -d $TESTDIR/1/2 mod1" \
 "U $TESTDIR/1/2/file1"
-           rm -r $TESTDIR/1
+           rm -rf $TESTDIR/1
          fi
          dotest abspath-3.2 "$testcvs -q co -d 1/2 mod1" \
 "U 1/2/file1"
-         rm -r 1
+         rm -rf 1
 
          # We don't to mess with an existing directory just to traverse it,
          # for example by creating a CVS directory, but currently we can't
@@ -15465,7 +15379,7 @@
          # Finished with all tests.  Cleanup.
          dokeep
          cd ../..
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/mod1 $CVSROOT_DIRNAME/mod2
          ;;
 
@@ -15566,7 +15480,7 @@
 ${SPROG} update: Updating top-dir"
 
          cd ..
-         rm -r 1; mkdir 1; cd 1
+         rm -rf 1; mkdir 1; cd 1
          dotest toplevel-10 "${testcvs} co top-dir" \
 "${SPROG} checkout: Updating top-dir
 U top-dir/file1"
@@ -15603,7 +15517,7 @@
          dokeep
          restore_adm
          cd ..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -15671,7 +15585,7 @@
 "${SPROG} update: Updating top-dir"
 
          cd ..
-         rm -r 1; mkdir 1; cd 1
+         rm -rf 1; mkdir 1; cd 1
          dotest toplevel2-10 "${testcvs} co top-dir" \
 "${SPROG} checkout: Updating top-dir
 U top-dir/file1"
@@ -15683,7 +15597,7 @@
          dokeep
          cd ..
          restore_adm
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/top-dir \
                             $CVSROOT_DIRNAME/second-dir
          ;;
@@ -15925,7 +15839,7 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Committing in .
@@ -15936,7 +15850,7 @@
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Committing in .
@@ -15963,7 +15877,7 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Committing in .
@@ -15974,7 +15888,7 @@
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Modified Files:
@@ -15995,7 +15909,7 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Committing in .
@@ -16006,7 +15920,7 @@
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-xCVS: ----------------------------------------------------------------------
+${log_keyid}xCVS: 
----------------------------------------------------------------------
 xCVS: Enter Log.  Lines beginning with .CVS:. are removed automatically
 xCVS:
 xCVS: Committing in .
@@ -16162,7 +16076,7 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: +0 -0;  
commitid: ${commitid};
-\*\*\* empty log message \*\*\*
+${log_keyid}\*\*\* empty log message \*\*\*
 ============================================================================="
 
          # clean up
@@ -16310,7 +16224,7 @@
          if $remote; then
            dotest errmsg1-168r "${testcvs} -q update" \
 "${SPROG} update: \`foo' is no longer in the repository
-$CPROG update: unable to remove \./foo: Permission denied" \
+$CPROG update: unable to remove foo: Permission denied" \
 "${SPROG} update: \`foo' is no longer in the repository"
          else
            dotest errmsg1-168 "${testcvs} -q update" \
@@ -16477,6 +16391,42 @@
 
 
 
+       errmsg4)
+         # Look for the warning when files with keywords are committed with
+         # an OpenPGP signature.
+         if $gpg; then :; else
+           skip errmsg4 "No OpenPGP tool configured."
+           continue
+         fi
+
+         test_uses_keywords
+
+         mkdir errmsg4
+         cd errmsg4
+         dotest errmsg4-init-1 "$testcvs -Q import -m. errmsg4 VENDOR RELEASE"
+         dotest errmsg4-init-2 "$testcvs -Q co errmsg4"
+
+         cd errmsg4
+         echo '$''Revision$' >filewithkeyword
+         dotest errmsg4-init-3 "$testcvs -Q add filewithkeyword"
+
+         # The following test intentionally uses -q.  This message should only
+         # disappear with -Q.
+         dotest errmsg4-1 "$testcvs ci -mgen-msg" \
+"$CPROG commit: Examining \.
+$CPROG commit: warning: signed file \`filewithkeyword' contains at least one 
RCS keyword
+$CVSROOT_DIRNAME/errmsg4/filewithkeyword,v  <--  filewithkeyword
+initial revision: 1\.1"
+
+         dokeep
+         cd ../..
+         rm -rf errmsg4
+         modify_repo rm -rf $CVSROOT_DIRNAME/errmsg4
+         test_uses_keywords_done
+         ;;
+
+
+
        close-stdout)
          # Ensure that cvs update -p FILE > /dev/full fails
          # Perform this test IFF /dev/full is a writable character device.
@@ -16495,7 +16445,7 @@
 
            dokeep
            cd ..
-           rm -r close-stdout
+           rm -rf close-stdout
            modify_repo rm -rf $CVSROOT_DIRNAME/closeout
          else
            skip close-stdout '/dev/full is not available'
@@ -16644,7 +16594,7 @@
          dotest_fail devcom-9b "test -w abc"
 
          dotest devcom-10 "$testcvs editors"
-         dotest devcom-11 "$testcvs edit abb"
+         dotest devcom-11 "$testcvs -q edit abb"
 
          # Here we test for the traditional ISO C ctime() date format.
          # We assume the C locale; I guess that works provided we set
@@ -16666,11 +16616,11 @@
 
          dotest_fail devcom-16 "test -w abb"
 
-         dotest devcom-17 "$testcvs edit abc"
+         dotest devcom-17 "$testcvs -q edit abc"
 
          # Unedit of an unmodified file.
          dotest devcom-18 "$testcvs unedit abc"
-         dotest devcom-19 "$testcvs edit abc"
+         dotest devcom-19 "$testcvs -q edit abc"
 
          echo changedabc >abc
          # Try to unedit a modified file; cvs should ask for confirmation
@@ -17053,7 +17003,7 @@
          dotest_fail watch4-8 "test -w first-dir/file1" ''
          dotest_fail watch4-9 "test -w first-dir/subdir/sfile" ''
          cd first-dir
-         dotest watch4-10 "${testcvs} edit file1" ''
+         dotest watch4-10 "$testcvs -q edit file1"
          echo 'edited in 2' >file1
          cd ../..
 
@@ -17063,7 +17013,7 @@
             #  to maintain partial compatibility with CVS versions
             #  prior to the edit check patch.
           editorsLineRE="file1 $username       [SMTWF][uoehra][neduit] 
[JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000   
$hostname       $TESTDIR/2/first-dir"
-         dotest watch4-11 "$testcvs edit file1" "$editorsLineRE"
+         dotest watch4-11 "$testcvs -q edit file1"
 
          echo 'edited in 1' >file1
          dotest watch4-12 "${testcvs} -q ci -m edit-in-1" \
@@ -17071,13 +17021,9 @@
 new revision: 1\.2; previous revision: 1\.1"
          cd ../..
          cd 2/first-dir
-         dotest watch4-13 "${testcvs} -q update" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1 and 1\.2 into file1
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in file1
+         dotest watch4-13 "$testcvs -q update" \
+"Merging differences between 1\.1 and 1\.2 into \`file1'
+$CPROG update: conflicts during merge
 C file1"
          if (echo yes | ${testcvs} unedit file1) >>${LOGFILE}; then
            pass watch4-14
@@ -17140,7 +17086,7 @@
          dotest watch5-3 "${testcvs} -q ci -m add" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 initial revision: 1\.1"
-         dotest watch5-4 "${testcvs} edit file1" ''
+         dotest watch5-4 "$testcvs -q edit file1"
          dotest watch5-5 "test -f CVS/Base/file1" ''
          if ${testcvs} status file1 >>${LOGFILE} 2>&1; then
                pass watch5-6
@@ -17344,8 +17290,8 @@
 
           NF_editorsLineRE="   [-a-zA-Z0-9_]*  [SMTWF][uoehra][neduit] 
[JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000   
$hostname       $TESTDIR/edit-check/first-dir"
 
-          dotest edit-check-3 "$testcvs edit file1"
-          dotest edit-check-4 "$testcvs edit file1" "$editorsLineRE"
+          dotest edit-check-3 "$testcvs -q edit file1"
+          dotest edit-check-4 "$testcvs -q edit file1"
 
           dotest_fail edit-check-5a "$testcvs edit -c file1" \
 "$editorsLineRE
@@ -17353,7 +17299,7 @@
 
           dotest edit-check-5b "$testcvs editors" "$editorsLineRE"
 
-          dotest edit-check-6a "$testcvs edit -c -f file1" "$editorsLineRE"
+          dotest edit-check-6a "$testcvs -q edit -c -f file1"
           dotest edit-check-6b "$testcvs editors" "$editorsLineRE"
 
           dotest edit-check-7a "cat file1" "foo"
@@ -17386,10 +17332,9 @@
           dotest edit-check-9b "$testcvs editors"
           dotest edit-check-9c "cat file1" "foo"
 
-          dotest edit-check-10 "$testcvs edit -c file1"
-          dotest_fail edit-check-11 "$testcvs edit -c file1" \
-"$editorsLineRE
-$SPROG edit: Skipping file \`file1' due to existing editors\."
+          dotest edit-check-10 "$testcvs -q edit -c file1"
+          dotest_fail edit-check-11 "$testcvs -q edit -c file1" \
+"$SPROG edit: Skipping file \`file1' due to existing editors\."
 
           echo "morefoo" > file1
           dotest edit-check-12a "$testcvs commit -m 'c2' -c file1" \
@@ -17409,7 +17354,7 @@
 new revision: 1\.3; previous revision: 1\.2"
           dotest edit-check-14b "$testcvs editors file1"
 
-          dotest edit-check-15 "$testcvs edit -c file1"
+          dotest edit-check-15 "$testcvs -q edit -c file1"
           cd ..
 
           dotest edit-check-16a "echo yes | $testcvs release -d first-dir" \
@@ -17421,11 +17366,10 @@
           dotest edit-check-16c "$testcvs editors file1"
 
           cd ..
-          dotest edit-check-17a "$testcvs edit -c"
-          dotest_fail edit-check-17b "$testcvs edit -c" \
-"$R_editorsLineRE
-$SPROG edit: Skipping file \`first-dir/file1' due to existing editors\."
-          dotest edit-check-17c "$testcvs edit -c -f" "$R_editorsLineRE"
+          dotest edit-check-17a "$testcvs -q edit -c"
+          dotest_fail edit-check-17b "$testcvs -q edit -c" \
+"$SPROG edit: Skipping file \`first-dir/file1' due to existing editors\."
+          dotest edit-check-17c "$testcvs -q edit -c -f"
 
           echo "more changes" > first-dir/file1
           dotest edit-check-18a "$testcvs -q commit -m 'c5' -c" \
@@ -17461,7 +17405,7 @@
 
           O_editorsLineRE="file1       $otherUser      [SMTWF][uoehra][neduit] 
[JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000   
$hostname       $TESTDIR[0-9]/edit-check/first-dir"
 
-          dotest edit-check-19a "$testcvs edit file1" "$O_editorsLineRE"
+          dotest edit-check-19a "$testcvs -q edit file1"
           dotest edit-check-19b "$testcvs editors" \
 "$A_editorsLineRE
 $NF_editorsLineRE"
@@ -17469,12 +17413,11 @@
           dotest edit-check-20a "$testcvs unedit file1"
           dotest edit-check-20b "$testcvs editors" "$O_editorsLineRE"
 
-          dotest_fail edit-check-21a "$testcvs edit -c file1" \
-"$O_editorsLineRE
-$SPROG edit: Skipping file \`file1' due to existing editors\."
+          dotest_fail edit-check-21a "$testcvs -q edit -c file1" \
+"$SPROG edit: Skipping file \`file1' due to existing editors\."
           dotest edit-check-21b "$testcvs editors" "$O_editorsLineRE"
 
-          dotest edit-check-22a "$testcvs edit -c -f file1" "$O_editorsLineRE"
+          dotest edit-check-22a "$testcvs -q edit -c -f file1"
           dotest edit-check-22b "$testcvs editors" \
 "$A_editorsLineRE
 $NF_editorsLineRE"
@@ -17499,7 +17442,7 @@
           dotest edit-check-25b "$testcvs editors" "$O_editorsLineRE"
           dotest_fail edit-check-25c "test -w file1"
 
-          dotest edit-check-26a "$testcvs edit file1" "$O_editorsLineRE"
+          dotest edit-check-26a "$testcvs -q edit file1"
           dotest edit-check-26b "$testcvs editors file1" \
 "$A_editorsLineRE
 $NF_editorsLineRE"
@@ -17540,7 +17483,7 @@
             # (if the process doing the exec exits before the parent
             # gets around to sending data to it) or "broken pipe" (if it
             # is the other way around).
-            dotest_fail edit-check-31ar "$testcvs edit file1" \
+            dotest_fail edit-check-31ar "$testcvs -q edit file1" \
 "$SPROG \[edit aborted\]: cannot exec $TESTDIR/cvs-none: $DOTSTAR"
             dotest edit-check-31br "test -w file1"
             dotest edit-check-31cr "cat CVS/Notify" \
@@ -17583,7 +17526,7 @@
 
           cd ..
 
-          dotest edit-check-33a "$testcvs edit -c"
+          dotest edit-check-33a "$testcvs -q edit -c"
 
           dotest edit-check-33b "$testcvs editors" \
 "$AF_editorsLineRE
@@ -17591,10 +17534,8 @@
 $F3_editorsLineRE"
           dotest edit-check-33c "test -w second-dir/file3"
 
-          dotest_fail edit-check-34a "$testcvs edit -c file1 file2" \
-"$AF_editorsLineRE
-$SPROG edit: Skipping file \`file1' due to existing editors\.
-$AF_editorsLineRE
+          dotest_fail edit-check-34a "$testcvs -q edit -c file1 file2" \
+"$SPROG edit: Skipping file \`file1' due to existing editors\.
 $SPROG edit: Skipping file \`file2' due to existing editors\."
 
           dotest edit-check-34b "$testcvs editors file1 file2" \
@@ -17659,14 +17600,14 @@
          dotest unedit-without-baserev-7 "${testcvs} -Q co x" ''
          cd x
 
-         dotest unedit-without-baserev-10 "${testcvs} edit m" ''
+         dotest unedit-without-baserev-10 "$testcvs -q edit m"
          echo 'edited in 2' >m
          cd ../..
 
          cd 1/x
 
           editorsLineRE="m     $username       [SMTWF][uoehra][neduit] 
[JFAMSOND][aepuco][nbrylgptvc] [0-9 ][0-9] [0-9:]* [0-9][0-9][0-9][0-9] -0000   
$hostname       $TESTDIR/2/x"
-         dotest unedit-without-baserev-11 "$testcvs edit m" "$editorsLineRE"
+         dotest unedit-without-baserev-11 "$testcvs -q edit m"
 
          echo 'edited in 1' >m
          dotest unedit-without-baserev-12 "${testcvs} -q ci -m edit-in-1" \
@@ -17674,13 +17615,9 @@
 new revision: 1\.2; previous revision: 1\.1"
          cd ../..
          cd 2/x
-         dotest unedit-without-baserev-13 "${testcvs} -q update" \
-"RCS file: ${CVSROOT_DIRNAME}/x/m,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.2
-Merging differences between 1\.1\.1\.1 and 1\.2 into m
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in m
+         dotest unedit-without-baserev-13 "$testcvs -q update" \
+"Merging differences between 1\.1\.1\.1 and 1\.2 into \`m'
+$CPROG update: conflicts during merge
 C m"
          rm CVS/Baserev
          dotest unedit-without-baserev-14 "echo yes |${testcvs} unedit m" \
@@ -17700,7 +17637,7 @@
          dokeep
          cd ../..
          rm -rf 1
-         rm -r 2
+         rm -rf 2
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
          ;;
 
@@ -17894,11 +17831,12 @@
 new revision: 1\.1\.2\.2; previous revision: 1\.1\.2\.1"
          dotest ignore-on-branch-6 "$testcvs -q up -rbranch2" \
 "${SPROG} update: \`file2' is no longer in the repository"
-         dotest ignore-on-branch-7 "$testcvs -q up -jbranch" 'U file2'
+         dotest ignore-on-branch-7 "$testcvs -q up -jbranch" \
+"$SPROG update: scheduling addition from revision 1\.1\.2\.2 of \`file2'\."
 
          dokeep
          cd ../..
-         rm -r ignore-on-branch
+         rm -rf ignore-on-branch
          modify_repo rm -rf $CVSROOT_DIRNAME/ignore-on-branch
          ;;
 
@@ -17913,6 +17851,9 @@
          #   * -k wrappers: binwrap, binwrap2, binwrap3
          #   * "cvs import" and wrappers: binwrap, binwrap2, binwrap3
          #   * -k option to "cvs import": none yet, as far as I know.
+
+         test_uses_keywords
+
          modify_repo mkdir $CVSROOT_DIRNAME/first-dir
          mkdir 1; cd 1
          dotest binfiles-1 "${testcvs} -q co first-dir" ''
@@ -17969,7 +17910,7 @@
          # also used when operating on files instead of whole
          # directories
           cd ../..
-         rm -r 2a
+         rm -rf 2a
          mkdir 3; cd 3
          dotest binfiles-5.5b0 "${testcvs} -q co first-dir/binfile" \
 'U first-dir/binfile'
@@ -17985,13 +17926,13 @@
    Sticky Date:                (none)
    Sticky Options:     -kb"
          cd ../..
-         rm -r 3
+         rm -rf 3
          # test that "-kk" does not override "-kb"
          mkdir 3; cd 3
-         dotest binfiles-5.5b0 "${testcvs} -q co -kk first-dir/binfile" \
+         dotest binfiles-5.5b2 "${testcvs} -q co -kk first-dir/binfile" \
 'U first-dir/binfile'
          cd first-dir
-         dotest binfiles-5.5b1 "${testcvs} status binfile" \
+         dotest binfiles-5.5b3 "${testcvs} status binfile" \
 "===================================================================
 File: binfile                  Status: Up-to-date
 
@@ -18002,7 +17943,7 @@
    Sticky Date:                (none)
    Sticky Options:     -kb"
          cd ../..
-         rm -r 3
+         rm -rf 3
          cd 2/first-dir
 
          cp ../../1/binfile2.dat binfile
@@ -18064,13 +18005,11 @@
    Sticky Date:                (none)
    Sticky Options:     -kb"
          cd ../..
-         rm -r 3
+         rm -rf 3
 
          cd 2/first-dir
          echo 'this file is $''RCSfile$' >binfile
-         dotest binfiles-14a "${testcvs} -q ci -m modify-it" \
-"$CVSROOT_DIRNAME/first-dir/binfile,v  <--  binfile
-new revision: 1\.5; previous revision: 1\.4"
+         dotest binfiles-14a "${testcvs} -Q ci -m modify-it"
          dotest binfiles-14b "cat binfile" 'this file is $''RCSfile$'
          # See binfiles-5.5 for discussion of -kb.
          dotest binfiles-14c "${testcvs} status binfile" \
@@ -18185,13 +18124,23 @@
 
          # Check that the contents were right.  This isn't the hard case
          # (in which RCS_delete_revs does a diff), but might as well.
-         dotest binfiles-o4 "${testcvs} -q update binfile" "U binfile"
-         dotest binfiles-o5 "cmp binfile ../../1/binfile.dat" ""
+         if $remote && $bases; then
+           dotest_fail binfiles-o4r "$testcvs -q update binfile" \
+"$SPROG \[update aborted\]: could not find desired version 1\.5 in 
$CVSROOT_DIRNAME/first-dir/binfile,v"
+         else
+           # FIXCVS: Local mode silently overwrites what it thinks is
+           # revision 1.5 of binfile with revision 1.3 of binfile when
+           # the later revisions disappear.  This doesn't sound right.
+           # Either way, the behavior should match.
+           dotest binfiles-o4 "$testcvs -q update binfile" "U binfile"
+           dotest binfiles-o5 "cmp binfile ../../1/binfile.dat"
+         fi
 
          dokeep
          cd ../..
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r 1 2
+         rm -rf 1 2
+         test_uses_keywords_done
          ;;
 
 
@@ -18285,17 +18234,18 @@
 new revision: 1\.2; previous revision: 1\.1"
          cp ../binfile3 brmod-wdmod
 
-         dotest binfiles2-8 "${testcvs} -q update -j br" \
-"U binfile\.dat
-U brmod
-${SPROG} update: nonmergeable file needs merge
-${SPROG} update: revision 1.1.2.1 from repository is now in brmod-trmod
-${SPROG} update: file from working directory is now in .#brmod-trmod.1.2
+         dotest binfiles2-8 "$testcvs -q update -j br" \
+"$SPROG update: scheduling addition from revision 1\.1\.2\.1 of 
\`binfile.dat'\.
+$SPROG update: Replacing \`brmod' with contents of revision 1\.1\.2\.1\.
+M brmod
+$SPROG update: Nonmergeable file needs merge\.
+$SPROG update: Replacing \`brmod-trmod' with contents of revision 1\.1\.2\.1\.
+$SPROG update: File from working directory is now in \`\.#brmod-trmod\.1\.2'\.
 C brmod-trmod
 M brmod-wdmod
-${SPROG} update: nonmergeable file needs merge
-${SPROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod
-${SPROG} update: file from working directory is now in .#brmod-wdmod.1.1
+$SPROG update: Nonmergeable file needs merge\.
+$SPROG update: Replacing \`brmod-wdmod' with contents of revision 1\.1\.2\.1\.
+$SPROG update: File from working directory is now in \`\.#brmod-wdmod\.1\.1'\.
 C brmod-wdmod"
 
          dotest binfiles2-9 "cmp ../binfile binfile.dat"
@@ -18306,7 +18256,13 @@
          dotest binfiles2-9a-brmod-wdmod "cmp ../binfile3 .#brmod-wdmod.1.1"
 
          # Test that everything was properly scheduled.
-         dotest binfiles2-10 "${testcvs} -q ci -m checkin" \
+         dotest_fail binfiles2-10a "${testcvs} -q ci -m checkin" \
+"$SPROG commit: file \`brmod-trmod' had a conflict and has not been modified
+$SPROG commit: file \`brmod-wdmod' had a conflict and has not been modified
+$SPROG \[commit aborted\]: correct above errors first!"
+
+         touch brmod-trmod brmod-wdmod
+         dotest binfiles2-10b "${testcvs} -q ci -m checkin" \
 "$CVSROOT_DIRNAME/first-dir/binfile\.dat,v  <--  binfile\.dat
 new revision: 1\.2; previous revision: 1\.1
 $CVSROOT_DIRNAME/first-dir/brmod,v  <--  brmod
@@ -18343,13 +18299,13 @@
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-checkin
+${log_keyid}checkin
 ============================================================================="
 
          dokeep
          cd ../..
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
-         rm -r 1
+         rm -rf 1
          ;;
 
 
@@ -18391,7 +18347,7 @@
          # in checkaddfile()); should also test the case in which
          # we are changing it from one non-default value to another.
          dotest binfiles3-7 "$testcvs -q ci -m readd-it" \
-"$SPROG commit: changing keyword expansion mode to -kb
+"$SPROG commit: changing keyword expansion mode of \`file1' from \`-kkv' to 
\`-kb'
 $CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.3; previous revision: 1\.2"
          dotest binfiles3-8 "${testcvs} -q log -h -N file1" "
@@ -18429,7 +18385,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -18521,16 +18477,17 @@
 new revision: 1\.2; previous revision: 1\.1"
            echo 'modify brmod-wdmod in working dir' >brmod-wdmod
 
-           dotest mcopy-8 "${testcvs} -q update -j br" \
-"U brmod
-${SPROG} update: nonmergeable file needs merge
-${SPROG} update: revision 1.1.2.1 from repository is now in brmod-trmod
-${SPROG} update: file from working directory is now in .#brmod-trmod.1.2
+           dotest mcopy-8 "$testcvs -q update -j br" \
+"$SPROG update: Replacing \`brmod' with contents of revision 1\.1\.2\.1\.
+M brmod
+$SPROG update: nonmergeable file needs merge
+$SPROG update: revision 1.1.2.1 from repository is now in brmod-trmod
+$SPROG update: file from working directory is now in .#brmod-trmod.1.2
 C brmod-trmod
 M brmod-wdmod
-${SPROG} update: nonmergeable file needs merge
-${SPROG} update: revision 1.1.2.1 from repository is now in brmod-wdmod
-${SPROG} update: file from working directory is now in .#brmod-wdmod.1.1
+$SPROG update: nonmergeable file needs merge
+$SPROG update: revision 1.1.2.1 from repository is now in brmod-wdmod
+$SPROG update: file from working directory is now in .#brmod-wdmod.1.1
 C brmod-wdmod"
 
            dotest mcopy-9 "cat brmod brmod-trmod brmod-wdmod" \
@@ -18605,7 +18562,7 @@
    Sticky Options:     -kb"
 
          dokeep
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -18656,7 +18613,7 @@
    Sticky Options:     -kb"
 
          dokeep
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -18819,7 +18776,7 @@
 
           # Now check out the module and see which files are binary.
           cd ..
-         rm -r binwrap3
+         rm -rf binwrap3
           dotest binwrap3-3 "${testcvs} co binwrap3" "${DOTSTAR}"
           cd binwrap3
 
@@ -18919,7 +18876,7 @@
           # Restore and clean up
          dokeep
           cd ..
-         rm -r binwrap3 CVSROOT
+         rm -rf binwrap3 CVSROOT
          cd ..
          rm -r wnt
          modify_repo rm -rf $CVSROOT_DIRNAME/binwrap3
@@ -18998,8 +18955,8 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r CVSROOT
-         rm -r m1 m2
+         rm -rf CVSROOT
+         rm -rf m1 m2
          cd ..
          rm -r wnt
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
@@ -20036,7 +19993,7 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -20165,7 +20122,7 @@
          dokeep
          cd ../..
          restore_adm
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -20196,11 +20153,7 @@
 new revision: 1\.[0-9]*; previous revision: 1\.[0-9]*
 $SPROG commit: Rebuilding administrative file database"
          dotest config-3a "$testcvs -Q update -jHEAD -jconfig-start" \
-"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: 
syntax error: missing \`=' between keyword and value
-RCS file: $CVSROOT_DIRNAME/CVSROOT/config,v
-retrieving revision 1.[0-9]*
-retrieving revision 1.[0-9]*
-Merging differences between 1.[0-9]* and 1.[0-9]* into config"
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[1-9][0-9]*\]: 
syntax error: missing \`=' between keyword and value"
          echo 'BogusOption=yes' >>config
          if $proxy; then
            dotest config-4p "$testcvs -q ci -m change-to-bogus-opt" \
@@ -20269,7 +20222,7 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r wnt
+         rm -rf wnt
          ;;
 
 
@@ -20352,9 +20305,11 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r wnt
+         rm -rf wnt
          ;;
 
+
+
        config3)
          # Verify comments, white space, & [rootspecs] in CVSROOT/config
          #
@@ -20391,8 +20346,7 @@
 
          cd CVSROOT
          dotest config3-init-2a "$testcvs -Q up -jHEAD -jinitial-config" \
-"$DOTSTAR
-Merging differences between 1\.[0-9]* and 1\.[0-9]* into config"
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: 
unrecognized keyword \`GLOBAL-BAD-OPTION'"
 
          cat <<EOF >>config
              # Ignore a comment with leading spaces.
@@ -20439,8 +20393,7 @@
          # root is ignored.
          cd CVSROOT
          dotest config3-init-3a "$testcvs -Q up -jHEAD -jinitial-config" \
-"$DOTSTAR
-Merging differences between 1\.[0-9]* and 1\.[0-9]* into config"
+"$SPROG [a-z]*: $SECONDARY_CVSROOT_DIRNAME/CVSROOT/config \[[0-9]*\]: 
unrecognized keyword \`PROCESS-BAD-OPTION'"
 
          cat <<EOF >>config
              HistoryLogPath=$TESTDIR/historylog
@@ -20497,7 +20450,7 @@
          dokeep
          restore_adm
          cd ..
-         rm -r config3
+         rm -rf config3
          modify_repo rm -rf $CVSROOT_DIRNAME/config3
          ;;
 
@@ -20536,7 +20489,7 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r config4
+         rm -rf config4
          modify_repo rm -rf $CVSROOT_DIRNAME/config4
          ;;
 
@@ -20622,6 +20575,9 @@
          # much of a test for local CVS.
          # We test this with some keyword expansion games, but the situation
          # also arises if the user modifies the file while CVS is running.
+
+         test_uses_keywords
+
          modify_repo mkdir $CVSROOT_DIRNAME/first-dir
          mkdir 1
          cd 1
@@ -20636,9 +20592,7 @@
 "$SPROG add: scheduling file \`file1' for addition
 $SPROG add: use \`$SPROG commit' to add this file permanently"
 
-         dotest serverpatch-3 "${testcvs} -q commit -m add" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-initial revision: 1\.1"
+         dotest serverpatch-3 "$testcvs -Q commit -m add"
 
          # Tag the file.
          dotest serverpatch-4 "${testcvs} -q tag tag file1" 'T file1'
@@ -20657,22 +20611,21 @@
          # Modify and check in the first copy.
          cd ../1/first-dir
          echo '2' >> file1
-         dotest serverpatch-7 "${testcvs} -q ci -mx file1" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.2; previous revision: 1\.1"
+         dotest serverpatch-7 "$testcvs -Q ci -mx file1"
 
          # Now update the second copy.  When using remote CVS, the
          # patch will fail, forcing the file to be refetched.
          cd ../../2/first-dir
          dotest serverpatch-8 "$testcvs -q update" 'U file1' \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
 
          dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -20780,22 +20733,22 @@
          log_commitid="  commitid: ${commitid};"
          log_rev1="${log_dash} 1\.1
 ${log_date}${log_commitid}
-line 1
+${log_keyid}line 1
 
 line 2"
          log_rev2="${log_dash} 1\.2
 ${log_date}${log_lines}${log_commitid}
 branches:  1\.2\.2;
-2"
+${log_keyid}2"
          log_rev3="${log_dash} 1\.3
 ${log_date}${log_lines}${log_commitid}
-3"
+${log_keyid}3"
          log_rev1b="${log_dash} 1\.2\.2\.1
 ${log_date}${log_lines}${log_commitid}
-1b"
+${log_keyid}1b"
          log_rev2b="${log_dash} 1\.2\.2\.2
 ${log_date}${log_lines}${log_commitid}
-2b"
+${log_keyid}2b"
          
log_trailer='============================================================================='
 
          # Now, finally, test the log output.
@@ -21414,7 +21367,7 @@
 4"
          log_rev22="${log_dash} 1\.2
 ${log_date}${log_lines}${log_commitid}
-2"
+${log_keyid}2"
 
          dotest log-d3 "${testcvs} log -rbranch file1" \
 "${log_header1}
@@ -21728,7 +21681,7 @@
 
          dokeep
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -21766,7 +21719,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-1
+${log_keyid}1
 ============================================================================="
 
          fi # end of tests skipped for remote
@@ -21788,7 +21741,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-1
+${log_keyid}1
 ============================================================================="
 
          echo 'longer description' >${TESTDIR}/descrip
@@ -21813,7 +21766,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-1
+${log_keyid}1
 ============================================================================="
 
          # TODO: `cvs admin -t "my message" file1' is a request to
@@ -21836,7 +21789,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-1
+${log_keyid}1
 ============================================================================="
 
          dokeep
@@ -22102,6 +22055,9 @@
          # the output of `cvs annotate' -- it uses values from the previous
          # delta.  In this case, `1.1' instead of `1.2', even though it puts
          # the proper version number on the prefix to each line of output.
+
+         test_uses_keywords
+
          mkdir 1; cd 1
          dotest ann-id-1 "$testcvs -q co -l ."
          module=x
@@ -22134,6 +22090,7 @@
          cd ../..
          rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
+         test_uses_keywords_done
          ;;
 
 
@@ -22310,14 +22267,9 @@
 
           CVS_SERVER=$CVS_SERVER_save; export CVS_SERVER
 
-         if $keep; then
-           echo Keeping ${TESTDIR} and exiting due to --keep
-           exit 0
-         fi
-
          dokeep
           rm -f $TESTDIR/cvs-setHome
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          rm -rf $TESTDIR/crerepos
          ;;
@@ -22332,6 +22284,11 @@
 
          # See tests admin-13, admin-25 and rcs-8a for exporting RCS files.
 
+         # This test doesn't really use keywords, but there are no signatures
+         # in the RCS content that has been pasted into this script, so
+         # supress the OpenPGP support.
+         test_uses_keywords
+
          # Save the timezone and set it to UTC for these tests to make the
          # value more predicatable.
          save_TZ=$TZ
@@ -22640,7 +22597,7 @@
 branches;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 
 desc
 @@
@@ -22765,7 +22722,7 @@
 ----------------------------
 revision 1\.2\.6\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-mod
+${log_keyid}mod
 ----------------------------
 revision 1\.2\.6\.1
 date: 1971-01-01 08:00:05 [+-]0000;  author: joe;  state: Exp;  lines: 
${PLUS}1 -1;
@@ -22814,8 +22771,9 @@
          dokeep
          TZ=$save_TZ
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -22824,6 +22782,7 @@
          # More date tests.  Might as well do this as a separate
          # test from "rcs", so that we don't need to perturb the
          # "written by RCS 5.7" RCS file.
+         test_uses_keywords
          modify_repo mkdir $CVSROOT_DIRNAME/first-dir
          # Significance of various dates:
          # * At least one Y2K standard refers to recognizing 9 Sep 1999
@@ -22903,8 +22862,9 @@
 
          dokeep
          cd ..
-         rm -r first-dir
+         rm -rf first-dir
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -22912,6 +22872,7 @@
        rcs3)
          # More RCS file tests, in particular at least some of the
          # error handling issues.
+         test_uses_keywords
          mkdir ${CVSROOT_DIRNAME}/first-dir
          cat <<EOF >$TESTDIR/file1,v
 head 1.1; access; symbols; locks; expand o; 1.1 date 2007.03.20.04.03.02
@@ -22973,8 +22934,9 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -23063,7 +23025,7 @@
          dokeep
          TZ=$save_TZ
          cd ../..
-          rm -r rcs4
+          rm -rf rcs4
           modify_repo rm -rf $CVSROOT_DIRNAME/rcs4-dir
          ;;
 
@@ -23082,6 +23044,7 @@
          # spec, though it doesn't appear to be possible to create such a log
          # message using RCS 5.7.
 
+         test_uses_keywords
          modify_repo mkdir $CVSROOT_DIRNAME/rcs5
          cat <<\EOF >$TESTDIR/file1,v
 head 1.1;
@@ -23124,8 +23087,9 @@
 line5"
 
          cd ..
-          rm -r rcs5
+          rm -rf rcs5
           modify_repo rm -rf $CVSROOT_DIRNAME/rcs5
+         test_uses_keywords_done
          ;;
 
 
@@ -23350,7 +23314,7 @@
          umask $save_umask
          unset CVSUMASK
          rm -r $TESTDIR/locks
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -23377,6 +23341,7 @@
          #   Granted, the developer should have been notified not to do this
          #     by now, but still...
          #
+         test_uses_keywords
          mkdir backuprecover; cd backuprecover
          mkdir 1; cd 1
          dotest backuprecover-1 "$testcvs -q co -l ."
@@ -23504,11 +23469,23 @@
          #
          # Feel free to imagine the horrific scream of despair
          cd ../../1/first-dir
-         dotest backuprecover-15 "${testcvs} update" \
-"${SPROG} update: Updating .
+         if $remote && $bases; then
+           # FIXCVS
+           # See the note above about lost data and a few other comments in
+           # other tests.  At least with base files, no data is lost, but this
+           # is a side effect of sending diffs against bases and should
+           # probably be caught explicitly, such that it would also be caught
+           # in local mode.
+           dotest_fail backuprecover-15r "$testcvs update" \
+"$SPROG update: Updating .
+$SPROG \[update aborted\]: could not find desired version 1\.5 in 
$CVSROOT_DIRNAME/first-dir/file1,v"
+         else
+           dotest backuprecover-15 "$testcvs update" \
+"$SPROG update: Updating .
 U file1
-${SPROG} update: Updating dir
+$SPROG update: Updating dir
 U dir/file2"
+         fi
 
          # Developer 3 tries the same thing (he has an office)
          # but fails without losing data since all of his files have
@@ -23559,20 +23536,12 @@
          cd ../../4/first-dir
          dotest backuprecover-20 "${testcvs} update" \
 "${SPROG} update: Updating \.
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.3
-retrieving revision 1\.4
-Merging differences between 1\.3 and 1\.4 into file1
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in file1
+Merging differences between 1\.3 and 1\.4 into \`file1'
+$CPROG update: conflicts during merge
 C file1
-${SPROG} update: Updating dir
-RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v
-retrieving revision 1\.3
-retrieving revision 1\.4
-Merging differences between 1\.3 and 1\.4 into file2
-rcsmerge: warning: conflicts during merge
-${SPROG} update: conflicts found in dir/file2
+$SPROG update: Updating dir
+Merging differences between 1\.3 and 1\.4 into \`dir/file2'
+$CPROG update: conflicts during merge
 C dir/file2"
          sed -e \
 "/^<<<<<<</,/^=======/d
@@ -23587,15 +23556,7 @@
 
          # go back and commit developer 2's stuff to prove it can still be done
          cd ../../2/first-dir
-         dotest backuprecover-22 "${testcvs} -Q update" \
-"RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.2
-retrieving revision 1\.4
-Merging differences between 1\.2 and 1\.4 into file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/dir/file2,v
-retrieving revision 1\.2
-retrieving revision 1\.5
-Merging differences between 1\.2 and 1\.5 into file2"
+         dotest backuprecover-22 "$testcvs -Q update"
          dotest backuprecover-23 "${testcvs} -q ci -mtest" \
 "$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.5; previous revision: 1\.4
@@ -23604,12 +23565,13 @@
 
          # and restore the data to developer 1
          cd ../../1/first-dir
-         dotest backuprecover-24 "${testcvs} -Q update" ''
+         dotest backuprecover-24 "$testcvs -Q update" 
 
          dokeep
          cd ../../..
-         rm -r backuprecover
+         rm -rf backuprecover
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -23752,7 +23714,7 @@
          dokeep
          cd ../../..
          CVSROOT=$save_CVSROOT
-         rm -r parseroot2
+         rm -rf parseroot2
          ;;
 
 
@@ -23787,7 +23749,7 @@
          cd ..
 
          # Initial checkout.
-         rm -r CVSROOT
+         rm -rf CVSROOT
          
CVSROOT=":ext;cvs_RSH=$save_CVS_RSH;CVS_Server=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
          dotest parseroot3-3 "$testcvs -Q co CVSROOT"
          cd CVSROOT
@@ -23795,7 +23757,7 @@
          cd ..
 
          # Checkout bogus values for Redirect
-         rm -r CVSROOT
+         rm -rf CVSROOT
          
CVSROOT=":ext;Redirect=bogus;CVS_RSH=$save_CVS_RSH;CVS_SERVER=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
          dotest parseroot3-5 "$testcvs -Q co CVSROOT" \
 "$SPROG checkout: CVSROOT: unrecognized value \`bogus' for \`Redirect'"
@@ -23807,7 +23769,7 @@
          cd ..
 
          # Checkout good values for Redirect
-         rm -r CVSROOT
+         rm -rf CVSROOT
          
CVSROOT=":EXT;Redirect=no;CVS_RSH=$save_CVS_RSH;CVS_SERVER=$save_CVS_SERVER:$host$CVSROOT_DIRNAME"
          dotest parseroot3-7 "$testcvs -Q co CVSROOT"
          cd CVSROOT
@@ -23825,7 +23787,7 @@
          CVS_RSH=$save_CVS_RSH
          CVS_SERVER=$save_CVS_SERVER
          export CVS_RSH CVS_SERVER
-         rm -r parseroot3
+         rm -rf parseroot3
          ;;
 
 
@@ -23963,13 +23925,9 @@
          echo "add a line to the end" >>file1
 
          dotest_fail big-4b "$testcvs -q diff -u" \
-"Index: file1
-===================================================================
-RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
-retrieving revision 1\.1
-diff -u -r1\.1 file1
+"diff -u -r1\.1 file1
 --- file1      $RFCDATE        1\.1
-$PLUS$PLUS$PLUS file1  $RFCDATE
+$PLUS$PLUS$PLUS file1$LOCAL_RFCDATE
 @@ -998,3 ${PLUS}998,4 @@
  This is line (9,9,7) which goes into the file file1 for testing
  This is line (9,9,8) which goes into the file file1 for testing
@@ -23986,7 +23944,7 @@
 
          dokeep
          cd ../..
-         rm -r first-dir 2
+         rm -rf first-dir 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -24186,6 +24144,7 @@
          cd ../..
          # Restore umask.
          umask $save_umask
+         unset CVSUMASK
          rm -r 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
@@ -24313,7 +24272,7 @@
 
          dokeep
          cd ..
-         rm -r 1
+         rm -rf 1
          # quiet down this one as it will be noisy in proxy mode
          modify_repo chmod u+rwx $CVSROOT_DIRNAME/first-dir 2>/dev/null
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir \
@@ -24324,6 +24283,7 @@
 
        stamps)
          # Test timestamps.
+         test_uses_keywords
          mkdir 1; cd 1
          dotest stamps-1 "${testcvs} -q co -l ." ''
          mkdir first-dir
@@ -24354,11 +24314,8 @@
          dotest stamps-4kw \
 "$diff_u $TESTDIR/1/stamp.kw.touch $TESTDIR/1/stamp.kw.add"
          sleep 60
-         dotest stamps-5 "${testcvs} -q ci -m add" \
-"$CVSROOT_DIRNAME/first-dir/aa,v  <--  aa
-initial revision: 1\.1
-$CVSROOT_DIRNAME/first-dir/kw,v  <--  kw
-initial revision: 1\.1"
+         dotest stamps-5 "$testcvs -Q ci -m add"
+
          # Cygwin, *cough*, puts the year in the time column until the minute
          # is no longer the current minute.  Sleep 60 seconds to avoid this
          # problem.
@@ -24397,11 +24354,7 @@
          sleep 60
          echo add a line >>aa
          echo add a line >>kw
-         dotest stamps-9 "${testcvs} -q ci -m change-them" \
-"$CVSROOT_DIRNAME/first-dir/aa,v  <--  aa
-new revision: 1\.2; previous revision: 1\.1
-$CVSROOT_DIRNAME/first-dir/kw,v  <--  kw
-new revision: 1\.2; previous revision: 1\.1"
+         dotest stamps-9 "$testcvs -Q ci -m change-them"
          
          # Cygwin, *cough*, puts the year in the time column until the minute
          # is no longer the current minute.  Sleep 60 seconds to avoid this
@@ -24436,8 +24389,9 @@
 
          dokeep
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -24747,7 +24701,7 @@
          dokeep
          restore_adm
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -24766,6 +24720,7 @@
          # I don't think any test is testing "cvs import -k".
          # Other keyword expansion tests:
          #   keywordlog - $Log.
+         test_uses_keywords
          mkdir 1; cd 1
          dotest keyword-1 "${testcvs} -q co -l ." ''
          mkdir first-dir
@@ -24794,9 +24749,7 @@
          dotest keyword-3 "${testcvs} add file1" \
 "${SPROG} add: scheduling file .file1. for addition
 ${SPROG} add: use .${SPROG} commit. to add this file permanently"
-         dotest keyword-4 "${testcvs} -q ci -m add" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-initial revision: 1\.1"
+         dotest keyword-4 "$testcvs -Q ci -m add"
          dotest keyword-5 "cat file1" \
 '\$'"Author: ${username} "'\$'"
 "'\$'"Date: [0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9] 
[0-9][0-9]:[0-9][0-9]:[0-9][0-9] "'\$'"
@@ -24926,48 +24879,36 @@
          dotest keyword-17 "${testcvs} update -A file1" "U file1"
 
          echo '$''Name$' > file1
-         dotest keyword-18 "${testcvs} ci -m modify file1" \
-"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
-new revision: 1\.2; previous revision: 1\.1"
+         dotest keyword-18 "$testcvs -Q ci -m modify file1"
          dotest keyword-19 "${testcvs} -q tag tag1" "T file1"
          echo "change" >> file1
-         dotest keyword-20 "${testcvs} -q ci -m mod2 file1" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.3; previous revision: 1\.2"
-         # FIXCVS - These unpatchable files are happening because the tag
-         # associated with the current base version of the file in the
-         # sandbox is not available in these cases.  See the note in the
-         # patch_file function in update.c.
-         dotest keyword-21 "${testcvs} -q update -r tag1" "U file1" \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+         dotest keyword-20 "$testcvs -Q ci -m mod2 file1"
+         dotest keyword-21 "$testcvs -q update -r tag1" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
 
          dotest keyword-22 "cat file1" '\$'"Name: tag1 "'\$'
 
-         if $remote; then
-           # Like serverpatch-8.  Not sure there is anything much we
-           # can or should do about this.
-           dotest keyword-23r "${testcvs} update -A file1" \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+         dotest keyword-23 "$testcvs update -A file1" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
-         else
-           dotest keyword-23 "${testcvs} update -A file1" "U file1"
-         fi
          dotest keyword-24 "cat file1" '\$'"Name:  "'\$'"
 change"
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
 
        keywordlog)
          # Test the Log keyword.
+         test_uses_keywords
          mkdir 1; cd 1
          dotest keywordlog-1 "${testcvs} -q co -l ." ''
          mkdir first-dir
@@ -24999,13 +24940,24 @@
 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
 "${SPROG} commit: sticky tag .1\.3. for file .file1. is not a branch
 ${SPROG} \[commit aborted\]: correct above errors first!"
-         dotest keywordlog-4c "${testcvs} -q update -A" "M file1"
+         if $bases; then
+           dotest keywordlog-4b-2 "cat CVS/Base/.#file1.1.3" initial
+         fi
+         dotest keywordlog-4b-3 "cat file1" \
+'initial
+xx $''Log$'
+         dotest keywordlog-4c "$testcvs -q update -A" "M file1"
+         if $bases; then
+           dotest keywordlog-4c-2 "cat CVS/Base/.#file1.1.3" initial
+         fi
+         dotest keywordlog-4c-3 "cat file1" \
+'initial
+xx $''Log$'
 
-         dotest keywordlog-5 "${testcvs} ci -F ${TESTDIR}/comment.tmp file1" \
-"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
-new revision: 1\.4; previous revision: 1\.3"
-         rm -f ${TESTDIR}/comment.tmp
-         dotest keywordlog-6 "${testcvs} -q tag -b br" "T file1"
+         dotest keywordlog-5 "$testcvs -Q ci -F $TESTDIR/comment.tmp file1"
+         rm -f $TESTDIR/comment.tmp
+
+         dotest keywordlog-6 "$testcvs -q tag -b br" "T file1"
          dotest keywordlog-7 "cat file1" \
 "initial
 xx "'\$'"Log: file1,v "'\$'"
@@ -25026,9 +24978,7 @@
          cd ../../1/first-dir
 
          echo "change" >> file1
-         dotest keywordlog-10 "${testcvs} ci -m modify file1" \
-"${CVSROOT_DIRNAME}/first-dir/file1,v  <--  file1
-new revision: 1\.5; previous revision: 1\.4"
+         dotest keywordlog-10 "$testcvs -Q ci -m modify file1"
          dotest keywordlog-11 "cat file1" \
 "initial
 xx "'\$'"Log: file1,v "'\$'"
@@ -25058,9 +25008,7 @@
          cd ../../1/first-dir
          dotest keywordlog-14 "${testcvs} -q update -r br" "U file1"
          echo br-change >>file1
-         dotest keywordlog-15 "${testcvs} -q ci -m br-modify" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.4\.2\.1; previous revision: 1\.4"
+         dotest keywordlog-15 "$testcvs -Q ci -m br-modify"
          dotest keywordlog-16 "cat file1" \
 "initial
 xx "'\$'"Log: file1,v "'\$'"
@@ -25213,6 +25161,11 @@
          dotest keywordlog-32 "$testcvs -Q ci -mset-UseArchiveCommentLeader"
 
          cd ../first-dir
+
+         # FIXCVS: It seems like an awful lot to ask that the base files
+         # determine a correct diff when the CVSROOT/config options have
+         # changed, but this needs checksum/resend.
+if false; then
          dotest keywordlog-33 "$testcvs -Q ci -fmrevision-7 file1"
          dotest keywordlog-34 "cat file1" \
 "initial
@@ -25250,12 +25203,13 @@
 xx First log line
 xx Second log line
 xx"
-
+fi
          dokeep
          cd ../..
          restore_adm
-         rm -r 1 2 3
+         rm -rf 1 2 3
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -25264,6 +25218,7 @@
          # Test the Name keyword.
          # See the keyword test for a descriptions of some other tests that
          # test keyword expansion modes.
+         test_uses_keywords
          mkdir keywordname; cd keywordname
          mkdir 1; cd 1
          dotest keywordname-init-1 "${testcvs} -q co -l ." ''
@@ -25280,11 +25235,7 @@
 ${SPROG} add: use .${SPROG} commit. to add these files permanently"
 
          # See "rmadd" for a list of other tests of cvs ci -r.
-         dotest keywordname-init-4 "${testcvs} -q ci -r 1.3 -m add" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-initial revision: 1\.3
-$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
-initial revision: 1\.3"
+         dotest keywordname-init-4 "$testcvs -Q ci -r 1.3 -m add"
 
          dotest keywordname-init-6 "${testcvs} -q up -A"
          dotest keywordname-init-7 "${testcvs} -q tag -b br" \
@@ -25292,9 +25243,7 @@
 T file2"
 
          echo new data >>file1
-         dotest keywordname-init-8 "${testcvs} -q ci -mchange" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.4; previous revision: 1\.3"
+         dotest keywordname-init-8 "$testcvs -Q ci -mchange"
 
          # First check out a branch.
          #
@@ -25306,8 +25255,8 @@
          # An update -kk or -A will unsub and sub keywords without updates
          # being required.
          # FIXCVS - see note above keyword-21
-         dotest keywordname-update-1 "${testcvs} -q up -rbr" "U file1" \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+         dotest keywordname-update-1 "$testcvs -q up -rbr" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
          dotest keywordname-update-2 "cat file1" '\$'"Name: br "'\$'
@@ -25319,8 +25268,8 @@
 "T file1
 T file2"
          # FIXCVS - see note above keyword-21
-         dotest keywordname-update-5 "${testcvs} -q up -A" "U file1" \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+         dotest keywordname-update-5 "$testcvs -q up -A" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
          dotest keywordname-update-6 "cat file1" \
@@ -25330,16 +25279,16 @@
 
          # But updating to a static tag does cause a substitution
          # FIXCVS - see same note above
-         dotest keywordname-update-8 "${testcvs} -q up -rfirsttag" "U file1" \
-"$CPROG update: checksum failure after patch to \`\./file1'; will refetch
+         dotest keywordname-update-8 "$testcvs -q up -rfirsttag" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
          dotest keywordname-update-9 "cat file1" '\$'"Name: firsttag "'\$'
          dotest keywordname-update-10 "cat file2" '\$'"Name:  "'\$'
 
          # And reverify the trunk update when the change is actually removed.
-         dotest keywordname-update-11 "${testcvs} -q up -A" "U file1" \
-"$CPROG update: checksum failure after patch to \`./file1'; will refetch
+         dotest keywordname-update-11 "$testcvs -q up -A" "U file1" \
+"$CPROG update: checksum failure after patch to \`file1'; will refetch
 $CPROG client: refetching unpatchable files
 U file1"
          dotest keywordname-update-12 "cat file1" \
@@ -25361,8 +25310,9 @@
 
          dokeep
          cd ../../..
-         rm -r keywordname
+         rm -rf keywordname
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -25377,6 +25327,7 @@
          #    test sequence
          # Note2:  We are testing positive on binary corruption here
          #    we probably really DON'T want to 'cvs update -kk' a binary 
file...
+         test_uses_keywords
          mkdir 1; cd 1
          dotest keyword2-1 "${testcvs} -q co -l ." ''
          mkdir first-dir
@@ -25410,43 +25361,29 @@
 "${SPROG} add: scheduling file .binfile\.dat. for addition
 ${SPROG} add: use .${SPROG} commit. to add this file permanently"
 
-         dotest keyword2-6 "${testcvs} -q ci -m add" \
-"$CVSROOT_DIRNAME/first-dir/binfile\.dat,v  <--  binfile\.dat
-initial revision: 1\.1
-$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-initial revision: 1\.1"
+         dotest keyword2-6 "$testcvs -Q ci -m add"
 
          dotest keyword2-7 "${testcvs} -q tag -b branch" \
 "T binfile\.dat
 T file1"
 
          sed -e 's/our/the best of and the worst of/' file1 >f; mv f file1
-         dotest keyword2-8 "${testcvs} -q ci -m change" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.2; previous revision: 1\.1"
+         dotest keyword2-8 "$testcvs -Q ci -m change"
 
          dotest keyword2-9 "${testcvs} -q update -r branch" 'U file1'
 
          echo "what else do we have?" >>file1
-         dotest keyword2-10 "${testcvs} -q ci -m change" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
-new revision: 1\.1\.2\.1; previous revision: 1\.1"
+         dotest keyword2-10 "$testcvs -Q ci -m change"
 
          # Okay, first a conflict in file1 - should be okay with binfile.dat
-         dotest keyword2-11 "${testcvs} -q update -A -j branch" \
+         dotest keyword2-11 "$testcvs -q update -A -j branch" \
 "U file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.1
-Merging differences between 1\.1 and 1\.1\.2\.1 into file1
-rcsmerge: warning: conflicts during merge"
+Merging differences between 1\.1 and 1\.1\.2\.1 into \`file1'
+$CPROG update: conflicts during merge
+C file1"
 
          dotest_fail keyword2-12 "${testcvs} diff file1" \
-"Index: file1
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.2
-diff -r1\.2 file1
+"diff -r1\.2 file1
 0a1
 > <<<<<<< file1
 1a3,5
@@ -25458,18 +25395,17 @@
 
          # Here's the problem... shouldn't -kk a binary file...
          rm file1
-         dotest keyword2-13 "${testcvs} -q update -A -kk -j branch" \
-"${SPROG} update: warning: \`file1' was lost
+         dotest keyword2-13 "$testcvs -q update -A -kk -j branch" \
+"$SPROG update: warning: \`file1' was lost
 U file1
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.1
-retrieving revision 1\.1\.2\.1
-Merging differences between 1\.1 and 1\.1\.2\.1 into file1"
+Merging differences between 1\.1 and 1\.1\.2\.1 into \`file1'
+M file1"
 
          # binfile won't get checked in, but it is now corrupt and could
          # have been checked in if it had changed on the branch...
+         # $DOTSTAR here accounts for the keyword-in-signed-file warning.
          dotest keyword2-14 "${testcvs} -q ci -m change" \
-"$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
+"$DOTSTAR$CVSROOT_DIRNAME/first-dir/file1,v  <--  file1
 new revision: 1\.3; previous revision: 1\.2"
 
          # "-kk" no longer corrupts binary files
@@ -25486,8 +25422,9 @@
 
          ${AWK} 'BEGIN { printf "address@hidden", 2, 10, 137, 13, 10 }' \
            </dev/null | ${TR} '@' '\000' >>binfile.dat
+         # $DOTSTAR here accounts for the keyword-in-signed-file warning.
          dotest keyword2-19 "$testcvs -q ci -m badbadbad" \
-"$CVSROOT_DIRNAME/first-dir/binfile\.dat,v  <--  binfile\.dat
+"$DOTSTAR$CVSROOT_DIRNAME/first-dir/binfile\.dat,v  <--  binfile\.dat
 new revision: 1\.1\.4\.1; previous revision: 1\.1"
          # "-kk" no longer affects binary files
 
@@ -25495,13 +25432,15 @@
          #       looks like a bug!
          dotest keyword2-20 "${testcvs} -q update -A -kk -j branch2" \
 "U binfile\.dat
-U binfile\.dat
+$SPROG update: Replacing \`binfile\.dat' with contents of revision 1\.1\.4\.1\.
+M binfile\.dat
 U file1"
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
+         test_uses_keywords_done
          ;;
 
 
@@ -25566,12 +25505,7 @@
          # and diff thinks so too.  Case (a) from the comment in
          # cvs.texinfo (Common options).
          dotest_fail head-trunk-diff "${testcvs} -q diff -c -r HEAD -r br1" \
-"Index: file1
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.3
-retrieving revision 1\.3\.2\.2
-diff -c -r1\.3 -r1\.3\.2\.2
+"diff -c -r1\.3 -r1\.3\.2\.2
 \*\*\* file1   ${RFCDATE}      1\.3
 --- file1      ${RFCDATE}      1\.3\.2\.2
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -25619,12 +25553,7 @@
          # Like head-brtag-diff, there is a non-branch sticky tag.
          dotest_fail head-trunktag-diff \
            "${testcvs} -q diff -c -r HEAD -r br1" \
-"Index: file1
-===================================================================
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
-retrieving revision 1\.3
-retrieving revision 1\.3\.2\.2
-diff -c -r1\.3 -r1\.3\.2\.2
+"diff -c -r1\.3 -r1\.3\.2\.2
 \*\*\* file1   ${RFCDATE}      1\.3
 --- file1      ${RFCDATE}      1\.3\.2\.2
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
@@ -25664,7 +25593,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -25741,12 +25670,7 @@
          # Test diff -r<tag>:<date> with two revisions specified.
          dotest_fail tagdate-13b \
 "$testcvs -q diff -u -rbr2:'$date_T3' -rbr2:now file1" \
-"Index: file1
-===================================================================
-RCS file: $CVSROOT_DIRNAME/first-dir/file1,v
-retrieving revision 1\.1\.4\.1
-retrieving revision 1\.1\.4\.2
-diff -u -r1\.1\.4\.1 -r1\.1\.4\.2
+"diff -u -r1\.1\.4\.1 -r1\.1\.4\.2
 --- file1      $RFCDATE        1\.1\.4\.1
 +++ file1      $RFCDATE        1\.1\.4\.2
 @@ -1 ${PLUS}1 @@
@@ -26156,7 +26080,7 @@
          TZ=$save_TZ
 
          dokeep
-         rm -r 1 2 3 4
+         rm -rf 1 2 3 4
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -26225,15 +26149,15 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
 branches:  1\.1\.2;  1\.1\.4;
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.4\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-modify-on-B
+${log_keyid}modify-on-B
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  lines: ${PLUS}1 -1;  
commitid: ${commitid};
-modify-on-A
+${log_keyid}modify-on-A
 ============================================================================="
 
          # This one is more concise.
@@ -26255,28 +26179,26 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
 branches:  1\.1\.2;  1\.1\.4;
-add
+${log_keyid}add
 ============================================================================="
 
          # OK, try very much the same thing except we run update -j to
          # bring the changes from B to A.  Probably tests many of the
          # same code paths but might as well keep it separate, I guess.
 
-         dotest multibranch2-13 "${testcvs} -q update -r B" "U file1
+         dotest multibranch2-13 "$testcvs -q update -r B" "U file1
 U file2"
-         dotest multibranch2-14 "${testcvs} -q update -r A -j B file2" \
+         dotest multibranch2-14 "$testcvs -q update -r A -j B file2" \
 "U file2
-RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
-retrieving revision 1.1
-retrieving revision 1.1.4.1
-Merging differences between 1.1 and 1.1.4.1 into file2"
+$SPROG update: Replacing \`file2' with contents of revision 1\.1\.4\.1\.
+M file2"
          dotest multibranch2-15 "${testcvs} -q ci -m commit-on-A file2" \
 "$CVSROOT_DIRNAME/first-dir/file2,v  <--  file2
 new revision: 1\.1\.2\.1; previous revision: 1\.1"
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -26350,7 +26272,7 @@
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf $CVSROOT_DIRNAME/$module
          ;;
 
@@ -26504,11 +26426,11 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: foo;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-branch
+${log_keyid}modify-on-branch
 ============================================================================="
          dotest admin-12 "${testcvs} -q admin -bbr file1" \
 "RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
@@ -26530,11 +26452,11 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: foo;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-branch
+${log_keyid}modify-on-branch
 ============================================================================="
 
          # "cvs log" doesn't print the comment leader.  RCS 5.7 will print
@@ -26567,13 +26489,13 @@
        1\.1\.2\.1;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 1\.1\.2\.1
 date   ${RCSDELTADATE};        author ${username};     state foo;
 branches;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 
 desc
 @@
@@ -26615,7 +26537,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          dotest admin-14-3 "${testcvs} -q admin -aauth3 -aauth2,foo \
@@ -26641,7 +26563,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: oneone;  commitid: 
${commitid};
-changed-log-message
+${log_keyid}changed-log-message
 ============================================================================="
 
          dotest admin-16 "${testcvs} -q admin \
@@ -26669,11 +26591,11 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: foo;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-branch
+${log_keyid}modify-on-branch
 ============================================================================="
 
          dotest_fail admin-18 "${testcvs} -q admin -nbr:1.1.2 file1" \
@@ -26700,11 +26622,11 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-add
+${log_keyid}add
 ----------------------------
 revision 1.1.2.1
 date: ${ISO8601DATE};  author: ${username};  state: foo;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-branch
+${log_keyid}modify-on-branch
 ============================================================================="
 
          # OK, this is starting to get ridiculous, in terms of
@@ -26819,7 +26741,7 @@
 ----------------------------
 revision 1\.6  locked by: ${username};
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-sixth
+${log_keyid}sixth
 ============================================================================="
          dotest_fail admin-22-o10 "${testcvs} admin -o1.5: aaa" \
 "RCS file: ${CVSROOT_DIRNAME}/first-dir/aaa,v
@@ -26848,23 +26770,30 @@
 ----------------------------
 revision 1\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-fourth
+${log_keyid}fourth
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-third
+${log_keyid}third
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-second
+${log_keyid}second
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-first
+${log_keyid}first
 ============================================================================="
 
          dotest admin-22-o14 "${testcvs} tag -b -r1.3 br1 aaa" "T aaa"
-         dotest admin-22-o15 "${testcvs} update -rbr1 aaa" "U aaa"
+         if $remote && $bases; then
+           # FIXCVS: The remote behavior is probably correct here.
+           dotest_fail admin-22-o15ar "$testcvs update -rbr1 aaa" \
+"$SPROG \[update aborted\]: could not find desired version 1\.6 in 
$CVSROOT_DIRNAME/first-dir/aaa,v"
+           rm -f aaa CVS/Base/.#aaa.1.6
+           sed /aaa/d <CVS/Entries >tmp; mv tmp CVS/Entries
+         fi
+         dotest admin-22-o15b "$testcvs update -rbr1 aaa" "U aaa"
          echo new branch rev >> aaa
          dotest admin-22-o16 "${testcvs} ci -m new-branch aaa" \
 "$CVSROOT_DIRNAME/first-dir/aaa,v  <--  aaa
@@ -26917,24 +26846,24 @@
 ----------------------------
 revision 1\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-fourth
+${log_keyid}fourth
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
 branches:  1\.3\.2;
-third
+${log_keyid}third
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-second
+${log_keyid}second
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-first
+${log_keyid}first
 ----------------------------
 revision 1\.3\.2\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}4 -0;  
commitid: ${commitid};
-branch-four
+${log_keyid}branch-four
 ============================================================================="
 
          dotest admin-22-o24 "${testcvs} -q update -p -r 1.3.2.4 aaa" \
@@ -26969,7 +26898,7 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-modify
+${log_keyid}modify
 ============================================================================="
 
          dotest admin-25 "cat ${CVSROOT_DIRNAME}/first-dir/file1,v" \
@@ -26988,13 +26917,13 @@
        1\.1\.2\.1;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 1\.1\.2\.1
 date   ${RCSDELTADATE};        author ${username};     state foo;
 branches;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 
 desc
 @@
@@ -27163,19 +27092,19 @@
 branches;
 next   1\.3;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 1\.3
 date   ${RCSDELTADATE};        author ${username};     state Exp;
 branches;
 next   1\.2;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 1\.2
 date   ${RCSDELTADATE};        author ${username};     state Exp;
 branches;
 next   ;
 commitid       ${commitid};
-
+$OPENPGP_PHRASE
 
 desc
 @@
@@ -27236,24 +27165,24 @@
 ----------------------------
 revision 1\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-fourth
+${log_keyid}fourth
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
 branches:  1\.3\.2;
-third
+${log_keyid}third
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-second
+${log_keyid}second
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-first
+${log_keyid}first
 ----------------------------
 revision 1\.3\.2\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}4 -0;  
commitid: ${commitid};
-branch-four
+${log_keyid}branch-four
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/file1,v
@@ -27274,11 +27203,11 @@
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
 branches:  1\.1\.2;
-add
+${log_keyid}add
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: foo;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-modify-on-branch
+${log_keyid}modify-on-branch
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/file2,v
@@ -27305,15 +27234,15 @@
 ----------------------------
 revision 1\.4
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-yet_another
+${log_keyid}yet_another
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-nuthr_line
+${log_keyid}nuthr_line
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-modify
+${log_keyid}modify
 =============================================================================
 
 RCS file: ${CVSROOT_DIRNAME}/first-dir/Attic/file3,v
@@ -27335,7 +27264,7 @@
 ----------------------------
 revision 1\.1\.2\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-another-log-message
+${log_keyid}another-log-message
 ============================================================================="
 
          # Currently, this test outputs 36 identical lines, so I am just
@@ -27348,7 +27277,7 @@
          # clean up our after ourselves
          restore_adm
          cd ../..
-         rm -r 1 2
+         rm -rf 1 2
          modify_repo rm -rf $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -27399,7 +27328,7 @@
 ----------------------------
 revision 1\.1  locked by: ${username};
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          # Note that this just tests the owner of the lock giving
@@ -27422,7 +27351,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-add
+${log_keyid}add
 ============================================================================="
 
          # rcslock.pl tests.  Of course, the point isn't to test
@@ -27552,7 +27481,7 @@
 $SPROG commit: Rebuilding administrative file database"
 
          dokeep
-         cd ..; rm -r CVSROOT
+         cd ..; rm -rf CVSROOT
          cd ..
          rm -r 1
          rm $TESTDIR/lockme
@@ -27645,56 +27574,37 @@
          # update, after both my modifications and your checkin:
          cd ../mine
          diffmerge_create_my_files
-         dotest diffmerge1_mine "${testcvs} -q update -j tag" \
-"M testcase01
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase01,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase01
+         dotest diffmerge1_mine "$testcvs update -j tag" \
+"$SPROG update: Updating \.
+M testcase01
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase01'
+M testcase01
+M testcase02
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase02'
 M testcase02
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase02,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase02
 M testcase03
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase03,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase03
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase03'
+M testcase03
 M testcase04
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase04,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase04
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase05,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase05
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase06,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase06
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase04'
+M testcase04
+$SPROG update: Replacing \`testcase05' with contents of revision 
1\.1\.1\.1\.2\.1\.
+M testcase05
+$SPROG update: Replacing \`testcase06' with contents of revision 
1\.1\.1\.1\.2\.1\.
+M testcase06
+M testcase07
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase07'
+\`testcase07' already contains the differences between 1\.1\.1\.1 and 
1\.1\.1\.1\.2\.1
 M testcase07
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase07,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase07
-testcase07 already contains the differences between 1\.1\.1\.1 and 
1\.1\.1\.1\.2\.1
 M testcase08
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase08,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase08
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase08'
+M testcase08
+M testcase09
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase09'
 M testcase09
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase09,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase09
 M testcase10
-RCS file: ${CVSROOT_DIRNAME}/diffmerge1/testcase10,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.1\.1\.1\.2\.1
-Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into testcase10"
+Merging differences between 1\.1\.1\.1 and 1\.1\.1\.1\.2\.1 into \`testcase10'
+M testcase10"
 
          # So if your changes didn't make it into my working copy, or
          # in any case if the files do not look like the final text
@@ -27711,7 +27621,7 @@
          # Clean up after ourselves:
          dokeep
          cd ..
-         rm -r diffmerge1
+         rm -rf diffmerge1
          modify_repo rm -rf $CVSROOT_DIRNAME/diffmerge1
          ;;
 
@@ -27722,6 +27632,7 @@
          # FIXME: This test should be rewritten to be much more concise.
          # It currently weighs in at something like 600 lines, but the
          # same thing could probably be tested in more like 50-100 lines.
+         test_uses_keywords
          mkdir diffmerge2
 
          # This tests for another diffmerge bug reported by Martin
@@ -28392,8 +28303,9 @@
            "$testcvs co diffmerge2" "${DOTSTAR}U $DOTSTAR"
          cd diffmerge2
          dotest diffmerge2_update \
-           "${testcvs} update -j Review_Phase_2_Enhancements sgrid.h" \
-           "${DOTSTAR}erging ${DOTSTAR}"
+           "$testcvs update -j Review_Phase_2_Enhancements sgrid.h" \
+           "$SPROG update: Replacing \`sgrid.h' with contents of revision 
1\.1\.2\.1\.
+M sgrid\.h"
          # This is the one that counts -- there should be no output:
          dotest diffmerge2_diff \
            "${testcvs} diff -r Review_V1p3 sgrid.h" ''
@@ -28402,6 +28314,7 @@
          cd ..
          rm -rf diffmerge2
          modify_repo rm -rf $CVSROOT_DIRNAME/diffmerge2
+         test_uses_keywords_done
          ;;
 
 
@@ -28517,17 +28430,17 @@
          dotest release-20 '$testcvs -q ci -m add' \
 "$CVSROOT_DIRNAME/first-dir/second-dir/file1,v  <--  file1
 initial revision: 1\.1"
-         dotest release-21 "$testcvs edit file1"
+         dotest release-21 "$testcvs -q edit file1"
          cd ..
          dotest release-22 "echo yes | $testcvs release -d second-dir" \
 "You have \[0\] altered files in this repository.
 Are you sure you want to release (and delete) directory \`second-dir': "
          dotest release-23 "$testcvs -q update -d" "U second-dir/file1"
-         dotest release-24 "$testcvs edit"
+         dotest release-24 "$testcvs -q edit"
 
          dokeep
          cd ../..
-         rm -r 1
+         rm -rf 1
          modify_repo rm -rf 1 $CVSROOT_DIRNAME/first-dir
          ;;
 
@@ -28657,7 +28570,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
              dotest recase-6sscs "$testcvs status FiLe" \
 "===================================================================
@@ -28684,7 +28597,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
            else # server sensitive && client insensitive
              # Client finds same Entry for file & FiLe.
@@ -28713,7 +28626,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
              dotest recase-6ss "$testcvs status FiLe" \
 "===================================================================
@@ -28740,7 +28653,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
            fi
          else # server insensitive
@@ -28772,15 +28685,15 @@
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: $username;  state: Exp;  lines: +1 -1;  
commitid: ${commitid};
-recase
+${log_keyid}recase
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: $username;  state: dead;  lines: +0 -0;  
commitid: ${commitid};
-rm
+${log_keyid}rm
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
            dotest recase-6si "$testcvs status FiLe" \
 "===================================================================
@@ -28808,15 +28721,15 @@
 ----------------------------
 revision 1\.3
 date: ${ISO8601DATE};  author: $username;  state: Exp;  lines: +1 -1;  
commitid: ${commitid};
-recase
+${log_keyid}recase
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: $username;  state: dead;  lines: +0 -0;  
commitid: ${commitid};
-rm
+${log_keyid}rm
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
          fi
 
@@ -28925,7 +28838,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-add
+${log_keyid}add
 ============================================================================="
            dotest recase-15sscs "$testcvs status FiLe" \
 "===================================================================
@@ -28952,7 +28865,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
              dotest recase-17sscs "$testcvs status FILE" \
 "===================================================================
@@ -28979,7 +28892,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
            else # $server_sensitive && !$client_sensitive
              # Client finds same Entry for file & FiLe.
@@ -29008,7 +28921,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
              dotest recase-17ssci "$testcvs status FILE" \
 "===================================================================
@@ -29035,7 +28948,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: $username;  state: Exp;  commitid: ${commitid};
-recase
+${log_keyid}recase
 ============================================================================="
            fi
          else # !$server_sensitive
@@ -29086,7 +28999,7 @@
 
          dokeep
          cd ..
-         rm -r 1 2 3
+         rm -rf 1 2 3
          if $server_sensitive && test -n "$remotehost"; then
            # It is necessary to remove one of the case-conflicted files before
            # recursively removing the rest under Cygwin on a Samba share or
@@ -29278,54 +29191,30 @@
          dotest_fail multiroot-diff-1 "${testcvs} diff" \
 "${SPROG} diff: Diffing \.
 ${SPROG} diff: Diffing mod1-1
-Index: mod1-1/file1-1
-===================================================================
-RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
-retrieving revision 1\.1
-diff -r1\.1 file1-1
+diff -r1\.1 mod1-1/file1-1
 1a2
 > bobby
 ${SPROG} diff: Diffing mod1-2
-Index: mod1-2/file1-2
-===================================================================
-RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
-retrieving revision 1\.1
-diff -r1\.1 file1-2
+diff -r1\.1 mod1-2/file1-2
 1a2
 > brown
 ${SPROG} diff: Diffing mod2-2/mod1-2
 ${SPROG} diff: Diffing mod1-2/mod2-2
 ${SPROG} diff: Diffing mod2-1
-Index: mod2-1/file2-1
-===================================================================
-RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
-retrieving revision 1\.1
-diff -r1\.1 file2-1
+diff -r1\.1 mod2-1/file2-1
 1a2
 > goes
 ${SPROG} diff: Diffing mod2-2
-Index: mod2-2/file2-2
-===================================================================
-RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
-retrieving revision 1\.1
-diff -r1\.1 file2-2
+diff -r1\.1 mod2-2/file2-2
 1a2
 > down" \
 "${SPROG} diff: Diffing \.
 ${SPROG} diff: Diffing mod1-1
-Index: mod1-1/file1-1
-===================================================================
-RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
-retrieving revision 1\.1
-diff -r1\.1 file1-1
+diff -r1\.1 mod1-1/file1-1
 1a2
 > bobby
 ${SPROG} diff: Diffing mod1-2
-Index: mod1-2/file1-2
-===================================================================
-RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
-retrieving revision 1\.1
-diff -r1\.1 file1-2
+diff -r1\.1 mod1-2/file1-2
 1a2
 > brown
 ${SPROG} diff: Diffing mod2-2
@@ -29333,19 +29222,11 @@
 ${SPROG} diff: Diffing mod1-2
 ${SPROG} diff: Diffing mod1-2/mod2-2
 ${SPROG} diff: Diffing mod2-1
-Index: mod2-1/file2-1
-===================================================================
-RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
-retrieving revision 1\.1
-diff -r1\.1 file2-1
+diff -r1\.1 mod2-1/file2-1
 1a2
 > goes
 ${SPROG} diff: Diffing mod2-2
-Index: mod2-2/file2-2
-===================================================================
-RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
-retrieving revision 1\.1
-diff -r1\.1 file2-2
+diff -r1\.1 mod2-2/file2-2
 1a2
 > down"
 
@@ -29746,7 +29627,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
@@ -29763,11 +29644,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod1-2
 
@@ -29784,7 +29665,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
@@ -29801,11 +29682,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod2-2/mod1-2
 
@@ -29822,7 +29703,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
@@ -29839,11 +29720,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod1-2/mod2-2
 
@@ -29860,7 +29741,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
@@ -29877,11 +29758,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 =============================================================================
 ${SPROG} log: Logging mod2-1
 
@@ -29898,7 +29779,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
@@ -29915,11 +29796,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 =============================================================================
 ${SPROG} log: Logging mod2-2
 
@@ -29936,7 +29817,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
@@ -29953,11 +29834,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 =============================================================================" 
\
 "${SPROG} log: Logging \.
 ${SPROG} log: Logging mod1-1
@@ -29975,7 +29856,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-1/file1-1,v
@@ -29992,11 +29873,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod1-2
 
@@ -30013,7 +29894,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
@@ -30030,11 +29911,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod2-2
 ${SPROG} log: Logging mod2-2/mod1-2
@@ -30052,7 +29933,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT1_DIRNAME}/mod1-2/file1-2,v
@@ -30069,11 +29950,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-is
+${log_keyid}is
 =============================================================================
 ${SPROG} log: Logging mod1-2
 ${SPROG} log: Logging mod1-2/mod2-2
@@ -30091,7 +29972,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
@@ -30108,11 +29989,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 =============================================================================
 ${SPROG} log: Logging mod2-1
 
@@ -30129,7 +30010,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-1/file2-1,v
@@ -30146,11 +30027,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 =============================================================================
 ${SPROG} log: Logging mod2-2
 
@@ -30167,7 +30048,7 @@
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-reading
+${log_keyid}reading
 =============================================================================
 
 RCS file: ${CVSROOT2_DIRNAME}/mod2-2/file2-2,v
@@ -30184,11 +30065,11 @@
 ----------------------------
 revision 1\.2
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  lines: ${PLUS}1 -0;  
commitid: ${commitid};
-actually
+${log_keyid}actually
 ----------------------------
 revision 1\.1
 date: ${ISO8601DATE};  author: ${username};  state: Exp;  commitid: 
${commitid};
-anyone
+${log_keyid}anyone
 ============================================================================="
 
 
@@ -30200,7 +30081,7 @@
 
          # clean up after ourselves
          cd ..
-         rm -r 1
+         rm -rf 1
 
          # clean up our repositories
          rm -rf ${CVSROOT1_DIRNAME} ${CVSROOT2_DIRNAME}
@@ -30292,6 +30173,9 @@
  *-> Write_Template (dir1, ${TESTDIR}/root1/dir1)
 ${CPROG} update: Updating dir1
  *-> Reader_Lock(${TESTDIR}/root1/dir1)
+ *-> update_fileproc (dir1/file1)
+ *-> classify_file (dir1/file1, (null), (null), (null))
+ *-> Version_TS (dir1/file1, (null), (null), (null), 1, 0)
  *-> Simple_Lock_Cleanup()
  *-> main loop with CVSROOT=${TESTDIR}/root2
  *-> parse_config ($TESTDIR/root2)
@@ -30299,10 +30183,16 @@
  *-> Write_Template (dir1/sdir, ${TESTDIR}/root2/dir1/sdir)
 ${CPROG} update: Updating dir1/sdir
  *-> Reader_Lock(${TESTDIR}/root2/sdir)
+ *-> update_fileproc (dir1/sdir/sfile)
+ *-> classify_file (dir1/sdir/sfile, (null), (null), (null))
+ *-> Version_TS (dir1/sdir/sfile, (null), (null), (null), 1, 0)
  *-> Simple_Lock_Cleanup()
  *-> Write_Template (dir1/sdir/ssdir, ${TESTDIR}/root2/sdir/ssdir)
 ${CPROG} update: Updating dir1/sdir/ssdir
  *-> Reader_Lock(${TESTDIR}/root2/sdir/ssdir)
+ *-> update_fileproc (dir1/sdir/ssdir/ssfile)
+ *-> classify_file (dir1/sdir/ssdir/ssfile, (null), (null), (null))
+ *-> Version_TS (dir1/sdir/ssdir/ssfile, (null), (null), (null), 1, 0)
  *-> Simple_Lock_Cleanup()
  *-> Lock_Cleanup()
  *-> Simple_Lock_Cleanup()" \
@@ -30346,22 +30236,12 @@
 T dir1/sdir/ssdir/ssfile"
          dotest_fail multiroot2-12 \
 "${testcvs} -q diff -u -r tag1 -r tag2" \
-"Index: dir1/file1
-===================================================================
-RCS file: ${TESTDIR}/root1/dir1/file1,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.2
-diff -u -r1\.1\.1\.1 -r1\.2
+"diff -u -r1\.1\.1\.1 -r1\.2
 --- dir1/file1 ${RFCDATE}      1\.1\.1\.1
 ${PLUS}${PLUS}${PLUS} dir1/file1       ${RFCDATE}      1\.2
 @@ -1 ${PLUS}1,2 @@
  file1
 ${PLUS}change it
-Index: dir1/sdir/sfile
-===================================================================
-RCS file: ${TESTDIR}/root2/sdir/sfile,v
-retrieving revision 1\.1\.1\.1
-retrieving revision 1\.2
 diff -u -r1\.1\.1\.1 -r1\.2
 --- dir1/sdir/sfile    ${RFCDATE}      1\.1\.1\.1
 ${PLUS}${PLUS}${PLUS} dir1/sdir/sfile  ${RFCDATE}      1\.2
@@ -30369,14 +30249,10 @@
  sfile
 ${PLUS}change him too"
 
-         if $keep; then
-           echo Keeping ${TESTDIR} and exiting due to --keep
-           exit 0
-         fi
-
          # clean up after ourselves
+         dokeep
          cd ..
-         rm -r imp-dir 1
+         rm -rf imp-dir 1
 
          # clean up our repositories
          rm -rf root1 root2
@@ -30726,7 +30602,7 @@
          # sure that CVS is using the correct one.
 
          cd ../..
-         rm -r imp-dir 1
+         rm -rf imp-dir 1
          rm -rf root1 root2
          unset CVSROOT1
          ;;
@@ -31195,7 +31071,7 @@
 
            dokeep
            cd ../..
-           rm -r 1
+           rm -rf 1
            restore_adm
            servercvs=$save_servercvs
          fi # skip the whole thing for local
@@ -31549,6 +31425,13 @@
            continue
          fi
 
+         if $gpg; then
+           # The openpgp2 tests test client responses to these old Responses.
+           skip client \
+"Tested functionality incompatible with checkout signature verification."
+           continue
+         fi
+
          if $proxy; then
            # Skip these tests in proxy mode since they assume we are not
            # writing through a proxy server.  There is no writeproxy-client
@@ -31737,7 +31620,7 @@
 EOF
          sleep 1
          dotest_fail client-11 "$testcvs update" \
-"$CPROG \[update aborted\]: patch original file \./\.bashrc does not exist"
+"$CPROG \[update aborted\]: patch original file \.bashrc does not exist"
 
          # A third try at a client exploit.  This one did used to fail like
          # client-10.
@@ -31930,7 +31813,7 @@
          dokeep
 
          rm -rf ${CVSROOT_DIRNAME}
-         rm -r dir1 module1
+         rm -rf dir1 module1
          CVSROOT_DIRNAME=${CVSROOT_DIRNAME_save}
          CVSROOT=${CVSROOT_save}
          ;;
@@ -32260,7 +32143,7 @@
          SECONDARY_CVSROOT=`newroot $SECONDARY_CVSROOT_DIRNAME`
 
          # Initialize the primary repository
-         dotest writeproxy-init-1 "$testcvs -d$PRIMARY_CVSROOT init"
+         dotest writeproxy-init-1 "$testcvs -d$PRIMARY_CVSROOT_DIRNAME init"
          mkdir writeproxy; cd writeproxy
          mkdir primary; cd primary
          dotest writeproxy-init-2 "$testcvs -Qd$PRIMARY_CVSROOT co CVSROOT"
@@ -32281,7 +32164,7 @@
          save_CVS_SERVER=$CVS_SERVER
          ln -s $PRIMARY_CVSROOT_DIRNAME $TESTDIR/primary_link
          dotest writeproxy-0 "$CVS_SERVER server" \
-"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify 
Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream 
wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log 
rlog list rlist global-list-quiet ls add remove update-patches 
gzip-file-contents status rdiff tag rtag import admin export history release 
watch-on watch-off watch-add watch-remove watchers editors edit init annotate 
rannotate noop version
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Signature Base-diff Is-modified UseUnchanged 
Unchanged Notify Hostname LocalDir Questionable Argument Argumentx 
Global_option Gzip-stream wrapper-sendme-rcsOptions Set 
${DOTSTAR}expand-modules ci co update diff log rlog list rlist 
global-list-quiet ls add remove update-patches gzip-file-contents sign status 
rdiff tag rtag import admin export history release watch-on watch-off watch-add 
watch-remove watchers editors edit init annotate rannotate noop version
 ok
 ok
 ok" \
@@ -32428,12 +32311,13 @@
 
          dokeep
          cd ../../..
-         rm -r writeproxy $TESTDIR/referrer
+         rm -rf writeproxy $TESTDIR/referrer
          rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
          PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
          PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
          SECONDARY_CVSROOT_DIRNAME=$SECONDARY_CVSROOT_DIRNAME_save
          SECONDARY_CVSROOT=$SECONDARY_CVSROOT_save
+         test_uses_keywords_done
          ;;
 
 
@@ -32468,6 +32352,8 @@
          SECONDARY_CVSROOT_DIRNAME_save=$SECONDARY_CVSROOT_DIRNAME
          SECONDARY_CVSROOT_DIRNAME=$TESTDIR/writeproxy_cvsroot
 
+         test_uses_keywords
+
          # Initialize the primary repository
          dotest writeproxy-noredirect-init-1 \
 "$testcvs -d'$PRIMARY_CVSROOT' init"
@@ -32565,7 +32451,7 @@
          mv $TESTDIR/save-root $PRIMARY_CVSROOT_DIRNAME
 
          dotest writeproxy-noredirect-5 "$CVS_SERVER server" \
-"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify 
Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream 
wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log 
rlog list rlist global-list-quiet ls add remove update-patches 
gzip-file-contents status rdiff tag rtag import admin export history release 
watch-on watch-off watch-add watch-remove watchers editors edit init annotate 
rannotate noop version
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Signature Base-diff Is-modified UseUnchanged 
Unchanged Notify Hostname LocalDir Questionable Argument Argumentx 
Global_option Gzip-stream wrapper-sendme-rcsOptions Set 
${DOTSTAR}expand-modules ci co update diff log rlog list rlist 
global-list-quiet ls add remove update-patches gzip-file-contents sign status 
rdiff tag rtag import admin export history release watch-on watch-off watch-add 
watch-remove watchers editors edit init annotate rannotate noop version
 ok
 ok
 ok
@@ -32597,7 +32483,7 @@
          cd firstdir
          echo now you see me >file1
          dotest writeproxy-noredirect-6 "$CVS_SERVER server" \
-"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify 
Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream 
wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log 
rlog list rlist global-list-quiet ls add remove update-patches 
gzip-file-contents status rdiff tag rtag import admin export history release 
watch-on watch-off watch-add watch-remove watchers editors edit init annotate 
rannotate noop version
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Signature Base-diff Is-modified UseUnchanged 
Unchanged Notify Hostname LocalDir Questionable Argument Argumentx 
Global_option Gzip-stream wrapper-sendme-rcsOptions Set 
${DOTSTAR}expand-modules ci co update diff log rlog list rlist 
global-list-quiet ls add remove update-patches gzip-file-contents sign status 
rdiff tag rtag import admin export history release watch-on watch-off watch-add 
watch-remove watchers editors edit init annotate rannotate noop version
 ok
 ok
 ok
@@ -32627,7 +32513,7 @@
          echo /file1/0/dummy+timestamp// >>CVS/Entries
 
          dotest writeproxy-noredirect-7 "$CVS_SERVER server" \
-"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Is-modified UseUnchanged Unchanged Notify 
Hostname LocalDir Questionable Argument Argumentx Global_option Gzip-stream 
wrapper-sendme-rcsOptions Set ${DOTSTAR}expand-modules ci co update diff log 
rlog list rlist global-list-quiet ls add remove update-patches 
gzip-file-contents status rdiff tag rtag import admin export history release 
watch-on watch-off watch-add watch-remove watchers editors edit init annotate 
rannotate noop version
+"Valid-requests Root Valid-responses valid-requests Command-prep Referrer 
Repository Directory Relative-directory Max-dotdot Static-directory Sticky 
Entry Kopt Checkin-time Modified Signature Base-diff Is-modified UseUnchanged 
Unchanged Notify Hostname LocalDir Questionable Argument Argumentx 
Global_option Gzip-stream wrapper-sendme-rcsOptions Set 
${DOTSTAR}expand-modules ci co update diff log rlog list rlist 
global-list-quiet ls add remove update-patches gzip-file-contents sign status 
rdiff tag rtag import admin export history release watch-on watch-off watch-add 
watch-remove watchers editors edit init annotate rannotate noop version
 ok
 ok
 Mode u=rw,g=rw,o=r
@@ -32692,7 +32578,7 @@
 
          dokeep
          cd ../../../..
-         rm -r writeproxy-noredirect
+         rm -rf writeproxy-noredirect
          rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
          rm $TESTDIR/writeproxy-secondary-wrapper \
             $TESTDIR/writeproxy-primary-wrapper
@@ -32798,7 +32684,7 @@
 
          dokeep
          cd ../../..
-         rm -r writeproxy-ssh
+         rm -rf writeproxy-ssh
          rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
          PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
          PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
@@ -32924,7 +32810,7 @@
 
          dokeep
          cd ../../..
-         rm -r writeproxy-ssh-noredirect
+         rm -rf writeproxy-ssh-noredirect
          rm -rf $PRIMARY_CVSROOT_DIRNAME $SECONDARY_CVSROOT_DIRNAME
          PRIMARY_CVSROOT_DIRNAME=$PRIMARY_CVSROOT_DIRNAME_save
          PRIMARY_CVSROOT=$PRIMARY_CVSROOT_save
@@ -32937,6 +32823,203 @@
 
 
 
+       openpgp)
+         if $gpg; then :; else
+           skip openpgp "No OpenPGP tool configured."
+           continue
+         fi
+
+         if $remote; then
+           if $bases; then :; else
+             skip openpgp "OpenPGP signatures require support for Base files."
+             continue
+           fi
+         fi
+
+         # More tests of basic/miscellaneous openpgp functionality.
+         mkdir openpgp; cd openpgp
+         mkdir top; cd top
+         dotest openpgp-init-1 "$testcvs -q co -l ."
+         mkdir openpgp
+         dotest openpgp-init-2 "$testcvs -Q add openpgp"
+
+         cd ..
+         dotest openpgp-init-3 "$testcvs -Q co CVSROOT"
+         cd CVSROOT
+         echo VerifyCommits >>config
+         dotest openpgp-init-4 \
+"$testcvs -Q ci -m'Turn on commit verification.'"
+
+         cd ..
+         dotest openpgp-init-5 "$testcvs -q co openpgp"
+         cd openpgp
+         echo some content >file1
+         dotest openpgp-init-6 "$testcvs -Q add file1"
+
+         # Make GPG noisy again.
+         save_CVS_VERIFY_TEMPLATE=$CVS_VERIFY_TEMPLATE
+         unset CVS_VERIFY_TEMPLATE
+
+         dotest openpgp-0 "$testcvs -Q ci -m newfile file1" \
+"$DOTSTAR Good signature from \"CVS Test Script $DOTSTAR"
+
+         dotest openpgp-1 "$testcvs verify file1" \
+"$DOTSTAR Good signature from \"CVS Test Script $DOTSTAR"
+         dotest openpgp-2 "$testcvs verify -p file1 >tmp"
+
+         if $remote; then
+           # CVS/Base files are not used in local mode.
+           dotest openpgp-3 "cmp tmp CVS/Base/.#file1.1.1.sig"
+         fi
+
+         dotest openpgp-4 "$testcvs sign file1" \
+"$DOTSTAR Good signature from \"CVS Test Script $DOTSTAR"
+         dotest openpgp-5 "$testcvs verify file1" \
+"$DOTSTAR Good signature from \"CVS Test Script $DOTSTAR
+$DOTSTAR Good signature from \"CVS Test Script $DOTSTAR"
+
+         dotest openpgp-6 "$testcvs sign -d0xF133BDE9 file1"
+         dotest_fail openpgp-7 "$testcvs verify file1" \
+"$SPROG verify: No signature available for \`file1'"
+
+         dokeep
+         cd ../..
+         restore_adm
+         rm -rf openpgp
+         modify_repo rm -rf $CVSROOT_DIRNAME/openpgp
+         CVS_VERIFY_TEMPLATE=$save_CVS_VERIFY_TEMPLATE
+         ;;
+
+
+
+       openpgp2)
+         # Some tests of the client (independent of the server).
+         if $remote; then :; else
+           remoteonly openpgp2
+           continue
+         fi
+
+         if $proxy; then
+           # Skip these tests in proxy mode since they assume we are not
+           # writing through a proxy server.  There is no writeproxy-openpgp
+           # test currently.  The writeproxy & writeproxy-noredirect tests
+           # test the writeproxy server.
+           notproxy openpgp2
+           continue
+         fi
+
+         save_CVS_VERIFY_TEMPLATE=$CVS_VERIFY_TEMPLATE
+         CVS_VERIFY_TEMPLATE="$DEFAULT_VERIFY_TEMPLATE"
+         export CVS_VERIFY_TEMPLATE
+
+         cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+# This is admittedly a bit cheezy, in the sense that we make lots
+# of assumptions about what the client is going to send us.
+# We don't mention Repository, because current clients don't require it.
+# Sending these at our own pace, rather than waiting for the client to
+# make the requests, is bogus, but hopefully we can get away with it.
+cat <<IEOF
+Valid-requests Root Valid-responses valid-requests Directory Entry Modified 
Unchanged Argument Argumentx ci co update
+ok
+M special message
+Created first-dir/
+$CVSROOT_DIRNAME/first-dir/file1
+/file1/1.1///
+u=rw,g=rw,o=rw
+4
+xyz
+ok
+M second special message
+IEOF
+cat >/dev/null
+EOF
+         # Cygwin.  Pthffffffffft!
+         if test -n "$remotehost"; then
+           $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme"
+         else
+           chmod +x $TESTDIR/serveme
+         fi
+         save_CVS_SERVER=$CVS_SERVER
+         CVS_SERVER=$TESTDIR/serveme; export CVS_SERVER
+         mkdir openpgp2; cd openpgp2
+         dotest_fail openpgp2-1 "$testcvs co first-dir" \
+"special message
+$CPROG \[checkout aborted\]: The server sent unsigned file content\."
+
+         cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+# This is admittedly a bit cheezy, in the sense that we make lots
+# of assumptions about what the client is going to send us.
+# We don't mention Repository, because current clients don't require it.
+# Sending these at our own pace, rather than waiting for the client to
+# make the requests, is bogus, but hopefully we can get away with it.
+cat <<IEOF
+Valid-requests Root Valid-responses valid-requests Directory Entry Modified 
Unchanged Argument Argumentx ci co update
+ok
+M special message
+Patched first-dir/
+$CVSROOT_DIRNAME/first-dir/file1
+/file1/1.1///
+u=rw,g=rw,o=rw
+4
+xyz
+ok
+M second special message
+IEOF
+cat >/dev/null
+EOF
+         # Cygwin.  Pthffffffffft!
+         if test -n "$remotehost"; then
+           $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme"
+         else
+           chmod +x $TESTDIR/serveme
+         fi
+         dotest_fail openpgp2-2 "$testcvs co first-dir" \
+"special message
+$CPROG \[checkout aborted\]: The server sent unsigned file content\."
+
+         cat >$TESTDIR/serveme <<EOF
+#!$TESTSHELL
+# This is admittedly a bit cheezy, in the sense that we make lots
+# of assumptions about what the client is going to send us.
+# We don't mention Repository, because current clients don't require it.
+# Sending these at our own pace, rather than waiting for the client to
+# make the requests, is bogus, but hopefully we can get away with it.
+cat <<IEOF
+Valid-requests Root Valid-responses valid-requests Directory Entry Modified 
Unchanged Argument Argumentx ci co update
+ok
+M special message
+Rcs-diff first-dir/
+$CVSROOT_DIRNAME/first-dir/file1
+/file1/1.1///
+u=rw,g=rw,o=rw
+4
+xyz
+ok
+M second special message
+IEOF
+cat >/dev/null
+EOF
+         # Cygwin.  Pthffffffffft!
+         if test -n "$remotehost"; then
+           $CVS_RSH $remotehost "chmod +x $TESTDIR/serveme"
+         else
+           chmod +x $TESTDIR/serveme
+         fi
+         dotest_fail openpgp2-3 "$testcvs co first-dir" \
+"special message
+$CPROG \[checkout aborted\]: The server sent unsigned file content\."
+
+         dokeep
+         cd ..
+         rm -r openpgp2
+         CVS_SERVER=$save_CVS_SERVER; export CVS_SERVER
+         CVS_VERIFY_TEMPLATE=$save_CVS_VERIFY_TEMPLATE
+         ;;
+
+
+
        trace)
          # Check that there are no core dumps lurking in the trace
          # options. 
@@ -35180,7 +35263,6 @@
 0a1
 ===================================================================
 > foo
-Index: file1
 RCS file: ${CVSROOT_DIRNAME}/trace/file1,v
 diff -r1\.1 -r1\.2
 retrieving revision 1\.1
Index: ccvs/src/server.c
diff -u ccvs/src/server.c:1.458 ccvs/src/server.c:1.459
--- ccvs/src/server.c:1.458     Thu Apr 20 19:20:45 2006
+++ ccvs/src/server.c   Mon Apr 24 18:50:27 2006
@@ -1,32 +1,50 @@
-/* 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 2, 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.  */
+/*
+ * Copyright (C) 2006 The 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 2, 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.
+ */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-/* CVS */
-#include "command_line_opt.h"
-#include "edit.h"
-#include "fileattr.h"
-#include "watch.h"
+/* Validate API.  */
+#include "server.h"
 
-/* GNULIB */
-#include "buffer.h"
+/* GNULIB headers.  */
 #include "getline.h"
 #include "getnline.h"
 #include "setenv.h"
 #include "wait.h"
 
+/* CVS headers.  */
+#include "base.h"
+#include "buffer.h"
+#include "command_line_opt.h"
+#include "edit.h"
+#include "fileattr.h"
+#include "gpg.h"
+#include "ignore.h"
+#include "repos.h"
+#include "watch.h"
+#include "wrapper.h"
+
+#include "cvs.h"
+
+
+
 int server_active = 0;
+int trace = 0;
 
 #if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
-
 # include "log-buffer.h"
 # include "ms-buffer.h"
 #endif /* defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) */
@@ -133,6 +151,7 @@
 
 /* This buffer is used to read input from the client.  */
 static struct buffer *buf_from_net;
+static struct buffer *sig_buf;
 
 
 
@@ -1869,6 +1888,81 @@
 
 
 
+/* Returns false on errors.
+ */
+static bool
+server_write_sigfile (const char *file, struct buffer *sig_buf)
+{
+    char *sigfile_name, *sig_data;
+    int fd, rc;
+    size_t got;
+    bool err = false;
+
+    /* Write the file.  */
+    sigfile_name = get_sigfile_name (file);
+    fd = CVS_OPEN (sigfile_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+    if (fd < 0)
+    {
+       int save_errno = errno;
+       if (alloc_pending (40 + strlen (sigfile_name)))
+           sprintf (pending_error_text, "E cannot open `%s'",
+                    sigfile_name);
+       pending_error = save_errno;
+       err = true;
+       goto done;
+    }
+
+    while (!buf_empty_p (sig_buf))
+    {
+       if ((rc = buf_read_data (sig_buf, buf_length (sig_buf), &sig_data,
+                                &got)))
+       {
+           /* Since !buf_empty_p confirmed that the buffer was not empty,
+            * it should be impossible to get EOF here.
+            */
+           assert (rc != -1);
+
+           if (rc == -2)
+               pending_error = ENOMEM;
+           else if (alloc_pending (80))
+               sprintf (pending_error_text,
+                        "E error reading signature buffer.");
+           pending_error = rc;
+           err = true;
+           goto done;
+       }
+
+       if (write (fd, sig_data, got) < 0)
+       {
+           int save_errno = errno;
+           if (alloc_pending (80 + strlen (sigfile_name)))
+               sprintf (pending_error_text,
+                        "E error writing temporary signature file `%s'.",
+                        sigfile_name);
+           pending_error = save_errno;
+           err = true;
+           goto done;
+        }
+    }
+
+done:
+    if (fd >= 0
+       && close (fd) < 0)
+    {
+       if (!error_pending ()
+           && alloc_pending_warning (80 + strlen (sigfile_name)))
+           sprintf (pending_warning_text,
+                    "E error closing temporary signature file `%s'.",
+                    sigfile_name);
+       err = true;
+    }
+
+    free (sigfile_name);
+    return !err;
+}
+
+
+
 static void
 serve_modified (char *arg)
 {
@@ -2043,6 +2137,46 @@
        non-kopt case alone.  */
     if (kopt != NULL)
        serve_is_modified (arg);
+
+    /* If an OpenPGP signature was sent for this file, write it to a temp
+     * file.
+     */
+    if (sig_buf)
+    {
+       bool err = !server_write_sigfile (arg, sig_buf);
+
+       /* We're done with the SIG_BUF.  */
+       buf_free (sig_buf);
+       sig_buf = NULL;
+
+       if (err) return;
+    }
+}
+
+
+
+static void
+serve_signature (char *arg)
+{
+    int status;
+
+    if (sig_buf)
+    {
+       if (alloc_pending (80))
+           sprintf (pending_error_text,
+"E Multiple Signature requests received for a single file.");
+    }
+    else
+       sig_buf = buf_nonio_initialize (NULL);
+
+    status = next_signature (buf_from_net, sig_buf);
+    if (status)
+    {
+       if (alloc_pending (80))
+           sprintf (pending_error_text,
+                    "E Malformed Signature encountered.");
+    }
+    return;
 }
 
 
@@ -2163,6 +2297,20 @@
            break;
        }
     }
+
+    /* If an OpenPGP signature was sent for this file, write it to a temp
+     * file.
+     */
+    if (sig_buf)
+    {
+       bool err = !server_write_sigfile (arg, sig_buf);
+
+       /* We're done with the SIG_BUF.  */
+       buf_free (sig_buf);
+       sig_buf = NULL;
+
+       if (err) return;
+    }
 }
 
 
@@ -3777,6 +3925,7 @@
           that CVS can't write such lines unless there is a bug.  */
 
        buf_free (protocol);
+       protocol = NULL;
 
        /* Close the pipes explicitly in order to send an EOF to the parent,
         * then wait for the parent to close the flow control pipe.  This
@@ -4678,6 +4827,14 @@
 
 
 static void
+serve_sign (char *arg)
+{
+    do_cvs_command ("sign", sign);
+}
+
+
+
+static void
 serve_status (char *arg)
 {
     do_cvs_command ("status", cvsstatus);
@@ -4995,6 +5152,164 @@
 
 
 
+void
+server_send_checksum (const unsigned char *checksum)
+{
+    static int checksum_supported = -1;
+
+    if (checksum_supported < 0)
+       checksum_supported = supported_response ("Checksum");
+
+    if (checksum_supported)
+    {
+       int i;
+       char buf[3];
+
+       buf_output0 (protocol, "Checksum ");
+       for (i = 0; i < 16; i++)
+       {
+           sprintf (buf, "%02x", (unsigned int) checksum[i]);
+           buf_output0 (protocol, buf);
+       }
+       buf_append_char (protocol, '\n');
+    }
+}
+
+
+
+static inline void
+output_mode_string (mode_t mode)
+{
+    char *mode_string;
+
+    mode_string = mode_to_string (mode);
+    buf_output0 (protocol, mode_string);
+    buf_output0 (protocol, "\n");
+    free (mode_string);
+}
+
+
+
+static void
+server_send_buffer_as_file (struct buffer *in, mode_t mode)
+{
+    unsigned long size;
+    char *buf;
+
+    if (mode == (mode_t) -1)
+       error (1, 0,
+"CVS server internal error: no mode in server_send_data_as_file");
+
+    output_mode_string (mode);
+
+    size = buf_length (in);
+
+    buf = Xasprintf ("%lu\n", size);
+    buf_output0 (protocol, buf);
+    free (buf);
+
+    buf_append_buffer (protocol, in);
+}
+
+
+
+static void
+server_send_file (const char *file, const char *fullname, mode_t mode)
+{
+    struct stat sb;
+    unsigned long size;
+    char *buf;
+    FILE *f;
+
+    /* The contents of the file will be in one of filebuf or list/last.  */
+    struct buffer_data *list, *last;
+    unsigned char *contents;
+
+    if (stat (file, &sb) < 0)
+       error (1, errno, "reading %s", fullname);
+
+    if (mode == (mode_t) -1)
+       /* FIXME: When we check out files the umask of the
+          server (set in .bashrc if rsh is in use) affects
+          what mode we send, and it shouldn't.  */
+       mode = sb.st_mode;
+
+    output_mode_string (mode);
+
+    size = sb.st_size;
+    contents = NULL;
+
+    /* Throughout this section we use binary mode to read the
+       file we are sending.  The client handles any line ending
+       translation if necessary.  */
+
+    if (file_gzip_level
+       /*
+        * For really tiny files, the gzip process startup
+        * time will outweigh the compression savings.  This
+        * might be computable somehow; using 100 here is just
+        * a first approximation.
+        */
+       && size > 100)
+    {
+       /* Basing this routine on read_and_gzip is not a
+          high-performance approach.  But it seems easier
+          to code than the alternative (and less
+          vulnerable to subtle bugs).  Given that this feature
+          is mainly for compatibility, that is the better
+          tradeoff.  */
+
+       int fd;
+       size_t file_allocated = 0;
+       size_t file_used = 0;
+
+       fd = CVS_OPEN (file, O_RDONLY | OPEN_BINARY, 0);
+       if (fd < 0)
+           error (1, errno, "reading %s", fullname);
+       if (read_and_gzip (fd, fullname, &contents,
+                          &file_allocated, &file_used,
+                          file_gzip_level))
+           error (1, 0, "aborting due to compression error");
+       size = file_used;
+       if (close (fd) < 0)
+           error (1, errno, "reading %s", fullname);
+       /* Prepending length with "z" is flag for using gzip here.  */
+       buf_output0 (protocol, "z");
+    }
+    else if (size > 0)
+    {
+       long status;
+
+       f = CVS_FOPEN (file, "rb");
+       if (f == NULL)
+           error (1, errno, "reading %s", fullname);
+       status = buf_read_file (f, size, &list, &last);
+       if (status == -2)
+           (*protocol->memory_error) (protocol);
+       else if (status != 0)
+           error (1, ferror (f) ? errno : 0, "reading %s", fullname);
+       if (fclose (f) == EOF)
+           error (1, errno, "reading %s", fullname);
+    }
+    else
+       contents = (unsigned char *) xstrdup ("");
+
+    buf = Xasprintf ("%lu\n", size);
+    buf_output0 (protocol, buf);
+    free (buf);
+
+    if (contents)
+    {
+       buf_output (protocol, (char *) contents, size);
+       free (contents);
+    }
+    else
+       buf_append_data (protocol, list, last);
+    /* Note we only send a newline here if the file ended with one.  */
+}
+
+
+
 /* See server.h for description.  */
 void
 server_updated (
@@ -5005,6 +5320,15 @@
     unsigned char *checksum,
     struct buffer *filebuf)
 {
+    /* The case counter to the assertion below should be easy to handle but it
+     * never has been, to my knowledge, so there appears to be no need.
+     */
+    assert (!(filebuf && file_gzip_level));
+
+    TRACE (TRACE_FUNCTION, "server_updated (%s, %s, %s, %d)",
+          finfo->fullname, vers ? vers->vn_rcs : "(null)",
+          vers ? vers->options : "(null)", updated);
+
     if (noexec)
     {
        /* Hmm, maybe if we did the same thing for entries_file, we
@@ -5022,76 +5346,39 @@
 
     if (entries_line != NULL && scratched_file == NULL)
     {
-       FILE *f;
-       struct buffer_data *list, *last;
-       unsigned long size;
-       char size_text[80];
-
-       /* The contents of the file will be in one of filebuf,
-          list/last, or here.  */
-       unsigned char *file;
-       size_t file_allocated;
-       size_t file_used;
-
-       if (filebuf != NULL)
-       {
-           size = buf_length (filebuf);
-           if (mode == (mode_t) -1)
-               error (1, 0, "\
-CVS server internal error: no mode in server_updated");
-       }
-       else
+       if (!filebuf && !isfile (finfo->file))
        {
-           struct stat sb;
-
-           if (stat (finfo->file, &sb) < 0)
-           {
-               if (existence_error (errno))
-               {
-                   /* If we have a sticky tag for a branch on which
-                      the file is dead, and cvs update the directory,
-                      it gets a T_CHECKOUT but no file.  So in this
-                      case just forget the whole thing.  */
-                   free (entries_line);
-                   entries_line = NULL;
-                   goto done;
-               }
-               error (1, errno, "reading %s", finfo->fullname);
-           }
-           size = sb.st_size;
-           if (mode == (mode_t) -1)
-           {
-               /* FIXME: When we check out files the umask of the
-                  server (set in .bashrc if rsh is in use) affects
-                  what mode we send, and it shouldn't.  */
-               mode = sb.st_mode;
-           }
+           /* If we have a sticky tag for a branch on which
+              the file is dead, and cvs update the directory,
+              it gets a T_CHECKOUT but no file.  So in this
+              case just forget the whole thing.  */
+           free (entries_line);
+           entries_line = NULL;
+           return;
        }
 
-       if (checksum != NULL)
+       if (strcmp (cvs_cmd_name, "export")
+           && supported_response ("Base-entry"))
        {
-           static int checksum_supported = -1;
-
-           if (checksum_supported == -1)
-           {
-               checksum_supported = supported_response ("Checksum");
-           }
-
-           if (checksum_supported)
-           {
-               int i;
-               char buf[3];
-
-               buf_output0 (protocol, "Checksum ");
-               for (i = 0; i < 16; i++)
-               {
-                   sprintf (buf, "%02x", (unsigned int) checksum[i]);
-                   buf_output0 (protocol, buf);
-               }
-               buf_append_char (protocol, '\n');
-           }
+           /* The client was already asked to create the base file and copy
+            * it into a temp file.  This will complete the process and print
+            * the "U file" line.
+            */
+           if (updated == SERVER_MERGED)
+               buf_output0 (protocol, "Base-merged ");
+           else
+               buf_output0 (protocol, "Base-entry ");
+           output_dir (finfo->update_dir, finfo->repository);
+           buf_output0 (protocol, finfo->file);
+           buf_output (protocol, "\n", 1);
+           new_entries_line ();
+           buf_send_counted (protocol);
+           return;
        }
 
+       if (checksum)
+           server_send_checksum (checksum);
+
        if (updated == SERVER_UPDATED)
        {
            Node *node;
@@ -5131,98 +5418,10 @@
 
        new_entries_line ();
 
-       {
-           char *mode_string;
-
-           mode_string = mode_to_string (mode);
-           buf_output0 (protocol, mode_string);
-           buf_output0 (protocol, "\n");
-           free (mode_string);
-       }
-
-       list = last = NULL;
-
-       file = NULL;
-       file_allocated = 0;
-       file_used = 0;
-
-       if (size > 0)
-       {
-           /* Throughout this section we use binary mode to read the
-              file we are sending.  The client handles any line ending
-              translation if necessary.  */
-
-           if (file_gzip_level
-               /*
-                * For really tiny files, the gzip process startup
-                * time will outweigh the compression savings.  This
-                * might be computable somehow; using 100 here is just
-                * a first approximation.
-                */
-               && size > 100)
-           {
-               /* Basing this routine on read_and_gzip is not a
-                  high-performance approach.  But it seems easier
-                  to code than the alternative (and less
-                  vulnerable to subtle bugs).  Given that this feature
-                  is mainly for compatibility, that is the better
-                  tradeoff.  */
-
-               int fd;
-
-               /* Callers must avoid passing us a buffer if
-                  file_gzip_level is set.  We could handle this case,
-                  but it's not worth it since this case never arises
-                  with a current client and server.  */
-               if (filebuf != NULL)
-                   error (1, 0, "\
-CVS server internal error: unhandled case in server_updated");
-
-               fd = CVS_OPEN (finfo->file, O_RDONLY | OPEN_BINARY, 0);
-               if (fd < 0)
-                   error (1, errno, "reading %s", finfo->fullname);
-               if (read_and_gzip (fd, finfo->fullname, &file,
-                                  &file_allocated, &file_used,
-                                  file_gzip_level))
-                   error (1, 0, "aborting due to compression error");
-               size = file_used;
-               if (close (fd) < 0)
-                   error (1, errno, "reading %s", finfo->fullname);
-               /* Prepending length with "z" is flag for using gzip here.  */
-               buf_output0 (protocol, "z");
-           }
-           else if (filebuf == NULL)
-           {
-               long status;
-
-               f = CVS_FOPEN (finfo->file, "rb");
-               if (f == NULL)
-                   error (1, errno, "reading %s", finfo->fullname);
-               status = buf_read_file (f, size, &list, &last);
-               if (status == -2)
-                   (*protocol->memory_error) (protocol);
-               else if (status != 0)
-                   error (1, ferror (f) ? errno : 0, "reading %s",
-                          finfo->fullname);
-               if (fclose (f) == EOF)
-                   error (1, errno, "reading %s", finfo->fullname);
-           }
-       }
-
-       sprintf (size_text, "%lu\n", size);
-       buf_output0 (protocol, size_text);
-
-       if (file != NULL)
-       {
-           buf_output (protocol, (char *) file, file_used);
-           free (file);
-           file = NULL;
-       }
-       else if (filebuf == NULL)
-           buf_append_data (protocol, list, last);
+       if (filebuf)
+           server_send_buffer_as_file (filebuf, mode);
        else
-           buf_append_buffer (protocol, filebuf);
-       /* Note we only send a newline here if the file ended with one.  */
+           server_send_file (finfo->file, finfo->fullname, mode);
 
        /*
         * Avoid using up too much disk space for temporary files.
@@ -5291,7 +5490,15 @@
        error (1, 0,
               "CVS server internal error: Register *and* Scratch_Entry.\n");
     buf_send_counted (protocol);
-  done:;
+}
+
+
+
+/* Return whether we should send operations on base files.  */
+bool
+server_use_bases (void)
+{
+    return supported_response ("Base-checkout");
 }
 
 
@@ -5612,7 +5819,7 @@
     {
        buf_output0 (buf_to_net, "Wrapper-rcsOption ");
        buf_output0 (buf_to_net, wrapper_line);
-       buf_output0 (buf_to_net, "\012");;
+       buf_output0 (buf_to_net, "\012");
        free (wrapper_line);
     }
 
@@ -5925,6 +6132,8 @@
   REQ_LINE("Kopt", serve_kopt, 0),
   REQ_LINE("Checkin-time", serve_checkin_time, 0),
   REQ_LINE("Modified", serve_modified, RQ_ESSENTIAL),
+  REQ_LINE("Signature", serve_signature, 0),
+  REQ_LINE("Base-diff", serve_noop, 0),
   REQ_LINE("Is-modified", serve_is_modified, 0),
 
   /* The client must send this request to interoperate with CVS 1.5
@@ -5982,6 +6191,7 @@
   REQ_LINE("remove", serve_remove, 0),
   REQ_LINE("update-patches", serve_ignore, 0),
   REQ_LINE("gzip-file-contents", serve_gzip_contents, RQ_ROOTLESS),
+  REQ_LINE("sign", serve_sign, 0),
   REQ_LINE("status", serve_status, 0),
   REQ_LINE("rdiff", serve_rdiff, 0),
   REQ_LINE("tag", serve_tag, 0),
@@ -6289,12 +6499,12 @@
             * than getting lost.
             */
            struct buffer *buf_to_net_save = buf_to_net;
+           error_use_protocol = 0;
            buf_to_net = NULL;
 
            (void) buf_flush (buf_to_net_save, 1);
            (void) buf_shutdown (buf_to_net_save);
            buf_free (buf_to_net_save);
-           error_use_protocol = 0;
        }
        /* SIG_endCrSect(); */
     }
@@ -8039,6 +8249,324 @@
 
 
 
+static void
+server_send_signatures (struct file_info *finfo, const char *rev)
+{
+    char *sig;
+    size_t len;
+    int status;
+    struct buffer *inbuf, *outbuf;
+
+    if (!supported_response ("OpenPGP-signature"))
+       return;
+
+    if (!RCS_get_openpgp_signatures (finfo, rev, &sig, &len))
+       error (1, 0,
+              "Corrupt signature in r%s of `%s' (base64 decode failed).",
+              rev, finfo->fullname);
+
+    if (!sig)
+       /* No signature data available.  */
+       return;
+
+    /* Copy the sig into an input buffer.  */
+    inbuf = buf_nonio_initialize (NULL);
+    buf_output (inbuf, sig, len);
+    free (sig);
+
+    /* Create an output buffer.  */
+    outbuf = buf_nonio_initialize (NULL);
+
+    /* Read each signature, copying them to the net.  */
+    do
+    {
+       status = next_signature (inbuf, outbuf);
+       if (!status)
+       {
+           buf_output0 (protocol, "OpenPGP-signature\n");
+           buf_append_buffer (protocol, outbuf);
+       } else if (status == -2)
+           xalloc_die ();
+       /* else status == EOF */
+    } while (!status);
+
+    buf_send_counted (protocol);
+}
+
+
+
+/* Try to tell the client about checking out a base REV of FILE, sending the
+ * diff against PREV when possible.  If the client doesn't understand this
+ * response, just ignore it and later code will also avoid the Base-*
+ * responses.
+ *
+ * NOTES
+ *   Processes PREV == NULL, PREV == REV, and PREV == "0", for convenience.
+ */
+static void
+iserver_base_checkout (RCSNode *rcs, struct file_info *finfo, const char *prev,
+                      const char *rev, const char *ptag, const char *tag,
+                      const char *poptions, const char *options,
+                      const char *basefile, const char *fullbase, bool istemp)
+{
+    char *tmpfile = NULL;
+    bool senddiff;
+
+    assert (rev);
+
+    TRACE (TRACE_FUNCTION,
+          "iserver_base_checkout (%s, %s, %s, %s, %s, %s, %s, %s)",
+          finfo->fullname, prev, rev, ptag, tag, poptions, options,
+          istemp ? "true" : "false");
+
+    if (!supported_response (istemp ? "Temp-checkout" : "Base-checkout"))
+       return;
+
+    if (/* Not sending a temp file...  */
+       !istemp
+       /* ...and entry rev and new rev are the same...  */
+       && prev && !strcmp (prev, rev)
+       /* ...and... */
+       && (   /* ...both option specs are empty...  */
+           (  (!poptions || !poptions[0]) && (!options || !options[0]))
+              /* ...or the option specs match...  */
+           || (poptions && options && !strcmp (poptions, options)))
+       /* ...and... */
+       && (   /* ...both tag specs are empty...  */
+           (  (!ptag || !ptag[0]) && (!tag || !tag[0]))
+              /* ...or the tag specs match.  */
+           || (ptag && tag && !strcmp (ptag, tag)))
+       )
+       /* PREV & REV are the same, so the client should already have this
+        * base file.
+        */
+       return;
+
+    server_send_signatures (finfo, rev);
+
+    /* FIXME: It would be more efficient if diffs could be sent when the
+     * revision numbers haven't changed but the keywords have.
+     */
+    if (prev && strcmp (prev, "0") && strcmp (prev, rev))
+    {
+       /* Compute and send diff.  */
+       int dargc = 0;
+       size_t darg_allocated = 0;
+       char **dargv = NULL;
+       int status;
+       char *pbasefile;
+       bool save_noexec = noexec;
+
+       pbasefile = cvs_temp_name ();
+       noexec = false;
+       status = RCS_checkout (rcs, pbasefile, prev, ptag, poptions,
+                              NULL, NULL, NULL);
+       noexec = save_noexec;
+
+       if (status)
+           error (1, 0, "Failed to checkout revision %s of `%s'",
+                  prev, finfo->file);
+
+       run_add_arg_p (&dargc, &darg_allocated, &dargv, "-n");
+       tmpfile = cvs_temp_name ();
+       status = diff_exec (pbasefile, basefile, NULL, NULL, dargc, dargv,
+                           tmpfile);
+       run_arg_free_p (dargc, dargv);
+       free (dargv);
+       if (CVS_UNLINK (pbasefile) < 0)
+           error (0, errno, "cannot remove `%s'", pbasefile);
+       free (pbasefile);
+
+       /* A STATUS of 0 means no differences.  1 means some differences.  */
+       if (status != 0 && status != 1)
+           senddiff = false;
+       else
+           senddiff = true;
+    }
+    else senddiff = false;
+
+    if (senddiff)
+    {
+       struct stat bfi, dfi;
+
+       /* Check to make sure the patch is really shorter */
+       if (stat (basefile, &bfi) < 0)
+           error (1, errno, "could not stat `%s'", basefile);
+       if (stat (tmpfile, &dfi) < 0)
+           error (1, errno, "could not stat `%s'", tmpfile);
+       if (bfi.st_size <= dfi.st_size)
+           senddiff = false;
+    }
+
+    buf_output0 (protocol, istemp ? "Temp-checkout " : "Base-checkout ");
+    output_dir (finfo->update_dir, finfo->repository);
+    buf_output0 (protocol, finfo->file);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, options);
+    buf_output (protocol, "\n", 1);
+
+    /* If we are not sending a diff, don't send PREV, or the client will expect
+     * one.
+     */
+    buf_output0 (protocol, prev && senddiff ? prev : "");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev);
+    buf_output (protocol, "\n", 1);
+
+    if (senddiff)
+       server_send_file (tmpfile, fullbase, -1);
+    else
+       /* The client does not have a previous base revision, so send the whole
+        * file.
+        */
+       server_send_file (basefile, fullbase, -1);
+
+    buf_send_counted (protocol);
+
+    if (tmpfile)
+    {
+       if (CVS_UNLINK (tmpfile) < 0)
+           error (0, errno, "cannot remove `%s'", tmpfile);
+       free (tmpfile);
+    }
+}
+
+
+
+void
+server_base_checkout (RCSNode *rcs, struct file_info *finfo, const char *prev,
+                     const char *rev, const char *ptag, const char *tag,
+                     const char *poptions, const char *options)
+{
+    char *basefile;
+    char *fullbase;
+
+    basefile = make_base_file_name (finfo->file, rev);
+    fullbase = Xasprintf ("%s/%s",
+                         *(finfo->update_dir) ? finfo->update_dir : ".",
+                         basefile);
+
+    iserver_base_checkout (rcs, finfo, prev, rev, ptag, tag, poptions, options,
+                          basefile, fullbase, false);
+
+    free (fullbase);
+    free (basefile);
+}
+
+
+
+void
+server_temp_checkout (RCSNode *rcs, struct file_info *finfo, const char *prev,
+                     const char *rev, const char *ptag, const char *tag,
+                     const char *poptions, const char *options,
+                     const char *tempfile)
+{
+    iserver_base_checkout (rcs, finfo, prev, rev, ptag, tag, poptions, options,
+                          tempfile, tempfile, true);
+}
+
+
+
+void
+server_base_copy (struct file_info *finfo, const char *rev, const char *flags)
+{
+    if (!supported_response ("Base-copy")) return;
+
+    buf_output0 (protocol, "Base-copy ");
+    output_dir (finfo->update_dir, finfo->repository);
+    buf_output0 (protocol, finfo->file);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, flags);
+    buf_output (protocol, "\n", 1);
+    buf_send_counted (protocol);
+}
+
+
+
+/* Assume CVS/Base/.#FILE.REV1 & CVS/Base/FILE.REV2 exist.  If the client
+ * supports it, ask it to perform a merge using these files.  If not, perform
+ * the merge ourselves.
+ */
+void
+server_base_merge (struct file_info *finfo, const char *rev1, const char *rev2)
+{
+    if (!supported_response ("Base-merge")) return;
+
+    buf_output0 (protocol, "Base-merge ");
+    output_dir (finfo->update_dir, finfo->repository);
+    buf_output0 (protocol, finfo->file);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev1);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev2);
+    buf_output (protocol, "\n", 1);
+    buf_send_counted (protocol);
+    return;
+}
+
+
+
+void
+server_base_signatures (struct file_info *finfo, const char *rev)
+{
+    if (!supported_response ("Base-signatures")
+       || !supported_response ("Base-clear-signatures"))
+       return;
+
+    if (RCS_has_openpgp_signatures (finfo, rev))
+    {
+       server_send_signatures (finfo, rev);
+       buf_output0 (protocol, "Base-signatures ");
+    }
+    else
+       buf_output0 (protocol, "Base-clear-signatures ");
+
+    output_dir (finfo->update_dir, finfo->repository);
+    buf_output0 (protocol, finfo->file);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev);
+    buf_output (protocol, "\n", 1);
+    buf_send_counted (protocol);
+    return;
+}
+
+
+
+void
+server_base_diff (struct file_info *finfo, const char *f1, const char *rev1,
+                 const char *label1, const char *f2, const char *rev2,
+                 const char *label2)
+{
+    if (!supported_response ("Base-diff"))
+       return;
+
+    buf_output0 (protocol, "Base-diff ");
+    output_dir (finfo->update_dir, finfo->repository);
+    buf_output0 (protocol, finfo->file);
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, strcmp (f1, DEVNULL) ? "TEMP" : "DEVNULL");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev1 ? rev1 : "");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, label1 ? label1 : "");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, strcmp (f2, DEVNULL)
+                          ? (rev2 ? "TEMP" : "WORKFILE")
+                          : "DEVNULL");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, rev2 ? rev2 : "");
+    buf_output (protocol, "\n", 1);
+    buf_output0 (protocol, label2 ? label2 : "");
+    buf_output (protocol, "\n", 1);
+    buf_send_counted (protocol);
+
+    return;
+}
+
+
+
 /*
  * void cvs_trace(int level, const char *fmt, ...)
  *
@@ -8051,15 +8579,20 @@
     if (trace >= level)
     {
        va_list va;
+       char *buf;
+       int size;
 
        va_start (va, fmt);
 #ifdef SERVER_SUPPORT
-       fprintf (stderr,"%c -> ",server_active?(isProxyServer()?'P':'S'):' ');
-#else /* ! SERVER_SUPPORT */
-       fprintf (stderr,"  -> ");
+       cvs_outerr (server_active ? (isProxyServer() ? "P" : "S") : " ", 1);
+#else
+       cvs_outerr (" ", 1);
 #endif
-       vfprintf (stderr, fmt, va);
-       fprintf (stderr,"\n");
+       cvs_outerr (" -> ", 4);
+       if ((size = vasprintf (&buf, fmt, va)) < 0)
+           abort ();
+       cvs_outerr (buf, size);
+       cvs_outerr ("\n", 1);
        va_end (va);
     }
 }
Index: ccvs/src/server.h
diff -u ccvs/src/server.h:1.45 ccvs/src/server.h:1.46
--- ccvs/src/server.h:1.45      Thu Apr 13 14:31:10 2006
+++ ccvs/src/server.h   Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -12,6 +12,13 @@
  * This file contains the interface between the server and the rest of CVS.
  */
 
+#ifndef SERVER_H
+#define SERVER_H
+
+/* CVS Headers.  */
+#include "root.h"
+#include "vers_ts.h"
+
 /* Miscellaneous stuff which isn't actually particularly server-specific.  */
 #ifndef STDIN_FILENO
 #define STDIN_FILENO 0
@@ -120,6 +127,7 @@
                      enum server_updated_arg4 updated, mode_t mode,
                      unsigned char *checksum, struct buffer *filebuf);
 
+bool server_use_bases (void);
 /* Whether we should send RCS format patches.  */
 int server_use_rcs_diff (void);
 
@@ -198,12 +206,16 @@
 extern struct request requests[];
 
 /* Gzip library, see zlib.c.  */
+int gunzip_in_mem (const char *, unsigned char *, size_t *, char **);
 int gunzip_and_write (int, const char *, unsigned char *, size_t);
 int read_and_gzip (int, const char *, unsigned char **, size_t *, size_t *,
                    int);
 void server_edit_file (struct file_info *finfo);
 
+
+
 /* The TRACE macro */
+extern int trace;              /* User defined trace level.  */
 void cvs_trace (int level, const char *fmt, ...)
   __attribute__ ((__format__ (__printf__, 2, 3)));
 #define TRACE cvs_trace
@@ -221,4 +233,34 @@
 #define TRACE_FLOW             2
 #define TRACE_DATA             3
 
+
+
 extern cvsroot_t *referrer;
+
+void server_base_checkout (RCSNode *rcs, struct file_info *finfo,
+                          const char *prev, const char *rev, const char *ptag,
+                          const char *tag, const char *poptions,
+                          const char *options);
+void server_temp_checkout (RCSNode *rcs, struct file_info *finfo,
+                          const char *prev, const char *rev, const char *ptag,
+                          const char *tag, const char *poptions,
+                          const char *options, const char *tempfile);
+
+void server_base_copy (struct file_info *file, const char *rev,
+                      const char *flags);
+void server_base_merge (struct file_info *finfo, const char *rev1,
+                       const char *rev2);
+void server_base_signatures (struct file_info *finfo, const char *rev);
+void server_base_diff (struct file_info *finfo, const char *f1,
+                      const char *rev1, const char *label1, const char *f2,
+                      const char *rev2, const char *label2);
+bool server_use_bases (void);
+
+void cvs_output (const char *, size_t);
+void cvs_output_binary (char *, size_t);
+void cvs_outerr (const char *, size_t);
+void cvs_flusherr (void);
+void cvs_flushout (void);
+void cvs_output_tagged (const char *, const char *);
+
+#endif /* !defined SERVER_H */
Index: ccvs/src/status.c
diff -u ccvs/src/status.c:1.68 ccvs/src/status.c:1.69
--- ccvs/src/status.c:1.68      Fri Sep 23 03:19:24 2005
+++ ccvs/src/status.c   Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -13,8 +13,20 @@
  * Status Information
  */
 
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* CVS headers.  */
+#include "classify.h"
+#include "ignore.h"
+#include "recurse.h"
+#include "wrapper.h"
+
 #include "cvs.h"
 
+
+
 static Dtype status_dirproc (void *callerdat, const char *dir,
                              const char *repos, const char *update_dir,
                              List *entries);
Index: ccvs/src/subr.c
diff -u ccvs/src/subr.c:1.148 ccvs/src/subr.c:1.149
--- ccvs/src/subr.c:1.148       Thu Sep 29 04:33:38 2005
+++ ccvs/src/subr.c     Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -13,14 +13,25 @@
  * Various useful functions for the CVS support code.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "subr.h"
 
+/* GNULIB headers.  */
 #include "canonicalize.h"
 #include "canon-host.h"
 #include "getline.h"
 #include "vasprintf.h"
 #include "vasnprintf.h"
 
+/* CVS headers.  */
+#include "wrapper.h"
+
+#include "cvs.h"
+
 /* Get wint_t.  */
 #ifdef HAVE_WINT_T
 # include <wchar.h>
@@ -609,6 +620,31 @@
 
 
 
+bool
+file_contains_keyword (const struct file_info *finfo)
+{
+    FILE *fp;
+    bool result;
+    struct stat st;
+    char *content;
+
+    fp = CVS_FOPEN (finfo->file, "r");
+    if (fp == NULL)
+       error (1, errno, "cannot open %s", finfo->fullname);
+    if (fstat (fileno (fp), &st))
+       error (1, errno, "cannot fstat `%s'", finfo->fullname);
+    content = xmalloc (st.st_size);
+    if (fread (content, sizeof *content, st.st_size, fp) < st.st_size)
+       error (1, errno, "Failed to read from `%s'", finfo->fullname);
+    result = contains_keyword (content, st.st_size);
+    if (fclose (fp) < 0)
+       error (0, errno, "cannot close %s", finfo->fullname);
+    free (content);
+    return result;
+}
+
+
+
 /* Read the entire contents of the file NAME into *BUF.
    If NAME is NULL, read from stdin.  *BUF
    is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
@@ -699,6 +735,44 @@
 
 
 
+/* Write DATA of length LEN to FILE, ignoring NOEXEC.  */
+void
+force_write_file (const char *file, const char *data, size_t len)
+{
+    FILE *fp;
+
+    TRACE (TRACE_FUNCTION,
+          "force_write_file (%s, %s, %u)", file, data, (unsigned int)len);
+
+    if (!(fp = fopen (file, "wb")))
+       error (1, errno, "cannot create `%s'", file);
+
+    if (len > 0)
+    {
+       if (fwrite (data, sizeof *data, len, fp) != len)
+           error (1, errno, "cannot write file `%s'", file);
+    }
+
+    if (fclose (fp) < 0)
+       error (1, errno, "cannot close `%s'", file);
+}
+
+
+
+/* Write DATA of length LEN to FILE, honoring NOEXEC.  */
+void
+write_file (const char *file, const char *data, size_t len)
+{
+    TRACE (TRACE_FUNCTION,
+          "write_file (%s, %s, %u)", file, data, (unsigned int)len);
+
+    if (noexec) return;
+
+    force_write_file (file, data, len);
+}
+
+
+
 /* Follow a chain of symbolic links to its destination.  FILENAME
    should be a handle to a malloc'd block of memory which contains the
    beginning of the chain.  This routine will replace the contents of
@@ -1689,15 +1763,23 @@
 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
                            /* the *only* case possible without
                             * SUPPORT_OLD_INFO_FORMAT_STRINGS
-                            * - !onearg */
-                           if (!inquotes)
+                            * - !onearg
+                            */
+                           /* Avoid adding an empty argument for NULL data.
+                            */
+                           if (!inquotes && b->data)
                            {
                                doff = d - buf;
                                expand_string (&buf, &length, doff + 1);
                                d = buf + doff;
                                *d++ = '"';
                            }
-                           outstr = cmdlineescape (inquotes ? inquotes : '"', 
b->data);
+                           if (b->data)
+                               outstr = cmdlineescape (inquotes ? inquotes
+                                                                : '"',
+                                                       b->data);
+                           else
+                               outstr = xstrdup ("");
 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
                        } /* onearg */
 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
@@ -1711,7 +1793,7 @@
                        {
                            free(outstr);
 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
-                           if (!inquotes)
+                           if (!inquotes && b->data)
                            {
                                doff = d - buf;
                                expand_string (&buf, &length, doff + 1);
Index: ccvs/src/subr.h
diff -u ccvs/src/subr.h:1.7 ccvs/src/subr.h:1.8
--- ccvs/src/subr.h:1.7 Fri Sep 23 03:19:24 2005
+++ ccvs/src/subr.h     Mon Apr 24 18:50:27 2006
@@ -18,6 +18,21 @@
 #ifndef SUBR_H
 # define SUBR_H
 
+/* FIXME - This shouldn't be needed here.  Any routine that needs to understand
+ * the underlying structure of an RCSNode should be in rcs*.c.
+ */
+#include "rcs.h"
+
+
+
+#ifdef USE_VMS_FILENAMES
+# define BAKPREFIX     "_$"
+#else /* USE_VMS_FILENAMES */
+# define BAKPREFIX     ".#"            /* when rcsmerge'ing */
+#endif /* USE_VMS_FILENAMES */
+
+
+
 void expand_string (char **, size_t *, size_t);
 char *Xreadlink (const char *link, size_t size);
 void xrealloc_and_strcat (char **, size_t *, const char *);
@@ -34,8 +49,11 @@
 void check_numeric (const char *, int, char **);
 char *make_message_rcsvalid (const char *message);
 int file_has_markers (const struct file_info *);
+bool file_contains_keyword (const struct file_info *finfo);
 void get_file (const char *, const char *, const char *,
                char **, size_t *, size_t *);
+void force_write_file (const char *file, const char *data, size_t len);
+void write_file (const char *file, const char *data, size_t len);
 void resolve_symlink (char **filename);
 char *backup_file (const char *file, const char *suffix);
 char *shell_escape (char *buf, const char *str);
Index: ccvs/src/tag.c
diff -u ccvs/src/tag.c:1.144 ccvs/src/tag.c:1.145
--- ccvs/src/tag.c:1.144        Fri Mar 10 16:29:34 2006
+++ ccvs/src/tag.c      Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -17,9 +17,23 @@
  * the modules database, if necessary.
  */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB headers.  */
 #include "save-cwd.h"
 
+/* CVS headers.  */
+#include "classify.h"
+#include "ignore.h"
+#include "recurse.h"
+#include "repos.h"
+
+#include "cvs.h"
+
+
+
 static int rtag_proc (int argc, char **argv, char *xwhere,
                      char *mwhere, char *mfile, int shorten,
                      int local_specified, char *mname, char *msg);
@@ -240,9 +254,10 @@
        {
            send_files (argc, argv, local, 0,
 
-                   /* I think the -c case is like "cvs status", in
-                      which we really better be correct rather than
-                      being fast; it is just too confusing otherwise.  */
+                       /* I think the -c case is like "cvs status", in
+                        * which we really better be correct rather than
+                        * being fast; it is just too confusing otherwise.
+                        */
                        check_uptodate ? 0 : SEND_NO_CONTENTS);
            send_file_names (argc, argv, SEND_EXPAND_WILD);
            send_to_server ("tag\012", 0);
Index: ccvs/src/update.c
diff -u ccvs/src/update.c:1.260 ccvs/src/update.c:1.261
--- ccvs/src/update.c:1.260     Mon Jan 16 18:56:06 2006
+++ ccvs/src/update.c   Mon Apr 24 18:50:27 2006
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
+ * Copyright (C) 1986-2006 The Free Software Foundation, Inc.
  *
  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
  *                                  and others.
@@ -38,23 +38,42 @@
  * as well.
  */
 
-#include "cvs.h"
-#include <assert.h>
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* GNULIB */
+#include "getline.h"
 #include "save-cwd.h"
+
 #ifdef SERVER_SUPPORT
 # include "md5.h"
 #endif
-#include "watch.h"
-#include "fileattr.h"
-#include "edit.h"
-#include "getline.h"
+
+/* ANSI C headers.  */
+#include <assert.h>
+
+/* CVS headers.  */
+#include "base.h"
 #include "buffer.h"
+#include "classify.h"
+#include "edit.h"
+#include "fileattr.h"
+#include "ignore.h"
+#include "no_diff.h"
+#include "recurse.h"
+#include "repos.h"
+#include "watch.h"
+#include "wrapper.h"
+
+#include "cvs.h"
 #include "hardlink.h"
 
+
+
 static int checkout_file (struct file_info *finfo, Vers_TS *vers_ts,
                                 int adding, int merging, int update_server);
 #ifdef SERVER_SUPPORT
-static void checkout_to_buffer (void *, const char *, size_t);
 static int patch_file (struct file_info *finfo,
                        Vers_TS *vers_ts, 
                        int *docheckout, struct stat *file_info,
@@ -107,8 +126,8 @@
 static int pipeout = 0;
 static int dotemplate = 0;
 #ifdef SERVER_SUPPORT
-static int patches = 0;
-static int rcs_diff_patches = 0;
+static bool bases;
+static bool rcs_diff_patches;
 #endif
 static List *ignlist = NULL;
 static time_t last_register_time;
@@ -233,10 +252,7 @@
            case 'u':
 #ifdef SERVER_SUPPORT
                if (server_active)
-               {
-                   patches = 1;
                    rcs_diff_patches = server_use_rcs_diff ();
-               }
                else
 #endif
                    usage (update_usage);
@@ -472,6 +488,10 @@
           preload_update_dir ? preload_update_dir : "(null)", xdotemplate,
           repository ? repository : "(null)");
 
+    /* Set globals.  */
+    if (server_active && server_use_bases ())
+       bases = true;
+
     /* fill in the statics */
     options = xoptions;
     tag = xtag;
@@ -590,6 +610,8 @@
     Ctype status;
     Vers_TS *vers;
 
+    TRACE (TRACE_FUNCTION, "update_fileproc (%s)", finfo->fullname);
+
     status = Classify_File (finfo, tag, date, options, force_tag_match,
                            aflag, &vers, pipeout);
 
@@ -716,7 +738,7 @@
                break;
            case T_PATCH:               /* needs patch */
 #ifdef SERVER_SUPPORT
-               if (patches)
+               if (server_active && !bases)
                {
                    int docheckout;
                    struct stat file_info;
@@ -725,9 +747,9 @@
                    retval = patch_file (finfo,
                                         vers, &docheckout,
                                         &file_info, checksum);
-                   if (! docheckout)
+                   if (!docheckout)
                    {
-                       if (server_active && retval == 0)
+                       if (retval == 0)
                            server_updated (finfo, vers,
                                            (rcs_diff_patches
                                             ? SERVER_RCS_DIFF
@@ -738,9 +760,10 @@
                    }
                }
 #endif
-               /* If we're not running as a server, just check the
-                  file out.  It's simpler and faster than producing
-                  and applying patches.  */
+               /* If we're not running as a server or the client can handle
+                * base operations, just check the file out.  It's simpler and
+                * faster than producing and applying patches.
+                */
                /* Fall through.  */
            case T_CHECKOUT:            /* needs checkout */
                retval = checkout_file (finfo, vers, 0, 0, 1);
@@ -1187,6 +1210,13 @@
 
 /*
  * Check out a file.
+ *
+ * INPUTS
+ *   finfo             The file to be updated.
+ *   vers_ts           Version information about the file to be updated.
+ *   adding
+ *   merging
+ *   update_server
  */
 static int
 checkout_file (struct file_info *finfo, Vers_TS *vers_ts, int adding,
@@ -1195,11 +1225,11 @@
     char *backup;
     int set_time, retval = 0;
     int status;
-    int file_is_dead;
-    struct buffer *revbuf;
+    bool file_is_dead;
+
+    TRACE (TRACE_FUNCTION, "checkout_file (%s)", finfo->fullname);
 
     backup = NULL;
-    revbuf = NULL;
 
     /* Don't screw with backup files if we're going to stdout, or if
        we are the server.  */
@@ -1207,7 +1237,7 @@
     {
        backup = Xasprintf ("%s/%s%s", CVSADM, CVSPREFIX, finfo->file);
        if (isfile (finfo->file))
-           rename_file (finfo->file, backup);
+           force_copy_file (finfo->file, backup);
        else /* FIXME: -f/-t has been disabled for so long it should probably
              * just be stripped out to reduce clutter.
              */
@@ -1249,74 +1279,52 @@
                cvs_outerr (vers_ts->vn_rcs, 0);
                cvs_outerr ("\n***************\n", 0);
            }
-       }
 
-#ifdef SERVER_SUPPORT
-       if (update_server
-           && server_active
-           && ! pipeout
-           && ! file_gzip_level
-           && ! joining ()
-           && ! wrap_name_has (finfo->file, WRAP_FROMCVS))
-       {
-           revbuf = buf_nonio_initialize (NULL);
-           status = RCS_checkout (vers_ts->srcfile, NULL,
-                                  vers_ts->vn_rcs, vers_ts->tag,
-                                  vers_ts->options, RUN_TTY,
-                                  checkout_to_buffer, revbuf);
-       }
-       else
-#endif
            status = RCS_checkout (vers_ts->srcfile,
                                   pipeout ? NULL : finfo->file,
                                   vers_ts->vn_rcs, vers_ts->tag,
                                   vers_ts->options, RUN_TTY, NULL, NULL);
+       }
+       else
+           /* There used to be a special case here to check out to a buffer
+            * when UPDATE_SERVER && SERVER_ACTIVE && !PIPEOUT
+            * && !FILE_GZIP_LEVEL && !joining ()
+            * && !wrap_name_has (finfo->file, WRAP_FROMCVS), but I don't think
+            * it is important to optimize for old clients which don't support
+            * bandwidth saving base files and openpgp signatures.
+            */
+           status = base_checkout (vers_ts->srcfile, finfo,
+                                   vers_ts->vn_user, vers_ts->vn_rcs,
+                                   vers_ts->entdata
+                                   ? vers_ts->entdata->tag : NULL,
+                                   vers_ts->tag,
+                                   vers_ts->entdata
+                                   ? vers_ts->entdata->options : NULL,
+                                   vers_ts->options);
     }
+
     if (file_is_dead || status == 0)
     {
-       mode_t mode;
-
-       mode = (mode_t) -1;
+       mode_t mode = (mode_t) -1;
 
        if (!pipeout)
        {
            Vers_TS *xvers_ts;
 
-           if (revbuf != NULL && !noexec)
+           if (!file_is_dead)
            {
-               struct stat sb;
-
-               /* FIXME: We should have RCS_checkout return the mode.
-                  That would also fix the kludge with noexec, above, which
-                  is here only because noexec doesn't write srcfile->path
-                  for us to stat.  */
-               if (stat (vers_ts->srcfile->path, &sb) < 0)
-               {
-#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
-                   buf_free (revbuf);
-#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
-                   error (1, errno, "cannot stat %s",
-                          vers_ts->srcfile->path);
-               }
-               mode = sb.st_mode &~ (S_IWRITE | S_IWGRP | S_IWOTH);
-           }
-
-           if (cvswrite
-               && !file_is_dead
-               && !fileattr_get (finfo->file, "_watched"))
-           {
-               if (revbuf == NULL)
-                   xchmod (finfo->file, 1);
+               char flags[3];
+               if (vers_ts->ts_user)
+                   flags[0] = 'y';
                else
-               {
-                   /* We know that we are the server here, so
-                       although xchmod checks umask, we don't bother.  */
-                   mode |= (((mode & S_IRUSR) ? S_IWUSR : 0)
-                            | ((mode & S_IRGRP) ? S_IWGRP : 0)
-                            | ((mode & S_IROTH) ? S_IWOTH : 0));
-               }
+                   flags[0] = 'n';
+               if (cvswrite && !fileattr_get (finfo->file, "_watched"))
+                   flags[1] = 'y';
+               else
+                   flags[1] = 'n';
+               flags[2] = '\0';
+               base_copy (finfo, vers_ts->vn_rcs, flags);
            }
-
            {
                /* A newly checked out file is never under the spell
                   of "cvs edit".  If we think we were editing it
@@ -1336,8 +1344,8 @@
            /* set the time from the RCS file iff it was unknown before */
            set_time =
                (!noexec
-                && (vers_ts->vn_user == NULL ||
-                    strncmp (vers_ts->ts_rcs, "Initial", 7) == 0)
+                && (!vers_ts->vn_user ||
+                    !strncmp (vers_ts->ts_rcs, "Initial", 7))
                 && !file_is_dead);
 
            wrap_fromcvs_process_file (finfo->file);
@@ -1347,27 +1355,6 @@
            if (strcmp (xvers_ts->options, "-V4") == 0)
                xvers_ts->options[0] = '\0';
 
-           if (revbuf != NULL)
-           {
-               /* If we stored the file data into a buffer, then we
-                   didn't create a file at all, so xvers_ts->ts_user
-                   is wrong.  The correct value is to have it be the
-                   same as xvers_ts->ts_rcs, meaning that the working
-                   file is unchanged from the RCS file.
-
-                  FIXME: We should tell Version_TS not to waste time
-                  statting the nonexistent file.
-
-                  FIXME: Actually, I don't think the ts_user value
-                  matters at all here.  The only use I know of is
-                  that it is printed in a trace message by
-                  Server_Register.  */
-
-               if (xvers_ts->ts_user != NULL)
-                   free (xvers_ts->ts_user);
-               xvers_ts->ts_user = xstrdup (xvers_ts->ts_rcs);
-           }
-
            (void) time (&last_register_time);
 
            if (file_is_dead)
@@ -1403,6 +1390,8 @@
            /* fix up the vers structure, in case it is used by join */
            if (join_rev1)
            {
+               Node *n;
+
                /* FIXME: Throwing away the original revision info is almost
                   certainly wrong -- what if join_rev1 is "BASE"?  */
                if (vers_ts->vn_user != NULL)
@@ -1411,26 +1400,29 @@
                    free (vers_ts->vn_rcs);
                vers_ts->vn_user = xstrdup (xvers_ts->vn_rcs);
                vers_ts->vn_rcs = xstrdup (xvers_ts->vn_rcs);
+               n = findnode_fn (finfo->entries, finfo->file);
+               if (n)
+                   vers_ts->entdata = n->data;
+               else
+                   vers_ts->entdata = NULL;
            }
 
            /* If this is really Update and not Checkout, recode history */
            if (strcmp (cvs_cmd_name, "update") == 0)
-               history_write ('U', finfo->update_dir, xvers_ts->vn_rcs, 
finfo->file,
-                              finfo->repository);
+               history_write ('U', finfo->update_dir, xvers_ts->vn_rcs,
+                              finfo->file, finfo->repository);
 
            freevers_ts (&xvers_ts);
 
            if (!really_quiet && !file_is_dead)
-           {
                write_letter (finfo, 'U');
-           }
        }
 
 #ifdef SERVER_SUPPORT
        if (update_server && server_active)
            server_updated (finfo, vers_ts,
                            merging ? SERVER_MERGED : SERVER_UPDATED,
-                           mode, NULL, revbuf);
+                           mode, NULL, NULL);
 #endif
     }
     else
@@ -1447,7 +1439,7 @@
        retval = status;
     }
 
-    if (backup != NULL)
+    if (backup)
     {
        /* If -f/-t wrappers are being used to wrap up a directory,
           then backup might be a directory instead of just a file.  */
@@ -1461,10 +1453,6 @@
        free (backup);
     }
 
-#if defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT)
-    if (revbuf != NULL)
-       buf_free (revbuf);
-#endif /* defined (SERVER_SUPPORT) || defined (CLIENT_SUPPORT) */
     return retval;
 }
 
@@ -1472,21 +1460,6 @@
 
 #ifdef SERVER_SUPPORT
 
-/* This function is used to write data from a file being checked out
-   into a buffer.  */
-
-static void
-checkout_to_buffer (void *callerdat, const char *data, size_t len)
-{
-    struct buffer *buf = (struct buffer *) callerdat;
-
-    buf_output (buf, data, len);
-}
-
-#endif /* SERVER_SUPPORT */
-
-#ifdef SERVER_SUPPORT
-
 /* This structure is used to pass information between patch_file and
    patch_file_write.  */
 
@@ -1865,19 +1838,25 @@
 /* Reregister a file after a merge.  */
 static void
 RegisterMerge (struct file_info *finfo, Vers_TS *vers,
-              const char *backup, int has_conflicts)
+              const char *backup, bool has_conflicts, bool force_addition)
 {
     /* This file is the result of a merge, which means that it has
        been modified.  We use a special timestamp string which will
        not compare equal to any actual timestamp.  */
     char *cp = NULL;
 
+    TRACE (TRACE_FUNCTION, "RegisterMerge (%s, %s, %s, %s, %s)",
+          finfo->fullname, vers->vn_user, backup,
+          has_conflicts ? "true" : "false",
+          force_addition ? "true" : "false");
+
     if (has_conflicts)
     {
        time (&last_register_time);
        cp = time_stamp (finfo->file);
     }
-    Register (finfo->entries, finfo->file, vers->vn_rcs ? vers->vn_rcs : "0",
+    Register (finfo->entries, finfo->file,
+             vers->vn_rcs && !force_addition ? vers->vn_rcs : "0",
              "Result of merge", vers->options, vers->tag, vers->date, cp);
     if (cp)
        free (cp);
@@ -1888,8 +1867,9 @@
        the message only after the file has safely been written.  */
     if (server_active)
     {
-        server_copy_file (finfo->file, finfo->update_dir, finfo->repository,
-                         backup);
+       if (vers->ts_user)
+           server_copy_file (finfo->file, finfo->update_dir,
+                             finfo->repository, backup);
        server_updated (finfo, vers, SERVER_MERGED, (mode_t) -1, NULL, NULL);
     }
 #endif
@@ -1942,8 +1922,11 @@
           thought needs to go into this, and in the meantime it is safe
           to treat any such mismatch as an automatic conflict. -twp */
 
-       status = RCS_checkout (finfo->rcs, finfo->file, vers->vn_rcs,
-                              vers->tag, vers->options, NULL, NULL, NULL);
+       status = base_checkout (finfo->rcs, finfo, vers->vn_user, vers->vn_rcs,
+                               vers->entdata->tag, vers->tag,
+                               vers->entdata->options, vers->options);
+       base_copy (finfo, vers->vn_rcs, "yy");
+
        if (status)
        {
            error (0, 0, "failed to check out `%s' file", finfo->fullname);
@@ -1954,9 +1937,7 @@
            goto out;
        }
 
-       xchmod (finfo->file, 1);
-
-       RegisterMerge (finfo, vers, backup, 1);
+       RegisterMerge (finfo, vers, backup, true, false);
 
        /* Is there a better term than "nonmergeable file"?  What we
           really mean is, not something that CVS cannot or does not
@@ -1974,18 +1955,23 @@
        goto out;
     }
 
-    status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
-                       vers->options, vers->vn_user, vers->vn_rcs);
+    status = base_merge (finfo->rcs, finfo, vers->entdata->tag,
+                        vers->entdata->options, vers->options, vers->vn_user,
+                        vers->vn_user, vers->vn_rcs, false);
+
     if (status != 0 && status != 1)
     {
        error (0, status == -1 ? errno : 0,
-              "could not merge revision %s of %s", vers->vn_user, 
finfo->fullname);
+              "could not merge revision %s of %s", vers->vn_user,
+              finfo->fullname);
        error (status == -1 ? 1 : 0, 0, "restoring %s from backup file %s",
               finfo->fullname, backup);
        rename_file (backup, finfo->file);
        retval = 1;
+       base_remove (finfo->file, vers->vn_rcs);
        goto out;
     }
+    base_remove (finfo->file, vers->vn_user);
 
     if (strcmp (vers->options, "-V4") == 0)
        vers->options[0] = '\0';
@@ -2000,13 +1986,12 @@
        vers->vn_user = xstrdup (vers->vn_rcs);
     }
 
-    RegisterMerge (finfo, vers, backup, status);
+    RegisterMerge (finfo, vers, backup, status, false);
 
     if (status == 1)
     {
-       error (0, 0, "conflicts found in %s", finfo->fullname);
-
-       write_letter (finfo, 'C');
+       if (!really_quiet)
+           write_letter (finfo, 'C');
 
        history_write ('C', finfo->update_dir, vers->vn_rcs, finfo->file,
                       finfo->repository);
@@ -2014,25 +1999,37 @@
     }
     else /* status == 0 */
     {
+       /* FIXME: When BASES, a zero status might mean the server didn't
+        * perform the merge.
+        */
        history_write ('G', finfo->update_dir, vers->vn_rcs, finfo->file,
                       finfo->repository);
 
        /* FIXME: the noexec case is broken.  RCS_merge could be doing the
           xcmp on the temporary files without much hassle, I think.  */
-       if (!noexec && !xcmp (backup, finfo->file))
+       if (!noexec && !bases && !xcmp (backup, finfo->file))
        {
-           cvs_output (finfo->fullname, 0);
-           cvs_output (" already contains the differences between ", 0);
-           cvs_output (vers->vn_user, 0);
-           cvs_output (" and ", 0);
-           cvs_output (vers->vn_rcs, 0);
-           cvs_output ("\n", 1);
+           if (!quiet)
+           {
+               /* The client will handle these messages when BASES.  */
+               cvs_output ("`", 1);
+               cvs_output (finfo->fullname, 0);
+               cvs_output ("' already contains the differences between ", 0);
+               cvs_output (vers->vn_user, 0);
+               cvs_output (" and ", 5);
+               cvs_output (vers->vn_rcs, 0);
+               cvs_output ("\n", 1);
+           }
 
            retval = 0;
            goto out;
        }
 
-       write_letter (finfo, 'M');
+       if (!bases)
+           /* The client may determine this is a conflict rather than
+            * modified.  Let it write the correct message.
+            */
+           write_letter (finfo, 'M');
     }
     retval = 0;
  out:
@@ -2071,8 +2068,9 @@
     char *jrev2;
     char *jdate1;
     char *jdate2;
+    bool replace_it;
 
-    TRACE (TRACE_FUNCTION, "join_file(%s, %s%s%s%s, %s, %s)",
+    TRACE (TRACE_FUNCTION, "join_file (%s, %s%s%s%s, %s, %s)",
           finfo->file,
           vers->tag ? vers->tag : "",
           vers->tag ? " (" : "",
@@ -2280,7 +2278,7 @@
            server_checked_in (finfo->file, finfo->update_dir,
                               finfo->repository);
 #endif
-       if (! really_quiet)
+       if (!really_quiet)
            error (0, 0, "scheduling `%s' for removal", finfo->fullname);
 
        return;
@@ -2307,12 +2305,13 @@
         && strcmp (vers->ts_user, vers->ts_rcs) == 0
         && strcmp (rev2, vers->vn_user) == 0)
     {
-       if (!really_quiet)
+       if (!quiet)
        {
+           cvs_output ("`", 1);
            cvs_output (finfo->fullname, 0);
-           cvs_output (" already contains the differences between ", 0);
+           cvs_output ("' already contains the differences between ", 0);
            cvs_output (rev1 ? rev1 : "creation", 0);
-           cvs_output (" and ", 0);
+           cvs_output (" and ", 5);
            cvs_output (rev2, 0);
            cvs_output ("\n", 1);
        }
@@ -2337,25 +2336,46 @@
            addition.  */
        if (vers->vn_user == NULL)
        {
-           char *saved_options = options;
            Vers_TS *xvers;
+           char *tempfile;
 
-           xvers = Version_TS (finfo, vers->options, jrev2, jdate2, 1, 0);
-
-           /* Reset any keyword expansion option.  Otherwise, when a
+           /* Use NULL for keyword expansion options.  Otherwise, when a
               command like `cvs update -kk -jT1 -jT2' creates a new file
               (because a file had the T2 tag, but not T1), the subsequent
               commit of that just-added file effectively would set the
               admin `-kk' option for that file in the repository.  */
-           options = NULL;
+           xvers = Version_TS (finfo, NULL, jrev2, jdate2, 1, 0);
+
+           if (!really_quiet)
+               error (0, 0, "scheduling addition from revision %s of `%s'.",
+                      xvers->vn_rcs, finfo->fullname);
 
-           /* FIXME: If checkout_file fails, we should arrange to
+           TRACE (TRACE_DATA, "Adding with keyword mode `%s'", xvers->options);
+
+           /* FIXME: If base_checkout fails, we should arrange to
                return a non-zero exit status.  */
-           status = checkout_file (finfo, xvers, 1, 0, 1);
-           options = saved_options;
+           tempfile = temp_checkout (xvers->srcfile, finfo,
+                                     NULL, xvers->vn_rcs,
+                                     xvers->entdata
+                                     ? xvers->entdata->tag : NULL,
+                                     xvers->tag,
+                                     xvers->entdata
+                                     ? xvers->entdata->options : NULL,
+                                     xvers->options);
+           /* Added files are always writable until commit.  */
+           temp_copy (finfo, "ny", tempfile);
+           free (tempfile);
 
-           freevers_ts (&xvers);
+           Register (finfo->entries, finfo->file, "0",
+                     "Result of merge", NULL, vers->tag, vers->date, NULL);
+           if (server_active)
+               /* No need to create a backup for an addition - if the file
+                * exists, the client will abort with a warning.
+                */
+               server_updated (finfo, vers, SERVER_UPDATED, (mode_t) -1,
+                               NULL, NULL);
 
+           freevers_ts (&xvers);
            return;
        }
 
@@ -2438,18 +2458,28 @@
        as such).  In the text file case, this is probably quite
        similar to the RCS_merge, but in the binary file case,
        RCS_merge gives all kinds of trouble.  */
-    if (vers->vn_user != NULL
-       && strcmp (rev1, vers->vn_user) == 0
+    replace_it =
+       vers->vn_user && !strcmp (rev1, vers->vn_user)
        /* See comments above about how No_Difference has already been
           called.  */
-       && vers->ts_user != NULL
-       && strcmp (vers->ts_user, vers->ts_rcs) == 0
+       && vers->ts_user && !strcmp (vers->ts_user, vers->ts_rcs);
 
-       /* Avoid this in the text file case.  See below for why.
-        */
-       && (strcmp (t_options, "-kb") == 0
-           || wrap_merge_is_copy (finfo->file)))
+    if (!strcmp (vers->options, "-kb")
+       || special_file_mismatch (finfo, rev1, rev2)
+       || replace_it)
     {
+       if (!really_quiet)
+       {
+           /* Is there a better term than "nonmergeable file"?  What we
+              really mean is, not something that CVS cannot or does not
+              want to merge (there might be an external manual or
+              automatic merge process).  */
+           if (!replace_it)
+               error (0, 0, "Nonmergeable file needs merge.");
+           error (0, 0, "Replacing `%s' with contents of revision %s.",
+                  finfo->fullname, rev2);
+       }
+
        /* FIXME: Verify my comment below:
         *
         * RCS_merge does nothing with keywords.  It merges the changes between
@@ -2466,73 +2496,37 @@
         * Also, it is safe to pass in NULL for nametag since we know no
         * substitution is happening during the binary mode checkout.
         */
-       if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL, t_options,
-                         RUN_TTY, NULL, NULL) != 0)
-           status = 2;
-       else
-           status = 0;
+       if (base_checkout (finfo->rcs, finfo, vers->vn_user, rev2,
+                          vers->entdata->tag, vers->tag,
+                          vers->entdata->options, t_options) != 0)
+           error (1, 0, "Checkout of revision %s of `%s' failed.",
+                  rev2, finfo->fullname);
 
-       /* OK, this is really stupid.  RCS_checkout carefully removes
-          write permissions, and we carefully put them back.  But
-          until someone gets around to fixing it, that seems like the
-          easiest way to get what would seem to be the right mode.
-          I don't check CVSWRITE or _watched; I haven't thought about
-          that in great detail, but it seems like a watched file should
-          be checked out (writable) after a merge.  */
-       xchmod (finfo->file, 1);
-
-       /* Traditionally, the text file case prints a whole bunch of
-          scary looking and verbose output which fails to tell the user
-          what is really going on (it gives them rev1 and rev2 but doesn't
-          indicate in any way that rev1 == vn_user).  I think just a
-          simple "U foo" is good here; it seems analogous to the case in
-          which the file was added on the branch in terms of what to
-          print.  */
-       write_letter (finfo, 'U');
-    }
-    else if (strcmp (t_options, "-kb") == 0
-            || wrap_merge_is_copy (finfo->file)
-            || special_file_mismatch (finfo, rev1, rev2))
-    {
-       /* We are dealing with binary files, or files with a
-          permission/linkage mismatch (this second case only occurs when
-          PRESERVE_PERMISSIONS_SUPPORT is enabled), and real merging would
-          need to take place.  This is a conflict.  We give the user
-          the two files, and let them resolve it.  It is possible
-          that we should require a "touch foo" or similar step before
-          we allow a checkin.  */
-       if (RCS_checkout (finfo->rcs, finfo->file, rev2, NULL,
-                         t_options, RUN_TTY, NULL, NULL) != 0)
-           status = 2;
-       else
-           status = 0;
+       base_copy (finfo, rev2, "yy");
 
-       /* OK, this is really stupid.  RCS_checkout carefully removes
-          write permissions, and we carefully put them back.  But
-          until someone gets around to fixing it, that seems like the
-          easiest way to get what would seem to be the right mode.
-          I don't check CVSWRITE or _watched; I haven't thought about
-          that in great detail, but it seems like a watched file should
-          be checked out (writable) after a merge.  */
-       xchmod (finfo->file, 1);
-
-       /* Hmm.  We don't give them REV1 anywhere.  I guess most people
-          probably don't have a 3-way merge tool for the file type in
-          question, and might just get confused if we tried to either
-          provide them with a copy of the file from REV1, or even just
-          told them what REV1 is so they can get it themself, but it
-          might be worth thinking about.  */
-       /* See comment in merge_file about the "nonmergeable file"
-          terminology.  */
-       error (0, 0, "nonmergeable file needs merge");
-       error (0, 0, "revision %s from repository is now in %s",
-              rev2, finfo->fullname);
-       error (0, 0, "file from working directory is now in %s", backup);
-       write_letter (finfo, 'C');
+       if (replace_it)
+       {
+           /* FIXME: It would be more consistent if the client printed this
+            * message when BASES.
+            */
+           if (!really_quiet && bases)
+               write_letter (finfo, 'M');
+           status = 0;
+       }
+       else
+       {
+           if (!really_quiet)
+           {
+               error (0, 0, "File from working directory is now in `%s'.",
+                      backup);
+           }
+           status = 1;
+       }
     }
     else
-       status = RCS_merge (finfo->rcs, vers->srcfile->path, finfo->file,
-                           t_options, rev1, rev2);
+       status = base_merge (finfo->rcs, finfo, vers->entdata->tag,
+                            vers->entdata->options, t_options,
+                            vers->vn_user, rev1, rev2, true);
 
     if (status != 0)
     {
@@ -2544,28 +2538,54 @@
                   finfo->fullname, backup);
            rename_file (backup, finfo->file);
        }
+       else if (!really_quiet)
+           /* FIXME: It would be more consistent if the client printed
+            * this message when BASES.
+            */
+           write_letter (finfo, 'C');
     }
-    else /* status == 0 */
+    else if (!bases) /* status == 0 */
     {
+       bool unchanged, isbase;
+       char *basefile;
+       /* The client will handle these messages when BASES.  */
+
        /* FIXME: the noexec case is broken.  RCS_merge could be doing the
           xcmp on the temporary files without much hassle, I think.  */
        if (!noexec && !xcmp (backup, finfo->file))
+           unchanged = true;
+       else
+           unchanged = false;
+       basefile = make_base_file_name (finfo->file, vers->vn_user);
+       if (!noexec
+           && ((isfile (basefile) && !xcmp (basefile, finfo->file))
+               || (strcmp (vers->vn_user, "0")
+                   && !RCS_cmp_file (finfo->rcs, vers->tag, vers->vn_user,
+                                     NULL, NULL, vers->options,
+                                     finfo->file))))
+           isbase = true;
+       else
+           isbase = false;
+       free (basefile);
+       if (unchanged && !quiet)
        {
-           if (!really_quiet)
-           {
-               cvs_output (finfo->fullname, 0);
-               cvs_output (" already contains the differences between ", 0);
-               cvs_output (rev1, 0);
-               cvs_output (" and ", 0);
-               cvs_output (rev2, 0);
-               cvs_output ("\n", 1);
-           }
+           cvs_output ("`", 1);
+           cvs_output (finfo->fullname, 0);
+           cvs_output ("' already contains the differences between ", 0);
+           cvs_output (rev1, 0);
+           cvs_output (" and ", 5);
+           cvs_output (rev2, 0);
+           cvs_output ("\n", 1);
+       }
 
+       if (!isbase && !really_quiet)
+           write_letter (finfo, 'M');
+
+       if (unchanged)
            /* and skip the registering and sending the new file since it
             * hasn't been updated.
             */
            goto out;
-       }
     }
 
     /* The file has changed, but if we just checked it out it may
@@ -2578,7 +2598,7 @@
        RCS_checkout above, and we aren't running as the server.
        However, that is not the normal case, and calling Register
        again won't cost much in that case.  */
-    RegisterMerge (finfo, vers, backup, status);
+    RegisterMerge (finfo, vers, backup, status, false);
 
 out:
     free (rev1);
Index: ccvs/src/vers_ts.c
diff -u ccvs/src/vers_ts.c:1.65 ccvs/src/vers_ts.c:1.66
--- ccvs/src/vers_ts.c:1.65     Fri Sep 23 03:19:24 2005
+++ ccvs/src/vers_ts.c  Mon Apr 24 18:50:27 2006
@@ -34,12 +34,16 @@
  *   set_time          If set, set the last modification time of the user file
  *                     specified by FINFO to the checkin time of RET->vn_rcs.
  *
+ * OUTPUTS
+ *   finfo             FINFO->RCS will be updated if it was empty and RCS data
+ *                     is found and parsed.
+ *
  * RETURNS
  *   Vers_TS structure for FINFO.
  */
 Vers_TS *
-Version_TS (struct file_info *finfo, char *options, char *tag, char *date,
-            int force_tag_match, int set_time)
+Version_TS (struct file_info *finfo, const char *options, const char *tag,
+           const char *date, int force_tag_match, int set_time)
 {
     Node *p;
     RCSNode *rcsdata;
@@ -48,6 +52,10 @@
     Entnode *entdata;
     char *rcsexpand = NULL;
 
+    TRACE (TRACE_FUNCTION, "Version_TS (%s, %s, %s, %s, %d, %d)",
+          finfo->fullname, options ? options : "(null)", tag ? tag : "(null)",
+          date ? date : "(null)", force_tag_match, set_time);
+
     /* get a new Vers_TS struct */
 
     vers_ts = xmalloc (sizeof (Vers_TS));
@@ -71,6 +79,7 @@
 
     if (p == NULL)
     {
+       TRACE (TRACE_DATA, "Version_TS: No entries data found.");
        entdata = NULL;
     }
     else
@@ -190,6 +199,11 @@
     {
        /* squirrel away the rcsdata pointer for others */
        vers_ts->srcfile = rcsdata;
+       if (!finfo->rcs)
+       {
+           rcsdata->refcount++;
+           finfo->rcs = rcsdata;
+       }
 
        if (vers_ts->tag && strcmp (vers_ts->tag, TAG_BASE) == 0)
        {
@@ -271,7 +285,7 @@
            vers_ts->ts_user = time_stamp (finfo->file);
     }
 
-    return (vers_ts);
+    return vers_ts;
 }
 
 
@@ -318,9 +332,9 @@
        else if (entdata->conflict
                 && entdata->conflict[0] == '=')
        {
-           /* These just need matching content.  Might as well minimize it.  */
-           vers_ts->ts_user = xstrdup ("");
-           vers_ts->ts_conflict = xstrdup ("");
+           /* These need matching content that doesn't match ->ts_rcs.  */
+           vers_ts->ts_user = xstrdup ("Is-modified");
+           vers_ts->ts_conflict = xstrdup ("Is-modified");
        }
        else if (entdata->timestamp
                 && (entdata->timestamp[0] == 'M'
Index: ccvs/src/watch.c
diff -u ccvs/src/watch.c:1.45 ccvs/src/watch.c:1.46
--- ccvs/src/watch.c:1.45       Thu Sep 15 01:52:26 2005
+++ ccvs/src/watch.c    Mon Apr 24 18:50:27 2006
@@ -1,19 +1,35 @@
-/* Implementation for "cvs watch add", "cvs watchers", and related commands
+/*
+ * Copyright (C) 2006 The Free Software Foundation, Inc.
+ *
+ * Implementation for "cvs watch add", "cvs watchers", and related commands
+ *
+ * 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 2, 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
 
-   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 2, 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.  */
+/* Verify interface.  */
+#include "watch.h"
 
-#include "cvs.h"
+/* CVS headers.  */
 #include "edit.h"
 #include "fileattr.h"
-#include "watch.h"
+#include "ignore.h"
+#include "recurse.h"
+
+#include "cvs.h"
+
+
 
 const char *const watch_usage[] =
 {
Index: ccvs/src/wrapper.c
diff -u ccvs/src/wrapper.c:1.47 ccvs/src/wrapper.c:1.48
--- ccvs/src/wrapper.c:1.47     Fri Sep  2 21:51:09 2005
+++ ccvs/src/wrapper.c  Mon Apr 24 18:50:27 2006
@@ -1,16 +1,32 @@
-/* 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 2, 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.  */
+/*
+ * Copyright (C) 2006 The 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 2, 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.
+ */
 
-#include "cvs.h"
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Verify interface.  */
+#include "wrapper.h"
+
+/* GNULIB headers.  */
 #include "getline.h"
 
+/* CVS headers.  */
+#include "cvs.h"
+
+
+
 /*
   Original Author:  address@hidden <Andrew C. Athan> 2/1/94
   Modified By:      address@hidden
Index: ccvs/src/zlib.c
diff -u ccvs/src/zlib.c:1.33 ccvs/src/zlib.c:1.34
--- ccvs/src/zlib.c:1.33        Fri Jan 27 17:15:33 2006
+++ ccvs/src/zlib.c     Mon Apr 24 18:50:27 2006
@@ -500,14 +500,18 @@
    it is an error we can't recover from.  */
 
 int
-gunzip_and_write (int fd, const char *fullname, unsigned char *buf,
-                 size_t size)
+gunzip_in_mem (const char *fullname, unsigned char *buf, size_t *size_in,
+              char **retval)
 {
     size_t pos;
     z_stream zstr;
     int zstatus;
     unsigned char outbuf[32768];
     unsigned long crc;
+    size_t size = *size_in;
+
+    *retval = NULL;
+    *size_in = 0;
 
     if (size < 10)
     {
@@ -609,13 +613,13 @@
        if (zstatus != Z_STREAM_END && zstatus != Z_OK)
        {
            compress_error (0, zstatus, &zstr, fullname);
+           if (*retval) free (*retval);
            return 1;
        }
-       if (write (fd, outbuf, sizeof (outbuf) - zstr.avail_out) < 0)
-       {
-           error (0, errno, "writing decompressed file %s", fullname);
-           return 1;
-       }
+       *retval = xrealloc (*retval,
+                          *size_in + sizeof (outbuf) - zstr.avail_out);
+       memcpy (*retval + *size_in, outbuf, sizeof (outbuf) - zstr.avail_out);
+       *size_in += sizeof (outbuf) - zstr.avail_out;
        crc = crc32 (crc, outbuf, sizeof (outbuf) - zstr.avail_out);
     } while (zstatus != Z_STREAM_END);
     zstatus = inflateEnd (&zstr);
@@ -629,6 +633,7 @@
     if (size - pos != 8)
     {
        error (0, 0, "gzip data incomplete for %s (no trailer)", fullname);
+       if (*retval) free (*retval);
        return 1;
     }
 
@@ -638,6 +643,7 @@
                + ((unsigned long)buf[pos + 3] << 24)))
     {
        error (0, 0, "CRC error uncompressing %s", fullname);
+       if (*retval) free (*retval);
        return 1;
     }
 
@@ -647,12 +653,36 @@
                           + ((unsigned long)buf[pos + 7] << 24)))
     {
        error (0, 0, "invalid length uncompressing %s", fullname);
+       if (*retval) free (*retval);
        return 1;
     }
 
     return 0;
 }
 
+
+
+int
+gunzip_and_write (int fd, const char *fullname, unsigned char *buf,
+                 size_t size)
+{
+    char *dbuf;
+
+    if (gunzip_in_mem (fullname, buf, &size, &dbuf)) return 1;
+
+    if (write (fd, dbuf, size) < 0)
+    {
+       error (0, errno, "writing decompressed file %s", fullname);
+       free (dbuf);
+       return 1;
+    }
+
+    free (dbuf);
+    return 0;
+}
+
+
+
 /* Read all of FD and put the gzipped data (RFC1952/RFC1951) into *BUF,
    replacing previous contents of *BUF.  *BUF is xmalloc'd and *SIZE is
    its allocated size.  Put the actual number of bytes of data in
Index: ccvs/tools/Makefile.in
diff -u ccvs/tools/Makefile.in:1.86 ccvs/tools/Makefile.in:1.87
--- ccvs/tools/Makefile.in:1.86 Wed Apr 12 19:55:27 2006
+++ ccvs/tools/Makefile.in      Mon Apr 24 18:50:27 2006
@@ -62,8 +62,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -154,6 +154,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -169,6 +170,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/vms/Makefile.in
diff -u ccvs/vms/Makefile.in:1.89 ccvs/vms/Makefile.in:1.90
--- ccvs/vms/Makefile.in:1.89   Wed Apr 12 19:55:27 2006
+++ ccvs/vms/Makefile.in        Mon Apr 24 18:50:27 2006
@@ -65,8 +65,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -157,6 +157,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -172,6 +173,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/windows-NT/Makefile.in
diff -u ccvs/windows-NT/Makefile.in:1.118 ccvs/windows-NT/Makefile.in:1.119
--- ccvs/windows-NT/Makefile.in:1.118   Wed Apr 12 19:55:27 2006
+++ ccvs/windows-NT/Makefile.in Mon Apr 24 18:50:27 2006
@@ -66,8 +66,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -167,6 +167,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -182,6 +183,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/windows-NT/SCC/Makefile.in
diff -u ccvs/windows-NT/SCC/Makefile.in:1.80 
ccvs/windows-NT/SCC/Makefile.in:1.81
--- ccvs/windows-NT/SCC/Makefile.in:1.80        Wed Apr 12 19:55:27 2006
+++ ccvs/windows-NT/SCC/Makefile.in     Mon Apr 24 18:50:27 2006
@@ -63,8 +63,8 @@
        $(top_srcdir)/m4/acx_with_gssapi.m4 $(top_srcdir)/m4/alloca.m4 \
        $(top_srcdir)/m4/allocsa.m4 \
        $(top_srcdir)/m4/asx_version_compare.m4 \
-       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/bison.m4 \
-       $(top_srcdir)/m4/canon-host.m4 \
+       $(top_srcdir)/m4/atexit.m4 $(top_srcdir)/m4/base64.m4 \
+       $(top_srcdir)/m4/bison.m4 $(top_srcdir)/m4/canon-host.m4 \
        $(top_srcdir)/m4/canonicalize.m4 \
        $(top_srcdir)/m4/chdir-long.m4 $(top_srcdir)/m4/clock_time.m4 \
        $(top_srcdir)/m4/closeout.m4 $(top_srcdir)/m4/codeset.m4 \
@@ -155,6 +155,7 @@
 CPPFLAGS = @CPPFLAGS@
 CSH = @CSH@
 CYGPATH_W = @CYGPATH_W@
+DEFAULT_VERIFY_TEMPLATE = @DEFAULT_VERIFY_TEMPLATE@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 ECHO_C = @ECHO_C@
@@ -170,6 +171,7 @@
 GL_COND_LIBTOOL_FALSE = @GL_COND_LIBTOOL_FALSE@
 GL_COND_LIBTOOL_TRUE = @GL_COND_LIBTOOL_TRUE@
 GMSGFMT = @GMSGFMT@
+GPG = @GPG@
 HAVE_LONG_64BIT = @HAVE_LONG_64BIT@
 HAVE_LONG_LONG_64BIT = @HAVE_LONG_LONG_64BIT@
 HAVE__BOOL = @HAVE__BOOL@
Index: ccvs/windows-NT/config.h
diff -u ccvs/windows-NT/config.h:1.178 ccvs/windows-NT/config.h:1.179
--- ccvs/windows-NT/config.h:1.178      Wed Apr 12 19:55:27 2006
+++ ccvs/windows-NT/config.h    Mon Apr 24 18:50:27 2006
@@ -69,6 +69,25 @@
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
+/* Define to a command line template that will write an OpenPGP signature for
+   the file `%s' to its standard out. `%t' is substituted at run time with an
+   option which flags files as text files, when necessary, and the empty
+   string, otherwise. `%a' is substituted with a list of arguments provided by
+   the user. */
+#undef DEFAULT_SIGN_TEMPLATE
+
+/* Define to the option string that the OpenPGP program used in the
+   DEFAULT_SIGN_TEMPLATE would like to see for text files (substituted at run
+   time in place of `%t' in the DEFAULT_SIGN_TEMPLATE). */
+#undef DEFAULT_SIGN_TEXTMODE
+
+/* Define to a command line template that will read an OpenPGP signature from
+   the file `%s' and use it to verify the integrity of the file `%d'. `%t' is
+   substituted at run time with an option which flags files as text files,
+   when necessary, and the empty string, otherwise. `%a' is substituted with a
+   list of arguments provided by the user. */
+#undef DEFAULT_VERIFY_TEMPLATE
+
 /* Define if there is a member named d_ino in the struct describing directory
    headers. */
 #undef D_INO_IN_DIRENT
@@ -573,6 +592,11 @@
 /* Define to 1 if you have the `openat' function. */
 #undef HAVE_OPENAT
 
+/* Define if an OpenPGP capable program is available (and, assumedly, usable
+   command line templates are in the DEFAULT_SIGN_TEMPLATE and
+   DEFAULT_VERIFY_TEMPLATE macros). */
+#undef HAVE_OPENPGP
+
 /* Define to 1 if you have the <OS.h> header file. */
 #undef HAVE_OS_H
 
Index: ccvs/windows-NT/config.h.in
diff -u ccvs/windows-NT/config.h.in:1.106 ccvs/windows-NT/config.h.in:1.107
--- ccvs/windows-NT/config.h.in:1.106   Wed Apr 12 19:55:27 2006
+++ ccvs/windows-NT/config.h.in Mon Apr 24 18:50:27 2006
@@ -62,6 +62,25 @@
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
+/* Define to a command line template that will write an OpenPGP signature for
+   the file `%s' to its standard out. `%t' is substituted at run time with an
+   option which flags files as text files, when necessary, and the empty
+   string, otherwise. `%a' is substituted with a list of arguments provided by
+   the user. */
+#undef DEFAULT_SIGN_TEMPLATE
+
+/* Define to the option string that the OpenPGP program used in the
+   DEFAULT_SIGN_TEMPLATE would like to see for text files (substituted at run
+   time in place of `%t' in the DEFAULT_SIGN_TEMPLATE). */
+#undef DEFAULT_SIGN_TEXTMODE
+
+/* Define to a command line template that will read an OpenPGP signature from
+   the file `%s' and use it to verify the integrity of the file `%d'. `%t' is
+   substituted at run time with an option which flags files as text files,
+   when necessary, and the empty string, otherwise. `%a' is substituted with a
+   list of arguments provided by the user. */
+#undef DEFAULT_VERIFY_TEMPLATE
+
 /* Define if there is a member named d_ino in the struct describing directory
    headers. */
 #undef D_INO_IN_DIRENT
@@ -566,6 +585,11 @@
 /* Define to 1 if you have the `openat' function. */
 #undef HAVE_OPENAT
 
+/* Define if an OpenPGP capable program is available (and, assumedly, usable
+   command line templates are in the DEFAULT_SIGN_TEMPLATE and
+   DEFAULT_VERIFY_TEMPLATE macros). */
+#undef HAVE_OPENPGP
+
 /* Define to 1 if you have the <OS.h> header file. */
 #undef HAVE_OS_H
 
Index: ccvs/windows-NT/stamp-chi
diff -u ccvs/windows-NT/stamp-chi:1.92 ccvs/windows-NT/stamp-chi:1.93
--- ccvs/windows-NT/stamp-chi:1.92      Wed Apr 12 19:55:27 2006
+++ ccvs/windows-NT/stamp-chi   Mon Apr 24 18:50:27 2006
@@ -62,6 +62,25 @@
 /* Define to 1 if using `alloca.c'. */
 #undef C_ALLOCA
 
+/* Define to a command line template that will write an OpenPGP signature for
+   the file `%s' to its standard out. `%t' is substituted at run time with an
+   option which flags files as text files, when necessary, and the empty
+   string, otherwise. `%a' is substituted with a list of arguments provided by
+   the user. */
+#undef DEFAULT_SIGN_TEMPLATE
+
+/* Define to the option string that the OpenPGP program used in the
+   DEFAULT_SIGN_TEMPLATE would like to see for text files (substituted at run
+   time in place of `%t' in the DEFAULT_SIGN_TEMPLATE). */
+#undef DEFAULT_SIGN_TEXTMODE
+
+/* Define to a command line template that will read an OpenPGP signature from
+   the file `%s' and use it to verify the integrity of the file `%d'. `%t' is
+   substituted at run time with an option which flags files as text files,
+   when necessary, and the empty string, otherwise. `%a' is substituted with a
+   list of arguments provided by the user. */
+#undef DEFAULT_VERIFY_TEMPLATE
+
 /* Define if there is a member named d_ino in the struct describing directory
    headers. */
 #undef D_INO_IN_DIRENT
@@ -566,6 +585,11 @@
 /* Define to 1 if you have the `openat' function. */
 #undef HAVE_OPENAT
 
+/* Define if an OpenPGP capable program is available (and, assumedly, usable
+   command line templates are in the DEFAULT_SIGN_TEMPLATE and
+   DEFAULT_VERIFY_TEMPLATE macros). */
+#undef HAVE_OPENPGP
+
 /* Define to 1 if you have the <OS.h> header file. */
 #undef HAVE_OS_H
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]